NetBurner 3.5.6
PDF Version
TCP

TCP socket programming interface. More...

Topics

 TCP Notification System
 Advanced callback mechanism for asynchronous TCP socket event notification.
 
 TCP Socket Options
 Configuration flags for TCP socket behavior.
 
 TCP Socket State
 TCP connection state machine values (RFC 793)
 
 TCP Socket Status
 Status codes and error values for TCP socket operations.
 

Functions

int accept (int listening_socket, IPADDR *address, uint16_t *port, uint16_t timeout)
 Accept an incoming connection on a listening socket.
 
int accept (int listening_socket, IPADDR *address, uint16_t *port, TickTimeout &timeout)
 Accept an incoming connection on a listening socket with timeout object.
 
int connect (const IPADDR &ipAddress, uint16_t remotePort, uint32_t timeout)
 Establish a TCP connection to a remote host.
 
int connectvia (const IPADDR &ipAddress, uint16_t remotePort, uint32_t timeout, const IPADDR &localIpAddress)
 Establish a TCP connection using a specific local interface IP address.
 
int connectvia (const IPADDR &ipAddress, uint16_t remotePort, uint32_t timeout, int ifnum)
 Establish a TCP connection using a specific local interface number.
 
int connectwlocal (const IPADDR &ipAddress, uint16_t localPort, uint16_t remotePort, uint32_t timeout, const IPADDR &localIpAddress=IPADDR::NullIP(), int intf=-1)
 Establish a TCP connection with full control over local parameters.
 
int connect (const IPADDR &ipAddress, uint16_t remotePort, TickTimeout &timeout)
 Establish a TCP connection to a remote host with TickTimeout object.
 
int connectvia (const IPADDR &ipAddress, uint16_t remotePort, TickTimeout &timeout, const IPADDR &localIpAddress)
 Establish a TCP connection using a specific local interface IP with TickTimeout.
 
int connectvia (const IPADDR &ipAddress, uint16_t remotePort, TickTimeout &timeout, int ifnum)
 Establish a TCP connection using a specific local interface number with TickTimeout.
 
int connectwlocal (const IPADDR &ipAddress, uint16_t localPort, uint16_t remotePort, TickTimeout timeout, const IPADDR &localIpAddress=IPADDR::NullIP(), int intf=-1)
 Establish a TCP connection with full control over local parameters and TickTimeout.
 
int listen (const IPADDR &addr, uint16_t port, uint8_t maxpend=5)
 Create a listening socket to accept incoming TCP connections.
 
int listenvia (const IPADDR &addr, uint16_t port, int ifn, uint8_t maxpend=5)
 Create a listening socket on a specific network interface.
 
int listenvia (const IPADDR &addr, uint16_t port, const IPADDR &localIpAddress, uint8_t maxpend=5)
 Create a listening socket bound to a specific interface IP address.
 
int NoBlockConnect (const IPADDR &ipAddress, uint16_t remotePort)
 Initiate a non-blocking TCP connection.
 
int NoBlockConnectVia (const IPADDR &ipAddress, uint16_t remotePort, const IPADDR &interfaceIpAddress=IPADDR::NullIP())
 Initiate a non-blocking TCP connection via a specific interface.
 
int NoBlockConnectVia (const IPADDR &ipAddress, uint16_t remotePort, int ifnum)
 Initiate a non-blocking TCP connection via a specific interface number.
 
int NoBlockConnectwlocal (const IPADDR &ipAddress, uint16_t localPort, uint16_t remotePort, IPADDR interfaceIpAddress=IPADDR::NullIP(), int ifn=-1)
 Initiate a non-blocking TCP connection with full local parameter control.
 
int getsocketerror (int fd)
 Get the error status of a socket.
 
IPADDR GetSocketRemoteAddr (int fd)
 Get the remote host IP address for a socket connection.
 
IPADDR GetSocketLocalAddr (int fd)
 Get the local interface IP address for a socket connection.
 
uint16_t GetSocketRemotePort (int fd)
 Get the remote host port number for a socket connection.
 
uint16_t GetSocketLocalPort (int fd)
 Get the local port number for a socket connection.
 
uint32_t TcpGetLastRxTime (int fd)
 Get the system tick count when the last packet was received.
 
void TcpSendKeepAlive (int fd)
 Send a TCP keepalive probe packet.
 
uint32_t TcpGetLastRxInterval (int fd)
 Get the time elapsed since the last received packet.
 
int GetTcpRtxCount (int fd)
 Get the number of TCP retransmissions on a socket.
 
uint8_t SetOutOfOrderBuffers (int fd, uint8_t max)
 Configure the maximum number of out-of-order buffers for a TCP socket.
 
int setsockoption (int fd, int option)
 Enable TCP socket options.
 
int clrsockoption (int fd, int option)
 Disable TCP socket options.
 
int getsockoption (int fd)
 Query current TCP socket options.
 
int SetSocketUnackBuffers (int fd, uint8_t val)
 Configure the maximum number of unacknowledged transmit buffers.
 
int SetSocketRxBuffers (int fd, int n)
 Configure the number of TCP receive buffers.
 
int SetSocketTxBuffers (int fd, int n)
 Configure the number of TCP transmit buffers.
 
int abortsocket (int fd)
 Abort a TCP connection immediately.
 
int SockReadWithTimeout (int fd, char *buf, int nbytes, uint32_t timeout)
 Read from a TCP socket with a timeout.
 
char SocketPeek (int fd)
 Peek at the next available byte without removing it from the receive buffer.
 
void DumpTcpDebug ()
 Display current TCP debug information to the console.
 
void EnableTcpDebug (uint16_t dbFlags)
 Enable TCP debug output with specified flags.
 
int TcpGetSocketInterface (int fd)
 Get the network interface number associated with a TCP socket.
 
uint8_t TcpGetSocketState (int fd)
 Get the current TCP state of a socket.
 
uint16_t TcpGetRxBufferSpaceUsed (int fd)
 Get the number of bytes currently in the receive buffer.
 
uint16_t TcpGetTxBufferAvailSpace (int fd)
 Get the available space in the transmit buffer.
 
uint16_t TcpGetTxDataWaiting (int fd)
 Get the number of bytes queued for transmission.
 
BOOL TcpAllDataAcked (int socket)
 Check if all transmitted data has been acknowledged.
 
BOOL WaitForSocketFlush (int fd, uint32_t ticks)
 Wait for all transmitted data to be acknowledged.
 

Detailed Description

TCP socket programming interface.

#include< tcp.h>


Overview

The NetBurner TCP API provides a robust, Berkeley-sockets-style interface for TCP/IP networking with support for both blocking and non-blocking operations. This API is designed specifically for embedded systems and real-time applications, offering fine-grained control over socket behavior, buffer management, and connection state.

Key Features:

Basic Usage Patterns

The TCP API supports three primary usage patterns:

Server Pattern (Listen/Accept)

Create a listening socket to accept incoming client connections:

  1. Call listen() to create a listening socket on a specific port
  2. Call accept() to wait for and accept incoming connections
  3. Use read() / write() for data transfer on accepted connections
  4. Call close() when done with each connection

Client Pattern (Connect)

Establish an outbound connection to a remote server:

  1. Call connect() to establish a connection to a remote host
  2. Use read() / write() for data transfer
  3. Call close() when done with the connection

Non-Blocking Pattern

For applications requiring immediate return without waiting:

  1. Call NoBlockConnect() to initiate a connection
  2. Poll connection state with TcpGetSocketState() or writeavail()
  3. Once TCP_STATE_ESTABLISHED, use read() / write() for data transfer
  4. Register read/write notification callbacks for event-driven operation

Important Concepts

Entry Point

NetBurner applications start in UserMain(), not main(). Always call init() at the beginning of UserMain() to initialize the network stack before using TCP functions.

Timeout Values

Many functions accept timeout parameters in system ticks. Use the TICKS_PER_SECOND constant for conversion:

File Descriptors

TCP sockets are represented by integer file descriptors (fd). Functions that create sockets (listen(), accept(), connect()) return:

Always check return values:

int fd = connect(serverAddr, 80, TICKS_PER_SECOND * 5);
if (fd < 0) {
printf("Connection failed with error: %d\n", fd);
return;
}
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
int connect(const IPADDR &ipAddress, uint16_t remotePort, uint32_t timeout)
Establish a TCP connection to a remote host.
Definition tcp.h:1547

Buffer Management

TCP sockets use system buffer pools for transmit and receive operations. The default buffer allocation is conservative (5 buffers per socket) to support many simultaneous connections. For high-throughput applications, you can increase buffer allocations:

Socket States

TCP connections progress through well-defined states (RFC 793). Use TcpGetSocketState() to query the current state:

Resource Management

Always call close() on sockets when finished to free system resources. This applies even if the socket enters an error state or TCP_STATE_CLOSING. Failing to close sockets will leak file descriptors and network buffers.

Function Categories

Connection Management

Data Transfer

Socket Query Functions

Configuration Functions

Monitoring and Diagnostics

Event Notification

Throughput Monitoring (#define TCP_THROUGHPUT_INFO)

Error Handling

TCP functions use negative return values to indicate errors. Always check return values and handle errors appropriately:

Common error codes (see TCP Socket Status):

For detailed return code information, causes and solutions, see: Programmers Guide TCP Error Codes

Advanced Features

Multi-Interface Control

When multiple network interfaces are available, you can control which interface is used for connections:

Keepalive Implementation

Detect stale connections using the keepalive mechanism:

  1. Record lastRxTime with TcpGetLastRxTime()
  2. Send keepalive probe with TcpSendKeepAlive()
  3. Wait for response (2-3 seconds)
  4. Check if lastRxTime changed
  5. If unchanged, connection may be lost

Nagle Algorithm Control

The Nagle algorithm buffers small packets to improve efficiency but can add latency for interactive applications. Use SO_NONAGLE option to disable:

setsockoption(fd, SO_NONAGLE); // Disable Nagle, send immediately
int setsockoption(int fd, int option)
Enable TCP socket options.
#define SO_NONAGLE
Disable Nagle's algorithm (send data immediately without delay)
Definition tcp.h:11374

Event-Driven Programming

For event-driven architectures, register notification callbacks instead of polling:

void OnDataReady(int fd) {
char buffer[1024];
int n = read(fd, buffer, sizeof(buffer));
// Process data...
}
RegisterTCPReadNotify(fd, OnDataReady);
int read(int fd, char *buf, int nbytes)
Read data from a file descriptor (fd).
void RegisterTCPReadNotify(int tcpFd, tcp_notify_handler *notifyHandler)
Register a callback for read event notifications.

Best Practices

DO:

DON'T:

IPv6 Support

The TCP API conditionally compiles for IPv4-only (IPV4ONLY) or dual-stack IPv6 support. When IPv6 is enabled:

Performance Tuning

Bulk Data Transfer

For maximum throughput when transferring large amounts of data:

Low Latency

For interactive or real-time applications requiring minimal latency:

Many Simultaneous Connections

For servers handling many concurrent connections:

Thread Safety

The NetBurner TCP implementation is designed for use in a multi-threaded RTOS environment. However, individual socket operations are not automatically thread-safe:

Related APIs

The TCP API works in conjunction with other NetBurner APIs:

Further Reading

See also
TCP
TCP Socket Status
TCP Socket Options
TCP Socket State
TCP Notification System

Function Documentation

◆ abortsocket()

int abortsocket ( int fd)

#include <tcp.h>

Abort a TCP connection immediately.

Forcefully terminates a TCP connection by sending a RST (reset) packet to the remote host. Unlike a normal close(), this does not perform a graceful shutdown and any pending data will be lost. Use this only when you need to terminate a connection immediately without the normal shutdown handshake.

Parameters
fdSocket file descriptor
Returns
Status code: TCP Socket Status
See also
close()

Expand for Example Usage

Examples

Basic Usage - Aborting a Connection
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// Something went wrong, abort immediately
int result = abortsocket(fd);
if (result == TCP_ERR_NONE) {
printf("Connection aborted\n");
}
int abortsocket(int fd)
Abort a TCP connection immediately.
Timeout Handler - Aborting Unresponsive Connection
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
uint32_t startTime = Secs;
char response[100];
while (Secs - startTime < 30) { // 30 second timeout
int n = read(fd, response, sizeof(response));
if (n > 0) {
// Process response
break;
}
OSTimeDly(TICKS_PER_SECOND);
}
if (Secs - startTime >= 30) {
printf("Connection timeout, aborting...\n");
abortsocket(fd); // Force immediate termination
} else {
close(fd); // Normal graceful close
}
int close(int fd)
Close the specified file descriptor and free the associated resources.
Error Recovery - Abort vs Close
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if (write(fd, data, dataLen) < 0) {
// Critical error occurred
printf("Write failed, aborting connection\n");
abortsocket(fd); // RST - immediate termination, no graceful shutdown
} else {
// Normal operation complete
close(fd); // FIN - graceful shutdown with handshake
}
int write(int fd, const char *buf, int nbytes)
Write data to the stream associated with a file descriptor (fd). Can be used to write data to stdio,...
Protocol Violation - Immediate Abort
void HandleConnection(int clientFd) {
char buffer[256];
int n = read(clientFd, buffer, sizeof(buffer));
// Check for protocol violation
if (n > 0 && !IsValidProtocolHeader(buffer)) {
printf("Invalid protocol header detected\n");
abortsocket(clientFd); // Immediate abort for security
return;
}
// Normal processing...
ProcessRequest(buffer, n);
close(clientFd); // Graceful close for valid connections
}

◆ accept() [1/2]

int accept ( int listening_socket,
IPADDR * address,
uint16_t * port,
TickTimeout & timeout )

#include <tcp.h>

Accept an incoming connection on a listening socket with timeout object.

Accepts a pending connection request from the listen queue using a TickTimeout object for more flexible timeout management. The listening socket must have been created with listen() before calling this function. Each successful accept frees one slot in the listen queue for additional incoming connections.

This overload of accept() uses a TickTimeout object instead of a simple tick count, providing more sophisticated timeout behavior. The TickTimeout object can track elapsed time across multiple operations and provides precise timeout management for complex scenarios.

Parameters
listening_socketFile descriptor of the listening socket (obtained from listen())
addressPointer to IPADDR to store the remote client's IP address. Pass NULL if you don't need the client's IP address
portPointer to uint16_t to store the remote client's port number. Pass NULL if you don't need the client's port
timeoutReference to TickTimeout object specifying the maximum wait time. The TickTimeout tracks elapsed time and can be reused across multiple operations. Create with TickTimeout(ticks) where ticks is the total timeout period in system ticks
Returns
Positive file descriptor on success (use this for read/write with the client), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: No connection within timeout period
  • TCP_ERR_NOSUCH_SOCKET: Invalid listening socket
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool

Notes:

  • The TickTimeout object is updated by this function to reflect the remaining time. This allows multiple operations to share a common timeout budget.
  • Always call close() on the returned file descriptor when finished with the client connection to free system resources.
  • TickTimeout provides more accurate timeout tracking than simple tick counts, especially when performing multiple sequential operations with a shared deadline.
Warning
The timeout parameter is passed by reference and will be modified by this function. If you need to preserve the original timeout value, create a copy.

Expand for Example Usage

Examples

Basic Accept with TickTimeout
#include <tcp.h>
#include <init.h>
void ServerWithTickTimeout(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
printf("Server listening on port 8080\n");
// Create TickTimeout object for 30 second timeout
TickTimeout timeout(TICKS_PER_SECOND * 30);
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, timeout);
if (fdClient > 0) {
printf("Client connected from %s:%d\n",
clientAddr.print(), clientPort);
// Check remaining time in timeout
printf("Remaining timeout: %lu ticks\n", timeout.GetTimeLeft());
// Use connection...
close(fdClient);
} else if (fdClient == TCP_ERR_TIMEOUT) {
printf("No connection received within 30 seconds\n");
} else {
printf("Accept failed: %d\n", fdClient);
}
close(fdListen);
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition ipv6_addr.h:41
void print(bool bCompact=true, bool bShowV4Raw=false) const
Print the IP address value to stdout.
int accept(int listening_socket, IPADDR *address, uint16_t *port, uint16_t timeout)
Accept an incoming connection on a listening socket.
int listen(const IPADDR &addr, uint16_t port, uint8_t maxpend=5)
Create a listening socket to accept incoming TCP connections.
Definition tcp.h:6629
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...
#define TCP_ERR_TIMEOUT
Operation timed out before completion.
Definition tcp.h:355
Shared Timeout Across Multiple Operations
#include <tcp.h>
#include <init.h>
// Accept connection and perform handshake within total time budget
bool AcceptAndHandshake(int fdListen, uint32_t totalTimeoutTicks) {
// Create single TickTimeout for all operations
TickTimeout timeout(totalTimeoutTicks);
printf("Total timeout budget: %lu seconds\n", totalTimeoutTicks / TICKS_PER_SECOND);
// Step 1: Accept connection (uses part of timeout)
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, timeout);
if (fdClient < 0) {
printf("Accept failed: %d\n", fdClient);
return false;
}
printf("Client connected, remaining time: %lu ticks\n", timeout.GetTimeLeft());
// Step 2: Read handshake message (uses remaining timeout)
char handshake[64];
int n = ReadWithTimeout(fdClient, handshake, sizeof(handshake), timeout);
if (n <= 0) {
printf("Handshake read failed: %d\n", n);
close(fdClient);
return false;
}
printf("Handshake received, remaining time: %lu ticks\n", timeout.GetTimeLeft());
// Step 3: Send response (uses remaining timeout)
const char *response = "OK\r\n";
n = WriteWithTimeout(fdClient, response, strlen(response), timeout);
if (n <= 0) {
printf("Response write failed: %d\n", n);
close(fdClient);
return false;
}
printf("Handshake complete, time used: %lu ticks\n", totalTimeoutTicks - timeout.GetTimeLeft());
close(fdClient);
return true;
}
void UserMain(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
// Give entire handshake process 10 seconds to complete
bool success = AcceptAndHandshake(fdListen, TICKS_PER_SECOND * 10);
printf("Handshake %s\n", success ? "succeeded" : "failed");
close(fdListen);
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
int ReadWithTimeout(int fd, char *buf, int nbytes, unsigned long timeout)
Read data from a file descriptor(fd), or return if at least one byte is not read within the specified...
bool WaitForActiveNetwork(uint32_t ticks_to_wait=120 *TICKS_PER_SECOND, int interface=-1)
Wait for an active network connection on at least one interface.
Multiple Accept Attempts with Shared Timeout
#include <tcp.h>
#include <init.h>
// Try to accept connections from multiple clients within time limit
int AcceptMultipleClients(int fdListen, int maxClients, uint32_t totalTimeout) {
TickTimeout timeout(totalTimeout);
int clientFds[10];
int acceptedCount = 0;
printf("Accepting up to %d clients within %lu seconds\n",
maxClients, totalTimeout / TICKS_PER_SECOND);
while (acceptedCount < maxClients && !timeout.Expired()) {
IPADDR clientAddr;
uint16_t clientPort;
printf("Waiting for client %d (timeout left: %lu ticks)...\n",
acceptedCount + 1, timeout.GetTimeLeft());
int fdClient = accept(fdListen, &clientAddr, &clientPort, timeout);
if (fdClient > 0) {
clientFds[acceptedCount] = fdClient;
acceptedCount++;
printf(" Client %d connected: %s:%d\n", acceptedCount, clientAddr.print(), clientPort);
} else if (fdClient == TCP_ERR_TIMEOUT) {
printf(" Timeout reached\n");
break;
} else {
printf(" Accept error: %d\n", fdClient);
break;
}
}
printf("Accepted %d clients\n", acceptedCount);
// Broadcast message to all clients
char msg[64];
snprintf(msg, sizeof(msg), "Group of %d clients ready\r\n", acceptedCount);
for (int i = 0; i < acceptedCount; i++) {
write(clientFds[i], msg, strlen(msg));
close(clientFds[i]);
}
return acceptedCount;
}
void UserMain(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 9000, 5);
// Accept up to 5 clients within 60 seconds
int count = AcceptMultipleClients(fdListen, 5, TICKS_PER_SECOND * 60);
printf("Session complete with %d clients\n", count);
close(fdListen);
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Polling Loop with Decaying Timeout
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
void PollingServerWithTimeout(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
printf("Server listening on port 8080\n");
// Give server 5 minutes to handle all connections
TickTimeout serverTimeout(TICKS_PER_SECOND * 300);
int connectionCount = 0;
while (!serverTimeout.Expired()) {
// Calculate time spent so far
uint32_t elapsed = serverTimeout.GetElapsedTime();
uint32_t remaining = serverTimeout.GetTimeLeft();
printf("\n[%d connections] Elapsed: %lu s, Remaining: %lu s\n",
connectionCount,
elapsed / TICKS_PER_SECOND,
remaining / TICKS_PER_SECOND);
// Create short-term timeout for this accept attempt
TickTimeout acceptTimeout(TICKS_PER_SECOND * 5);
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, acceptTimeout);
if (fdClient > 0) {
connectionCount++;
printf("Client %d connected: %s:%d\n", connectionCount, clientAddr.print(), clientPort);
// Quick interaction
char buffer[256];
int n = read(fdClient, buffer, sizeof(buffer));
if (n > 0) {
write(fdClient, buffer, n);
}
close(fdClient);
} else if (fdClient == TCP_ERR_TIMEOUT) {
printf("No connection in last 5 seconds\n");
} else {
printf("Accept error: %d\n", fdClient);
}
// Check if we should continue
if (serverTimeout.GetTimeLeft() < (TICKS_PER_SECOND * 10)) {
printf("Less than 10 seconds remaining - final call\n");
}
}
printf("Server timeout reached after %d connections\n", connectionCount);
close(fdListen);
}
Timeout Monitoring and Adjustment
#include <tcp.h>
#include <init.h>
void AdaptiveTimeoutServer(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 7777, 5);
while (1) {
// Start with 30 second timeout
TickTimeout timeout(TICKS_PER_SECOND * 30);
IPADDR clientAddr;
uint16_t clientPort;
uint32_t startTicks = TimeTick;
int fdClient = accept(fdListen, &clientAddr, &clientPort, timeout);
uint32_t acceptDuration = TimeTick - startTicks;
if (fdClient > 0) {
printf("Client connected after %lu ticks (%lu ms)\n",
acceptDuration,
acceptDuration * 1000 / TICKS_PER_SECOND);
printf("Timeout had %lu ticks remaining\n", timeout.GetTimeLeft());
// Adjust future timeout based on how long this took
if (acceptDuration < (TICKS_PER_SECOND * 5)) {
printf("Fast connection - might reduce future timeout\n");
} else if (acceptDuration > (TICKS_PER_SECOND * 20)) {
printf("Slow connection - might increase future timeout\n");
}
close(fdClient);
} else if (fdClient == TCP_ERR_TIMEOUT) {
printf("Accept timeout - timeout object expired: %s\n", timeout.Expired() ? "yes" : "no");
printf("Time left: %lu ticks\n", timeout.GetTimeLeft());
}
}
}
Reusing TickTimeout Object Across Calls
#include <tcp.h>
#include <init.h>
void ReuseTimeoutExample(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
while (1) {
// Create fresh timeout for each iteration
TickTimeout timeout(TICKS_PER_SECOND * 20);
printf("\n=== New accept cycle ===\n");
printf("Initial timeout: %lu ticks\n", timeout.GetTimeLeft());
printf("Expired: %s\n", timeout.Expired() ? "yes" : "no");
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, timeout);
if (fdClient > 0) {
printf("Connection accepted\n");
printf("After accept - remaining: %lu ticks\n", timeout.GetTimeLeft());
printf("After accept - elapsed: %lu ticks\n", timeout.GetElapsedTime());
printf("After accept - expired: %s\n", timeout.Expired() ? "yes" : "no");
close(fdClient);
} else {
printf("Accept failed or timeout: %d\n", fdClient);
printf("Final timeout state - remaining: %lu ticks\n", timeout.GetTimeLeft());
printf("Final timeout state - expired: %s\n", timeout.Expired() ? "yes" : "no");
}
OSTimeDly(TICKS_PER_SECOND); // Brief pause between cycles
}
}
Connection Rate Limiting
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
// Accept connections with rate limiting
void RateLimitedServer(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
const int MAX_CONNECTIONS_PER_MINUTE = 10;
int connectionsThisMinute = 0;
// One minute window
TickTimeout windowTimeout(TICKS_PER_SECOND * 60);
while (1) {
// Reset counter when window expires
if (windowTimeout.Expired()) {
printf("Minute window expired - accepted %d connections\n", connectionsThisMinute);
connectionsThisMinute = 0;
windowTimeout.Reset(TICKS_PER_SECOND * 60);
}
// Check if we've hit the rate limit
if (connectionsThisMinute >= MAX_CONNECTIONS_PER_MINUTE) {
uint32_t waitTime = windowTimeout.GetTimeLeft();
printf("Rate limit reached - waiting %lu seconds\n", waitTime / TICKS_PER_SECOND);
OSTimeDly(waitTime);
continue;
}
// Accept with short timeout
TickTimeout acceptTimeout(TICKS_PER_SECOND * 2);
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, acceptTimeout);
if (fdClient > 0) {
connectionsThisMinute++;
printf("Connection %d/%d this minute from %s:%d\n",
connectionsThisMinute, MAX_CONNECTIONS_PER_MINUTE,
clientAddr.print(), clientPort);
// Handle connection...
close(fdClient);
}
}
}
Graceful Shutdown with Timeout
#include <tcp.h>
#include <init.h>
volatile bool g_shutdownRequested = false;
void GracefulShutdownServer(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
printf("Server started - will shutdown gracefully when requested\n");
while (!g_shutdownRequested) {
// Use short timeout so we check shutdown flag frequently
TickTimeout timeout(TICKS_PER_SECOND * 2);
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, timeout);
if (fdClient > 0) {
printf("Client connected: %s:%d\n", clientAddr.print(), clientPort);
// Check shutdown flag before processing
if (g_shutdownRequested) {
printf("Shutdown requested - rejecting client\n");
const char *msg = "Server shutting down\r\n";
write(fdClient, msg, strlen(msg));
close(fdClient);
break;
}
// Normal client handling...
close(fdClient);
} else if (fdClient == TCP_ERR_TIMEOUT) {
// Timeout is normal - gives us a chance to check shutdown flag
continue;
} else {
printf("Accept error: %d\n", fdClient);
}
}
close(fdListen);
printf("Server shutdown complete\n");
}

See also
listen(), close(), accept(int, IPADDR*, uint16_t*, uint16_t), TickTimeout

◆ accept() [2/2]

int accept ( int listening_socket,
IPADDR * address,
uint16_t * port,
uint16_t timeout )

#include <tcp.h>

Accept an incoming connection on a listening socket.

Accepts a pending connection request from the listen queue. The listening socket must have been created with listen() before calling this function. Each successful accept frees one slot in the listen queue for additional incoming connections.

This function blocks until either a connection arrives or the timeout expires. When a client connects, accept() returns a new socket file descriptor for communicating with that specific client. The original listening socket remains open and continues to accept new connections.

Parameters
listening_socketFile descriptor of the listening socket (obtained from listen())
addressPointer to IPADDR to store the remote client's IP address. Pass NULL if you don't need the client's IP address
portPointer to uint16_t to store the remote client's port number. Pass NULL if you don't need the client's port
timeoutMaximum wait time in system ticks:
  • 0 = wait indefinitely until a connection arrives
  • Use TICKS_PER_SECOND * n for n second timeout
  • Example: TICKS_PER_SECOND * 5 for 5 second timeout
  • Example: TICKS_PER_SECOND * 30 for 30 second timeout
Returns
Positive file descriptor on success (use this for read/write with the client), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: No connection within timeout period
  • TCP_ERR_NOSUCH_SOCKET: Invalid listening socket
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool

Notes:

  • Always call close() on the returned file descriptor when finished with the client connection to free system resources.
  • The listening socket is not consumed by accept() and can be used repeatedly to accept multiple client connections.
  • If you pass NULL for both address and port parameters, the function still works but you won't know which client connected.
Warning
  • When timeout is 0 (infinite wait), the calling task will block indefinitely until a connection arrives. Use finite timeouts in production code to prevent hanging tasks.
  • If the system runs out of available sockets (TCP_ERR_NONE_AVAIL), you must close existing sockets before new connections can be accepted.

Expand for Example Usage

Examples

Basic Accept with Infinite Wait
#include <tcp.h>
#include <init.h>
void ServerTask(void *pd) {
init();
// Create listening socket on port 8080
int fdListen = listen(INADDR_ANY, 8080, 5);
if (fdListen < 0) {
printf("Failed to create listening socket\n");
return;
}
printf("Server listening on port 8080\n");
// Accept connections (wait indefinitely)
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, 0);
if (fdClient > 0) {
printf("Client connected from %s:%d\n",
clientAddr.print(), clientPort);
// Communicate with client...
char buffer[256];
int n = read(fdClient, buffer, sizeof(buffer));
close(fdClient);
printf("Client disconnected\n");
}
close(fdListen);
}
Accept with Timeout
#include <tcp.h>
#include <init.h>
void ServerWithTimeout(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 9000, 5);
printf("Waiting for connection (30 second timeout)...\n");
IPADDR clientAddr;
uint16_t clientPort;
// Wait up to 30 seconds for a connection
int fdClient = accept(fdListen, &clientAddr, &clientPort,
if (fdClient == TCP_ERR_TIMEOUT) {
printf("No connection received within timeout period\n");
} else if (fdClient < 0) {
printf("Accept failed with error: %d\n", fdClient);
} else {
printf("Client connected: %s:%d\n",
clientAddr.print(), clientPort);
// Handle client connection...
close(fdClient);
}
close(fdListen);
}
Accept with Error Handling
#include <tcp.h>
#include <init.h>
void RobustAccept(int fdListen) {
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort,
// Comprehensive error handling
if (fdClient > 0) {
printf("Connection accepted from %s:%d (fd=%d)\n",
clientAddr.print(), clientPort, fdClient);
// Use connection...
close(fdClient);
} else {
// Handle specific error codes
switch (fdClient) {
printf("Accept timeout - no client connected within 60 seconds\n");
break;
printf("Invalid listening socket - was it closed?\n");
break;
printf("No sockets available - too many open connections!\n");
printf("Close unused sockets to free resources\n");
break;
printf("No connection on listening socket\n");
break;
default:
printf("Accept failed with error code: %d\n", fdClient);
break;
}
}
}
#define TCP_ERR_NOCON
No active connection exists on this socket.
Definition tcp.h:356
#define TCP_ERR_NOSUCH_SOCKET
The specified socket does not exist.
Definition tcp.h:358
#define TCP_ERR_NONE_AVAIL
No sockets available in the system pool.
Definition tcp.h:359

See also
listen(), close(), connect(), read(), write(), writeall(), readall()

◆ clrsockoption()

int clrsockoption ( int fd,
int option )

#include <tcp.h>

Disable TCP socket options.

Clears one or more option flags for the specified socket. Socket options control various aspects of TCP behavior such as the Nagle algorithm and PUSH flag handling. Multiple options can be combined using bitwise OR.

Parameters
fdSocket file descriptor
optionSocket option flags to disable: TCP Socket Options
Returns
Bitmask of all currently enabled options for the socket, or negative value on error

Notes:

  • This function does not affect options that are not specified in the parameter. Only the specified options are cleared.
  • After clearing options, the return value shows the remaining enabled options.
  • Multiple options can be cleared simultaneously using bitwise OR: clrsockoption(fd, SO_NODELAY | SO_PUSH);
See also
setsockoption(), getsockoption(), SetSocketUnackBuffers(), SetSocketRxBuffers(), SetSocketTxBuffers()

Expand for Example Usage

Examples

Re-enable Nagle Algorithm
#include <tcp.h>
#include <nbrtos.h>
void BulkTransferWithNagle(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Initially disable Nagle for handshake
setsockoption(fd, SO_NODELAY);
printf("SO_NODELAY enabled for handshake\r\n");
// Send handshake
const char *handshake = "READY\r\n";
write(fd, handshake, strlen(handshake));
// Read acknowledgment
char ack[64];
read(fd, ack, sizeof(ack) - 1, TICKS_PER_SECOND * 5);
// Now switch to bulk transfer mode - re-enable Nagle for efficiency
int result = clrsockoption(fd, SO_NODELAY);
if (result >= 0)
{
printf("SO_NODELAY disabled for bulk transfer\r\n");
printf("Nagle algorithm now active - current options: 0x%X\r\n", result);
}
// Send large amount of data efficiently with Nagle
char buffer[512];
for (int i = 0; i < 1000; i++)
{
snprintf(buffer, sizeof(buffer), "Data packet %d\r\n", i);
write(fd, buffer, strlen(buffer));
}
printf("Bulk transfer complete with Nagle optimization\r\n");
close(fd);
}
int clrsockoption(int fd, int option)
Disable TCP socket options.
Dynamic Option Management
#include <tcp.h>
#include <nbrtos.h>
void AdaptiveSocketOptions(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Start with low-latency configuration
setsockoption(fd, SO_NODELAY | SO_PUSH);
printf("Initial config: Low-latency mode\r\n");
// Send interactive commands
const char *cmd1 = "STATUS\r\n";
write(fd, cmd1, strlen(cmd1));
OSTimeDly(TICKS_PER_SECOND);
// Check if we're about to do bulk transfer
const char *cmd2 = "START_BULK\r\n";
write(fd, cmd2, strlen(cmd2));
// Switch to bulk transfer mode
printf("Switching to bulk transfer mode...\r\n");
// Clear low-latency options
int result = clrsockoption(fd, SO_NODELAY | SO_PUSH);
printf("Options cleared - remaining: 0x%X\r\n", result);
printf("Nagle algorithm and normal buffering now active\r\n");
// Perform bulk transfer with default TCP behavior
char data[1024];
for (int i = 0; i < 500; i++)
{
snprintf(data, sizeof(data), "BULK_DATA_%d", i);
write(fd, data, strlen(data));
}
close(fd);
}
Selective Option Clearing
#include <tcp.h>
#include <nbrtos.h>
void SelectiveOptionControl(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Enable multiple options
int options = SO_NODELAY | SO_PUSH | SO_KEEPALIVE;
int result = setsockoption(fd, options);
printf("Initial options: 0x%X\r\n", result);
printf(" SO_NODELAY: %s\r\n", (result & SO_NODELAY) ? "ON" : "OFF");
printf(" SO_PUSH: %s\r\n", (result & SO_PUSH) ? "ON" : "OFF");
printf(" SO_KEEPALIVE: %s\r\n", (result & SO_KEEPALIVE) ? "ON" : "OFF");
OSTimeDly(TICKS_PER_SECOND * 2);
// Clear only SO_NODELAY, keep others
result = clrsockoption(fd, SO_NODELAY);
printf("\r\nAfter clearing SO_NODELAY: 0x%X\r\n", result);
printf(" SO_NODELAY: %s\r\n", (result & SO_NODELAY) ? "ON" : "OFF");
printf(" SO_PUSH: %s\r\n", (result & SO_PUSH) ? "ON" : "OFF");
printf(" SO_KEEPALIVE: %s\r\n", (result & SO_KEEPALIVE) ? "ON" : "OFF");
close(fd);
}
Reset All Options to Default
#include <tcp.h>
#include <nbrtos.h>
void ResetSocketOptions(int fd)
{
// Get current options
int currentOptions = getsockoption(fd);
if (currentOptions < 0)
{
printf("Failed to get current options\r\n");
return;
}
printf("Current options: 0x%X\r\n", currentOptions);
if (currentOptions != 0)
{
// Clear all options
int result = clrsockoption(fd, currentOptions);
printf("All options cleared - remaining: 0x%X\r\n", result);
printf("Socket reset to default behavior\r\n");
}
else
{
printf("No options to clear - already at defaults\r\n");
}
}
void OptionResetExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Set various options
setsockoption(fd, SO_NODELAY | SO_PUSH);
printf("Options configured\r\n");
// Do some work...
const char *msg = "Test\r\n";
write(fd, msg, strlen(msg));
// Reset to defaults before closing
printf("\r\nResetting socket options...\r\n");
ResetSocketOptions(fd);
close(fd);
}
int getsockoption(int fd)
Query current TCP socket options.

◆ connect() [1/2]

int connect ( const IPADDR & ipAddress,
uint16_t remotePort,
TickTimeout & timeout )
inline

#include <tcp.h>

Establish a TCP connection to a remote host with TickTimeout object.

Creates a new TCP socket and attempts to connect to the specified remote IP address and port using a TickTimeout object for timeout management. This overload provides more sophisticated timeout tracking compared to the simple tick count version, allowing the timeout to be shared across multiple operations and providing precise elapsed time tracking.

The function automatically selects the local interface based on the routing table and assigns an available local port. The TickTimeout object is updated to reflect the remaining time after the connection attempt, enabling accurate timeout management across sequential operations.

Parameters
ipAddressIP address of the remote host. Can be created using AsciiToIp() or obtained from DNS resolution. Example: AsciiToIp("192.168.1.100")
remotePortPort number on the remote host (1-65535). Common ports include:
  • 80 for HTTP
  • 443 for HTTPS
  • 23 for Telnet
  • 22 for SSH
timeoutReference to TickTimeout object specifying the maximum wait time. The TickTimeout tracks elapsed time and can be reused across multiple operations. Create with TickTimeout(ticks) where ticks is the total timeout period in system ticks. The object is updated by this function to reflect remaining time
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:

  • The TickTimeout object is updated by this function to reflect the remaining time. This allows multiple operations to share a common timeout budget.
  • The local port number is automatically assigned from the ephemeral port range.
  • The local network interface is automatically selected based on the routing table for the destination IP address.
  • Always call close() on the returned file descriptor when finished to free system resources, even if read/write operations fail.
  • This function blocks the calling task until the connection is established or the timeout expires. For non-blocking connection attempts, use NoBlockConnect().
  • TickTimeout provides more accurate timeout tracking than simple tick counts, especially when performing multiple sequential operations with a shared deadline.
Warning
The timeout parameter is passed by reference and will be modified by this function. If you need to preserve the original timeout value, create a copy.
Connection timeouts that are too short (less than 3 seconds) may fail on networks with moderate latency. Use at least 5 seconds for reliable operation.

Expand for Example Usage

Examples

Basic Connection with TickTimeout
#include <tcp.h>
#include <init.h>
void ConnectWithTickTimeout(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Create TickTimeout for 15 second timeout
TickTimeout timeout(TICKS_PER_SECOND * 15);
printf("Connecting with 15 second timeout...\n");
printf("Initial timeout: %lu ticks\n", timeout.GetTimeLeft());
int fd = connect(serverAddr, 8080, timeout);
if (fd > 0) {
printf("Connected successfully!\n");
printf("Connection time: %lu ticks\n", timeout.GetElapsedTime());
printf("Remaining timeout: %lu ticks\n", timeout.GetTimeLeft());
close(fd);
} else {
printf("Connection failed: %d\n", fd);
printf("Time spent: %lu ticks\n", timeout.GetElapsedTime());
}
}
Shared Timeout Across Multiple Operations
#include <tcp.h>
#include <init.h>
#include <utils.h>
// Connect and perform complete handshake within total time budget
bool ConnectAndHandshake(IPADDR serverAddr, uint16_t port,
uint32_t totalTimeoutTicks) {
// Create single TickTimeout for entire operation sequence
TickTimeout timeout(totalTimeoutTicks);
printf("Total time budget: %lu seconds\n",
totalTimeoutTicks / TICKS_PER_SECOND);
// Step 1: Connect (uses part of timeout)
printf("\nStep 1: Connecting...\n");
int fd = connect(serverAddr, port, timeout);
if (fd < 0) {
printf("Connection failed: %d\n", fd);
return false;
}
printf("Connected! Remaining time: %lu ticks\n", timeout.GetTimeLeft());
// Step 2: Send handshake (uses remaining timeout)
printf("\nStep 2: Sending handshake...\n");
const char *handshake = "HELLO\r\n";
int sent = WriteWithTimeout(fd, handshake, strlen(handshake), timeout);
if (sent != strlen(handshake)) {
printf("Handshake send failed\n");
close(fd);
return false;
}
printf("Handshake sent! Remaining time: %lu ticks\n", timeout.GetTimeLeft());
// Step 3: Receive response (uses remaining timeout)
printf("\nStep 3: Receiving response...\n");
char response[64];
int received = ReadWithTimeout(fd, response, sizeof(response), timeout);
if (received <= 0) {
printf("Response read failed\n");
close(fd);
return false;
}
response[received] = '\0';
printf("Received: %s\n", response);
printf("Remaining time: %lu ticks\n", timeout.GetTimeLeft());
// Summary
uint32_t totalUsed = timeout.GetElapsedTime();
printf("\n=== Summary ===\n");
printf("Total time used: %lu ticks (%.1f seconds)\n",
totalUsed, (float)totalUsed / TICKS_PER_SECOND);
printf("Time remaining: %lu ticks\n", timeout.GetTimeLeft());
printf("Handshake successful!\n");
close(fd);
return true;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Give entire sequence 20 seconds to complete
bool success = ConnectAndHandshake(serverAddr, 8080, TICKS_PER_SECOND * 20);
printf("\nOperation %s\n", success ? "SUCCEEDED" : "FAILED");
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Multiple Connection Attempts with Shared Timeout
#include <tcp.h>
#include <init.h>
// Try connecting to multiple backup servers within time limit
int ConnectToAnyServer(IPADDR servers[], int numServers,
uint16_t port, uint32_t totalTimeout) {
TickTimeout timeout(totalTimeout);
printf("Trying %d servers with total timeout of %lu seconds\n",
numServers, totalTimeout / TICKS_PER_SECOND);
for (int i = 0; i < numServers && !timeout.Expired(); i++) {
printf("\nAttempt %d: Connecting to %s...",
i + 1, servers[i].print());
printf(" (time left: %lu ticks)\n", timeout.GetTimeLeft());
int fd = connect(servers[i], port, timeout);
if (fd > 0) {
printf("Success! Connected to %s\n", servers[i].print());
printf("Total time used: %lu ticks\n", timeout.GetElapsedTime());
return fd;
}
printf("Failed: %d\n", fd);
}
if (timeout.Expired()) {
printf("\nTimeout expired after trying %d servers\n", numServers);
} else {
printf("\nAll %d servers failed\n", numServers);
}
return -1;
}
void UserMain(void *pd) {
init();
// Array of backup servers
IPADDR servers[] = {
AsciiToIp("192.168.1.10"), // Primary
AsciiToIp("192.168.1.20"), // Backup 1
AsciiToIp("192.168.1.30"), // Backup 2
AsciiToIp("192.168.1.40") // Backup 3
};
// Try all servers within 30 seconds total
int fd = ConnectToAnyServer(servers, 4, 8080, TICKS_PER_SECOND * 30);
if (fd > 0) {
// Use connection...
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
void print(const char *str)
Write out a zero-terminated, unbuffered string.
Connection with Performance Monitoring
#include <tcp.h>
#include <init.h>
void MonitorConnectionPerformance(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Test with different timeout values
uint32_t timeouts[] = {
};
for (int i = 0; i < 3; i++) {
TickTimeout timeout(timeouts[i]);
uint32_t timeoutSecs = timeouts[i] / TICKS_PER_SECOND;
printf("\n=== Test %d: %lu second timeout ===\n", i + 1, timeoutSecs);
uint32_t startTick = TimeTick;
int fd = connect(serverAddr, 8080, timeout);
uint32_t endTick = TimeTick;
uint32_t actualTicks = endTick - startTick;
uint32_t actualMs = (actualTicks * 1000) / TICKS_PER_SECOND;
if (fd > 0) {
printf("SUCCESS\n");
printf(" Connection time: %lu ms\n", actualMs);
printf(" Timeout object elapsed: %lu ticks\n",
timeout.GetElapsedTime());
printf(" Timeout object remaining: %lu ticks\n",
timeout.GetTimeLeft());
printf(" Timeout expired: %s\n",
timeout.Expired() ? "yes" : "no");
// Check efficiency
float efficiency = ((float)actualTicks / timeouts[i]) * 100.0f;
printf(" Timeout efficiency: %.1f%%\n", efficiency);
close(fd);
} else {
printf("FAILED: %d\n", fd);
printf(" Time spent: %lu ms\n", actualMs);
printf(" Timeout expired: %s\n",
timeout.Expired() ? "yes" : "no");
}
OSTimeDly(TICKS_PER_SECOND * 2);
}
}
Timeout Budget Management
#include <tcp.h>
#include <init.h>
// Manage a time budget for multiple connection attempts
void TimebudgetedConnections(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// 60 second total budget
TickTimeout totalBudget(TICKS_PER_SECOND * 60);
int successfulConnections = 0;
int failedConnections = 0;
printf("Starting connection attempts with 60 second total budget\n\n");
int attempt = 0;
while (!totalBudget.Expired()) {
attempt++;
uint32_t remainingTime = totalBudget.GetTimeLeft();
printf("Attempt %d (budget remaining: %lu sec)\n",
attempt, remainingTime / TICKS_PER_SECOND);
// Each attempt gets its own 5 second timeout
TickTimeout attemptTimeout(TICKS_PER_SECOND * 5);
int fd = connect(serverAddr, 8080, attemptTimeout);
if (fd > 0) {
successfulConnections++;
printf(" Connected! (took %lu ticks)\n",
attemptTimeout.GetElapsedTime());
// Do some work
const char *msg = "PING\r\n";
write(fd, msg, strlen(msg));
close(fd);
} else {
failedConnections++;
printf(" Failed: %d\n", fd);
}
// Small delay between attempts
if (!totalBudget.Expired()) {
OSTimeDly(TICKS_PER_SECOND * 2);
}
}
printf("\n=== Summary ===\n");
printf("Total attempts: %d\n", attempt);
printf("Successful: %d\n", successfulConnections);
printf("Failed: %d\n", failedConnections);
printf("Time budget exhausted: %lu ticks used\n",
totalBudget.GetElapsedTime());
}
Connection Retry with Exponential Backoff
#include <tcp.h>
#include <init.h>
// Retry connection with exponential backoff, respecting total timeout
int ConnectWithBackoff(IPADDR serverAddr, uint16_t port,
uint32_t totalTimeoutTicks) {
TickTimeout timeout(totalTimeoutTicks);
uint32_t attemptTimeout = TICKS_PER_SECOND * 3; // Start with 3 seconds
int attempt = 0;
printf("Connecting with exponential backoff\n");
printf("Total timeout: %lu seconds\n\n",
totalTimeoutTicks / TICKS_PER_SECOND);
while (!timeout.Expired()) {
attempt++;
// Don't let attempt timeout exceed remaining time
uint32_t remainingTime = timeout.GetTimeLeft();
uint32_t thisAttemptTimeout = (attemptTimeout < remainingTime) ?
attemptTimeout : remainingTime;
printf("Attempt %d: timeout = %lu sec, remaining = %lu sec\n",
attempt,
thisAttemptTimeout / TICKS_PER_SECOND,
remainingTime / TICKS_PER_SECOND);
TickTimeout attemptTimer(thisAttemptTimeout);
int fd = connect(serverAddr, port, attemptTimer);
if (fd > 0) {
printf("Success on attempt %d!\n", attempt);
return fd;
}
printf(" Failed: %d\n", fd);
// Exponential backoff (double the timeout, max 30 seconds)
attemptTimeout *= 2;
if (attemptTimeout > TICKS_PER_SECOND * 30) {
attemptTimeout = TICKS_PER_SECOND * 30;
}
// Brief pause before retry
if (!timeout.Expired()) {
OSTimeDly(TICKS_PER_SECOND);
}
}
printf("All attempts exhausted after %d tries\n", attempt);
return -1;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Try for up to 2 minutes total
int fd = ConnectWithBackoff(serverAddr, 8080, TICKS_PER_SECOND * 120);
if (fd > 0) {
// Use connection...
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Comparing TickTimeout vs Simple Timeout
#include <tcp.h>
#include <init.h>
void CompareTimeoutMethods(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Method 1: Simple timeout (uint32_t)
printf("=== Method 1: Simple Timeout ===\n");
uint32_t startTime1 = Secs;
int fd1 = connect(serverAddr, 8080, TICKS_PER_SECOND * 10);
uint32_t elapsed1 = Secs - startTime1;
if (fd1 > 0) {
printf("Connected in %lu seconds\n", elapsed1);
printf("Cannot determine remaining timeout\n");
printf("Cannot track elapsed time precisely\n");
close(fd1);
}
OSTimeDly(TICKS_PER_SECOND * 2);
// Method 2: TickTimeout object
printf("\n=== Method 2: TickTimeout Object ===\n");
TickTimeout timeout(TICKS_PER_SECOND * 10);
printf("Initial state:\n");
printf(" Time left: %lu ticks\n", timeout.GetTimeLeft());
printf(" Expired: %s\n\n", timeout.Expired() ? "yes" : "no");
int fd2 = connect(serverAddr, 8080, timeout);
if (fd2 > 0) {
printf("Connected!\n");
printf("After connection:\n");
printf(" Elapsed time: %lu ticks (%.2f seconds)\n",
timeout.GetElapsedTime(),
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf(" Time left: %lu ticks (%.2f seconds)\n",
timeout.GetTimeLeft(),
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
printf(" Expired: %s\n", timeout.Expired() ? "yes" : "no");
printf("\nAdvantages of TickTimeout:\n");
printf(" - Precise elapsed time tracking\n");
printf(" - Remaining time available\n");
printf(" - Can be shared across operations\n");
printf(" - Explicit expiration checking\n");
close(fd2);
}
}
Real-World Application: Multi-Step Protocol Handshake
#include <tcp.h>
#include <init.h>
#include <utils.h>
// Complex protocol with multiple request/response exchanges
bool PerformProtocolHandshake(IPADDR serverAddr, uint16_t port) {
// Give entire protocol handshake 30 seconds
TickTimeout protocolTimeout(TICKS_PER_SECOND * 30);
printf("Starting protocol handshake (30 second timeout)\n\n");
// Phase 1: Connect
printf("Phase 1: Connecting...\n");
int fd = connect(serverAddr, port, protocolTimeout);
if (fd < 0) {
printf("Connection failed: %d\n", fd);
return false;
}
printf("Connected (%.1f sec elapsed, %.1f sec remaining)\n\n",
(float)protocolTimeout.GetElapsedTime() / TICKS_PER_SECOND,
(float)protocolTimeout.GetTimeLeft() / TICKS_PER_SECOND);
// Phase 2: Send HELLO
printf("Phase 2: Sending HELLO...\n");
const char *hello = "HELLO v1.0\r\n";
if (WriteWithTimeout(fd, hello, strlen(hello), protocolTimeout) < 0) {
printf("HELLO send failed\n");
close(fd);
return false;
}
printf("HELLO sent (%.1f sec remaining)\n\n",
(float)protocolTimeout.GetTimeLeft() / TICKS_PER_SECOND);
// Phase 3: Receive HELLO_ACK
printf("Phase 3: Receiving HELLO_ACK...\n");
char ackBuf[64];
int n = ReadWithTimeout(fd, ackBuf, sizeof(ackBuf), protocolTimeout);
if (n <= 0) {
printf("HELLO_ACK receive failed\n");
close(fd);
return false;
}
ackBuf[n] = '\0';
printf("Received: %s", ackBuf);
printf("(%.1f sec remaining)\n\n",
(float)protocolTimeout.GetTimeLeft() / TICKS_PER_SECOND);
// Phase 4: Send AUTH
printf("Phase 4: Sending AUTH...\n");
const char *auth = "AUTH user:pass\r\n";
if (WriteWithTimeout(fd, auth, strlen(auth), protocolTimeout) < 0) {
printf("AUTH send failed\n");
close(fd);
return false;
}
printf("AUTH sent (%.1f sec remaining)\n\n",
(float)protocolTimeout.GetTimeLeft() / TICKS_PER_SECOND);
// Phase 5: Receive AUTH_OK
printf("Phase 5: Receiving AUTH_OK...\n");
n = ReadWithTimeout(fd, ackBuf, sizeof(ackBuf), protocolTimeout);
if (n <= 0) {
printf("AUTH_OK receive failed\n");
close(fd);
return false;
}
ackBuf[n] = '\0';
printf("Received: %s", ackBuf);
// Summary
printf("\n=== Handshake Complete ===\n");
printf("Total time: %.1f seconds\n",
(float)protocolTimeout.GetElapsedTime() / TICKS_PER_SECOND);
printf("Time budget remaining: %.1f seconds\n",
(float)protocolTimeout.GetTimeLeft() / TICKS_PER_SECOND);
printf("Success!\n");
close(fd);
return true;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
bool success = PerformProtocolHandshake(serverAddr, 9000);
printf("\nProtocol handshake %s\n", success ? "SUCCEEDED" : "FAILED");
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}

See also
connect(const IPADDR&, uint16_t, uint32_t), connectvia(), connectwlocal(), NoBlockConnect(), TickTimeout, ReadWithTimeout(), WriteWithTimeout()

◆ connect() [2/2]

int connect ( const IPADDR & ipAddress,
uint16_t remotePort,
uint32_t timeout )
inline

#include <tcp.h>

Establish a TCP connection to a remote host.

Creates a new TCP socket and attempts to connect to the specified remote IP address and port. This is a blocking call that waits up to the specified timeout period for the connection to be established. The function automatically selects the local interface based on the routing table and assigns an available local port.

This is the most commonly used function for establishing outbound TCP connections. The operating system automatically selects the appropriate local interface and port number based on the destination address and routing configuration.

Parameters
ipAddressIP address of the remote host. Can be created using AsciiToIp() or obtained from DNS resolution. Example: AsciiToIp("192.168.1.100")
remotePortPort number on the remote host (1-65535). Common ports include:
  • 80 for HTTP
  • 443 for HTTPS
  • 23 for Telnet
  • 22 for SSH
timeoutMaximum connection time in system ticks. Use TICKS_PER_SECOND macro:
  • TICKS_PER_SECOND * 5 for 5 second timeout
  • TICKS_PER_SECOND * 10 for 10 second timeout
  • TICKS_PER_SECOND * 30 for 30 second timeout Typical timeout values are 5-30 seconds
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:

  • The local port number is automatically assigned from the ephemeral port range. You should not attempt to control the local port unless you have a specific protocol requirement (see connectwlocal() for that use case).
  • The local network interface is automatically selected based on the routing table for the destination IP address. For multi-homed systems where you need to control which interface is used, see connectvia().
  • Always call close() on the returned file descriptor when finished to free system resources, even if read/write operations fail.
  • This function blocks the calling task until the connection is established or the timeout expires. For non-blocking connection attempts, use NoBlockConnect().
Warning
  • Connection timeouts that are too short (less than 3 seconds) may fail on networks with moderate latency. Use at least 5 seconds for reliable operation.
  • If the remote host is unreachable (network down, host down, firewall blocking), the function will wait the full timeout period before returning an error.

Expand for Example Usage

Examples

Basic HTTP Client Connection
#include <tcp.h>
#include <init.h>
void SimpleHttpClient(void *pd) {
init();
// Connect to web server
IPADDR serverAddr = AsciiToIp("93.184.216.34"); // example.com
int fd = connect(serverAddr, 80, TICKS_PER_SECOND * 10);
if (fd < 0) {
printf("Connection failed: %d\n", fd);
return;
}
printf("Connected to server!\n");
// Send HTTP GET request
const char *request =
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: close\r\n"
"\r\n";
writeall(fd, request, strlen(request));
// Read response
char buffer[512];
int n = read(fd, buffer, sizeof(buffer) - 1);
if (n > 0) {
buffer[n] = '\0';
printf("Received:\n%s\n", buffer);
}
close(fd);
printf("Connection closed\n");
}
int writeall(int fd, const char *buf, int nbytes=0)
Write the specified number of bytes to a file descriptor. Will block until all bytes are sent,...
Connection with Error Handling
#include <tcp.h>
#include <init.h>
int ConnectWithRetry(IPADDR serverAddr, uint16_t port, int maxAttempts) {
int attempt = 0;
while (attempt < maxAttempts) {
attempt++;
printf("Connection attempt %d/%d to %s:%d\n",
attempt, maxAttempts, serverAddr.print(), port);
int fd = connect(serverAddr, port, TICKS_PER_SECOND * 10);
if (fd > 0) {
printf("Connection successful on attempt %d\n", attempt);
return fd;
}
// Handle specific error codes
switch (fd) {
printf(" Timeout - server not responding\n");
break;
printf(" No sockets available - waiting for resources\n");
OSTimeDly(TICKS_PER_SECOND * 5);
break;
printf(" Connection reset by server\n");
break;
printf(" Connection aborted\n");
break;
default:
printf(" Unknown error: %d\n", fd);
break;
}
if (attempt < maxAttempts) {
printf(" Retrying in 2 seconds...\n");
OSTimeDly(TICKS_PER_SECOND * 2);
}
}
printf("Failed to connect after %d attempts\n", maxAttempts);
return -1;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int fd = ConnectWithRetry(serverAddr, 8080, 3);
if (fd > 0) {
// Use connection...
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
#define TCP_ERR_CON_RESET
Connection was reset by remote host.
Definition tcp.h:360
#define TCP_ERR_CON_ABORT
Connection was aborted.
Definition tcp.h:361
Telnet Client Example
#include <tcp.h>
#include <init.h>
#include <utils.h>
void TelnetClient(const char *hostname, uint16_t port) {
// Resolve hostname to IP
IPADDR serverAddr = AsciiToIp(hostname);
if (serverAddr == IPADDR::NullIP()) {
printf("Invalid hostname: %s\n", hostname);
return;
}
printf("Connecting to %s:%d...\n", hostname, port);
// Connect to telnet server
int fd = connect(serverAddr, port, TICKS_PER_SECOND * 15);
if (fd < 0) {
printf("Connection failed: %d\n", fd);
return;
}
printf("Connected! Remote: %s:%d, Local: %s:%d\n",
// Send command
const char *command = "help\r\n";
writeall(fd, command, strlen(command));
// Read response (simple version)
char buffer[1024];
int totalRead = 0;
while (1) {
int n = read(fd, buffer, sizeof(buffer) - 1);
if (n <= 0) break;
buffer[n] = '\0';
printf("%s", buffer);
totalRead += n;
if (n < sizeof(buffer) - 1) break; // No more data available
}
printf("\nTotal received: %d bytes\n", totalRead);
close(fd);
}
static IPADDR6 NullIP()
Static function to return a null IPADDR6 object.
uint16_t GetSocketLocalPort(int fd)
Get the local port number for a socket connection.
IPADDR GetSocketLocalAddr(int fd)
Get the local interface IP address for a socket connection.
Definition tcp.h:9470
uint16_t GetSocketRemotePort(int fd)
Get the remote host port number for a socket connection.
IPADDR GetSocketRemoteAddr(int fd)
Get the remote host IP address for a socket connection.
Definition tcp.h:9393
Multiple Sequential Connections
#include <tcp.h>
#include <init.h>
// Connect to multiple servers in sequence
void SequentialConnections(void *pd) {
init();
// List of servers to connect to
struct ServerInfo {
const char *name;
IPADDR addr;
uint16_t port;
};
ServerInfo servers[] = {
{"Web Server", AsciiToIp("192.168.1.10"), 80},
{"Database", AsciiToIp("192.168.1.20"), 5432},
{"API Server", AsciiToIp("192.168.1.30"), 8080},
{"Sensor Node", AsciiToIp("192.168.1.40"), 9000}
};
int numServers = sizeof(servers) / sizeof(servers[0]);
int successCount = 0;
printf("Checking connectivity to %d servers...\n\n", numServers);
for (int i = 0; i < numServers; i++) {
printf("[%d/%d] Connecting to %s (%s:%d)...",
i + 1, numServers,
servers[i].name,
servers[i].addr.print(),
servers[i].port);
uint32_t startTime = Secs;
int fd = connect(servers[i].addr, servers[i].port,
uint32_t elapsed = Secs - startTime;
if (fd > 0) {
printf(" OK (%lu sec)\n", elapsed);
successCount++;
close(fd);
} else {
printf(" FAILED (error %d after %lu sec)\n", fd, elapsed);
}
}
printf("\nConnectivity check complete: %d/%d successful\n",
successCount, numServers);
}
Timeout Comparison
#include <tcp.h>
#include <init.h>
// Test different timeout values
void TimeoutComparison(void *pd) {
init();
// Try connecting to unreachable host with different timeouts
IPADDR unreachable = AsciiToIp("10.255.255.1"); // Typically unreachable
uint32_t timeouts[] = {
TICKS_PER_SECOND * 3, // 3 seconds
TICKS_PER_SECOND * 5, // 5 seconds
TICKS_PER_SECOND * 10, // 10 seconds
TICKS_PER_SECOND * 30 // 30 seconds
};
for (int i = 0; i < 4; i++) {
uint32_t timeoutSecs = timeouts[i] / TICKS_PER_SECOND;
printf("\nAttempting connection with %lu second timeout...\n",
timeoutSecs);
uint32_t startTime = Secs;
int fd = connect(unreachable, 80, timeouts[i]);
uint32_t actualTime = Secs - startTime;
if (fd < 0) {
printf(" Failed: %d\n", fd);
printf(" Expected timeout: %lu seconds\n", timeoutSecs);
printf(" Actual time: %lu seconds\n", actualTime);
printf(" Difference: %ld seconds\n",
(long)(actualTime - timeoutSecs));
} else {
printf(" Unexpectedly succeeded!\n");
close(fd);
}
}
}
Simple Data Exchange Client
#include <tcp.h>
#include <init.h>
#include <utils.h>
bool SendCommand(IPADDR server, uint16_t port,
const char *command, char *response, int responseSize) {
// Connect to server
int fd = connect(server, port, TICKS_PER_SECOND * 10);
if (fd < 0) {
printf("Connection failed: %d\n", fd);
return false;
}
printf("Connected to %s:%d\n", server.print(), port);
// Send command
int sent = writeall(fd, command, strlen(command));
if (sent != strlen(command)) {
printf("Write failed\n");
close(fd);
return false;
}
printf("Sent: %s", command);
// Read response with timeout
int n = ReadWithTimeout(fd, response, responseSize - 1,
close(fd);
if (n > 0) {
response[n] = '\0';
printf("Received: %s\n", response);
return true;
}
printf("Read failed or timeout\n");
return false;
}
void UserMain(void *pd) {
init();
IPADDR server = AsciiToIp("192.168.1.100");
char response[256];
if (SendCommand(server, 9000, "GET STATUS\r\n", response, sizeof(response))) {
printf("Command successful\n");
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Connection Monitoring
#include <tcp.h>
#include <init.h>
void MonitoredConnection(void *pd) {
init();
IPADDR server = AsciiToIp("192.168.1.100");
uint16_t port = 8080;
printf("Attempting connection to %s:%d\n", server.print(), port);
printf("Timeout: 15 seconds\n");
// Record start time
uint32_t startTick = TimeTick;
int fd = connect(server, port, TICKS_PER_SECOND * 15);
uint32_t elapsedTicks = TimeTick - startTick;
uint32_t elapsedMs = (elapsedTicks * 1000) / TICKS_PER_SECOND;
if (fd > 0) {
printf("\n=== Connection Successful ===\n");
printf(" Connection time: %lu ms\n", elapsedMs);
printf(" Local endpoint: %s:%d\n",
printf(" Remote endpoint: %s:%d\n",
printf(" Socket state: %d\n", TcpGetSocketState(fd));
printf(" File descriptor: %d\n", fd);
// Test write availability
int writeSpace = writeavail(fd);
printf(" Write space: %d bytes\n", writeSpace);
close(fd);
printf("\nConnection closed\n");
} else {
printf("\n=== Connection Failed ===\n");
printf(" Error code: %d\n", fd);
printf(" Time taken: %lu ms\n", elapsedMs);
if (fd == TCP_ERR_TIMEOUT) {
printf(" Diagnosis: Server did not respond within timeout\n");
printf(" Suggestions:\n");
printf(" - Verify server is running\n");
printf(" - Check network connectivity\n");
printf(" - Verify firewall rules\n");
printf(" - Try longer timeout\n");
}
}
}
int writeavail(int fd)
Check the specified file descriptor to determine data can be written.
uint8_t TcpGetSocketState(int fd)
Get the current TCP state of a socket.
Persistent Connection with Reconnect
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
// Maintain persistent connection with automatic reconnect
void PersistentClient(void *pd) {
init();
IPADDR server = AsciiToIp("192.168.1.100");
uint16_t port = 9000;
int fd = -1;
printf("Starting persistent client to %s:%d\n",
server.print(), port);
while (1) {
// Establish connection if needed
if (fd < 0) {
printf("Connecting...\n");
fd = connect(server, port, TICKS_PER_SECOND * 10);
if (fd < 0) {
printf("Connection failed: %d, retrying in 5 seconds\n", fd);
OSTimeDly(TICKS_PER_SECOND * 5);
continue;
}
printf("Connected successfully\n");
}
// Use connection
const char *heartbeat = "PING\r\n";
int sent = write(fd, heartbeat, strlen(heartbeat));
if (sent <= 0) {
printf("Write failed, connection lost\n");
close(fd);
fd = -1;
continue;
}
// Check for response
char buffer[64];
int n = read(fd, buffer, sizeof(buffer));
if (n <= 0) {
printf("Read failed, connection lost\n");
close(fd);
fd = -1;
continue;
}
buffer[n] = '\0';
printf("Server response: %s", buffer);
// Wait before next heartbeat
OSTimeDly(TICKS_PER_SECOND * 10);
}
}

See also
connectvia(), connectwlocal(), NoBlockConnect(), listen(), accept(), close()

◆ connectvia() [1/4]

int connectvia ( const IPADDR & ipAddress,
uint16_t remotePort,
TickTimeout & timeout,
const IPADDR & localIpAddress )
inline

#include <tcp.h>

Establish a TCP connection using a specific local interface IP with TickTimeout.

Creates a new TCP socket and connects to the remote host using the specified local network interface identified by its IP address, with TickTimeout object for sophisticated timeout management. This combines the benefits of explicit interface selection with precise timeout tracking across multiple operations.

This function is ideal for multi-homed systems where you need both controlled interface selection and the ability to share timeout budgets across sequential operations. The TickTimeout object is updated to reflect remaining time, enabling accurate timeout management for complex connection sequences.

Parameters
ipAddressIP address of the remote host. Can be IPv4 or IPv6 depending on build configuration
remotePortPort number on the remote host (1-65535)
timeoutReference to TickTimeout object specifying the maximum wait time. The TickTimeout tracks elapsed time and can be reused across multiple operations. The object is updated by this function to reflect remaining time after the connection attempt
localIpAddressIP address of the local interface to use for this connection. The system will select the network interface that has this IP address assigned. Use IPADDR::NullIP() to fall back to automatic interface selection based on routing table
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:

  • The TickTimeout object is updated by this function to reflect the remaining time. This allows multiple operations to share a common timeout budget.
  • The local port is automatically assigned from the ephemeral port range.
  • If the specified local IP address does not exist on any interface, the behavior depends on the network stack implementation. Generally, the connection will fail or fall back to the default interface.
  • GetInterfaceIP() to obtain the IP address of a specific interface number before calling this function.
  • Always call close() on the returned file descriptor when finished to free system resources.

-is function blocks the calling task until the connection is established or the timeout expires. For non-blocking connection attempts, use NoBlockConnectVia().

Warning
  • The timeout parameter is passed by reference and will be modified by this function. If you need to preserve the original timeout value, create a copy.
  • Ensure the specified local IP address is actually assigned to an interface before calling this function. Use GetInterfaceIP() to verify.

Expand for Example Usage

Examples

Basic Interface Selection with TickTimeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void ConnectViaInterfaceWithTimeout(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
IPADDR localIP = GetInterfaceIP(1); // Use interface 1
printf("Connecting via interface %s\n", localIP.print());
// Create TickTimeout for 15 seconds
TickTimeout timeout(TICKS_PER_SECOND * 15);
int fd = connectvia(serverAddr, 8080, timeout, localIP);
if (fd > 0) {
printf("Connected successfully!\n");
printf(" Connection time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf(" Remaining timeout: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
printf(" Local endpoint: %s:%d\n",
// Verify correct interface
if (GetSocketLocalAddr(fd) == localIP) {
printf(" Verified: Using requested interface\n");
}
close(fd);
} else {
printf("Connection failed: %d\n", fd);
printf("Time spent: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
}
}
int connectvia(const IPADDR &ipAddress, uint16_t remotePort, uint32_t timeout, const IPADDR &localIpAddress)
Establish a TCP connection using a specific local interface IP address.
Definition tcp.h:2044
Multi-Interface Connection with Shared Timeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Try multiple interfaces within total time budget
int ConnectViaAnyInterface(IPADDR serverAddr, uint16_t port,
uint32_t totalTimeoutTicks) {
TickTimeout timeout(totalTimeoutTicks);
int numInterfaces = GetNumberOfInterfaces();
printf("Trying %d interfaces with %.1f second total budget\n\n",
numInterfaces,
(float)totalTimeoutTicks / TICKS_PER_SECOND);
for (int i = 0; i < numInterfaces && !timeout.Expired(); i++) {
IPADDR localIP = GetInterfaceIP(i);
printf("Attempt %d via interface %d (%s)...\n",
i + 1, i, localIP.print());
printf(" Time remaining: %.1f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
int fd = connectvia(serverAddr, port, timeout, localIP);
if (fd > 0) {
printf(" SUCCESS!\n");
printf(" Total time used: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf(" Time remaining: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
return fd;
}
printf(" Failed: %d\n", fd);
}
if (timeout.Expired()) {
printf("\nTimeout budget exhausted\n");
} else {
printf("\nAll interfaces failed\n");
}
return -1;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Try all interfaces within 30 seconds
int fd = ConnectViaAnyInterface(serverAddr, 8080, TICKS_PER_SECOND * 30);
if (fd > 0) {
// Use connection...
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Dual-Homed System with Complete Protocol Exchange
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <utils.h>
// Connect via specific interface and perform multi-step protocol
bool ProtocolViaInterface(IPADDR serverAddr, uint16_t port,
int interfaceNum, uint32_t totalTimeout) {
TickTimeout timeout(totalTimeout);
IPADDR localIP = GetInterfaceIP(interfaceNum);
printf("Starting protocol via interface %d (%s)\n",
interfaceNum, localIP.print());
printf("Total timeout: %.1f seconds\n\n",
(float)totalTimeout / TICKS_PER_SECOND);
// Step 1: Connect via specific interface
printf("Step 1: Connecting via interface %d...\n", interfaceNum);
int fd = connectvia(serverAddr, port, timeout, localIP);
if (fd < 0) {
printf("Connection failed: %d\n", fd);
return false;
}
printf("Connected! Elapsed: %.2f sec, Remaining: %.2f sec\n\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND,
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
// Step 2: Send initialization
printf("Step 2: Sending initialization...\n");
const char *init = "INIT\r\n";
if (WriteWithTimeout(fd, init, strlen(init), timeout) < 0) {
printf("Init send failed\n");
close(fd);
return false;
}
printf("Init sent. Remaining: %.2f sec\n\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
// Step 3: Receive acknowledgment
printf("Step 3: Receiving ACK...\n");
char ack[32];
int n = ReadWithTimeout(fd, ack, sizeof(ack), timeout);
if (n <= 0) {
printf("ACK receive failed\n");
close(fd);
return false;
}
ack[n] = '\0';
printf("Received: %s", ack);
printf("Remaining: %.2f sec\n\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
// Step 4: Send data
printf("Step 4: Sending data...\n");
const char *data = "DATA payload\r\n";
if (WriteWithTimeout(fd, data, strlen(data), timeout) < 0) {
printf("Data send failed\n");
close(fd);
return false;
}
printf("Protocol complete!\n");
printf("Total time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf("Unused time: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
close(fd);
return true;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Perform protocol via interface 1 with 20 second budget
bool success = ProtocolViaInterface(serverAddr, 8080, 1,
printf("\nProtocol %s\n", success ? "SUCCEEDED" : "FAILED");
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Interface Failover with Timeout Tracking
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Try primary interface, failover to backup if needed
int ConnectWithInterfaceFailover(IPADDR serverAddr, uint16_t port,
int primaryIF, int backupIF,
uint32_t totalTimeout) {
TickTimeout timeout(totalTimeout);
printf("Connection with failover (%.1f sec total budget)\n",
(float)totalTimeout / TICKS_PER_SECOND);
// Try primary interface
IPADDR primaryIP = GetInterfaceIP(primaryIF);
printf("\nTrying primary interface %d (%s)...\n",
primaryIF, primaryIP.print());
int fd = connectvia(serverAddr, port, timeout, primaryIP);
if (fd > 0) {
printf("Connected via primary interface\n");
printf("Connection time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
return fd;
}
printf("Primary failed: %d (%.2f sec elapsed)\n",
fd, (float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
// Check if we have time for backup
if (timeout.Expired()) {
printf("No time remaining for backup attempt\n");
return -1;
}
// Try backup interface
IPADDR backupIP = GetInterfaceIP(backupIF);
printf("\nFailing over to backup interface %d (%s)...\n",
backupIF, backupIP.print());
printf("Time remaining: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
fd = connectvia(serverAddr, port, timeout, backupIP);
if (fd > 0) {
printf("Connected via backup interface\n");
printf("Total time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
return fd;
}
printf("Backup also failed: %d\n", fd);
printf("Total time spent: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
return -1;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Try interface 0, failover to 1, with 20 second total budget
int fd = ConnectWithInterfaceFailover(serverAddr, 8080, 0, 1,
if (fd > 0) {
printf("\nConnection established!\n");
printf("Using interface: %d\n", TcpGetSocketInterface(fd));
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
int TcpGetSocketInterface(int fd)
Get the network interface number associated with a TCP socket.
Round-Robin Interface Selection with Time Budget
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Distribute connections across interfaces with total time limit
void RoundRobinWithBudget(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
// 60 second total budget for all connections
TickTimeout totalBudget(TICKS_PER_SECOND * 60);
int successCount = 0;
int failCount = 0;
int connectionNum = 0;
printf("Round-robin connections with 60 second budget\n");
printf("Interfaces: %d\n\n", numInterfaces);
while (!totalBudget.Expired()) {
int ifNum = connectionNum % numInterfaces;
IPADDR localIP = GetInterfaceIP(ifNum);
printf("Connection %d via interface %d (%s)...",
connectionNum + 1, ifNum, localIP.print());
printf(" [%.1f sec left]\n",
(float)totalBudget.GetTimeLeft() / TICKS_PER_SECOND);
// Each attempt gets up to 5 seconds
TickTimeout attemptTimeout(TICKS_PER_SECOND * 5);
int fd = connectvia(serverAddr, 8080, attemptTimeout, localIP);
if (fd > 0) {
successCount++;
printf(" Success (%.2f sec)\n",
(float)attemptTimeout.GetElapsedTime() / TICKS_PER_SECOND);
close(fd);
} else {
failCount++;
printf(" Failed: %d\n", fd);
}
connectionNum++;
// Small pause between connections
if (!totalBudget.Expired()) {
OSTimeDly(TICKS_PER_SECOND);
}
}
printf("\n=== Summary ===\n");
printf("Total attempts: %d\n", connectionNum);
printf("Successful: %d\n", successCount);
printf("Failed: %d\n", failCount);
printf("Time used: %.1f seconds\n",
(float)totalBudget.GetElapsedTime() / TICKS_PER_SECOND);
}
Performance Comparison Across Interfaces
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void CompareInterfacePerformance(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
printf("Comparing connection performance across interfaces\n\n");
for (int i = 0; i < numInterfaces; i++) {
IPADDR localIP = GetInterfaceIP(i);
printf("=== Interface %d (%s) ===\n", i, localIP.print());
// Measure 5 connection attempts
uint32_t totalTime = 0;
int successes = 0;
for (int attempt = 0; attempt < 5; attempt++) {
TickTimeout timeout(TICKS_PER_SECOND * 10);
int fd = connectvia(serverAddr, 8080, timeout, localIP);
if (fd > 0) {
uint32_t elapsed = timeout.GetElapsedTime();
totalTime += elapsed;
successes++;
printf(" Attempt %d: %.3f sec\n",
attempt + 1,
(float)elapsed / TICKS_PER_SECOND);
close(fd);
} else {
printf(" Attempt %d: FAILED (%d)\n", attempt + 1, fd);
}
OSTimeDly(TICKS_PER_SECOND / 2);
}
if (successes > 0) {
float avgTime = (float)totalTime / successes / TICKS_PER_SECOND;
printf("Average: %.3f sec (%d/%d successful)\n",
avgTime, successes, 5);
} else {
printf("All attempts failed\n");
}
printf("\n");
OSTimeDly(TICKS_PER_SECOND);
}
printf("Performance comparison complete\n");
}
Adaptive Timeout Based on Interface Performance
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Track performance and adjust timeouts accordingly
struct InterfaceStats {
uint32_t avgConnectionTime;
int attemptCount;
};
void AdaptiveInterfaceConnection(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
// Initialize statistics
InterfaceStats stats[4] = {0}; // Support up to 4 interfaces
for (int i = 0; i < numInterfaces; i++) {
stats[i].avgConnectionTime = TICKS_PER_SECOND * 5; // Initial 5 sec
stats[i].attemptCount = 0;
}
printf("Adaptive interface connection with learned timeouts\n\n");
for (int conn = 0; conn < 10; conn++) {
int ifNum = conn % numInterfaces;
IPADDR localIP = GetInterfaceIP(ifNum);
// Calculate adaptive timeout (avg + 50% margin)
uint32_t adaptiveTimeout = stats[ifNum].avgConnectionTime * 3 / 2;
printf("Connection %d via interface %d\n", conn + 1, ifNum);
printf(" Adaptive timeout: %.2f sec\n",
(float)adaptiveTimeout / TICKS_PER_SECOND);
TickTimeout timeout(adaptiveTimeout);
int fd = connectvia(serverAddr, 8080, timeout, localIP);
if (fd > 0) {
uint32_t elapsed = timeout.GetElapsedTime();
printf(" Success in %.2f sec\n",
(float)elapsed / TICKS_PER_SECOND);
// Update running average
if (stats[ifNum].attemptCount == 0) {
stats[ifNum].avgConnectionTime = elapsed;
} else {
stats[ifNum].avgConnectionTime =
(stats[ifNum].avgConnectionTime + elapsed) / 2;
}
stats[ifNum].attemptCount++;
printf(" New avg for IF%d: %.2f sec\n",
ifNum,
(float)stats[ifNum].avgConnectionTime / TICKS_PER_SECOND);
close(fd);
} else {
printf(" Failed: %d\n", fd);
}
printf("\n");
OSTimeDly(TICKS_PER_SECOND);
}
printf("=== Final Statistics ===\n");
for (int i = 0; i < numInterfaces; i++) {
printf("Interface %d: %.2f sec avg (%d attempts)\n",
i,
(float)stats[i].avgConnectionTime / TICKS_PER_SECOND,
stats[i].attemptCount);
}
}
Parallel Connection Attempts with First-Success
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
// Global results from parallel attempts
struct ConnectionAttempt {
int interfaceNum;
int fd;
uint32_t elapsedTime;
bool completed;
} g_attempts[4];
// Worker task for parallel connection
void ConnectionWorker(void *pdata) {
ConnectionAttempt *attempt = (ConnectionAttempt *)pdata;
IPADDR serverAddr = AsciiToIp("192.168.1.100");
IPADDR localIP = GetInterfaceIP(attempt->interfaceNum);
TickTimeout timeout(TICKS_PER_SECOND * 10);
printf("[Worker IF%d] Connecting via %s...\n",
attempt->interfaceNum, localIP.print());
attempt->fd = connectvia(serverAddr, 8080, timeout, localIP);
attempt->elapsedTime = timeout.GetElapsedTime();
attempt->completed = true;
if (attempt->fd > 0) {
printf("[Worker IF%d] SUCCESS in %.2f sec\n",
attempt->interfaceNum,
(float)attempt->elapsedTime / TICKS_PER_SECOND);
} else {
printf("[Worker IF%d] FAILED: %d\n",
attempt->interfaceNum, attempt->fd);
}
}
// Note: This is a conceptual example - actual implementation would
// require proper task synchronization and stack management
void ParallelConnectionExample(void *pd) {
init();
int numInterfaces = GetNumberOfInterfaces();
printf("Parallel connection attempts across %d interfaces\n\n",
numInterfaces);
// Initialize attempts
for (int i = 0; i < numInterfaces; i++) {
g_attempts[i].interfaceNum = i;
g_attempts[i].fd = -1;
g_attempts[i].completed = false;
}
// Launch workers (simplified - would need proper stack allocation)
printf("Launching parallel connection attempts...\n");
// Wait for first success or all complete
uint32_t startTime = Secs;
int firstSuccess = -1;
while ((Secs - startTime) < 15) {
for (int i = 0; i < numInterfaces; i++) {
if (g_attempts[i].completed && g_attempts[i].fd > 0) {
firstSuccess = i;
break;
}
}
if (firstSuccess >= 0) break;
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (firstSuccess >= 0) {
printf("\nFirst success: Interface %d\n", firstSuccess);
printf("Closing other connections...\n");
for (int i = 0; i < numInterfaces; i++) {
if (i != firstSuccess && g_attempts[i].fd > 0) {
close(g_attempts[i].fd);
}
}
close(g_attempts[firstSuccess].fd);
}
}
Connection Quality Monitoring
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void MonitorConnectionQuality(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
printf("Monitoring connection quality across interfaces\n\n");
for (int cycle = 0; cycle < 5; cycle++) {
printf("=== Cycle %d ===\n", cycle + 1);
for (int i = 0; i < numInterfaces; i++) {
IPADDR localIP = GetInterfaceIP(i);
TickTimeout timeout(TICKS_PER_SECOND * 8);
int fd = connectvia(serverAddr, 8080, timeout, localIP);
if (fd > 0) {
uint32_t connectTime = timeout.GetElapsedTime();
// Measure connection quality
const char *ping = "PING\r\n";
TickTimeout writeTimeout(TICKS_PER_SECOND * 2);
uint32_t writeStart = TimeTick;
int sent = WriteWithTimeout(fd, ping, strlen(ping),
writeTimeout);
uint32_t writeTime = TimeTick - writeStart;
printf("IF%d: Connect=%.2fms Write=%.2fms",
i,
(float)(connectTime * 1000) / TICKS_PER_SECOND,
(float)(writeTime * 1000) / TICKS_PER_SECOND);
if (sent > 0) {
printf(" [GOOD]\n");
} else {
printf(" [POOR]\n");
}
close(fd);
} else {
printf("IF%d: FAILED (%d)\n", i, fd);
}
}
printf("\n");
OSTimeDly(TICKS_PER_SECOND * 5);
}
}

See also
connectvia(const IPADDR&, uint16_t, uint32_t, const IPADDR&), connectvia(const IPADDR&, uint16_t, TickTimeout&, int), connectwlocal(), NoBlockConnectVia(), GetInterfaceIP(), TcpGetSocketInterface(), TickTimeout

◆ connectvia() [2/4]

int connectvia ( const IPADDR & ipAddress,
uint16_t remotePort,
TickTimeout & timeout,
int ifnum )
inline

#include <tcp.h>

Establish a TCP connection using a specific local interface number with TickTimeout.

Creates a new TCP socket and connects to the remote host using the specified local network interface number, with TickTimeout object for sophisticated timeout management. This provides the most direct interface control combined with precise timeout tracking, ideal for complex multi-homed systems requiring both explicit interface selection and accurate time budget management.

This function combines the unambiguous interface control of interface number selection with the advanced timeout capabilities of TickTimeout. The interface number takes precedence over all routing decisions, and the TickTimeout object tracks elapsed time for sharing timeout budgets across sequential operations.

Parameters
ipAddressIP address of the remote host. Can be IPv4 or IPv6 depending on build configuration
remotePortPort number on the remote host (1-65535)
timeoutReference to TickTimeout object specifying the maximum wait time. The TickTimeout tracks elapsed time and can be reused across multiple operations. The object is updated by this function to reflect remaining time after the connection attempt
ifnumLocal interface number (0, 1, 2, etc.) to use for this connection. This overrides all routing decisions based on destination IP addresses. The interface number directly corresponds to the physical or logical network interface. Valid range is 0 to (number of interfaces - 1). Use GetNumberOfInterfaces() to determine valid range
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:

  • The TickTimeout object is updated by this function to reflect the remaining time. This allows multiple operations to share a common timeout budget.
  • The local port is automatically assigned from the ephemeral port range.
  • Interface numbers typically start at 0 and increment sequentially. Interface 0 is usually the primary Ethernet port, but this can vary by platform and configuration.
  • This combination of interface number selection and TickTimeout provides the most control and precision for multi-homed systems with complex timing requirements.
  • Always call close() on the returned file descriptor when finished to free system resources.
  • This function blocks the calling task until the connection is established or the timeout expires. For non-blocking connection attempts, use NoBlockConnectVia().
Warning
  • The timeout parameter is passed by reference and will be modified by this function. If you need to preserve the original timeout value, create a copy.
  • Specifying an invalid interface number (negative or >= number of interfaces) may cause unpredictable behavior or connection failure. Always validate with GetNumberOfInterfaces() first.
  • The specified interface must be in an "up" state with a valid IP address assigned for the connection to succeed.

Expand for Example Usage

Examples

Basic Interface Number Selection with TickTimeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void ConnectViaInterfaceWithTimeout(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int interfaceNum = 1; // Use interface 1
printf("Connecting via interface %d\n", interfaceNum);
printf("Interface %d IP: %s\n",
interfaceNum, GetInterfaceIP(interfaceNum).print());
// Create TickTimeout for 15 seconds
TickTimeout timeout(TICKS_PER_SECOND * 15);
int fd = connectvia(serverAddr, 8080, timeout, interfaceNum);
if (fd > 0) {
printf("Connected successfully!\n");
printf(" Connection time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf(" Remaining timeout: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
printf(" Interface used: %d\n", TcpGetSocketInterface(fd));
printf(" Local endpoint: %s:%d\n",
close(fd);
} else {
printf("Connection failed: %d\n", fd);
printf("Time spent: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf("Timeout expired: %s\n", timeout.Expired() ? "yes" : "no");
}
}
Sequential Interface Attempts with Shared Timeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Try each interface in sequence until success or timeout
int ConnectViaAnyInterface(IPADDR serverAddr, uint16_t port,
uint32_t totalTimeoutTicks) {
TickTimeout timeout(totalTimeoutTicks);
int numInterfaces = GetNumberOfInterfaces();
printf("Trying %d interfaces sequentially\n", numInterfaces);
printf("Total timeout budget: %.1f seconds\n\n",
(float)totalTimeoutTicks / TICKS_PER_SECOND);
for (int i = 0; i < numInterfaces && !timeout.Expired(); i++) {
printf("Attempt %d: Interface %d (%s)\n",
i + 1, i, GetInterfaceIP(i).print());
printf(" Time remaining: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
int fd = connectvia(serverAddr, port, timeout, i);
if (fd > 0) {
printf(" SUCCESS!\n");
printf(" Total time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf(" Unused time: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
return fd;
}
printf(" Failed: %d (%.2f sec used)\n",
fd, (float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
}
if (timeout.Expired()) {
printf("\nTimeout budget exhausted (%.2f sec)\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
} else {
printf("\nAll %d interfaces failed\n", numInterfaces);
}
return -1;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Try all interfaces within 30 second budget
int fd = ConnectViaAnyInterface(serverAddr, 8080, TICKS_PER_SECOND * 30);
if (fd > 0) {
printf("\nConnection established!\n");
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Complete Protocol Sequence via Specific Interface
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <utils.h>
// Perform complete protocol handshake via specific interface
bool ProtocolViaInterface(IPADDR serverAddr, uint16_t port,
int interfaceNum, uint32_t totalTimeout) {
TickTimeout timeout(totalTimeout);
printf("Protocol sequence via interface %d\n", interfaceNum);
printf("Interface IP: %s\n", GetInterfaceIP(interfaceNum).print());
printf("Total timeout: %.1f seconds\n\n",
(float)totalTimeout / TICKS_PER_SECOND);
// Phase 1: Connect
printf("Phase 1: Connecting...\n");
int fd = connectvia(serverAddr, port, timeout, interfaceNum);
if (fd < 0) {
printf("Connection failed: %d\n", fd);
return false;
}
printf("Connected! Elapsed: %.2f sec, Remaining: %.2f sec\n\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND,
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
// Phase 2: Authentication
printf("Phase 2: Authentication...\n");
const char *auth = "AUTH user:password\r\n";
if (WriteWithTimeout(fd, auth, strlen(auth), timeout) < 0) {
printf("Auth send failed\n");
close(fd);
return false;
}
char authResp[64];
int n = ReadWithTimeout(fd, authResp, sizeof(authResp), timeout);
if (n <= 0) {
printf("Auth response read failed\n");
close(fd);
return false;
}
authResp[n] = '\0';
printf("Auth response: %s", authResp);
printf("Remaining: %.2f sec\n\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
// Phase 3: Command
printf("Phase 3: Sending command...\n");
const char *cmd = "GET STATUS\r\n";
if (WriteWithTimeout(fd, cmd, strlen(cmd), timeout) < 0) {
printf("Command send failed\n");
close(fd);
return false;
}
char cmdResp[256];
n = ReadWithTimeout(fd, cmdResp, sizeof(cmdResp), timeout);
if (n <= 0) {
printf("Command response read failed\n");
close(fd);
return false;
}
cmdResp[n] = '\0';
printf("Status: %s", cmdResp);
// Summary
printf("\n=== Protocol Complete ===\n");
printf("Total time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
printf("Time budget remaining: %.2f seconds\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
printf("Efficiency: %.1f%%\n",
(float)timeout.GetElapsedTime() * 100.0f / totalTimeout);
close(fd);
return true;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Execute protocol via interface 0 with 30 second budget
bool success = ProtocolViaInterface(serverAddr, 8080, 0,
printf("\nProtocol %s\n", success ? "SUCCEEDED" : "FAILED");
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Priority-Based Interface Selection with Timeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Try interfaces in priority order with exponential backoff
int ConnectWithPriority(IPADDR serverAddr, uint16_t port,
int priorityInterfaces[], int numPriorities,
uint32_t totalTimeout) {
TickTimeout timeout(totalTimeout);
printf("Priority-based connection attempt\n");
printf("Priorities: ");
for (int i = 0; i < numPriorities; i++) {
printf("%d ", priorityInterfaces[i]);
}
printf("\n\n");
uint32_t attemptTimeout = TICKS_PER_SECOND * 3; // Start with 3 seconds
for (int i = 0; i < numPriorities && !timeout.Expired(); i++) {
int ifNum = priorityInterfaces[i];
// Don't exceed remaining time
uint32_t thisTimeout = (attemptTimeout < timeout.GetTimeLeft()) ?
attemptTimeout : timeout.GetTimeLeft();
printf("Priority %d: Interface %d (%s)\n",
i + 1, ifNum, GetInterfaceIP(ifNum).print());
printf(" Attempt timeout: %.1f sec\n",
(float)thisTimeout / TICKS_PER_SECOND);
printf(" Total remaining: %.1f sec\n",
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
TickTimeout attemptTimer(thisTimeout);
int fd = connectvia(serverAddr, port, attemptTimer, ifNum);
if (fd > 0) {
printf(" SUCCESS at priority %d!\n", i + 1);
printf(" Time used: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
return fd;
}
printf(" Failed: %d\n", fd);
// Exponential backoff for next attempt
attemptTimeout *= 2;
if (attemptTimeout > TICKS_PER_SECOND * 15) {
attemptTimeout = TICKS_PER_SECOND * 15; // Cap at 15 seconds
}
}
printf("\nAll priority interfaces failed\n");
return -1;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Priority order: try interface 0, then 2, then 1
int priorities[] = {0, 2, 1};
int fd = ConnectWithPriority(serverAddr, 8080, priorities, 3,
if (fd > 0) {
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Load Balancing with Time Budget
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Distribute connections across interfaces with total time limit
void LoadBalancedConnections(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
// 2 minute total budget
TickTimeout totalBudget(TICKS_PER_SECOND * 120);
int connectionCounts[4] = {0}; // Support up to 4 interfaces
int totalConnections = 0;
int successCount = 0;
printf("Load-balanced connections with 2 minute budget\n");
printf("Interfaces: %d\n\n", numInterfaces);
while (!totalBudget.Expired()) {
// Round-robin interface selection
int ifNum = totalConnections % numInterfaces;
printf("Connection %d via interface %d [%.1f sec left]...",
totalConnections + 1, ifNum,
(float)totalBudget.GetTimeLeft() / TICKS_PER_SECOND);
// Each attempt gets up to 5 seconds
TickTimeout attemptTimeout(TICKS_PER_SECOND * 5);
int fd = connectvia(serverAddr, 8080, attemptTimeout, ifNum);
if (fd > 0) {
successCount++;
connectionCounts[ifNum]++;
printf(" OK (%.2f sec)\n",
(float)attemptTimeout.GetElapsedTime() / TICKS_PER_SECOND);
// Do some work
const char *msg = "PING\r\n";
write(fd, msg, strlen(msg));
close(fd);
} else {
printf(" FAILED: %d\n", fd);
}
totalConnections++;
// Brief pause
if (!totalBudget.Expired()) {
OSTimeDly(TICKS_PER_SECOND / 2);
}
}
printf("\n=== Summary ===\n");
printf("Total time: %.1f seconds\n",
(float)totalBudget.GetElapsedTime() / TICKS_PER_SECOND);
printf("Total attempts: %d\n", totalConnections);
printf("Successful: %d (%.1f%%)\n",
successCount,
(float)successCount * 100.0f / totalConnections);
printf("\nPer-Interface Distribution:\n");
for (int i = 0; i < numInterfaces; i++) {
printf(" Interface %d: %d connections\n", i, connectionCounts[i]);
}
}
Interface Performance Profiling
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
struct InterfaceProfile {
int interfaceNum;
uint32_t minTime;
uint32_t maxTime;
uint32_t totalTime;
int successCount;
int failCount;
};
void ProfileInterfacePerformance(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
InterfaceProfile profiles[4] = {0}; // Support up to 4 interfaces
// Initialize profiles
for (int i = 0; i < numInterfaces; i++) {
profiles[i].interfaceNum = i;
profiles[i].minTime = 0xFFFFFFFF;
profiles[i].maxTime = 0;
profiles[i].totalTime = 0;
profiles[i].successCount = 0;
profiles[i].failCount = 0;
}
printf("Profiling %d interfaces (10 attempts each)\n\n", numInterfaces);
// Profile each interface with 10 attempts
for (int i = 0; i < numInterfaces; i++) {
printf("Profiling Interface %d (%s)\n",
i, GetInterfaceIP(i).print());
for (int attempt = 0; attempt < 10; attempt++) {
TickTimeout timeout(TICKS_PER_SECOND * 10);
int fd = connectvia(serverAddr, 8080, timeout, i);
if (fd > 0) {
uint32_t elapsed = timeout.GetElapsedTime();
profiles[i].successCount++;
profiles[i].totalTime += elapsed;
if (elapsed < profiles[i].minTime) {
profiles[i].minTime = elapsed;
}
if (elapsed > profiles[i].maxTime) {
profiles[i].maxTime = elapsed;
}
printf(" Attempt %d: %.3f sec\n",
attempt + 1,
(float)elapsed / TICKS_PER_SECOND);
close(fd);
} else {
profiles[i].failCount++;
printf(" Attempt %d: FAILED (%d)\n", attempt + 1, fd);
}
OSTimeDly(TICKS_PER_SECOND / 2);
}
printf("\n");
OSTimeDly(TICKS_PER_SECOND);
}
// Display profile results
printf("=== Performance Profile Results ===\n\n");
for (int i = 0; i < numInterfaces; i++) {
printf("Interface %d:\n", i);
printf(" IP Address: %s\n", GetInterfaceIP(i).print());
printf(" Success Rate: %d/%d (%.1f%%)\n",
profiles[i].successCount,
profiles[i].successCount + profiles[i].failCount,
(float)profiles[i].successCount * 100.0f /
(profiles[i].successCount + profiles[i].failCount));
if (profiles[i].successCount > 0) {
float avgTime = (float)profiles[i].totalTime /
profiles[i].successCount / TICKS_PER_SECOND;
float minTime = (float)profiles[i].minTime / TICKS_PER_SECOND;
float maxTime = (float)profiles[i].maxTime / TICKS_PER_SECOND;
printf(" Min Time: %.3f sec\n", minTime);
printf(" Avg Time: %.3f sec\n", avgTime);
printf(" Max Time: %.3f sec\n", maxTime);
printf(" Variance: %.3f sec\n", maxTime - minTime);
}
printf("\n");
}
// Recommend best interface
int bestInterface = 0;
float bestScore = 0.0f;
for (int i = 0; i < numInterfaces; i++) {
if (profiles[i].successCount > 0) {
float avgTime = (float)profiles[i].totalTime /
profiles[i].successCount;
float successRate = (float)profiles[i].successCount /
(profiles[i].successCount + profiles[i].failCount);
// Score based on success rate and speed (lower time is better)
float score = successRate / avgTime;
if (score > bestScore) {
bestScore = score;
bestInterface = i;
}
}
}
printf("Recommended Interface: %d (%s)\n",
bestInterface, GetInterfaceIP(bestInterface).print());
}
Adaptive Retry Strategy
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Adaptively retry with learned timeout adjustments
int AdaptiveConnect(IPADDR serverAddr, uint16_t port, int interfaceNum,
uint32_t totalTimeout) {
TickTimeout timeout(totalTimeout);
// Start with short timeout
uint32_t attemptTimeout = TICKS_PER_SECOND * 2;
int attempt = 0;
printf("Adaptive connection via interface %d\n", interfaceNum);
printf("Total budget: %.1f seconds\n\n",
(float)totalTimeout / TICKS_PER_SECOND);
while (!timeout.Expired() && attempt < 10) {
attempt++;
uint32_t thisTimeout = (attemptTimeout < timeout.GetTimeLeft()) ?
attemptTimeout : timeout.GetTimeLeft();
printf("Attempt %d: timeout=%.1f sec, budget=%.1f sec\n",
attempt,
(float)thisTimeout / TICKS_PER_SECOND,
(float)timeout.GetTimeLeft() / TICKS_PER_SECOND);
TickTimeout attemptTimer(thisTimeout);
int fd = connectvia(serverAddr, port, attemptTimer, interfaceNum);
if (fd > 0) {
printf("SUCCESS on attempt %d!\n", attempt);
printf("Total time: %.2f seconds\n",
(float)timeout.GetElapsedTime() / TICKS_PER_SECOND);
return fd;
}
uint32_t usedTime = attemptTimer.GetElapsedTime();
bool timedOut = attemptTimer.Expired();
printf(" Failed: %d (%s)\n",
fd, timedOut ? "timeout" : "error");
// Adapt timeout based on result
if (timedOut) {
// Connection attempt used full timeout - increase it
attemptTimeout = (attemptTimeout * 3) / 2; // Increase 50%
printf(" Increasing timeout to %.1f sec\n",
(float)attemptTimeout / TICKS_PER_SECOND);
} else {
// Failed quickly - keep current timeout
printf(" Failed quickly (%.2f sec), keeping timeout\n",
(float)usedTime / TICKS_PER_SECOND);
}
// Cap maximum timeout
if (attemptTimeout > TICKS_PER_SECOND * 20) {
attemptTimeout = TICKS_PER_SECOND * 20;
}
// Brief pause before retry
if (!timeout.Expired()) {
OSTimeDly(TICKS_PER_SECOND);
}
}
printf("All attempts exhausted\n");
return -1;
}
Health Monitoring with Timeout Tracking
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
struct InterfaceHealth {
bool operational;
uint32_t lastSuccessTime;
uint32_t avgConnectTime;
int consecutiveFailures;
};
void MonitorInterfaceHealth(void *pd) {
init();
IPADDR testServer = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
InterfaceHealth health[4] = {0}; // Support up to 4 interfaces
printf("Starting interface health monitoring\n");
printf("Monitoring %d interfaces\n\n", numInterfaces);
// Monitor for 10 cycles
for (int cycle = 0; cycle < 10; cycle++) {
printf("=== Health Check Cycle %d ===\n", cycle + 1);
for (int i = 0; i < numInterfaces; i++) {
TickTimeout timeout(TICKS_PER_SECOND * 5);
int fd = connectvia(testServer, 8080, timeout, i);
if (fd > 0) {
uint32_t connectTime = timeout.GetElapsedTime();
health[i].operational = true;
health[i].lastSuccessTime = Secs;
health[i].consecutiveFailures = 0;
// Update running average
if (health[i].avgConnectTime == 0) {
health[i].avgConnectTime = connectTime;
} else {
health[i].avgConnectTime =
(health[i].avgConnectTime + connectTime) / 2;
}
printf("IF%d: OK (%.2f sec, avg=%.2f sec)\n",
i,
(float)connectTime / TICKS_PER_SECOND,
(float)health[i].avgConnectTime / TICKS_PER_SECOND);
close(fd);
} else {
health[i].consecutiveFailures++;
if (health[i].consecutiveFailures >= 3) {
health[i].operational = false;
}
printf("IF%d: FAIL (error %d, %d consecutive)\n",
i, fd, health[i].consecutiveFailures);
}
}
// Status summary
int healthyCount = 0;
for (int i = 0; i < numInterfaces; i++) {
if (health[i].operational) healthyCount++;
}
printf("Healthy interfaces: %d/%d\n\n",
healthyCount, numInterfaces);
OSTimeDly(TICKS_PER_SECOND * 10);
}
printf("Health monitoring complete\n");
}

See also
connectvia(const IPADDR&, uint16_t, uint32_t, int), connectvia(const IPADDR&, uint16_t, TickTimeout&, const IPADDR&), connectwlocal(), NoBlockConnectVia(), GetNumberOfInterfaces(), TcpGetSocketInterface(), TickTimeout

◆ connectvia() [3/4]

int connectvia ( const IPADDR & ipAddress,
uint16_t remotePort,
uint32_t timeout,
const IPADDR & localIpAddress )
inline

#include <tcp.h>

Establish a TCP connection using a specific local interface IP address.

Creates a new TCP socket and connects to the remote host using the specified local network interface identified by its IP address. This allows control over which interface is used when multiple network interfaces are available. The standard connect() function uses the default interface selected by the routing table, while this function overrides that decision.

This is particularly useful in multi-homed systems where you need to ensure traffic uses a specific network path, such as separating control and data traffic, routing through different network segments, or implementing failover between interfaces.

Parameters
ipAddressIP address of the remote host. Can be IPv4 or IPv6 depending on build configuration
remotePortPort number on the remote host (1-65535)
timeoutMaximum connection time in system ticks:
  • Use TICKS_PER_SECOND * n for n second timeout
  • Example: TICKS_PER_SECOND * 10 for 10 second timeout
  • Recommended: 5-30 seconds for most applications
localIpAddressIP address of the local interface to use for this connection. The system will select the network interface that has this IP address assigned. If multiple interfaces share the same IP (unusual configuration), the lower numbered interface is selected. Use IPADDR::NullIP() to fall back to automatic interface selection based on routing table (equivalent to calling connect())
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:

  • The local port is automatically assigned from the ephemeral port range. This function does not allow specification of the local port number.
  • If the specified local IP address does not exist on any interface, the behavior depends on the network stack implementation. Generally, the connection will fail or fall back to the default interface.
  • Use GetInterfaceIP() to obtain the IP address of a specific interface number before calling this function.
  • Always call close() on the returned file descriptor when finished to free system resources.
  • This function blocks the calling task until the connection is established or the timeout expires. For non-blocking connection attempts, use NoBlockConnectVia().
Warning
Ensure the specified local IP address is actually assigned to an interface before calling this function. Use GetInterfaceIP() to verify.

Expand for Example Usage

Examples

Basic Interface Selection
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void ConnectViaInterface(void *pd) {
init();
// Get IP address of interface 0
IPADDR localIP = GetInterfaceIP(0);
printf("Using local interface: %s\n", localIP.print());
// Connect to server using specific interface
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int fd = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 10, localIP);
if (fd > 0) {
printf("Connected successfully!\n");
printf(" Local endpoint: %s:%d\n",
printf(" Remote endpoint: %s:%d\n",
// Verify we used the correct interface
if (GetSocketLocalAddr(fd) == localIP) {
printf(" Confirmed: Using requested interface\n");
}
close(fd);
} else {
printf("Connection failed: %d\n", fd);
}
}
Dual-Homed System - Separate Control and Data Networks
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// System with two network interfaces:
// Interface 0: 192.168.1.x (Control network)
// Interface 1: 10.0.0.x (Data network)
void DualHomedExample(void *pd) {
init();
// Get interface IP addresses
IPADDR controlIP = GetInterfaceIP(0); // Control network
IPADDR dataIP = GetInterfaceIP(1); // Data network
printf("Control network IP: %s\n", controlIP.print());
printf("Data network IP: %s\n", dataIP.print());
// Connect to control server via control network
IPADDR controlServer = AsciiToIp("192.168.1.50");
printf("\nConnecting to control server via control network...\n");
int fdControl = connectvia(controlServer, 9000,
controlIP);
if (fdControl > 0) {
printf("Control connection established via %s\n",
GetSocketLocalAddr(fdControl).print());
// Send control commands
const char *cmd = "STATUS\r\n";
write(fdControl, cmd, strlen(cmd));
}
// Connect to data server via data network
IPADDR dataServer = AsciiToIp("10.0.0.50");
printf("\nConnecting to data server via data network...\n");
int fdData = connectvia(dataServer, 8080,
dataIP);
if (fdData > 0) {
printf("Data connection established via %s\n",
// Transfer bulk data
char buffer[1024];
// ... data transfer ...
}
// Clean up
if (fdControl > 0) close(fdControl);
if (fdData > 0) close(fdData);
printf("\nDual-homed operation complete\n");
}
Interface Failover
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Try primary interface first, failover to backup if unavailable
int ConnectWithFailover(IPADDR serverAddr, uint16_t port) {
// Try primary interface (interface 0)
IPADDR primaryIP = GetInterfaceIP(0);
printf("Attempting connection via primary interface %s...\n",
primaryIP.print());
int fd = connectvia(serverAddr, port, TICKS_PER_SECOND * 5, primaryIP);
if (fd > 0) {
printf("Connected via primary interface\n");
return fd;
}
printf("Primary interface failed: %d\n", fd);
// Try backup interface (interface 1)
IPADDR backupIP = GetInterfaceIP(1);
printf("Attempting connection via backup interface %s...\n",
backupIP.print());
fd = connectvia(serverAddr, port, TICKS_PER_SECOND * 5, backupIP);
if (fd > 0) {
printf("Connected via backup interface\n");
return fd;
}
printf("Backup interface also failed: %d\n", fd);
printf("All interfaces exhausted\n");
return fd;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int fd = ConnectWithFailover(serverAddr, 8080);
if (fd > 0) {
// Use connection...
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Round-Robin Interface Usage
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void RoundRobinConnections(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
printf("System has %d network interfaces\n", numInterfaces);
// Display all interface IPs
for (int i = 0; i < numInterfaces; i++) {
IPADDR ifIP = GetInterfaceIP(i);
printf(" Interface %d: %s\n", i, ifIP.print());
}
// Make multiple connections, rotating through interfaces
printf("\nMaking 10 connections with round-robin interface selection:\n");
for (int conn = 0; conn < 10; conn++) {
int interfaceNum = conn % numInterfaces;
IPADDR localIP = GetInterfaceIP(interfaceNum);
printf("\nConnection %d using interface %d (%s)...",
conn + 1, interfaceNum, localIP.print());
int fd = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 10, localIP);
if (fd > 0) {
printf(" Success\n");
printf(" Actual local IP: %s\n",
printf(" Local port: %d\n",
// Do work...
OSTimeDly(TICKS_PER_SECOND);
close(fd);
} else {
printf(" Failed: %d\n", fd);
}
}
}
Verifying Interface Selection
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void VerifyInterfaceSelection(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Test each available interface
int numInterfaces = GetNumberOfInterfaces();
for (int i = 0; i < numInterfaces; i++) {
IPADDR requestedIP = GetInterfaceIP(i);
printf("\n=== Testing Interface %d ===\n", i);
printf("Requested local IP: %s\n", requestedIP.print());
int fd = connectvia(serverAddr, 8080,
requestedIP);
if (fd > 0) {
IPADDR actualIP = GetSocketLocalAddr(fd);
int actualInterface = TcpGetSocketInterface(fd);
printf("Actual local IP: %s\n", actualIP.print());
printf("Actual interface: %d\n", actualInterface);
// Verify match
if (actualIP == requestedIP && actualInterface == i) {
printf("VERIFIED: Interface selection correct\n");
} else {
printf("WARNING: Interface mismatch!\n");
printf(" Expected interface %d with IP %s\n",
i, requestedIP.print());
printf(" Got interface %d with IP %s\n",
actualInterface, actualIP.print());
}
close(fd);
} else {
printf("Connection failed: %d\n", fd);
}
}
}
Comparing Automatic vs Explicit Interface Selection
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void CompareInterfaceSelection(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Test 1: Automatic interface selection (standard connect)
printf("=== Test 1: Automatic Interface Selection ===\n");
int fd1 = connect(serverAddr, 8080, TICKS_PER_SECOND * 10);
if (fd1 > 0) {
printf("Connected via automatic selection\n");
printf(" Selected interface: %d\n", TcpGetSocketInterface(fd1));
printf(" Local IP: %s\n", GetSocketLocalAddr(fd1).print());
printf(" (Determined by routing table)\n");
close(fd1);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 2: Explicit interface selection
printf("\n=== Test 2: Explicit Interface Selection ===\n");
IPADDR explicitIP = GetInterfaceIP(0);
printf("Requesting interface with IP: %s\n", explicitIP.print());
int fd2 = connectvia(serverAddr, 8080,
explicitIP);
if (fd2 > 0) {
printf("Connected via explicit selection\n");
printf(" Requested interface: %s\n", explicitIP.print());
printf(" Selected interface: %d\n", TcpGetSocketInterface(fd2));
printf(" Local IP: %s\n", GetSocketLocalAddr(fd2).print());
close(fd2);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 3: Using NullIP (equivalent to automatic)
printf("\n=== Test 3: connectvia with NullIP ===\n");
printf("Using IPADDR::NullIP() (should be like automatic)\n");
int fd3 = connectvia(serverAddr, 8080,
if (fd3 > 0) {
printf("Connected\n");
printf(" Selected interface: %d\n", TcpGetSocketInterface(fd3));
printf(" Local IP: %s\n", GetSocketLocalAddr(fd3).print());
close(fd3);
}
printf("\nComparison complete\n");
}
Multi-Interface Network Monitor
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
// Monitor connectivity to a server via all interfaces
void MonitorInterfaceConnectivity(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
uint16_t port = 8080;
int numInterfaces = GetNumberOfInterfaces();
printf("Monitoring connectivity to %s:%d via %d interfaces\n\n",
serverAddr.print(), port, numInterfaces);
// Monitor loop
for (int cycle = 0; cycle < 5; cycle++) {
printf("=== Check Cycle %d ===\n", cycle + 1);
for (int i = 0; i < numInterfaces; i++) {
IPADDR localIP = GetInterfaceIP(i);
printf("Interface %d (%s): ", i, localIP.print());
uint32_t startTime = Secs;
int fd = connectvia(serverAddr, port, TICKS_PER_SECOND * 5, localIP);
uint32_t elapsed = Secs - startTime;
if (fd > 0) {
printf("OK (%lu sec)\n", elapsed);
close(fd);
} else {
printf("FAILED (error %d after %lu sec)\n", fd, elapsed);
}
}
printf("\n");
OSTimeDly(TICKS_PER_SECOND * 10); // Wait 10 seconds between checks
}
printf("Monitoring complete\n");
}
Source Address Selection for Multi-Subnet Access
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Connect to servers on different subnets using appropriate interfaces
void MultiSubnetAccess(void *pd) {
init();
// Interface 0: 192.168.1.x/24
// Interface 1: 10.0.0.x/8
IPADDR interface0_IP = GetInterfaceIP(0);
IPADDR interface1_IP = GetInterfaceIP(1);
printf("Interface 0 IP: %s\n", interface0_IP.print());
printf("Interface 1 IP: %s\n", interface1_IP.print());
// Server on subnet 192.168.1.x - use interface 0
printf("\nConnecting to server on 192.168.1.x subnet...\n");
IPADDR server1 = AsciiToIp("192.168.1.50");
int fd1 = connectvia(server1, 8080, TICKS_PER_SECOND * 10, interface0_IP);
if (fd1 > 0) {
printf("Connected to %s via %s\n",
server1.print(),
// Communicate with server1...
close(fd1);
}
// Server on subnet 10.x.x.x - use interface 1
printf("\nConnecting to server on 10.x.x.x subnet...\n");
IPADDR server2 = AsciiToIp("10.0.1.50");
int fd2 = connectvia(server2, 8080, TICKS_PER_SECOND * 10, interface1_IP);
if (fd2 > 0) {
printf("Connected to %s via %s\n",
server2.print(),
// Communicate with server2...
close(fd2);
}
printf("\nMulti-subnet access complete\n");
}

See also
connect(), connectvia(const IPADDR&, uint16_t, uint32_t, int), connectwlocal(), NoBlockConnectVia(), GetInterfaceIP(), TcpGetSocketInterface()

◆ connectvia() [4/4]

int connectvia ( const IPADDR & ipAddress,
uint16_t remotePort,
uint32_t timeout,
int ifnum )
inline

#include <tcp.h>

Establish a TCP connection using a specific local interface number.

Creates a new TCP socket and connects to the remote host using the specified local network interface number. This allows direct control over which interface is used, completely overriding the routing table. The interface number takes precedence over any IP-based routing decisions, providing the most explicit control over interface selection.

This is the most direct way to control interface selection in multi-homed systems. Unlike selecting by IP address, specifying an interface number eliminates any ambiguity about which interface will be used, even if multiple interfaces share similar IP configurations.

Parameters
ipAddressIP address of the remote host. Can be IPv4 or IPv6 depending on build configuration
remotePortPort number on the remote host (1-65535)
timeoutMaximum connection time in system ticks:
  • Use TICKS_PER_SECOND * n for n second timeout
  • Example: TICKS_PER_SECOND * 10 for 10 second timeout
  • Recommended: 5-30 seconds for most applications
ifnumLocal interface number (0, 1, 2, etc.) to use for this connection. This overrides all routing decisions based on destination IP addresses. The interface number directly corresponds to the physical or logical network interface. Valid range is 0 to (number of interfaces - 1). Use GetNumberOfInterfaces() to determine valid range
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:

  • The local port is automatically assigned from the ephemeral port range. This function does not allow specification of the local port number.
  • Interface numbers typically start at 0 and increment sequentially. Interface 0 is usually the primary Ethernet port, but this can vary by platform and configuration.
  • If you specify an interface number that doesn't exist, the behavior is undefined. Always verify the interface count with GetNumberOfInterfaces() before using this function.
  • This method of interface selection is preferred over IP-based selection when you need guaranteed, unambiguous interface control.
  • Always call close() on the returned file descriptor when finished to free system resources.
  • This function blocks the calling task until the connection is established or the timeout expires. For non-blocking connection attempts, use NoBlockConnectVia().
Warning
  • Specifying an invalid interface number (negative or >= number of interfaces) may cause unpredictable behavior or connection failure.
  • The specified interface must be in an "up" state with a valid IP address assigned for the connection to succeed.

Expand for Example Usage

Examples

Basic Interface Number Selection
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void ConnectViaInterfaceNumber(void *pd) {
init();
// Connect using interface 1
int interfaceNum = 1;
printf("Connecting via interface %d\n", interfaceNum);
printf("Interface %d IP: %s\n",
interfaceNum, GetInterfaceIP(interfaceNum).print());
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int fd = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 10, interfaceNum);
if (fd > 0) {
printf("Connected successfully!\n");
printf(" Interface used: %d\n", TcpGetSocketInterface(fd));
printf(" Local address: %s:%d\n",
printf(" Remote address: %s:%d\n",
// Verify correct interface was used
if (TcpGetSocketInterface(fd) == interfaceNum) {
printf(" Verified: Correct interface selected\n");
}
close(fd);
} else {
printf("Connection failed: %d\n", fd);
}
}
Iterating Through All Interfaces
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void TestAllInterfaces(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
printf("System has %d network interfaces\n\n", numInterfaces);
// Try connecting via each interface
for (int i = 0; i < numInterfaces; i++) {
IPADDR ifAddr = GetInterfaceIP(i);
printf("Testing Interface %d (%s)...", i, ifAddr.print());
uint32_t startTime = Secs;
int fd = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 5, i);
uint32_t elapsed = Secs - startTime;
if (fd > 0) {
printf(" SUCCESS (%lu sec)\n", elapsed);
printf(" Confirmed interface: %d\n", TcpGetSocketInterface(fd));
printf(" Local endpoint: %s:%d\n",
close(fd);
} else {
printf(" FAILED (error %d after %lu sec)\n", fd, elapsed);
}
printf("\n");
}
printf("Interface testing complete\n");
}
Primary and Backup Interface with Automatic Failover
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Connect with automatic failover from primary to backup interface
int ConnectWithInterfaceFailover(IPADDR serverAddr, uint16_t port,
int primaryInterface, int backupInterface) {
// Try primary interface first
printf("Attempting connection via primary interface %d (%s)...\n",
primaryInterface,
GetInterfaceIP(primaryInterface).print());
int fd = connectvia(serverAddr, port, TICKS_PER_SECOND * 5, primaryInterface);
if (fd > 0) {
printf("Connected via primary interface\n");
return fd;
}
printf("Primary interface failed: %d\n", fd);
printf("Failing over to backup interface %d (%s)...\n",
backupInterface,
GetInterfaceIP(backupInterface).print());
fd = connectvia(serverAddr, port, TICKS_PER_SECOND * 5, backupInterface);
if (fd > 0) {
printf("Connected via backup interface\n");
return fd;
}
printf("Backup interface also failed: %d\n", fd);
printf("All interfaces exhausted\n");
return fd;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Try interface 0 first, failover to interface 1
int fd = ConnectWithInterfaceFailover(serverAddr, 8080, 0, 1);
if (fd > 0) {
printf("Connection established via interface %d\n",
// Use connection...
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Interface Validation Before Connection
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Safely connect via interface with validation
int SafeConnectViaInterface(IPADDR serverAddr, uint16_t port, int ifnum) {
// Validate interface number
int maxInterfaces = GetNumberOfInterfaces();
if (ifnum < 0 || ifnum >= maxInterfaces) {
printf("ERROR: Invalid interface number %d\n", ifnum);
printf("Valid range is 0 to %d\n", maxInterfaces - 1);
return -1;
}
// Get interface information
IPADDR ifAddr = GetInterfaceIP(ifnum);
// Check if interface has valid IP
if (ifAddr == IPADDR::NullIP()) {
printf("ERROR: Interface %d has no IP address assigned\n", ifnum);
return -1;
}
// Check if interface is up (platform-specific, may need additional checks)
printf("Interface %d status:\n", ifnum);
printf(" IP Address: %s\n", ifAddr.print());
// Proceed with connection
printf("Connecting via interface %d...\n", ifnum);
int fd = connectvia(serverAddr, port, TICKS_PER_SECOND * 10, ifnum);
if (fd > 0) {
printf("Connection successful\n");
} else {
printf("Connection failed: %d\n", fd);
}
return fd;
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int fd = SafeConnectViaInterface(serverAddr, 8080, 1);
if (fd > 0) {
close(fd);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Load Distribution Across Interfaces
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Distribute connections evenly across available interfaces
void LoadBalancedConnections(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
printf("Load balancing across %d interfaces\n\n", numInterfaces);
// Connection counters for each interface
int connectionCounts[4] = {0}; // Support up to 4 interfaces
int totalConnections = 20;
int successfulConnections = 0;
for (int i = 0; i < totalConnections; i++) {
// Round-robin interface selection
int interfaceNum = i % numInterfaces;
printf("Connection %d via interface %d...", i + 1, interfaceNum);
int fd = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 10, interfaceNum);
if (fd > 0) {
printf(" OK\n");
connectionCounts[interfaceNum]++;
successfulConnections++;
// Simulate some work
const char *msg = "PING\r\n";
write(fd, msg, strlen(msg));
close(fd);
} else {
printf(" FAILED: %d\n", fd);
}
OSTimeDly(TICKS_PER_SECOND / 2); // Small delay between connections
}
// Display statistics
printf("\n=== Connection Statistics ===\n");
printf("Total attempts: %d\n", totalConnections);
printf("Successful: %d\n", successfulConnections);
printf("Failed: %d\n\n", totalConnections - successfulConnections);
printf("Per-Interface Distribution:\n");
for (int i = 0; i < numInterfaces; i++) {
printf(" Interface %d: %d connections (%.1f%%)\n",
i,
connectionCounts[i],
(connectionCounts[i] * 100.0) / successfulConnections);
}
}
Interface-Specific Connection Pools
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#define MAX_CONNECTIONS_PER_INTERFACE 5
// Manage separate connection pools for each interface
struct InterfacePool {
int interfaceNum;
int connections[MAX_CONNECTIONS_PER_INTERFACE];
int activeCount;
};
void InitPool(InterfacePool *pool, int ifnum) {
pool->interfaceNum = ifnum;
pool->activeCount = 0;
for (int i = 0; i < MAX_CONNECTIONS_PER_INTERFACE; i++) {
pool->connections[i] = -1;
}
}
int AddConnection(InterfacePool *pool, IPADDR serverAddr, uint16_t port) {
if (pool->activeCount >= MAX_CONNECTIONS_PER_INTERFACE) {
printf("Interface %d pool full\n", pool->interfaceNum);
return -1;
}
int fd = connectvia(serverAddr, port,
pool->interfaceNum);
if (fd > 0) {
pool->connections[pool->activeCount++] = fd;
printf("Added connection to interface %d pool (now %d active)\n",
pool->interfaceNum, pool->activeCount);
}
return fd;
}
void CloseAllConnections(InterfacePool *pool) {
printf("Closing all connections on interface %d...\n", pool->interfaceNum);
for (int i = 0; i < pool->activeCount; i++) {
if (pool->connections[i] > 0) {
close(pool->connections[i]);
pool->connections[i] = -1;
}
}
pool->activeCount = 0;
printf("All connections closed on interface %d\n", pool->interfaceNum);
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Create pools for two interfaces
InterfacePool pool0, pool1;
InitPool(&pool0, 0);
InitPool(&pool1, 1);
// Add connections to each pool
printf("Building connection pools...\n");
for (int i = 0; i < 3; i++) {
AddConnection(&pool0, serverAddr, 8080);
AddConnection(&pool1, serverAddr, 8080);
}
printf("\nPools established\n");
printf("Interface 0: %d connections\n", pool0.activeCount);
printf("Interface 1: %d connections\n", pool1.activeCount);
// Use connections...
OSTimeDly(TICKS_PER_SECOND * 5);
// Clean up
CloseAllConnections(&pool0);
CloseAllConnections(&pool1);
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Comparing Interface Selection Methods
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void CompareSelectionMethods(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
IPADDR interface1IP = GetInterfaceIP(1);
printf("Comparing interface selection methods for interface 1\n");
printf("Interface 1 IP: %s\n\n", interface1IP.print());
// Method 1: By interface number (this function)
printf("Method 1: Selection by interface number\n");
uint32_t start1 = TimeTick;
int fd1 = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 10, 1);
uint32_t time1 = TimeTick - start1;
if (fd1 > 0) {
printf(" Success in %lu ticks\n", time1);
printf(" Interface: %d\n", TcpGetSocketInterface(fd1));
printf(" Local IP: %s\n", GetSocketLocalAddr(fd1).print());
close(fd1);
} else {
printf(" Failed: %d\n", fd1);
}
OSTimeDly(TICKS_PER_SECOND);
// Method 2: By IP address (overloaded version)
printf("\nMethod 2: Selection by IP address\n");
uint32_t start2 = TimeTick;
int fd2 = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 10, interface1IP);
uint32_t time2 = TimeTick - start2;
if (fd2 > 0) {
printf(" Success in %lu ticks\n", time2);
printf(" Interface: %d\n", TcpGetSocketInterface(fd2));
printf(" Local IP: %s\n", GetSocketLocalAddr(fd2).print());
close(fd2);
} else {
printf(" Failed: %d\n", fd2);
}
// Analysis
printf("\n=== Analysis ===\n");
printf("Interface number method is more direct and unambiguous\n");
printf("IP address method requires IP lookup step\n");
printf("Both methods should select the same interface\n");
if (fd1 > 0 && fd2 > 0) {
printf("\nTiming comparison:\n");
printf(" By number: %lu ticks\n", time1);
printf(" By IP: %lu ticks\n", time2);
printf(" Difference: %ld ticks\n", (long)(time2 - time1));
}
}
Interface Health Monitoring
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
// Monitor health of each interface by attempting periodic connections
void MonitorInterfaceHealth(void *pd) {
init();
IPADDR testServer = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
// Health tracking
struct InterfaceHealth {
int successCount;
int failureCount;
uint32_t lastSuccessTime;
uint32_t lastFailureTime;
} health[4] = {0}; // Support up to 4 interfaces
printf("Starting interface health monitoring\n");
printf("Test server: %s\n", testServer.print());
printf("Interfaces: %d\n\n", numInterfaces);
for (int cycle = 0; cycle < 10; cycle++) {
printf("=== Health Check Cycle %d ===\n", cycle + 1);
for (int i = 0; i < numInterfaces; i++) {
int fd = connectvia(testServer, 8080, TICKS_PER_SECOND * 3, i);
if (fd > 0) {
health[i].successCount++;
health[i].lastSuccessTime = Secs;
printf("Interface %d: HEALTHY\n", i);
close(fd);
} else {
health[i].failureCount++;
health[i].lastFailureTime = Secs;
printf("Interface %d: UNHEALTHY (error %d)\n", i, fd);
}
}
// Display statistics
printf("\nCurrent Statistics:\n");
for (int i = 0; i < numInterfaces; i++) {
int total = health[i].successCount + health[i].failureCount;
float successRate = (total > 0) ?
(health[i].successCount * 100.0f) / total : 0.0f;
printf(" Interface %d: %.1f%% success rate (%d/%d)\n",
i, successRate, health[i].successCount, total);
}
printf("\n");
OSTimeDly(TICKS_PER_SECOND * 5);
}
printf("Health monitoring complete\n");
}
Dynamic Interface Selection Based on Policy
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
enum ConnectionPolicy {
POLICY_PRIMARY_ONLY,
POLICY_ROUND_ROBIN,
POLICY_LEAST_LOADED,
POLICY_RANDOM
};
int connectionCounts[4] = {0}; // Track connections per interface
int currentRRInterface = 0; // Round-robin counter
int SelectInterface(ConnectionPolicy policy, int numInterfaces) {
switch (policy) {
case POLICY_PRIMARY_ONLY:
return 0; // Always use interface 0
case POLICY_ROUND_ROBIN:
{
int selected = currentRRInterface;
currentRRInterface = (currentRRInterface + 1) % numInterfaces;
return selected;
}
case POLICY_LEAST_LOADED:
{
int minCount = connectionCounts[0];
int minIndex = 0;
for (int i = 1; i < numInterfaces; i++) {
if (connectionCounts[i] < minCount) {
minCount = connectionCounts[i];
minIndex = i;
}
}
return minIndex;
}
case POLICY_RANDOM:
return rand() % numInterfaces;
default:
return 0;
}
}
void PolicyBasedConnections(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
ConnectionPolicy policy = POLICY_ROUND_ROBIN;
printf("Using policy: ROUND_ROBIN\n");
printf("Making 10 connections...\n\n");
for (int i = 0; i < 10; i++) {
int selectedIF = SelectInterface(policy, numInterfaces);
printf("Connection %d: Selected interface %d\n", i + 1, selectedIF);
int fd = connectvia(serverAddr, 8080, TICKS_PER_SECOND * 10, selectedIF);
if (fd > 0) {
connectionCounts[selectedIF]++;
printf(" Success via interface %d\n", selectedIF);
close(fd);
} else {
printf(" Failed: %d\n", fd);
}
}
printf("\n=== Final Distribution ===\n");
for (int i = 0; i < numInterfaces; i++) {
printf("Interface %d: %d connections\n", i, connectionCounts[i]);
}
}

See also
connect(), connectvia(const IPADDR&, uint16_t, uint32_t, const IPADDR&), connectwlocal(), NoBlockConnectVia(), GetNumberOfInterfaces(), GetInterfaceIP(), TcpGetSocketInterface()

◆ connectwlocal() [1/2]

int connectwlocal ( const IPADDR & ipAddress,
uint16_t localPort,
uint16_t remotePort,
TickTimeout timeout,
const IPADDR & localIpAddress = IPADDR::NullIP(),
int intf = -1 )
inline

#include <tcp.h>

Establish a TCP connection with full control over local parameters and TickTimeout.

Creates a new TCP socket with complete control over both local and remote connection parameters, using a TickTimeout object for sophisticated timeout management. This function allows specification of the local port, interface IP address, or interface number, combined with precise timeout tracking for complex connection sequences.

This is the most advanced connection function, providing maximum control over all connection parameters plus the ability to track elapsed time and share timeout budgets. Most applications should use simpler connection functions unless they have specific requirements for local port control, explicit interface selection, and advanced timeout management.

Warning
Specifying a local port number is not recommended and should be avoided except in specialized cases. Using a fixed local port can cause connection failures when the remote host has a half-open socket remaining from a previous connection.
Parameters
ipAddressIP address of the remote host. Can be IPv4 or IPv6 depending on build configuration
localPortLocal port number to bind (1-65535, or 0 for automatic assignment). Strongly recommend using 0 unless you have a specific protocol requirement (e.g., FTP active mode). Non-zero values can cause TCP_ERR_NOCON or connection failures when reconnecting if the previous connection is in TIME_WAIT state on the remote side
remotePortPort number on the remote host (1-65535)
timeoutTickTimeout object specifying the maximum wait time. Unlike the reference version, this is passed by value, so the original timeout object is not modified. The function creates an internal copy for timeout tracking
localIpAddressIP address of the local interface to use. Selects the network interface with this IP address. Use IPADDR::NullIP() if you want to specify interface by number instead (intf parameter). Default: IPADDR::NullIP() (automatic selection or use intf)
intfLocal interface number (0, 1, 2, etc.). Use -1 if you want to specify interface by IP address instead (localIpAddress parameter). Interface number takes precedence over IP-based routing. Default: -1 (use IP-based routing or localIpAddress)
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_NOCON: Local port is already in use or address binding failed
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:

  • Unlike the reference version (TickTimeout&), this function accepts TickTimeout by value, so the caller's timeout object is not modified. This is useful when you want to preserve the original timeout state.
  • Parameter Priority:
    • If intf >= 0: Uses the specified interface number, ignores localIpAddress
    • If intf == -1 and localIpAddress != NullIP(): Uses interface with that IP
    • If intf == -1 and localIpAddress == NullIP(): Uses routing table
  • Local Port Behavior:
    • localPort == 0: System assigns available ephemeral port (recommended)
    • localPort != 0: Attempts to bind to specific port (can fail if in use)
  • Always call close() on the returned file descriptor when finished to free system resources and release the local port.
  • This function blocks the calling task until the connection is established or the timeout expires. For non-blocking connection attempts, use NoBlockConnectwlocal().
Warning
The combination of local port, interface IP, and interface number must be logically consistent. Specifying conflicting parameters will result in unpredictable behavior.

Expand for Example Usage

Examples

Basic Usage with Preserved Timeout Object
#include <tcp.h>
#include <init.h>
void ConnectWithPreservedTimeout(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Create timeout that we want to preserve
TickTimeout timeout(TICKS_PER_SECOND * 15);
printf("Original timeout: %lu ticks\n", timeout.GetTimeLeft());
// Connect using value semantics (timeout is copied, not modified)
int fd = connectwlocal(serverAddr,
0, // Auto-assign local port
8080, // Remote port
timeout, // Passed by value
-1);
// Original timeout object is unchanged
printf("After connect, original timeout still: %lu ticks\n",
timeout.GetTimeLeft());
if (fd > 0) {
printf("Connected successfully!\n");
printf("Can reuse original timeout for other operations\n");
close(fd);
}
}
int connectwlocal(const IPADDR &ipAddress, uint16_t localPort, uint16_t remotePort, uint32_t timeout, const IPADDR &localIpAddress=IPADDR::NullIP(), int intf=-1)
Establish a TCP connection with full control over local parameters.
Definition tcp.h:3261
Multiple Connections with Same Timeout Template
#include <tcp.h>
#include <init.h>
// Make multiple connections using the same timeout template
void MultipleConnectionsSameTimeout(void *pd) {
init();
IPADDR servers[] = {
AsciiToIp("192.168.1.10"),
AsciiToIp("192.168.1.20"),
AsciiToIp("192.168.1.30")
};
// Create timeout template
TickTimeout timeoutTemplate(TICKS_PER_SECOND * 10);
printf("Connecting to 3 servers, each with fresh 10 sec timeout\n\n");
for (int i = 0; i < 3; i++) {
printf("Server %d (%s)...", i + 1, servers[i].print());
// Each connection gets a fresh copy of the timeout
int fd = connectwlocal(servers[i],
0,
8080,
timeoutTemplate, // Copy for each connection
-1);
if (fd > 0) {
printf(" Connected\n");
close(fd);
} else {
printf(" Failed: %d\n", fd);
}
// Verify template is unchanged
printf(" Template timeout still: %lu ticks\n",
timeoutTemplate.GetTimeLeft());
}
printf("\nAll connections attempted with independent timeouts\n");
}
Interface Selection by IP with TickTimeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void ConnectViaSpecificInterface(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
IPADDR localIP = GetInterfaceIP(1); // Use interface 1
printf("Connecting via interface %s\n", localIP.print());
TickTimeout timeout(TICKS_PER_SECOND * 15);
int fd = connectwlocal(serverAddr,
0, // Auto-assign port
8080, // Remote port
timeout, // By value
localIP, // Specific interface IP
-1); // Not using interface number
if (fd > 0) {
printf("Connected successfully!\n");
printf(" Local: %s:%d\n",
printf(" Remote: %s:%d\n",
// Verify correct interface used
if (GetSocketLocalAddr(fd) == localIP) {
printf(" Verified: Using requested interface\n");
}
close(fd);
} else {
printf("Connection failed: %d\n", fd);
}
}
Interface Selection by Number with TickTimeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void ConnectViaInterfaceNumber(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int interfaceNum = 0;
printf("Connecting via interface %d (%s)\n",
interfaceNum, GetInterfaceIP(interfaceNum).print());
TickTimeout timeout(TICKS_PER_SECOND * 15);
int fd = connectwlocal(serverAddr,
0, // Auto-assign port
8080, // Remote port
timeout, // By value
IPADDR::NullIP(), // Not using IP selection
interfaceNum); // Specific interface number
if (fd > 0) {
printf("Connected successfully!\n");
printf(" Interface used: %d\n", TcpGetSocketInterface(fd));
printf(" Local IP: %s\n", GetSocketLocalAddr(fd).print());
close(fd);
} else {
printf("Connection failed: %d\n", fd);
}
}
FTP Active Mode with Fixed Port
#include <tcp.h>
#include <init.h>
// FTP active mode requires fixed local port for data connection
void FtpActiveModeConnection(void *pd) {
init();
IPADDR ftpServer = AsciiToIp("192.168.1.10");
// Step 1: Connect to FTP control port
printf("Connecting to FTP control port...\n");
TickTimeout controlTimeout(TICKS_PER_SECOND * 10);
int fdControl = connectwlocal(ftpServer,
0, // Auto-assign
21, // FTP control
controlTimeout,
-1);
if (fdControl < 0) {
printf("Control connection failed: %d\n", fdControl);
return;
}
printf("FTP control connected\n");
// Step 2: For FTP active mode, we need a listening socket
// This is one of the few legitimate uses of fixed local port
uint16_t dataPort = 2000;
int fdDataListen = listen(INADDR_ANY, dataPort, 1);
if (fdDataListen < 0) {
printf("Data listen socket failed: %d\n", fdDataListen);
close(fdControl);
return;
}
printf("Data listen socket on port %d\n", dataPort);
// Step 3: Tell server our IP and port
IPADDR localIP = GetSocketLocalAddr(fdControl);
char portCmd[128];
uint8_t *ip = (uint8_t *)&localIP;
snprintf(portCmd, sizeof(portCmd),
"PORT %d,%d,%d,%d,%d,%d\r\n",
ip[0], ip[1], ip[2], ip[3],
dataPort >> 8, dataPort & 0xFF);
write(fdControl, portCmd, strlen(portCmd));
printf("Sent PORT command\n");
// Step 4: Accept data connection from server
printf("Waiting for server data connection...\n");
IPADDR serverDataAddr;
uint16_t serverDataPort;
int fdData = accept(fdDataListen, &serverDataAddr, &serverDataPort,
if (fdData > 0) {
printf("FTP data connection accepted from %s:%d\n",
serverDataAddr.print(), serverDataPort);
close(fdData);
}
close(fdDataListen);
close(fdControl);
printf("FTP active mode example complete\n");
}
Connection Pool with Per-Interface Timeout
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#define CONNECTIONS_PER_INTERFACE 3
struct ConnectionPool {
int interfaceNum;
int connections[CONNECTIONS_PER_INTERFACE];
int activeCount;
};
void CreateInterfacePool(ConnectionPool *pool, int ifNum,
IPADDR serverAddr, uint16_t port) {
pool->interfaceNum = ifNum;
pool->activeCount = 0;
IPADDR localIP = GetInterfaceIP(ifNum);
TickTimeout timeoutTemplate(TICKS_PER_SECOND * 10);
printf("Creating pool for interface %d (%s)\n",
ifNum, localIP.print());
for (int i = 0; i < CONNECTIONS_PER_INTERFACE; i++) {
printf(" Connection %d...", i + 1);
// Each connection gets fresh timeout (passed by value)
int fd = connectwlocal(serverAddr,
0, // Auto port
port,
timeoutTemplate, // Copy
localIP, // Via this interface
-1);
if (fd > 0) {
pool->connections[pool->activeCount++] = fd;
printf(" OK (port %d)\n", GetSocketLocalPort(fd));
} else {
pool->connections[i] = -1;
printf(" Failed: %d\n", fd);
}
}
printf("Pool created: %d/%d connections\n\n",
pool->activeCount, CONNECTIONS_PER_INTERFACE);
}
void UserMain(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
ConnectionPool pools[4]; // Support up to 4 interfaces
// Create pool for each interface
for (int i = 0; i < numInterfaces; i++) {
CreateInterfacePool(&pools[i], i, serverAddr, 8080);
}
// Use connections...
OSTimeDly(TICKS_PER_SECOND * 5);
// Clean up
for (int i = 0; i < numInterfaces; i++) {
for (int j = 0; j < pools[i].activeCount; j++) {
close(pools[i].connections[j]);
}
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Parallel Attempts Across Interfaces
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Try all interfaces in parallel with same timeout
void ParallelInterfaceAttempts(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = GetNumberOfInterfaces();
// Create shared timeout template
TickTimeout timeoutTemplate(TICKS_PER_SECOND * 8);
printf("Attempting parallel connections via all interfaces\n");
printf("Each attempt gets 8 second timeout\n\n");
int fds[4] = {-1, -1, -1, -1}; // Store results
uint32_t startTime = Secs;
// Launch all attempts (in real implementation, would use tasks)
for (int i = 0; i < numInterfaces; i++) {
IPADDR localIP = GetInterfaceIP(i);
printf("Interface %d (%s): Connecting...\n",
i, localIP.print());
// Each gets independent timeout copy
fds[i] = connectwlocal(serverAddr,
0,
8080,
timeoutTemplate, // Fresh copy
localIP,
-1);
if (fds[i] > 0) {
printf(" SUCCESS\n");
} else {
printf(" Failed: %d\n", fds[i]);
}
}
uint32_t elapsed = Secs - startTime;
// Summary
printf("\n=== Results ===\n");
printf("Total time: %lu seconds\n", elapsed);
int successCount = 0;
for (int i = 0; i < numInterfaces; i++) {
if (fds[i] > 0) {
successCount++;
printf("Interface %d: Connected (fd=%d)\n", i, fds[i]);
close(fds[i]);
} else {
printf("Interface %d: Failed\n", i);
}
}
printf("\nSuccess rate: %d/%d\n", successCount, numInterfaces);
}
Testing All Parameter Combinations
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
void TestAllParameterCombinations(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
IPADDR interface0IP = GetInterfaceIP(0);
TickTimeout timeoutTemplate(TICKS_PER_SECOND * 10);
printf("Testing connectwlocal parameter combinations\n\n");
// Test 1: Auto port, auto interface
printf("Test 1: Auto port, auto interface\n");
int fd1 = connectwlocal(serverAddr, 0, 8080,
timeoutTemplate,
if (fd1 > 0) {
printf(" Result: %s:%d\n",
close(fd1);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 2: Auto port, interface by IP
printf("\nTest 2: Auto port, interface by IP (%s)\n",
interface0IP.print());
int fd2 = connectwlocal(serverAddr, 0, 8080,
timeoutTemplate,
interface0IP, -1);
if (fd2 > 0) {
printf(" Result: %s:%d\n",
close(fd2);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 3: Auto port, interface by number
printf("\nTest 3: Auto port, interface by number (0)\n");
int fd3 = connectwlocal(serverAddr, 0, 8080,
timeoutTemplate,
if (fd3 > 0) {
printf(" Result: %s:%d\n",
close(fd3);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 4: Fixed port (NOT RECOMMENDED except for special cases)
printf("\nTest 4: Fixed port 7000 (NOT RECOMMENDED)\n");
int fd4 = connectwlocal(serverAddr, 7000, 8080,
timeoutTemplate,
if (fd4 > 0) {
printf(" Result: %s:%d\n",
close(fd4);
} else {
printf(" Failed: %d (may be in use)\n", fd4);
}
printf("\nTesting complete\n");
}
Timeout Template Library Pattern
#include <tcp.h>
#include <init.h>
// Create library of reusable timeout templates
namespace TimeoutTemplates {
TickTimeout Quick(TICKS_PER_SECOND * 3); // 3 seconds
TickTimeout Normal(TICKS_PER_SECOND * 10); // 10 seconds
TickTimeout Patient(TICKS_PER_SECOND * 30); // 30 seconds
TickTimeout VeryPatient(TICKS_PER_SECOND * 60); // 60 seconds
};
void UseTimeoutTemplates(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
// Quick attempt for high-priority connection
printf("Quick attempt (3 sec timeout)...\n");
int fd1 = connectwlocal(serverAddr, 0, 8080,
TimeoutTemplates::Quick,
if (fd1 < 0) {
printf("Quick failed, trying normal timeout...\n");
// Fall back to normal timeout
int fd2 = connectwlocal(serverAddr, 0, 8080,
TimeoutTemplates::Normal,
if (fd2 < 0) {
printf("Normal failed, using patient timeout...\n");
// Last resort with patient timeout
int fd3 = connectwlocal(serverAddr, 0, 8080,
TimeoutTemplates::Patient,
if (fd3 > 0) {
printf("Connected with patient timeout\n");
close(fd3);
}
} else {
printf("Connected with normal timeout\n");
close(fd2);
}
} else {
printf("Connected with quick timeout\n");
close(fd1);
}
// Template objects are preserved for reuse
printf("\nTimeout templates ready for next use\n");
}

See also
connectwlocal(const IPADDR&, uint16_t, uint16_t, uint32_t, const IPADDR&, int), connect(), connectvia(), NoBlockConnectwlocal(), TickTimeout

◆ connectwlocal() [2/2]

int connectwlocal ( const IPADDR & ipAddress,
uint16_t localPort,
uint16_t remotePort,
uint32_t timeout,
const IPADDR & localIpAddress = IPADDR::NullIP(),
int intf = -1 )
inline

#include <tcp.h>

Establish a TCP connection with full control over local parameters.

Creates a new TCP socket with complete control over both local and remote connection parameters. This function allows specification of the local port, interface IP address, or interface number. This is an advanced function intended for specialized use cases where standard connect() or connectvia() are insufficient.

Most applications should use connect() or connectvia() instead. This function is provided for protocols or scenarios that require specific local port numbers or explicit control over both the interface and local port simultaneously.

Warning
Specifying a local port number is not recommended and should be avoided except in specialized cases. Using a fixed local port can cause connection failures when the remote host has a half-open socket remaining from a previous connection. This is a common problem in client applications that reconnect frequently.
The combination of local port, interface IP, and interface number must be logically consistent. Specifying conflicting parameters will result in unpredictable behavior.
Parameters
ipAddressIP address of the remote host. Can be IPv4 or IPv6 depending on build configuration
localPortLocal port number to bind (1-65535, or 0 for automatic assignment). Strongly recommend using 0 unless you have a specific protocol requirement. Non-zero values can cause TCP_ERR_NOCON or connection failures when reconnecting if the previous connection is in TIME_WAIT state on the remote side
remotePortPort number on the remote host (1-65535)
timeoutMaximum connection time in system ticks:
  • Use TICKS_PER_SECOND * n for n second timeout
  • Example: TICKS_PER_SECOND * 10 for 10 second timeout
  • Recommended: 5-30 seconds for most applications
localIpAddressIP address of the local interface to use. Selects the network interface with this IP address. Use IPADDR::NullIP() if you want to specify interface by number instead (intf parameter). Default: IPADDR::NullIP() (automatic selection)
intfLocal interface number (0, 1, 2, etc.). Use -1 if you want to specify interface by IP address instead (localIpAddress parameter). Interface number takes precedence over IP-based routing. Default: -1 (use IP-based routing or localIpAddress)
Returns
Positive file descriptor on success (use for read/write operations), negative TCP Socket Status error code on failure:
  • TCP_ERR_TIMEOUT: Connection not established within timeout period
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_NOCON: Local port is already in use or address binding failed
  • TCP_ERR_CON_RESET: Connection was reset during establishment
  • TCP_ERR_CON_ABORT: Connection was aborted

Notes:
Parameter Priority:

  • If intf >= 0: Uses the specified interface number, ignores localIpAddress
  • If intf == -1 and localIpAddress != NullIP(): Uses interface with that IP
  • If intf == -1 and localIpAddress == NullIP(): Uses routing table

Local Port Behavior:

  • localPort == 0: System assigns available ephemeral port (recommended)
  • localPort != 0: Attempts to bind to specific port (can fail if in use)

Common Use Cases:

  • FTP active mode (requires specific local port for data connection)
  • Protocol testing and debugging (need predictable source port)
  • Load balancing across multiple interfaces
  • Binding to specific interface when routing is ambiguous

Always call close() on the returned file descriptor when finished to free system resources and release the local port.


Expand for Example Usage

Examples

Basic Usage - Interface Selection by IP
#include <tcp.h>
#include <init.h>
void ConnectViaSpecificInterface(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
IPADDR localAddr = GetInterfaceIP(0); // Use interface 0's IP
printf("Connecting to %s via local interface %s\n",
serverAddr.print(), localAddr.print());
// Connect using specific local interface, automatic port
int fd = connectwlocal(serverAddr,
0, // Auto-assign local port
8080, // Remote port
localAddr, // Specific interface IP
-1); // Not using interface number
if (fd > 0) {
printf("Connected!\n");
printf(" Local: %s:%d\n",
printf(" Remote: %s:%d\n",
close(fd);
} else {
printf("Connection failed: %d\n", fd);
}
}
Interface Selection by Number
#include <tcp.h>
#include <init.h>
void ConnectViaInterfaceNumber(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("10.0.1.50");
int interfaceNum = 1; // Use interface 1
printf("Connecting via interface %d\n", interfaceNum);
printf("Interface %d IP: %s\n",
interfaceNum, GetInterfaceIP(interfaceNum).print());
// Connect using interface number
int fd = connectwlocal(serverAddr,
0, // Auto-assign local port
9000, // Remote port
IPADDR::NullIP(), // Not using IP selection
interfaceNum); // Use interface 1
if (fd > 0) {
printf("Connected via interface %d\n", interfaceNum);
printf("Actual local IP used: %s\n",
close(fd);
} else {
printf("Connection failed: %d\n", fd);
}
}
Specifying Local Port (Not Recommended)
#include <tcp.h>
#include <init.h>
// Example showing why fixed local ports are problematic
void DemonstrateLocalPortProblem(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
uint16_t fixedLocalPort = 5000;
printf("Attempting first connection with local port %d\n", fixedLocalPort);
// First connection with fixed local port
int fd1 = connectwlocal(serverAddr,
fixedLocalPort, // Fixed local port
8080,
-1);
if (fd1 > 0) {
printf("First connection succeeded\n");
printf(" Local: %s:%d\n",
// Simulate some work
OSTimeDly(TICKS_PER_SECOND * 2);
close(fd1);
printf("First connection closed\n");
}
// Try to reconnect immediately with same local port
printf("\nAttempting second connection with same local port %d\n",
fixedLocalPort);
int fd2 = connectwlocal(serverAddr,
fixedLocalPort, // Same fixed local port
8080,
-1);
if (fd2 > 0) {
printf("Second connection succeeded (lucky!)\n");
close(fd2);
} else {
printf("Second connection FAILED: %d\n", fd2);
printf("This is why fixed local ports are problematic!\n");
printf("The local port may still be in TIME_WAIT state.\n");
}
// Show the correct approach
printf("\nCorrect approach - using automatic port assignment:\n");
int fd3 = connectwlocal(serverAddr,
0, // Auto-assign port (RECOMMENDED)
8080,
-1);
if (fd3 > 0) {
printf("Connection with auto-assigned port succeeded\n");
printf(" Assigned local port: %d\n", GetSocketLocalPort(fd3));
close(fd3);
}
}
Multi-Interface Load Balancing
#include <tcp.h>
#include <init.h>
// Distribute connections across multiple interfaces
void LoadBalancedConnections(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
int numInterfaces = 2; // Assume 2 network interfaces
int connectionCount = 0;
printf("Load balancing connections across %d interfaces\n", numInterfaces);
for (int i = 0; i < 10; i++) { // Make 10 connections
int interfaceNum = connectionCount % numInterfaces;
printf("\nConnection %d using interface %d\n", i + 1, interfaceNum);
int fd = connectwlocal(serverAddr,
0, // Auto port
8080,
interfaceNum);
if (fd > 0) {
printf(" Success - Local IP: %s, Port: %d\n",
connectionCount++;
// Do work...
const char *msg = "Hello\r\n";
write(fd, msg, strlen(msg));
close(fd);
} else {
printf(" Failed: %d\n", fd);
}
OSTimeDly(TICKS_PER_SECOND);
}
printf("\nTotal successful connections: %d\n", connectionCount);
}
FTP Active Mode (Legitimate Fixed Port Use Case)
#include <tcp.h>
#include <init.h>
// FTP active mode requires server to connect back to specific client port
void FtpActiveMode(void *pd) {
init();
IPADDR ftpServer = AsciiToIp("192.168.1.10");
// Step 1: Connect to FTP control port
int fdControl = connect(ftpServer, 21, TICKS_PER_SECOND * 10);
if (fdControl < 0) {
printf("FTP control connection failed: %d\n", fdControl);
return;
}
printf("FTP control connection established\n");
// Step 2: Create listening socket for data connection
uint16_t dataPort = 2000; // Our data port
int fdDataListen = listen(INADDR_ANY, dataPort, 1);
if (fdDataListen < 0) {
printf("Failed to create data listen socket: %d\n", fdDataListen);
close(fdControl);
return;
}
// Step 3: Send PORT command to FTP server
IPADDR localIP = GetSocketLocalAddr(fdControl);
char portCmd[128];
// Format: PORT h1,h2,h3,h4,p1,p2 where h=IP octets, p=port bytes
uint8_t *ip = (uint8_t *)&localIP;
snprintf(portCmd, sizeof(portCmd),
"PORT %d,%d,%d,%d,%d,%d\r\n",
ip[0], ip[1], ip[2], ip[3],
dataPort >> 8, dataPort & 0xFF);
write(fdControl, portCmd, strlen(portCmd));
printf("Sent: %s", portCmd);
// Step 4: Read FTP response
char response[256];
int n = read(fdControl, response, sizeof(response) - 1);
if (n > 0) {
response[n] = '\0';
printf("FTP response: %s", response);
}
// Step 5: Accept data connection from server
printf("Waiting for FTP server to connect to port %d...\n", dataPort);
IPADDR serverDataAddr;
uint16_t serverDataPort;
int fdData = accept(fdDataListen, &serverDataAddr, &serverDataPort,
if (fdData > 0) {
printf("FTP data connection accepted from %s:%d\n",
serverDataAddr.print(), serverDataPort);
// Transfer data...
close(fdData);
}
close(fdDataListen);
close(fdControl);
printf("FTP active mode example complete\n");
}
Comparing Interface Selection Methods
#include <tcp.h>
#include <init.h>
void CompareInterfaceSelection(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
printf("Comparing three interface selection methods:\n\n");
// Method 1: Automatic (standard connect)
printf("Method 1: Automatic interface selection\n");
int fd1 = connect(serverAddr, 8080, TICKS_PER_SECOND * 10);
if (fd1 > 0) {
printf(" Selected interface: %s\n",
printf(" Interface number: %d\n",
close(fd1);
}
OSTimeDly(TICKS_PER_SECOND);
// Method 2: By IP address
printf("\nMethod 2: Selection by IP address\n");
IPADDR interface0IP = GetInterfaceIP(0);
printf(" Requesting interface with IP: %s\n", interface0IP.print());
int fd2 = connectwlocal(serverAddr,
0,
8080,
interface0IP, // Select by IP
-1);
if (fd2 > 0) {
printf(" Selected interface: %s\n",
printf(" Interface number: %d\n",
close(fd2);
}
OSTimeDly(TICKS_PER_SECOND);
// Method 3: By interface number
printf("\nMethod 3: Selection by interface number\n");
int interfaceNum = 1;
printf(" Requesting interface number: %d\n", interfaceNum);
int fd3 = connectwlocal(serverAddr,
0,
8080,
interfaceNum); // Select by number
if (fd3 > 0) {
printf(" Selected interface: %s\n",
printf(" Interface number: %d\n",
close(fd3);
}
printf("\nComparison complete\n");
}
Error Handling for Local Port Conflicts
#include <tcp.h>
#include <init.h>
void HandleLocalPortConflicts(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
uint16_t desiredPort = 6000;
printf("Attempting to use local port %d\n", desiredPort);
int fd = connectwlocal(serverAddr,
desiredPort,
8080,
-1);
if (fd > 0) {
printf("Successfully bound to port %d\n",
close(fd);
} else if (fd == TCP_ERR_NOCON) {
printf("Port %d binding failed (TCP_ERR_NOCON)\n", desiredPort);
printf("Possible causes:\n");
printf(" - Port already in use by another socket\n");
printf(" - Port in TIME_WAIT state from previous connection\n");
printf(" - Insufficient permissions (ports < 1024)\n");
printf("\nRetrying with automatic port assignment...\n");
// Retry with automatic port
fd = connectwlocal(serverAddr,
0, // Let system choose
8080,
-1);
if (fd > 0) {
printf("Success with auto-assigned port %d\n",
close(fd);
}
} else {
printf("Connection failed: %d\n", fd);
}
}
Testing All Parameter Combinations
#include <tcp.h>
#include <init.h>
void TestParameterCombinations(void *pd) {
init();
IPADDR serverAddr = AsciiToIp("192.168.1.100");
IPADDR localIP = GetInterfaceIP(0);
printf("Testing connectwlocal parameter combinations:\n\n");
// Test 1: Auto port, no interface specification
printf("Test 1: Auto port, auto interface\n");
int fd1 = connectwlocal(serverAddr, 0, 8080,
if (fd1 > 0) {
printf(" Result: %s:%d\n",
close(fd1);
} else {
printf(" Failed: %d\n", fd1);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 2: Auto port, specific interface by IP
printf("\nTest 2: Auto port, interface by IP (%s)\n",
localIP.print());
int fd2 = connectwlocal(serverAddr, 0, 8080,
localIP, -1);
if (fd2 > 0) {
printf(" Result: %s:%d\n",
close(fd2);
} else {
printf(" Failed: %d\n", fd2);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 3: Auto port, specific interface by number
printf("\nTest 3: Auto port, interface by number (0)\n");
int fd3 = connectwlocal(serverAddr, 0, 8080,
if (fd3 > 0) {
printf(" Result: %s:%d\n",
close(fd3);
} else {
printf(" Failed: %d\n", fd3);
}
OSTimeDly(TICKS_PER_SECOND);
// Test 4: Fixed port, auto interface (NOT RECOMMENDED)
printf("\nTest 4: Fixed port 7000, auto interface (NOT RECOMMENDED)\n");
int fd4 = connectwlocal(serverAddr, 7000, 8080,
if (fd4 > 0) {
printf(" Result: %s:%d\n",
close(fd4);
} else {
printf(" Failed: %d (expected on retry)\n", fd4);
}
printf("\nTesting complete\n");
}

See also
connect(), connectvia(), NoBlockConnectwlocal(), listen(), listenvia()

◆ DumpTcpDebug()

void DumpTcpDebug ( )

#include <tcp.h>

Display current TCP debug information to the console.

Outputs detailed TCP debug information to the console, including active connections, socket states, buffer usage, and other TCP stack diagnostics. The information displayed depends on which debug flags have been enabled via EnableTcpDebug(). This function is useful for troubleshooting network issues and monitoring TCP connection states.

See also
EnableTcpDebug()

Expand for Example Usage

Examples

Basic Usage - Dumping TCP Debug Info
// Enable TCP debugging
EnableTcpDebug(0xFFFF); // Enable all debug flags
// Perform some TCP operations
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// Dump current TCP state
close(fd);
void EnableTcpDebug(uint16_t dbFlags)
Enable TCP debug output with specified flags.
void DumpTcpDebug()
Display current TCP debug information to the console.
Periodic Monitoring - Debug Output Every Second
void MonitoringTask(void *pd) {
EnableTcpDebug(0x0001); // Enable basic debug info
while (1) {
printf("\n=== TCP Debug Info ===\n");
printf("======================\n\n");
OSTimeDly(TICKS_PER_SECOND);
}
}
void UserMain(void *pd) {
init();
OSTaskCreate(MonitoringTask, NULL, &MonitorStack[USER_TASK_STK_SIZE],
MonitorStack, MAIN_PRIO - 1);
}
#define MAIN_PRIO
Recommend UserMain priority.
Definition constants.h:130
Troubleshooting Connection Issues
int fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Before connect:\n");
int result = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if (result < 0) {
printf("Connect failed! Debug info:\n");
DumpTcpDebug(); // See what went wrong
} else {
printf("After successful connect:\n");
DumpTcpDebug(); // Verify connection state
}
Debug Snapshot on Error
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
char buffer[1024];
int n = read(fd, buffer, sizeof(buffer));
if (n < 0) {
printf("Read error occurred! TCP state:\n");
DumpTcpDebug(); // Capture state at error time
printf("Error code: %d\n", n);
}

◆ EnableTcpDebug()

void EnableTcpDebug ( uint16_t dbFlags)

#include <tcp.h>

Enable TCP debug output with specified flags.

Configures which types of TCP debug information should be tracked and displayed when DumpTcpDebug() is called. The debug flags control the level of detail and which aspects of TCP operations are monitored. Use bitwise OR to combine multiple flags. Set to 0 to disable all TCP debugging.

Parameters
dbFlagsDebug flags to enable (bitwise OR of debug flag values)
  • 0x0000 = Disable all debugging
  • 0xFFFF = Enable all debugging
  • Individual flags control specific debug features (see TCP debug documentation)
See also
DumpTcpDebug()

Expand for Example Usage

Examples

Basic Usage - Enable All Debug Output
void UserMain(void *pd) {
init();
// Enable all TCP debugging
EnableTcpDebug(0xFFFF);
// TCP operations will now generate debug output
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
DumpTcpDebug(); // Display debug information
}
Selective Debug Output - Specific Flags
// Enable only specific debug features
#define TCP_DBG_CONNECTIONS 0x0001
#define TCP_DBG_BUFFERS 0x0002
#define TCP_DBG_RETRANSMIT 0x0004
// Enable connection and buffer debugging only
EnableTcpDebug(TCP_DBG_CONNECTIONS | TCP_DBG_BUFFERS);
DumpTcpDebug(); // Will show only connection and buffer info
Toggling Debug Mode
bool debugEnabled = false;
void ToggleDebugMode() {
if (debugEnabled) {
printf("Disabling TCP debug\n");
EnableTcpDebug(0x0000); // Disable all debugging
debugEnabled = false;
} else {
printf("Enabling TCP debug\n");
EnableTcpDebug(0xFFFF); // Enable all debugging
debugEnabled = true;
}
}
void UserMain(void *pd) {
init();
// Start with debugging disabled
EnableTcpDebug(0x0000);
// Can be toggled during runtime via command or button press
while (1) {
if (CheckDebugButton()) {
ToggleDebugMode();
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
}
Production vs Development Build
void UserMain(void *pd) {
init();
#ifdef DEBUG_BUILD
// Enable full debugging in development builds
EnableTcpDebug(0xFFFF);
printf("TCP debugging enabled (development build)\n");
#else
// Disable debugging in production builds
EnableTcpDebug(0x0000);
#endif
while (1) {
#ifdef DEBUG_BUILD
DumpTcpDebug(); // Periodic debug output in dev builds
#endif
OSTimeDly(TICKS_PER_SECOND * 10);
}
}
void StartHttp(uint16_t port, bool RunConfigMirror)
Start the HTTP web server. Further documentation in the Initialization section Initialization - Syste...
Conditional Debug Based on Connection Count
void MonitorConnections() {
static int lastConnectionCount = 0;
int currentConnections = GetActiveConnectionCount();
if (currentConnections > 10 && lastConnectionCount <= 10) {
// High connection count, enable detailed debugging
printf("High connection count detected, enabling TCP debug\n");
EnableTcpDebug(0xFFFF);
} else if (currentConnections <= 10 && lastConnectionCount > 10) {
// Connection count normalized, reduce debug output
printf("Connection count normalized, reducing TCP debug\n");
EnableTcpDebug(0x0001); // Basic info only
}
lastConnectionCount = currentConnections;
}
Debug On Demand via Network Command
void HandleDebugCommand(int clientFd, const char *cmd) {
if (strcmp(cmd, "DEBUG ON") == 0) {
EnableTcpDebug(0xFFFF);
write(clientFd, "TCP debug enabled\n", 18);
} else if (strcmp(cmd, "DEBUG OFF") == 0) {
EnableTcpDebug(0x0000);
write(clientFd, "TCP debug disabled\n", 19);
} else if (strcmp(cmd, "DEBUG STATUS") == 0) {
}
}

◆ getsocketerror()

int getsocketerror ( int fd)

#include <tcp.h>

Get the error status of a socket.

Retrieves the current error state of a socket file descriptor. This function is useful for diagnosing connection failures, especially with non-blocking sockets where errors may not be immediately apparent from the return value of connect() or other operations.

Parameters
fdFile descriptor of the socket to query
Returns
0 if no error, positive error code if an error occurred, negative value on invalid fd

Notes:

  • This function is particularly useful after a non-blocking connect operation to determine why a connection failed to establish.
  • Common error codes include:
    • 0: No error (success)
    • ECONNREFUSED: Connection refused by remote host
    • ETIMEDOUT: Connection attempt timed out
    • ENETUNREACH: Network is unreachable
    • EHOSTUNREACH: Host is unreachable
    • ECONNRESET: Connection reset by peer
  • After calling getsocketerror(), the error status is typically cleared.
See also
TcpGetSocketState(), NoBlockConnect(), NoBlockConnectVia(), connect()

Expand for Example Usage

Examples

Basic Error Checking After Non-Blocking Connect
#include <tcp.h>
#include <nbrtos.h>
#include <errno.h>
void CheckConnectionError(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Initiate non-blocking connection
int fd = NoBlockConnect(serverIp, serverPort);
if (fd < 0)
{
printf("Failed to create socket: %d\r\n", fd);
return;
}
printf("Connecting to %I:%d...\r\n", serverIp, serverPort);
// Wait for connection to complete or fail
uint32_t startTime = Secs;
bool connected = false;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
connected = true;
printf("Connection established successfully\r\n");
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
// Connection failed - check error code
int error = getsocketerror(fd);
if (error == 0)
{
printf("Connection closed without specific error\r\n");
}
else
{
printf("Connection failed with error: %d\r\n", error);
// Interpret common errors
switch (error)
{
case ECONNREFUSED:
printf(" Connection refused - server not listening\r\n");
break;
case ETIMEDOUT:
printf(" Connection timed out - no response from host\r\n");
break;
case ENETUNREACH:
printf(" Network unreachable - routing problem\r\n");
break;
case EHOSTUNREACH:
printf(" Host unreachable - host may be down\r\n");
break;
default:
printf(" Unknown error code\r\n");
break;
}
}
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (!connected && (Secs - startTime) >= 10)
{
printf("Connection timeout\r\n");
int error = getsocketerror(fd);
if (error != 0)
{
printf("Socket error at timeout: %d\r\n", error);
}
}
close(fd);
}
int getsocketerror(int fd)
Get the error status of a socket.
int NoBlockConnect(const IPADDR &ipAddress, uint16_t remotePort)
Initiate a non-blocking TCP connection.
Definition tcp.h:7893
#define TCP_STATE_CLOSED
Socket is closed, no connection exists.
Definition tcp.h:13301
#define TCP_STATE_CLOSING
Both sides closing simultaneously.
Definition tcp.h:13311
#define TCP_STATE_ESTABLISHED
Connection established, data transfer possible.
Definition tcp.h:13306
Enhanced Connection with Detailed Error Reporting
#include <tcp.h>
#include <nbrtos.h>
#include <errno.h>
const char* GetErrorDescription(int error)
{
switch (error)
{
case 0: return "No error";
case ECONNREFUSED: return "Connection refused";
case ETIMEDOUT: return "Connection timed out";
case ENETUNREACH: return "Network unreachable";
case EHOSTUNREACH: return "Host unreachable";
case ECONNRESET: return "Connection reset";
case ECONNABORTED: return "Connection aborted";
case ENETDOWN: return "Network is down";
case EHOSTDOWN: return "Host is down";
case EADDRINUSE: return "Address already in use";
case EADDRNOTAVAIL: return "Address not available";
default: return "Unknown error";
}
}
int ConnectWithDetailedErrors(const IPADDR &serverIp, uint16_t serverPort,
uint32_t timeoutSecs)
{
int fd = NoBlockConnect(serverIp, serverPort);
if (fd < 0)
{
printf("Socket creation failed: %d\r\n", fd);
return fd;
}
printf("Connecting to %I:%d (timeout: %lu seconds)...\r\n",
serverIp, serverPort, timeoutSecs);
uint32_t startTime = Secs;
while ((Secs - startTime) < timeoutSecs)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
printf("Connection established after %lu seconds\r\n",
Secs - startTime);
return fd;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
int error = getsocketerror(fd);
printf("Connection failed: %s (code: %d)\r\n",
GetErrorDescription(error), error);
close(fd);
return -error; // Return negative error code
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
// Timeout occurred
int error = getsocketerror(fd);
printf("Connection timeout after %lu seconds\r\n", timeoutSecs);
if (error != 0)
{
printf("Final socket error: %s (code: %d)\r\n",
GetErrorDescription(error), error);
}
close(fd);
return -ETIMEDOUT;
}
void DetailedConnectionExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = ConnectWithDetailedErrors(serverIp, serverPort, 10);
if (fd > 0)
{
// Connection successful - use socket
const char *message = "Hello, Server!\r\n";
write(fd, message, strlen(message));
close(fd);
}
else
{
printf("Failed to connect (error: %d)\r\n", -fd);
}
}
Monitoring Multiple Connections for Errors
#include <tcp.h>
#include <nbrtos.h>
#include <errno.h>
#define MAX_CONNECTIONS 5
struct ConnectionStatus
{
int fd;
IPADDR serverIp;
uint16_t serverPort;
bool active;
int errorCode;
};
void MonitorMultipleConnections(void *pd)
{
ConnectionStatus connections[MAX_CONNECTIONS];
// Initialize connections
const char *servers[] = {
"192.168.1.100",
"192.168.1.101",
"192.168.1.102",
"192.168.1.103",
"192.168.1.104"
};
printf("Initiating %d connections...\r\n", MAX_CONNECTIONS);
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
connections[i].serverIp = AsciiToIp(servers[i]);
connections[i].serverPort = 8080;
connections[i].active = false;
connections[i].errorCode = 0;
connections[i].fd = NoBlockConnect(connections[i].serverIp,
connections[i].serverPort);
if (connections[i].fd < 0)
{
printf(" Connection %d: Failed to create socket (%d)\r\n",
i, connections[i].fd);
}
else
{
printf(" Connection %d: Initiated to %I:%d\r\n",
i, connections[i].serverIp, connections[i].serverPort);
}
}
// Monitor connections
uint32_t startTime = Secs;
int activeCount = 0;
while ((Secs - startTime) < 15)
{
bool allResolved = true;
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (connections[i].fd < 0)
continue; // Already failed at creation
if (connections[i].active)
continue; // Already established
allResolved = false;
TcpState state = TcpGetSocketState(connections[i].fd);
if (state == TCP_STATE_ESTABLISHED)
{
connections[i].active = true;
activeCount++;
printf(" Connection %d: Established\r\n", i);
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
connections[i].errorCode = getsocketerror(connections[i].fd);
printf(" Connection %d: Failed (error: %d)\r\n",
i, connections[i].errorCode);
close(connections[i].fd);
connections[i].fd = -1;
}
}
if (allResolved)
{
printf("All connections resolved\r\n");
break;
}
OSTimeDly(TICKS_PER_SECOND / 5);
}
// Report final status
printf("\r\nFinal Connection Status:\r\n");
printf(" Active: %d/%d\r\n", activeCount, MAX_CONNECTIONS);
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (connections[i].fd < 0 && connections[i].errorCode == 0)
{
printf(" Connection %d: Socket creation failed\r\n", i);
}
else if (connections[i].active)
{
printf(" Connection %d: Active\r\n", i);
}
else
{
printf(" Connection %d: Failed (error: %d)\r\n",
i, connections[i].errorCode);
}
}
// Clean up
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (connections[i].fd > 0)
{
close(connections[i].fd);
}
}
}
Using select() with Error Detection
#include <tcp.h>
#include <nbrtos.h>
#include <errno.h>
void SelectBasedConnectionWithErrors(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = NoBlockConnect(serverIp, serverPort);
if (fd < 0)
{
printf("Socket creation failed: %d\r\n", fd);
return;
}
printf("Connecting to %I:%d using select()...\r\n", serverIp, serverPort);
// Use select to wait for connection completion
fd_set write_fds;
fd_set error_fds;
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &write_fds);
FD_SET(fd, &error_fds);
int result = select(fd + 1, NULL, &write_fds, &error_fds,
if (result < 0)
{
printf("select() error: %d\r\n", result);
close(fd);
return;
}
else if (result == 0)
{
printf("Connection timeout\r\n");
int error = getsocketerror(fd);
if (error != 0)
{
printf("Socket error at timeout: %d\r\n", error);
}
close(fd);
return;
}
// Check for errors first
if (FD_ISSET(fd, &error_fds))
{
int error = getsocketerror(fd);
printf("Socket error detected by select(): %d\r\n", error);
close(fd);
return;
}
// Check if socket is writable (connected)
if (FD_ISSET(fd, &write_fds))
{
// Double-check with getsocketerror() - socket may be writable but failed
int error = getsocketerror(fd);
if (error != 0)
{
printf("Socket writable but has error: %d\r\n", error);
close(fd);
return;
}
// Verify state is established
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
printf("Connection established successfully\r\n");
const char *message = "Hello via select()!\r\n";
write(fd, message, strlen(message));
}
else
{
printf("Socket writable but not established (state: %d)\r\n", state);
}
}
close(fd);
}
int FD_ISSET(int fd, fd_set *pfds)
A fd_set (file descriptor set) holds a set of file descriptors (fds). This function checks whether or...
void FD_SET(int fd, fd_set *pfds)
A fd_set (file descriptor set) holds a set of file descriptors (fds). This function sets or adds a sp...
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, unsigned long timeout)
Wait for events to occur on one or more I/O resources associated with a set of file descriptors (fds)...
void FD_ZERO(fd_set *pfds)
Clear (set to 0) a fd_set (file descriptor set) so no file descriptors (fds) are selected.

◆ GetSocketLocalAddr()

IPADDR GetSocketLocalAddr ( int fd)
inline

#include <tcp.h>

Get the local interface IP address for a socket connection.

Retrieves the IP address of the local network interface used for the specified socket connection. This function works for both client connections and server sockets that have accepted a connection.

Parameters
fdSocket file descriptor
Returns
IP address of the local interface, or IPADDR::NullIP() if socket is not bound

Notes: For listening sockets, this returns the address the socket is bound to. If bound to INADDR_ANY, it returns INADDR_ANY rather than a specific interface IP.

  • This function is useful for determining which network interface is being used when you have multiple interfaces (e.g., Ethernet and WiFi).
  • This function supports both IPv4 and IPv6 addresses through the IPADDR class.
See also
GetSocketRemoteAddr(), GetSocketRemotePort(), GetIPAddress()

Expand for Example Usage

Examples

Basic Usage - Determine Connection Interface
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
void DisplayConnectionDetails(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Connect to server
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Get local and remote addresses
IPADDR localAddr = GetSocketLocalAddr(fd);
IPADDR remoteAddr = GetSocketRemoteAddr(fd);
uint16_t remotePort = GetSocketRemotePort(fd);
printf("Connection established:\r\n");
printf(" Local address: %I\r\n", localAddr);
printf(" Remote address: %I:%d\r\n", remoteAddr, remotePort);
// Determine which interface was used
for (int i = 0; i < GetNumInterfaces(); i++)
{
if (localAddr == GetIPAddress(i))
{
printf(" Using interface %d\r\n", i);
break;
}
}
close(fd);
}

◆ GetSocketLocalPort()

uint16_t GetSocketLocalPort ( int fd)

#include <tcp.h>

Get the local port number for a socket connection.

Retrieves the local port number assigned to the specified socket connection.

Parameters
fdSocket file descriptor
Returns
Local port number
See also
GetSocketRemotePort()

◆ GetSocketRemoteAddr()

IPADDR GetSocketRemoteAddr ( int fd)
inline

#include <tcp.h>

Get the remote host IP address for a socket connection.

Retrieves the IP address of the remote host connected to the specified socket. This function works for both established connections and listening sockets that have accepted a client connection.

Parameters
fdSocket file descriptor
Returns
IP address of the remote host, or IPADDR::NullIP() if socket is not connected

Notes:

  • For listening sockets that have not accepted a connection, this function returns IPADDR::NullIP(). -note This function supports both IPv4 and IPv6 addresses through the IPADDR class.
See also
GetSocketLocalAddr(), GetSocketRemotePort(), accept()

Expand for Example Usage

Examples

Basic Usage - Get Remote Address After Connection
#include <tcp.h>
#include <nbrtos.h>
void DisplayConnectionInfo(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Connect to server
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Get remote address (should match serverIp)
IPADDR remoteAddr = GetSocketRemoteAddr(fd);
printf("Connected to remote host: %I\r\n", remoteAddr);
printf("Remote port: %d\r\n", serverPort);
// Send data
const char *message = "Hello, Server!\r\n";
write(fd, message, strlen(message));
close(fd);
}

◆ GetSocketRemotePort()

uint16_t GetSocketRemotePort ( int fd)

#include <tcp.h>

Get the remote host port number for a socket connection.

Retrieves the port number being used by the remote host in the specified socket connection. This function works for both client connections and server sockets that have accepted a connection.

Parameters
fdSocket file descriptor
Returns
Port number of the remote host, or 0 if socket is not connected

Notes:

  • For listening sockets that have not accepted a connection, this function returns 0.
  • The remote port is typically an ephemeral port (1024-65535) for client connections, or a well-known/registered port for server connections.
See also
GetSocketLocalPort(), GetSocketRemoteAddr(), GetSocketLocalAddr(), accept()

Expand for Example Usage

Examples

Basic Usage - Display Remote Connection Details
#include <tcp.h>
#include <nbrtos.h>
void DisplayRemoteConnectionInfo(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Connect to server
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Get remote connection details
IPADDR remoteAddr = GetSocketRemoteAddr(fd);
uint16_t remotePort = GetSocketRemotePort(fd);
printf("Connected to remote host:\r\n");
printf(" IP address: %I\r\n", remoteAddr);
printf(" Port: %d\r\n", remotePort);
// Verify it matches what we connected to
if (remoteAddr == serverIp && remotePort == serverPort)
{
printf(" Connection verified!\r\n");
}
close(fd);
}

◆ getsockoption()

int getsockoption ( int fd)

#include <tcp.h>

Query current TCP socket options.

Retrieves the currently enabled option flags for the specified socket. The return value is a bitmask where each set bit represents an enabled option.

Parameters
fdSocket file descriptor
Returns
Bitmask of all currently enabled options (TCP Socket Options), or negative value on error

Notes:

  • The returned bitmask can be tested for specific options using bitwise AND: if (getsockoption(fd) & SO_NODELAY) { ... }
  • A return value of 0 indicates no special options are enabled (all default behavior).
  • This function is useful for checking socket configuration before making changes or for debugging connection behavior.
See also
setsockoption(), clrsockoption(), SetSocketUnackBuffers(), SetSocketRxBuffers(), SetSocketTxBuffers()

Expand for Example Usage

Examples

Check Specific Option Status
#include <tcp.h>
#include <nbrtos.h>
void CheckNagleStatus(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Check if Nagle is disabled
int options = getsockoption(fd);
if (options < 0)
{
printf("Failed to get socket options: %d\r\n", options);
}
else
{
if (options & SO_NODELAY)
{
printf("Nagle algorithm is DISABLED (SO_NODELAY set)\r\n");
printf("Small packets will be sent immediately\r\n");
}
else
{
printf("Nagle algorithm is ENABLED (default)\r\n");
printf("Small packets will be buffered for efficiency\r\n");
}
}
close(fd);
}
Display All Active Options
#include <tcp.h>
#include <nbrtos.h>
void DisplaySocketOptions(int fd)
{
int options = getsockoption(fd);
if (options < 0)
{
printf("Error reading socket options: %d\r\n", options);
return;
}
printf("Socket Options (0x%X):\r\n", options);
if (options == 0)
{
printf(" No special options set (all defaults)\r\n");
}
else
{
if (options & SO_NODELAY)
printf(" SO_NODELAY - Nagle algorithm disabled\r\n");
if (options & SO_PUSH)
printf(" SO_PUSH - TCP PUSH flag enabled\r\n");
if (options & SO_KEEPALIVE)
printf(" SO_KEEPALIVE - Keepalive probes enabled\r\n");
// Check for any other unknown flags
int knownFlags = SO_NODELAY | SO_PUSH | SO_KEEPALIVE;
int unknownFlags = options & ~knownFlags;
if (unknownFlags)
{
printf(" Unknown flags: 0x%X\r\n", unknownFlags);
}
}
}
void OptionInspectionExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Initial socket configuration:\r\n");
DisplaySocketOptions(fd);
printf("\r\nEnabling SO_NODELAY and SO_PUSH...\r\n");
setsockoption(fd, SO_NODELAY | SO_PUSH);
printf("\r\nUpdated socket configuration:\r\n");
DisplaySocketOptions(fd);
close(fd);
}
Conditional Configuration
#include <tcp.h>
#include <nbrtos.h>
void ConditionallyEnableOption(int fd, int option, bool enable)
{
int currentOptions = getsockoption(fd);
if (currentOptions < 0)
{
printf("Failed to get current options\r\n");
return;
}
bool isCurrentlySet = (currentOptions & option) != 0;
if (enable && !isCurrentlySet)
{
printf("Enabling option 0x%X\r\n", option);
setsockoption(fd, option);
}
else if (!enable && isCurrentlySet)
{
printf("Disabling option 0x%X\r\n", option);
clrsockoption(fd, option);
}
else
{
printf("Option 0x%X already in desired state\r\n", option);
}
}
void SmartOptionManagement(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Only enable SO_NODELAY if not already set
ConditionallyEnableOption(fd, SO_NODELAY, true);
// Try to enable again (should be no-op)
ConditionallyEnableOption(fd, SO_NODELAY, true);
// Disable it
ConditionallyEnableOption(fd, SO_NODELAY, false);
close(fd);
}
Verify Configuration After Setting
#include <tcp.h>
#include <nbrtos.h>
bool VerifySocketOptions(int fd, int expectedOptions)
{
int actualOptions = getsockoption(fd);
if (actualOptions < 0)
{
printf("Error reading socket options: %d\r\n", actualOptions);
return false;
}
if ((actualOptions & expectedOptions) == expectedOptions)
{
printf("Socket options verified: 0x%X\r\n", actualOptions);
return true;
}
else
{
printf("Socket options mismatch!\r\n");
printf(" Expected: 0x%X\r\n", expectedOptions);
printf(" Actual: 0x%X\r\n", actualOptions);
printf(" Missing: 0x%X\r\n", expectedOptions & ~actualOptions);
return false;
}
}
void ConfigureAndVerify(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Configure socket
int desiredOptions = SO_NODELAY | SO_PUSH;
int result = setsockoption(fd, desiredOptions);
if (result >= 0)
{
printf("Options set, verifying...\r\n");
if (VerifySocketOptions(fd, desiredOptions))
{
printf("Configuration successful!\r\n");
}
else
{
printf("Configuration verification failed!\r\n");
}
}
else
{
printf("Failed to set options: %d\r\n", result);
}
close(fd);
}
Connection Diagnostics
#include <tcp.h>
#include <nbrtos.h>
void DiagnoseConnection(int fd)
{
printf("\r\n=== Connection Diagnostics ===\r\n");
// Socket options
int options = getsockoption(fd);
printf("Socket Options: 0x%X\r\n", options);
if (options >= 0)
{
printf(" Nagle: %s\r\n",
(options & SO_NODELAY) ? "Disabled" : "Enabled");
printf(" Push: %s\r\n",
(options & SO_PUSH) ? "Enabled" : "Disabled");
printf(" Keepalive: %s\r\n",
(options & SO_KEEPALIVE) ? "Enabled" : "Disabled");
}
// Connection state
TcpState state = TcpGetSocketState(fd);
printf("TCP State: %d\r\n", state);
// Retransmissions
int rtxCount = GetTcpRtxCount(fd);
printf("Retransmissions: %d\r\n", rtxCount);
// Idle time
uint32_t idleSeconds = TcpGetLastRxInterval(fd) / TICKS_PER_SECOND;
printf("Idle Time: %lu seconds\r\n", idleSeconds);
printf("==============================\r\n\r\n");
}
void ConnectionDiagnosticsTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Initial diagnostics
DiagnoseConnection(fd);
// Configure socket
setsockoption(fd, SO_NODELAY);
// Send some data
const char *msg = "Test message\r\n";
write(fd, msg, strlen(msg));
OSTimeDly(TICKS_PER_SECOND * 2);
// Check diagnostics after activity
DiagnoseConnection(fd);
close(fd);
}
int GetTcpRtxCount(int fd)
Get the number of TCP retransmissions on a socket.
uint32_t TcpGetLastRxInterval(int fd)
Get the time elapsed since the last received packet.

◆ GetTcpRtxCount()

int GetTcpRtxCount ( int fd)

#include <tcp.h>

Get the number of TCP retransmissions on a socket.

Returns the count of how many times TCP has retransmitted data on this connection. Retransmissions occur when acknowledgments are not received from the remote host within the expected timeout period. A high retransmission count may indicate network congestion, packet loss, or a slow/unstable connection.

Parameters
fdSocket file descriptor
Returns
Number of retransmissions that have occurred on this connection, or -1 if socket is invalid

Notes:

  • This counter is maintained for the lifetime of the connection and is reset when the socket is closed or reused.
  • A small number of retransmissions is normal in most networks. However, a rapidly increasing count or very high values may indicate network problems.
  • Each retransmitted segment increments this counter, so the same data being retransmitted multiple times will increment the counter each time.
See also
TcpGetSocketState(), getsocketerror()

Expand for Example Usage

Examples

Basic Retransmission Monitoring
#include <tcp.h>
#include <nbrtos.h>
void MonitorRetransmissions(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - monitoring retransmissions\r\n");
int lastRtxCount = 0;
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 5);
int currentRtxCount = GetTcpRtxCount(fd);
if (currentRtxCount > lastRtxCount)
{
int newRtx = currentRtxCount - lastRtxCount;
printf("Retransmissions detected: %d (total: %d)\r\n",
newRtx, currentRtxCount);
lastRtxCount = currentRtxCount;
}
// Send some data periodically
const char *message = "Test data\r\n";
write(fd, message, strlen(message));
// Check connection state
TcpState state = TcpGetSocketState(fd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Connection closed (state: %d)\r\n", state);
break;
}
}
int finalRtxCount = GetTcpRtxCount(fd);
printf("Connection closed - total retransmissions: %d\r\n", finalRtxCount);
close(fd);
}
Connection Quality Assessment
#include <tcp.h>
#include <nbrtos.h>
typedef enum
{
QUALITY_EXCELLENT, // 0 retransmissions
QUALITY_GOOD, // 1-5 retransmissions
QUALITY_FAIR, // 6-20 retransmissions
QUALITY_POOR // 20+ retransmissions
} ConnectionQuality;
ConnectionQuality AssessConnectionQuality(int fd)
{
int rtxCount = GetTcpRtxCount(fd);
if (rtxCount == 0)
return QUALITY_EXCELLENT;
else if (rtxCount <= 5)
return QUALITY_GOOD;
else if (rtxCount <= 20)
return QUALITY_FAIR;
else
return QUALITY_POOR;
}
const char* QualityToString(ConnectionQuality quality)
{
switch (quality)
{
case QUALITY_EXCELLENT: return "Excellent";
case QUALITY_GOOD: return "Good";
case QUALITY_FAIR: return "Fair";
case QUALITY_POOR: return "Poor";
default: return "Unknown";
}
}
void QualityMonitorTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - monitoring connection quality\r\n");
ConnectionQuality lastQuality = QUALITY_EXCELLENT;
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 10);
ConnectionQuality currentQuality = AssessConnectionQuality(fd);
int rtxCount = GetTcpRtxCount(fd);
if (currentQuality != lastQuality)
{
printf("Connection quality changed: %s -> %s (RTX: %d)\r\n",
QualityToString(lastQuality),
QualityToString(currentQuality),
rtxCount);
lastQuality = currentQuality;
// Take action based on quality
if (currentQuality == QUALITY_POOR)
{
printf("WARNING: Poor connection quality detected!\r\n");
// Could implement: reduce data rate, trigger reconnection, etc.
}
}
// Check connection state
TcpState state = TcpGetSocketState(fd);
if (state != TCP_STATE_ESTABLISHED)
{
break;
}
}
printf("Final connection quality: %s (RTX: %d)\r\n",
QualityToString(AssessConnectionQuality(fd)),
close(fd);
}
Server-Side Connection Diagnostics
#include <tcp.h>
#include <nbrtos.h>
void DiagnosticServerTask(void *pd)
{
const uint16_t SERVER_PORT = 8080;
int listenFd = listen(INADDR_ANY, SERVER_PORT, 5);
if (listenFd < 0)
{
printf("Failed to create listening socket: %d\r\n", listenFd);
return;
}
printf("Diagnostic server listening on port %d\r\n", SERVER_PORT);
while (1)
{
IPADDR clientAddr;
uint16_t clientPort;
int clientFd = accept(listenFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
printf("\r\nClient connected: %I:%d\r\n", clientAddr, clientPort);
int initialRtx = GetTcpRtxCount(clientFd);
uint32_t startTime = Secs;
uint32_t bytesTransferred = 0;
// Handle client for up to 60 seconds
while ((Secs - startTime) < 60)
{
char buffer[256];
int bytesRead = read(clientFd, buffer, sizeof(buffer) - 1,
if (bytesRead > 0)
{
bytesTransferred += bytesRead;
// Echo back
int bytesWritten = write(clientFd, buffer, bytesRead);
if (bytesWritten > 0)
{
bytesTransferred += bytesWritten;
}
}
// Check connection state
TcpState state = TcpGetSocketState(clientFd);
if (state != TCP_STATE_ESTABLISHED)
{
break;
}
}
// Display connection statistics
int finalRtx = GetTcpRtxCount(clientFd);
uint32_t duration = Secs - startTime;
printf("\r\nConnection Statistics for %I:\r\n", clientAddr);
printf(" Duration: %lu seconds\r\n", duration);
printf(" Bytes transferred: %lu\r\n", bytesTransferred);
printf(" Retransmissions: %d\r\n", finalRtx);
if (finalRtx > 0)
{
float rtxRate = (float)finalRtx / duration;
printf(" RTX rate: %.2f per second\r\n", rtxRate);
}
close(clientFd);
}
}
close(listenFd);
}
Adaptive Behavior Based on Retransmissions
#include <tcp.h>
#include <nbrtos.h>
#define RTX_THRESHOLD_REDUCE_RATE 10
#define RTX_THRESHOLD_RECONNECT 50
void AdaptiveDataTransfer(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - starting adaptive data transfer\r\n");
uint32_t sendInterval = 1; // Start with 1 second interval
int lastRtxCheck = 0;
while (1)
{
// Send data at current rate
char message[64];
snprintf(message, sizeof(message), "Data packet (interval: %lu sec)\r\n",
sendInterval);
write(fd, message, strlen(message));
OSTimeDly(sendInterval * TICKS_PER_SECOND);
// Check retransmissions
int currentRtx = GetTcpRtxCount(fd);
int newRtx = currentRtx - lastRtxCheck;
printf("RTX count: %d (new: %d)\r\n", currentRtx, newRtx);
if (currentRtx >= RTX_THRESHOLD_RECONNECT)
{
printf("RTX threshold exceeded - reconnecting\r\n");
close(fd);
OSTimeDly(TICKS_PER_SECOND * 5);
fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Reconnection failed\r\n");
break;
}
sendInterval = 1;
lastRtxCheck = 0;
printf("Reconnected - reset to 1 second interval\r\n");
}
else if (currentRtx >= RTX_THRESHOLD_REDUCE_RATE && sendInterval < 10)
{
sendInterval *= 2;
if (sendInterval > 10) sendInterval = 10;
printf("Reducing data rate - new interval: %lu seconds\r\n",
sendInterval);
}
else if (currentRtx == lastRtxCheck && sendInterval > 1)
{
// No new retransmissions - can increase rate
sendInterval = (sendInterval > 1) ? sendInterval / 2 : 1;
printf("Increasing data rate - new interval: %lu seconds\r\n",
sendInterval);
}
lastRtxCheck = currentRtx;
// Check connection state
TcpState state = TcpGetSocketState(fd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Connection closed (state: %d)\r\n", state);
break;
}
}
if (fd > 0) close(fd);
}

◆ listen()

int listen ( const IPADDR & addr,
uint16_t port,
uint8_t maxpend = 5 )
inline

#include <tcp.h>

Create a listening socket to accept incoming TCP connections.

Creates a socket that listens for incoming connection requests on the specified port. This is the server-side counterpart to connect(), enabling your application to accept connections from remote clients. Incoming connections are placed in a pending queue until accepted with accept(). The maxpend parameter determines how many connections can wait in the queue before new connection attempts are rejected by the TCP stack.

The listening socket itself does not handle data transfer - it only accepts new connections. Each accepted connection returns a new socket file descriptor for communicating with that specific client. The listening socket remains open and continues accepting new connections.

Parameters
addrIP address to bind to:
  • Use INADDR_ANY (or IPADDR::AnyIP()) to accept connections on all network interfaces. This is the most common usage for servers
  • Use a specific IP address to accept connections only on that interface
  • Example: INADDR_ANY for multi-homed systems
portPort number to listen on (1-65535). Common server ports include:
  • 80 for HTTP
  • 443 for HTTPS
  • 23 for Telnet
  • Custom ports typically use values above 1024 Ports below 1024 are traditionally reserved for well-known services
maxpendMaximum number of pending connections in the accept queue (default: 5). This is the maximum number of clients that can be waiting in the queue simultaneously. When this limit is reached, additional connection attempts will be refused by the TCP stack. Typical values are 5-20. Higher values consume more system resources but allow for burst connection handling
Returns
Positive file descriptor on success (use with accept() to get client connections), negative TCP Socket Status error code on failure:
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_NOCON: Port already in use or binding failed

Notes:

  • The listening socket uses one socket from the system pool. Each accepted connection uses an additional socket. Plan your maxpend value and system socket count accordingly.
  • Always call close() on the listening socket when your server is shutting down to free the socket resource and release the port.
  • The listening socket does not automatically close when the application exits. For clean shutdown, explicitly close all listening sockets.
  • If you need to listen on a specific interface in a multi-homed system, use listenvia() instead for explicit interface control.
  • Port numbers below 1024 may require special privileges on some systems, though this is typically not an issue on embedded NetBurner devices.
Warning
  • If the port is already in use (by another listening socket or active connection), listen() will fail with TCP_ERR_NOCON. Ensure the port is available before calling.
  • The maxpend parameter limits simultaneous pending connections, not total accepted connections. Once a connection is accepted with accept(), it no longer occupies a slot in the pending queue.

Expand for Example Usage

Examples

Basic Echo Server
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
void EchoServer(void *pd) {
init();
// Create listening socket on port 7 (echo port)
int fdListen = listen(INADDR_ANY, 7, 5);
if (fdListen < 0) {
printf("Failed to create listening socket: %d\n", fdListen);
return;
}
printf("Echo server listening on port 7\n");
printf("Waiting for connections...\n\n");
while (1) {
// Accept incoming connection
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, 0);
if (fdClient > 0) {
printf("Client connected: %s:%d\n",
clientAddr.print(), clientPort);
// Echo data back to client
char buffer[512];
while (1) {
int n = read(fdClient, buffer, sizeof(buffer));
if (n <= 0) break; // Connection closed
writeall(fdClient, buffer, n); // Echo back
}
close(fdClient);
printf("Client disconnected\n\n");
}
}
close(fdListen);
}
HTTP Server Example
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
void SimpleHttpServer(void *pd) {
init();
// Create listening socket on port 80 (HTTP)
int fdListen = listen(INADDR_ANY, 80, 10);
if (fdListen < 0) {
printf("Failed to create HTTP listener: %d\n", fdListen);
return;
}
printf("HTTP server listening on port 80\n");
while (1) {
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, 0);
if (fdClient > 0) {
printf("HTTP request from %s:%d\n",
clientAddr.print(), clientPort);
// Read HTTP request (simplified)
char request[1024];
int n = read(fdClient, request, sizeof(request) - 1);
if (n > 0) {
request[n] = '\0';
printf("Request: %s\n", request);
// Send HTTP response
const char *response =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<html><body><h1>Hello from NetBurner!</h1></body></html>";
writeall(fdClient, response, strlen(response));
}
close(fdClient);
}
}
}
Server with Error Handling
#include <tcp.h>
#include <init.h>
int CreateServer(uint16_t port, uint8_t backlog) {
int fdListen = listen(INADDR_ANY, port, backlog);
if (fdListen < 0) {
// Handle specific error cases
switch (fdListen) {
printf("ERROR: No sockets available\n");
printf("Too many open connections or sockets not freed\n");
break;
printf("ERROR: Cannot bind to port %d\n", port);
printf("Port may already be in use\n");
break;
default:
printf("ERROR: Failed to create listener: %d\n", fdListen);
break;
}
return -1;
}
printf("Server listening on port %d\n", port);
printf(" Backlog: %d connections\n", backlog);
printf(" Accepting on all interfaces\n");
return fdListen;
}
void UserMain(void *pd) {
init();
int fdListen = CreateServer(8080, 10);
if (fdListen > 0) {
// Accept connections...
close(fdListen);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Multi-Port Server
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
void MultiPortServer(void *pd) {
init();
// Listen on multiple ports
int fdTelnet = listen(INADDR_ANY, 23, 3); // Telnet
int fdHttp = listen(INADDR_ANY, 80, 10); // HTTP
int fdCustom = listen(INADDR_ANY, 9000, 5); // Custom
if (fdTelnet < 0 || fdHttp < 0 || fdCustom < 0) {
printf("Failed to create one or more listening sockets\n");
return;
}
printf("Multi-port server running:\n");
printf(" Telnet: port 23\n");
printf(" HTTP: port 80\n");
printf(" Custom: port 9000\n\n");
while (1) {
// Check for connections on any port
// In a real implementation, you'd use select() or tasks
// Check telnet port
IPADDR addr;
uint16_t port;
int fd = accept(fdTelnet, &addr, &port, TICKS_PER_SECOND / 10);
if (fd > 0) {
printf("Telnet connection from %s:%d\n", addr.print(), port);
// Handle telnet connection...
close(fd);
}
// Check HTTP port
fd = accept(fdHttp, &addr, &port, TICKS_PER_SECOND / 10);
if (fd > 0) {
printf("HTTP connection from %s:%d\n", addr.print(), port);
// Handle HTTP connection...
close(fd);
}
// Check custom port
fd = accept(fdCustom, &addr, &port, TICKS_PER_SECOND / 10);
if (fd > 0) {
printf("Custom connection from %s:%d\n", addr.print(), port);
// Handle custom connection...
close(fd);
}
}
}
Connection Limit Testing
#include <tcp.h>
#include <init.h>
void TestConnectionLimits(void *pd) {
init();
// Test with small backlog
uint8_t maxPending = 3;
int fdListen = listen(INADDR_ANY, 9000, maxPending);
if (fdListen < 0) {
printf("Failed to create listener: %d\n", fdListen);
return;
}
printf("Testing connection limits\n");
printf("Max pending connections: %d\n", maxPending);
printf("Waiting for connections...\n\n");
int acceptedCount = 0;
while (acceptedCount < 10) {
IPADDR addr;
uint16_t port;
// Try to accept with short timeout
int fd = accept(fdListen, &addr, &port, TICKS_PER_SECOND * 2);
if (fd > 0) {
acceptedCount++;
printf("Accepted connection %d from %s:%d\n",
acceptedCount, addr.print(), port);
// Don't close immediately - let them queue up
OSTimeDly(TICKS_PER_SECOND * 5);
close(fd);
printf(" Closed connection %d\n", acceptedCount);
} else if (fd == TCP_ERR_TIMEOUT) {
printf("No pending connections (timeout)\n");
} else {
printf("Accept error: %d\n", fd);
}
}
close(fdListen);
printf("\nTest complete: %d connections accepted\n", acceptedCount);
}
Graceful Server Shutdown
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
volatile bool g_serverRunning = true;
void GracefulServer(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
if (fdListen < 0) {
printf("Failed to create listener: %d\n", fdListen);
return;
}
printf("Server started on port 8080\n");
printf("Set g_serverRunning = false to shutdown\n\n");
while (g_serverRunning) {
// Accept with short timeout to check shutdown flag frequently
IPADDR addr;
uint16_t port;
int fd = accept(fdListen, &addr, &port, TICKS_PER_SECOND);
if (fd > 0) {
printf("Client connected: %s:%d\n", addr.print(), port);
// Check shutdown flag before processing
if (!g_serverRunning) {
const char *msg = "Server shutting down\r\n";
write(fd, msg, strlen(msg));
close(fd);
break;
}
// Handle client...
close(fd);
}
}
close(fdListen);
printf("Server shutdown complete\n");
}
Connection Statistics Monitoring
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
struct ServerStats {
int totalConnections;
int activeConnections;
int rejectedConnections;
uint32_t bytesReceived;
uint32_t bytesSent;
} g_stats = {0};
void MonitoredServer(void *pd) {
init();
int fdListen = listen(INADDR_ANY, 8080, 5);
if (fdListen < 0) {
printf("Failed to create listener: %d\n", fdListen);
return;
}
printf("Monitored server on port 8080\n\n");
uint32_t lastStatsTime = Secs;
while (1) {
IPADDR addr;
uint16_t port;
int fd = accept(fdListen, &addr, &port, TICKS_PER_SECOND);
if (fd > 0) {
g_stats.totalConnections++;
g_stats.activeConnections++;
printf("Connection %d from %s:%d\n",
g_stats.totalConnections, addr.print(), port);
// Handle connection
char buffer[256];
int n = read(fd, buffer, sizeof(buffer));
if (n > 0) {
g_stats.bytesReceived += n;
// Echo response
writeall(fd, buffer, n);
g_stats.bytesSent += n;
}
close(fd);
g_stats.activeConnections--;
} else if (fd < 0 && fd != TCP_ERR_TIMEOUT) {
g_stats.rejectedConnections++;
}
// Print statistics every 10 seconds
if ((Secs - lastStatsTime) >= 10) {
printf("\n=== Statistics ===\n");
printf("Total connections: %d\n", g_stats.totalConnections);
printf("Active connections: %d\n", g_stats.activeConnections);
printf("Rejected connections: %d\n", g_stats.rejectedConnections);
printf("Bytes received: %lu\n", g_stats.bytesReceived);
printf("Bytes sent: %lu\n\n", g_stats.bytesSent);
lastStatsTime = Secs;
}
}
}
Testing Port Availability
#include <tcp.h>
#include <init.h>
bool IsPortAvailable(uint16_t port) {
int fd = listen(INADDR_ANY, port, 1);
if (fd > 0) {
close(fd);
return true;
}
return false;
}
uint16_t FindAvailablePort(uint16_t startPort, uint16_t endPort) {
printf("Searching for available port in range %d-%d\n",
startPort, endPort);
for (uint16_t port = startPort; port <= endPort; port++) {
if (IsPortAvailable(port)) {
printf("Found available port: %d\n", port);
return port;
}
}
printf("No available ports in range\n");
return 0;
}
void UserMain(void *pd) {
init();
// Test specific port
if (IsPortAvailable(8080)) {
printf("Port 8080 is available\n");
} else {
printf("Port 8080 is in use\n");
}
// Find any available port in range
uint16_t port = FindAvailablePort(9000, 9100);
if (port > 0) {
int fdListen = listen(INADDR_ANY, port, 5);
if (fdListen > 0) {
printf("Server listening on port %d\n", port);
close(fdListen);
}
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Dynamic Backlog Adjustment
#include <tcp.h>
#include <init.h>
#include <nbrtos.h>
void AdaptiveBacklogServer(void *pd) {
init();
// Start with moderate backlog
uint8_t currentBacklog = 5;
int fdListen = listen(INADDR_ANY, 8080, currentBacklog);
if (fdListen < 0) {
printf("Failed to create listener: %d\n", fdListen);
return;
}
printf("Server started with backlog=%d\n", currentBacklog);
int recentConnections = 0;
uint32_t lastAdjustTime = Secs;
while (1) {
IPADDR addr;
uint16_t port;
int fd = accept(fdListen, &addr, &port, TICKS_PER_SECOND);
if (fd > 0) {
recentConnections++;
// Handle connection...
close(fd);
}
// Adjust backlog every 30 seconds based on load
if ((Secs - lastAdjustTime) >= 30) {
uint8_t newBacklog = currentBacklog;
if (recentConnections > 20 && currentBacklog < 20) {
// High load - increase backlog
newBacklog = currentBacklog + 5;
printf("High load (%d conn/30sec) - increasing backlog\n",
recentConnections);
} else if (recentConnections < 5 && currentBacklog > 5) {
// Low load - decrease backlog
newBacklog = currentBacklog - 2;
printf("Low load (%d conn/30sec) - decreasing backlog\n",
recentConnections);
}
if (newBacklog != currentBacklog) {
// Recreate listener with new backlog
close(fdListen);
fdListen = listen(INADDR_ANY, 8080, newBacklog);
if (fdListen > 0) {
currentBacklog = newBacklog;
printf("Backlog adjusted to %d\n", currentBacklog);
}
}
recentConnections = 0;
lastAdjustTime = Secs;
}
}
}

See also
accept(), listenvia(), close(), connect(), INADDR_ANY

◆ listenvia() [1/2]

int listenvia ( const IPADDR & addr,
uint16_t port,
const IPADDR & localIpAddress,
uint8_t maxpend = 5 )
inline

#include <tcp.h>

Create a listening socket bound to a specific interface IP address.

Creates a socket that listens for incoming connection requests on the specified port using the network interface with the given IP address. If multiple interfaces share the same IP address, the lower numbered interface is selected. Incoming connections are placed in a pending queue until accepted with accept().

Parameters
addrIP address to bind to (use INADDR_ANY to accept connections on any interface)
portPort number to listen on
localIpAddressIP address of the local interface to use. Selects the interface with this IP address (lower numbered interface if multiple match)
maxpendMaximum number of pending connections in the accept queue (default: 5)
Returns
Positive file descriptor on success, negative TCP Socket Status error code on failure
Note
This function is useful when you have multiple network interfaces and need to ensure the listening socket binds to a specific interface rather than all interfaces.
Warning
If multiple interfaces have the same IP address, the behavior is deterministic but may not match expectations - the lower numbered interface will be selected.
See also
accept(), listen(), close(), CoreListen()

Expand for Example Usage

Examples

Basic Usage - Listen on Specific Interface
#include <tcp.h>
#include <nbrtos.h>
void ServerTask(void *pd)
{
// Get the IP address of interface 0
IPADDR localIp = GetIPAddress(0);
// Create a listening socket on port 8080 bound to interface 0
int listenFd = listenvia(INADDR_ANY, 8080, localIp);
if (listenFd < 0)
{
printf("Failed to create listening socket: %d\r\n", listenFd);
return;
}
printf("Listening on %I:8080 via interface IP %I\r\n", INADDR_ANY, localIp);
while (1)
{
IPADDR clientAddr;
uint16_t clientPort;
// Accept incoming connections
int clientFd = accept(listenFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
printf("Client connected from %I:%d\r\n", clientAddr, clientPort);
// Handle client connection
// ... your code here ...
close(clientFd);
}
}
close(listenFd);
}
int listenvia(const IPADDR &addr, uint16_t port, int ifn, uint8_t maxpend=5)
Create a listening socket on a specific network interface.
Definition tcp.h:7299
Multi-Interface Server - Listen on Both Ethernet and WiFi
#include <tcp.h>
#include <nbrtos.h>
void MultiInterfaceServer(void *pd)
{
const uint16_t SERVER_PORT = 8080;
// Get IP addresses for Ethernet (interface 0) and WiFi (interface 1)
IPADDR ethernetIp = GetIPAddress(0);
IPADDR wifiIp = GetIPAddress(1);
// Create listening socket on Ethernet interface
int ethernetFd = listenvia(INADDR_ANY, SERVER_PORT, ethernetIp, 10);
if (ethernetFd < 0)
{
printf("Failed to bind to Ethernet interface: %d\r\n", ethernetFd);
return;
}
// Create listening socket on WiFi interface
int wifiFd = listenvia(INADDR_ANY, SERVER_PORT, wifiIp, 10);
if (wifiFd < 0)
{
printf("Failed to bind to WiFi interface: %d\r\n", wifiFd);
close(ethernetFd);
return;
}
printf("Server listening on:\r\n");
printf(" Ethernet: %I:%d\r\n", ethernetIp, SERVER_PORT);
printf(" WiFi: %I:%d\r\n", wifiIp, SERVER_PORT);
// Use select() to monitor both sockets
fd_set read_fds;
while (1)
{
FD_ZERO(&read_fds);
FD_SET(ethernetFd, &read_fds);
FD_SET(wifiFd, &read_fds);
int maxFd = (ethernetFd > wifiFd) ? ethernetFd : wifiFd;
if (select(maxFd + 1, &read_fds, NULL, NULL, TICKS_PER_SECOND * 5) > 0)
{
IPADDR clientAddr;
uint16_t clientPort;
if (FD_ISSET(ethernetFd, &read_fds))
{
int clientFd = accept(ethernetFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
printf("Client connected via Ethernet from %I:%d\r\n",
clientAddr, clientPort);
// Handle client...
close(clientFd);
}
}
if (FD_ISSET(wifiFd, &read_fds))
{
int clientFd = accept(wifiFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
printf("Client connected via WiFi from %I:%d\r\n",
clientAddr, clientPort);
// Handle client...
close(clientFd);
}
}
}
}
close(ethernetFd);
close(wifiFd);
}
Error Handling and Interface Validation
#include <tcp.h>
#include <netinterface.h>
int CreateInterfaceListener(int interfaceNum, uint16_t port)
{
// Validate interface exists and is active
if (interfaceNum < 0 || interfaceNum >= GetNumInterfaces())
{
printf("Invalid interface number: %d\r\n", interfaceNum);
return -1;
}
// Get interface IP address
IPADDR localIp = GetIPAddress(interfaceNum);
if (localIp == IPADDR_ANY)
{
printf("Interface %d has no IP address assigned\r\n", interfaceNum);
return -1;
}
// Create listening socket with custom queue size
int listenFd = listenvia(INADDR_ANY, port, localIp, 20);
if (listenFd < 0)
{
// Handle specific error codes
switch (listenFd)
{
case TCP_ERR_NOSOCKETS:
printf("No socket resources available\r\n");
break;
case TCP_ERR_PORT_IN_USE:
printf("Port %d already in use on interface\r\n", port);
break;
default:
printf("Failed to create listener: error %d\r\n", listenFd);
break;
}
return listenFd;
}
printf("Successfully listening on %I:%d (interface %d)\r\n",
localIp, port, interfaceNum);
return listenFd;
}

◆ listenvia() [2/2]

int listenvia ( const IPADDR & addr,
uint16_t port,
int ifn,
uint8_t maxpend = 5 )
inline

#include <tcp.h>

Create a listening socket on a specific network interface.

Creates a socket that listens for incoming connection requests on the specified port and network interface. This provides direct control over which interface accepts connections when multiple interfaces are available, useful in multi-homed systems where you need to segregate traffic by interface or ensure connections arrive on a specific network path.

This function is the interface-specific version of listen(). While listen() accepts connections on all interfaces (when using INADDR_ANY) or relies on IP routing, this function gives explicit control by interface number. Incoming connections are placed in a pending queue until accepted with accept().

Parameters
addrIP address to bind to:
  • Use INADDR_ANY (or IPADDR::AnyIP()) to accept connections on any IP address assigned to the specified interface
  • Use a specific IP address to accept only on that address (the IP must be assigned to the specified interface)
  • INADDR_ANY is the most common usage for interface-specific servers
portPort number to listen on (1-65535). The port must not already be in use on any interface
ifnNetwork interface number (0, 1, 2, etc.) to bind to. This forces the listening socket to accept connections only through this specific interface, regardless of routing table or IP address configuration. Valid range is 0 to (number of interfaces - 1). Use GetNumberOfInterfaces() to determine valid range
maxpendMaximum number of pending connections in the accept queue (default: 5). This is the maximum number of clients that can be waiting simultaneously. When this limit is reached, additional connection attempts will be refused
Returns
Positive file descriptor on success (use with accept() to get client connections), negative TCP Socket Status error code on failure:
  • TCP_ERR_NONE_AVAIL: No available sockets in system pool
  • TCP_ERR_NOCON: Port already in use or binding failed

Notes

  • The listening socket uses one socket from the system pool. Each accepted connection uses an additional socket.
  • Interface numbers typically start at 0 and increment sequentially. Interface 0 is usually the primary Ethernet port, but this can vary by platform.
  • If you specify an invalid interface number (negative or >= number of interfaces), the behavior is undefined. Always validate with GetNumberOfInterfaces() first.
  • The specified interface must be in an "up" state with a valid IP address assigned for connections to be accepted successfully.
  • Always call close() on the listening socket when shutting down to free the socket resource and release the port.
  • This function provides the most direct interface control for server applications. For interface selection by IP address, see the other listenvia() overload.
Warning
Specifying an invalid interface number may cause the listen to fail or bind to an unexpected interface. Always validate interface numbers before use.
The port is global across all interfaces - you cannot listen on the same port on multiple interfaces simultaneously. Each port can only have one listener.

Expand for Example Usage

Examples

Basic Interface-Specific Server
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
void InterfaceSpecificServer(void *pd) {
init();
int interfaceNum = 1; // Listen on interface 1
printf("Creating server on interface %d\n", interfaceNum);
printf("Interface IP: %s\n", GetInterfaceIP(interfaceNum).print());
// Listen on interface 1, port 8080
int fdListen = listenvia(INADDR_ANY, 8080, interfaceNum, 5);
if (fdListen < 0) {
printf("Failed to create listener: %d\n", fdListen);
return;
}
printf("Server listening on interface %d, port 8080\n", interfaceNum);
printf("Waiting for connections...\n\n");
while (1) {
IPADDR clientAddr;
uint16_t clientPort;
int fdClient = accept(fdListen, &clientAddr, &clientPort, 0);
if (fdClient > 0) {
printf("Client connected: %s:%d\n",
clientAddr.print(), clientPort);
// Verify connection came through correct interface
int connInterface = TcpGetSocketInterface(fdClient);
printf(" Connection via interface: %d\n", connInterface);
if (connInterface == interfaceNum) {
printf(" Verified: Correct interface\n");
}
// Handle client...
const char *msg = "Hello from interface-specific server\r\n";
write(fdClient, msg, strlen(msg));
close(fdClient);
}
}
close(fdListen);
}
Dual-Homed Server - Separate Control and Data Networks
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
// Interface 0: Control network (192.168.1.x)
// Interface 1: Data network (10.0.0.x)
void DualHomedServer(void *pd) {
init();
printf("Dual-homed server starting...\n");
printf("Control network (IF0): %s\n", GetInterfaceIP(0).print());
printf("Data network (IF1): %s\n\n", GetInterfaceIP(1).print());
// Create control server on interface 0, port 9000
int fdControl = listenvia(INADDR_ANY, 9000, 0, 5);
if (fdControl < 0) {
printf("Failed to create control listener: %d\n", fdControl);
return;
}
printf("Control server: interface 0, port 9000\n");
// Create data server on interface 1, port 8080
int fdData = listenvia(INADDR_ANY, 8080, 1, 10);
if (fdData < 0) {
printf("Failed to create data listener: %d\n", fdData);
close(fdControl);
return;
}
printf("Data server: interface 1, port 8080\n\n");
while (1) {
// Check for control connections (short timeout)
IPADDR addr;
uint16_t port;
int fd = accept(fdControl, &addr, &port, TICKS_PER_SECOND / 10);
if (fd > 0) {
printf("Control connection from %s:%d\n", addr.print(), port);
// Handle control commands
char cmd[128];
int n = read(fd, cmd, sizeof(cmd) - 1);
if (n > 0) {
cmd[n] = '\0';
printf(" Command: %s", cmd);
const char *resp = "OK\r\n";
write(fd, resp, strlen(resp));
}
close(fd);
}
// Check for data connections (short timeout)
fd = accept(fdData, &addr, &port, TICKS_PER_SECOND / 10);
if (fd > 0) {
printf("Data connection from %s:%d\n", addr.print(), port);
// Handle bulk data transfer
char buffer[1024];
int n = read(fd, buffer, sizeof(buffer));
if (n > 0) {
printf(" Received %d bytes of data\n", n);
}
close(fd);
}
}
}
Server on Each Interface
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
#define MAX_INTERFACES 4
struct InterfaceServer {
int interfaceNum;
int fdListen;
int connectionsAccepted;
};
void MultiInterfaceServer(void *pd) {
init();
int numInterfaces = GetNumberOfInterfaces();
InterfaceServer servers[MAX_INTERFACES];
printf("Creating server on each of %d interfaces\n\n", numInterfaces);
// Create listening socket on each interface
for (int i = 0; i < numInterfaces; i++) {
servers[i].interfaceNum = i;
servers[i].connectionsAccepted = 0;
IPADDR ifAddr = GetInterfaceIP(i);
printf("Interface %d (%s): ", i, ifAddr.print());
// Each interface listens on the same port (8080)
// This works because we're specifying different interfaces
servers[i].fdListen = listenvia(INADDR_ANY, 8080, i, 5);
if (servers[i].fdListen > 0) {
printf("Listening\n");
} else {
printf("Failed: %d\n", servers[i].fdListen);
}
}
printf("\nServers ready. All listening on port 8080\n\n");
// Accept connections from all interfaces
while (1) {
for (int i = 0; i < numInterfaces; i++) {
if (servers[i].fdListen < 0) continue;
IPADDR addr;
uint16_t port;
// Check each interface with short timeout
int fd = accept(servers[i].fdListen, &addr, &port,
if (fd > 0) {
servers[i].connectionsAccepted++;
printf("IF%d: Connection from %s:%d (#%d)\n",
i, addr.print(), port,
servers[i].connectionsAccepted);
// Send interface-specific response
char response[128];
snprintf(response, sizeof(response),
"Connected to interface %d\r\n", i);
write(fd, response, strlen(response));
close(fd);
}
}
}
}
Interface Validation and Error Handling
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
int CreateInterfaceServer(int interfaceNum, uint16_t port, uint8_t backlog) {
// Validate interface number
int maxInterfaces = GetNumberOfInterfaces();
if (interfaceNum < 0 || interfaceNum >= maxInterfaces) {
printf("ERROR: Invalid interface number %d\n", interfaceNum);
printf("Valid range: 0 to %d\n", maxInterfaces - 1);
return -1;
}
// Get interface information
IPADDR ifAddr = GetInterfaceIP(interfaceNum);
if (ifAddr == IPADDR::NullIP()) {
printf("ERROR: Interface %d has no IP address\n", interfaceNum);
return -1;
}
printf("Creating server:\n");
printf(" Interface: %d\n", interfaceNum);
printf(" IP Address: %s\n", ifAddr.print());
printf(" Port: %d\n", port);
printf(" Backlog: %d\n", backlog);
// Create listening socket
int fdListen = listenvia(INADDR_ANY, port, interfaceNum, backlog);
if (fdListen < 0) {
printf("ERROR: Failed to create listener: %d\n", fdListen);
switch (fdListen) {
printf(" No sockets available\n");
break;
printf(" Port %d may already be in use\n", port);
break;
default:
printf(" Unknown error\n");
break;
}
return -1;
}
printf("Server created successfully (fd=%d)\n", fdListen);
return fdListen;
}
void UserMain(void *pd) {
init();
int fdListen = CreateInterfaceServer(0, 8080, 10);
if (fdListen > 0) {
// Use server...
close(fdListen);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
Interface Failover Server
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
void FailoverServer(void *pd) {
init();
int primaryIF = 0;
int backupIF = 1;
int activeIF = primaryIF;
int fdListen = -1;
printf("Failover server starting\n");
printf("Primary interface: %d (%s)\n",
primaryIF, GetInterfaceIP(primaryIF).print());
printf("Backup interface: %d (%s)\n\n",
backupIF, GetInterfaceIP(backupIF).print());
// Try to start on primary interface
fdListen = listenvia(INADDR_ANY, 8080, primaryIF, 5);
if (fdListen < 0) {
printf("Primary interface failed, using backup\n");
activeIF = backupIF;
fdListen = listenvia(INADDR_ANY, 8080, backupIF, 5);
} else {
printf("Running on primary interface\n");
}
if (fdListen < 0) {
printf("Both interfaces failed: %d\n", fdListen);
return;
}
uint32_t lastHealthCheck = Secs;
while (1) {
// Accept connections
IPADDR addr;
uint16_t port;
int fd = accept(fdListen, &addr, &port, TICKS_PER_SECOND);
if (fd > 0) {
printf("Connection on IF%d from %s:%d\n",
activeIF, addr.print(), port);
// Handle connection...
close(fd);
}
// Periodic health check
if ((Secs - lastHealthCheck) >= 30) {
// Check if we should switch interfaces
if (activeIF == backupIF) {
// Currently on backup, try to restore primary
int testFd = listenvia(INADDR_ANY, 8081, primaryIF, 1);
if (testFd > 0) {
printf("\nPrimary interface recovered, switching back\n");
close(testFd);
close(fdListen);
fdListen = listenvia(INADDR_ANY, 8080, primaryIF, 5);
if (fdListen > 0) {
activeIF = primaryIF;
printf("Restored to primary interface\n\n");
}
}
}
lastHealthCheck = Secs;
}
}
}
Per-Interface Connection Limiting
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
#define MAX_CONNECTIONS_PER_IF 10
struct InterfaceLimits {
int interfaceNum;
int fdListen;
int activeConnections;
int maxConnections;
int rejectedCount;
};
void LimitedInterfaceServer(void *pd) {
init();
int numInterfaces = GetNumberOfInterfaces();
InterfaceLimits limits[4]; // Support up to 4 interfaces
printf("Creating rate-limited servers\n");
printf("Max connections per interface: %d\n\n", MAX_CONNECTIONS_PER_IF);
// Initialize each interface
for (int i = 0; i < numInterfaces; i++) {
limits[i].interfaceNum = i;
limits[i].activeConnections = 0;
limits[i].maxConnections = MAX_CONNECTIONS_PER_IF;
limits[i].rejectedCount = 0;
limits[i].fdListen = listenvia(INADDR_ANY, 8080, i, 5);
if (limits[i].fdListen > 0) {
printf("IF%d (%s): Ready\n",
i, GetInterfaceIP(i).print());
}
}
printf("\nServers running\n\n");
while (1) {
for (int i = 0; i < numInterfaces; i++) {
if (limits[i].fdListen < 0) continue;
// Check if we can accept more connections
if (limits[i].activeConnections >= limits[i].maxConnections) {
// At limit - just peek to reject
IPADDR addr;
uint16_t port;
int fd = accept(limits[i].fdListen, &addr, &port, 0);
if (fd > 0) {
limits[i].rejectedCount++;
const char *msg = "Server busy\r\n";
write(fd, msg, strlen(msg));
close(fd);
printf("IF%d: Rejected connection (at limit %d/%d)\n",
i, limits[i].activeConnections,
limits[i].maxConnections);
}
continue;
}
// Accept new connection
IPADDR addr;
uint16_t port;
int fd = accept(limits[i].fdListen, &addr, &port,
if (fd > 0) {
limits[i].activeConnections++;
printf("IF%d: Accepted %s:%d (%d/%d active)\n",
i, addr.print(), port,
limits[i].activeConnections,
limits[i].maxConnections);
// Handle connection (simplified - normally would track)
OSTimeDly(TICKS_PER_SECOND * 2);
close(fd);
limits[i].activeConnections--;
}
}
}
}
Interface Statistics Monitoring
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
#include <nbrtos.h>
struct InterfaceStats {
int interfaceNum;
int fdListen;
uint32_t totalConnections;
uint32_t bytesReceived;
uint32_t bytesSent;
};
void MonitoredInterfaceServer(void *pd) {
init();
int numInterfaces = GetNumberOfInterfaces();
InterfaceStats stats[4]; // Support up to 4 interfaces
// Initialize
for (int i = 0; i < numInterfaces; i++) {
stats[i].interfaceNum = i;
stats[i].totalConnections = 0;
stats[i].bytesReceived = 0;
stats[i].bytesSent = 0;
stats[i].fdListen = listenvia(INADDR_ANY, 8080, i, 5);
}
printf("Monitored interface servers running\n\n");
uint32_t lastStatsTime = Secs;
while (1) {
for (int i = 0; i < numInterfaces; i++) {
if (stats[i].fdListen < 0) continue;
IPADDR addr;
uint16_t port;
int fd = accept(stats[i].fdListen, &addr, &port,
if (fd > 0) {
stats[i].totalConnections++;
// Handle connection
char buffer[512];
int n = read(fd, buffer, sizeof(buffer));
if (n > 0) {
stats[i].bytesReceived += n;
// Echo back
writeall(fd, buffer, n);
stats[i].bytesSent += n;
}
close(fd);
}
}
// Print statistics every 30 seconds
if ((Secs - lastStatsTime) >= 30) {
printf("\n=== Interface Statistics ===\n");
for (int i = 0; i < numInterfaces; i++) {
if (stats[i].fdListen < 0) continue;
printf("Interface %d (%s):\n",
i, GetInterfaceIP(i).print());
printf(" Connections: %lu\n", stats[i].totalConnections);
printf(" RX: %lu bytes\n", stats[i].bytesReceived);
printf(" TX: %lu bytes\n", stats[i].bytesSent);
}
printf("\n");
lastStatsTime = Secs;
}
}
}
Dynamic Interface Server Allocation
#include <tcp.h>
#include <init.h>
#include <networkinterface.h>
// Automatically find best interface and create server
int CreateServerOnBestInterface(uint16_t port) {
int numInterfaces = GetNumberOfInterfaces();
printf("Finding best interface for server...\n");
// Try each interface in order
for (int i = 0; i < numInterfaces; i++) {
IPADDR ifAddr = GetInterfaceIP(i);
printf("Trying interface %d (%s)...", i, ifAddr.print());
// Check if interface has valid IP
if (ifAddr == IPADDR::NullIP()) {
printf(" No IP\n");
continue;
}
// Try to create server
int fd = listenvia(INADDR_ANY, port, i, 5);
if (fd > 0) {
printf(" Success!\n");
printf("Server created on interface %d, port %d\n", i, port);
return fd;
}
printf(" Failed: %d\n", fd);
}
printf("No suitable interface found\n");
return -1;
}
void UserMain(void *pd) {
init();
int fdListen = CreateServerOnBestInterface(8080);
if (fdListen > 0) {
// Use server...
close(fdListen);
}
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}

See also
listen(), listenvia(const IPADDR&, uint16_t, const IPADDR&, uint8_t), accept(), close(), GetNumberOfInterfaces(), GetInterfaceIP(), TcpGetSocketInterface()

◆ NoBlockConnect()

int NoBlockConnect ( const IPADDR & ipAddress,
uint16_t remotePort )
inline

#include <tcp.h>

Initiate a non-blocking TCP connection.

Creates a TCP socket and initiates a connection to the remote host, returning immediately without waiting for the connection to complete. The application must poll the socket state using TcpGetSocketState() to determine when the connection is established (TCP_STATE_ESTABLISHED). The connection status can also be checked using writeavail().

Parameters
ipAddressIP address of the remote host
remotePortPort number on the remote host
Returns
Positive file descriptor on success, negative TCP Socket Status error code on failure

Notes:

  • This function returns immediately and does not block waiting for the connection to establish. The socket will be in a connecting state, and the application must poll its state to determine when it becomes ready for data transfer.
  • The system will automatically select the local interface and port for the connection. Use NoBlockConnectVia() if you need control over which interface is used.
Warning
Always call close() to free system resources, even if the socket enters the TCP_STATE_CLOSING state. Failure to close will cause a resource leak.
See also
NoBlockConnectVia(), TcpGetSocketState(), writeavail(), connect(), connectvia(), connectwlocal(), close()

Expand for Example Usage

Examples

Basic Non-Blocking Connection with State Polling
#include <tcp.h>
#include <nbrtos.h>
void NonBlockingClientTask(void *pd)
{
// Target server details
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Initiate non-blocking connection
int fd = NoBlockConnect(serverIp, serverPort);
if (fd < 0)
{
printf("Failed to initiate connection: %d\r\n", fd);
return;
}
printf("Connection initiated to %I:%d (fd=%d)\r\n", serverIp, serverPort, fd);
// Poll for connection establishment (timeout after 10 seconds)
uint32_t startTime = Secs;
bool connected = false;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
connected = true;
printf("Connection established!\r\n");
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection failed (state: %d)\r\n", state);
break;
}
OSTimeDly(TICKS_PER_SECOND / 10); // Poll every 100ms
}
if (!connected)
{
printf("Connection timeout\r\n");
close(fd);
return;
}
// Connection successful - send data
const char *message = "Hello, Server!\r\n";
write(fd, message, strlen(message));
// Receive response
char buffer[256];
int bytesRead = read(fd, buffer, sizeof(buffer) - 1, TICKS_PER_SECOND * 5);
if (bytesRead > 0)
{
buffer[bytesRead] = '\0';
printf("Received: %s\r\n", buffer);
}
close(fd);
}
Using writeavail() to Check Connection Status
#include <tcp.h>
#include <nbrtos.h>
void CheckConnectionWithWriteavail(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 80;
int fd = NoBlockConnect(serverIp, serverPort);
if (fd < 0)
{
printf("Connection initiation failed: %d\r\n", fd);
return;
}
printf("Connecting to %I:%d...\r\n", serverIp, serverPort);
// Wait for connection using writeavail()
// writeavail() returns > 0 when socket is ready to write (connected)
uint32_t startTime = Secs;
bool connected = false;
while ((Secs - startTime) < 10)
{
int available = writeavail(fd);
if (available > 0)
{
// Socket is ready for writing - connection established
connected = true;
printf("Connection established (write buffer: %d bytes)\r\n", available);
break;
}
else if (available < 0)
{
// Negative value indicates error or closed socket
printf("Connection failed: %d\r\n", available);
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (!connected)
{
printf("Connection timeout\r\n");
}
close(fd);
}
Multiple Simultaneous Non-Blocking Connections
#include <tcp.h>
#include <nbrtos.h>
#define MAX_CONNECTIONS 5
struct Connection
{
int fd;
IPADDR serverIp;
uint16_t serverPort;
uint32_t startTime;
bool established;
};
void MultipleConnectionsTask(void *pd)
{
Connection connections[MAX_CONNECTIONS];
// Initialize connections to different servers
const char *servers[] = {
"192.168.1.100",
"192.168.1.101",
"192.168.1.102",
"192.168.1.103",
"192.168.1.104"
};
// Initiate all connections simultaneously
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
connections[i].serverIp = AsciiToIp(servers[i]);
connections[i].serverPort = 8080;
connections[i].startTime = Secs;
connections[i].established = false;
connections[i].fd = NoBlockConnect(connections[i].serverIp,
connections[i].serverPort);
if (connections[i].fd < 0)
{
printf("Failed to initiate connection %d: %d\r\n",
i, connections[i].fd);
}
else
{
printf("Initiated connection %d to %I:%d (fd=%d)\r\n",
i, connections[i].serverIp, connections[i].serverPort,
connections[i].fd);
}
}
// Poll all connections until established or timeout
int establishedCount = 0;
const uint32_t timeout = 10; // 10 seconds
while (establishedCount < MAX_CONNECTIONS && (Secs - connections[0].startTime) < timeout)
{
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (connections[i].fd < 0 || connections[i].established)
continue;
TcpState state = TcpGetSocketState(connections[i].fd);
if (state == TCP_STATE_ESTABLISHED)
{
connections[i].established = true;
establishedCount++;
printf("Connection %d established!\r\n", i);
// Send initial message
char msg[64];
snprintf(msg, sizeof(msg), "Hello from client %d\r\n", i);
write(connections[i].fd, msg, strlen(msg));
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection %d failed\r\n", i);
close(connections[i].fd);
connections[i].fd = -1;
establishedCount++; // Count as "done" even if failed
}
}
OSTimeDly(TICKS_PER_SECOND / 20); // Poll every 50ms
}
printf("Connection phase complete\r\n");
// Clean up all connections
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (connections[i].fd > 0)
{
close(connections[i].fd);
}
}
}
Non-Blocking Connection with select() for Event-Driven Design
#include <tcp.h>
#include <nbrtos.h>
void EventDrivenConnectionTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = NoBlockConnect(serverIp, serverPort);
if (fd < 0)
{
printf("Failed to initiate connection: %d\r\n", fd);
return;
}
printf("Connecting to %I:%d...\r\n", serverIp, serverPort);
// Use select() to wait for socket to become writable (connected)
fd_set write_fds;
fd_set error_fds;
FD_ZERO(&write_fds);
FD_ZERO(&error_fds);
FD_SET(fd, &write_fds);
FD_SET(fd, &error_fds);
// Wait up to 10 seconds for connection
int result = select(fd + 1, NULL, &write_fds, &error_fds, TICKS_PER_SECOND * 10);
if (result < 0)
{
printf("select() error: %d\r\n", result);
close(fd);
return;
}
else if (result == 0)
{
printf("Connection timeout\r\n");
close(fd);
return;
}
if (FD_ISSET(fd, &error_fds))
{
printf("Connection error\r\n");
close(fd);
return;
}
if (FD_ISSET(fd, &write_fds))
{
// Verify connection is truly established
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
printf("Connection established via select()!\r\n");
// Connection ready - proceed with communication
const char *request = "GET / HTTP/1.1\r\nHost: server\r\n\r\n";
write(fd, request, strlen(request));
// Read response...
}
else
{
printf("Socket writable but not established (state: %d)\r\n", state);
}
}
close(fd);
}

◆ NoBlockConnectVia() [1/2]

int NoBlockConnectVia ( const IPADDR & ipAddress,
uint16_t remotePort,
const IPADDR & interfaceIpAddress = IPADDR::NullIP() )
inline

#include <tcp.h>

Initiate a non-blocking TCP connection via a specific interface.

Creates a TCP socket and initiates a connection to the remote host using the specified local interface IP address. The function returns immediately without waiting for the connection to complete. The application must poll the socket state using TcpGetSocketState() to determine when the connection is established (TCP_STATE_ESTABLISHED).

Warning
Always call close() to free system resources, even if the socket enters the TCP_STATE_CLOSING state. Failure to close will cause a resource leak.
Parameters
ipAddressIP address of the remote host
remotePortPort number on the remote host
interfaceIpAddressIP address of the local interface to use (default: IPADDR::NullIP() for automatic selection based on routing)
Returns
Positive file descriptor on success, negative TCP Socket Status error code on failure
See also
NoBlockConnect(), TcpGetSocketState(), writeavail(), connect(), connectvia(), connectwlocal()

◆ NoBlockConnectVia() [2/2]

int NoBlockConnectVia ( const IPADDR & ipAddress,
uint16_t remotePort,
int ifnum )
inline

#include <tcp.h>

Initiate a non-blocking TCP connection via a specific interface number.

Creates a TCP socket and initiates a connection to the remote host using the specified local interface number. The function returns immediately without waiting for the connection to complete. The interface number overrides routing decisions based on destination IP address. The application must poll the socket state using TcpGetSocketState() to determine when the connection is established (TCP_STATE_ESTABLISHED).

Parameters
ipAddressIP address of the remote host
remotePortPort number on the remote host
ifnumNetwork interface number to use. Overrides all routing decisions
Returns
Positive file descriptor on success, negative TCP Socket Status error code on failure

Notes:

  • This function is useful when you have multiple network interfaces (e.g., Ethernet and WiFi) and need to force the connection through a specific interface regardless of routing tables.
  • Interface numbers are zero-based. Use GetNumInterfaces() to determine the total number of available interfaces and GetIPAddress(ifnum) to verify the interface has a valid IP.
Warning
  • Always call close() to free system resources, even if the socket enters the TCP_STATE_CLOSING state. Failure to close will cause a resource leak.
  • If the specified interface is not active or does not have a valid IP address, the connection will fail. Always validate the interface before use.
See also
NoBlockConnect(), TcpGetSocketState(), writeavail(), connect(), connectvia(), connectwlocal(), GetNumInterfaces(), GetIPAddress(), close()

Expand for Example Usage

Examples

Basic Non-Blocking Connection via Specific Interface
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
void ConnectViaEthernetTask(void *pd)
{
// Force connection through interface 0 (typically Ethernet)
const int ETHERNET_IF = 0;
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Verify interface is valid and has an IP address
if (ETHERNET_IF >= GetNumInterfaces())
{
printf("Interface %d does not exist\r\n", ETHERNET_IF);
return;
}
IPADDR localIp = GetIPAddress(ETHERNET_IF);
if (localIp == IPADDR_ANY)
{
printf("Interface %d has no IP address\r\n", ETHERNET_IF);
return;
}
printf("Connecting to %I:%d via interface %d (%I)\r\n",
serverIp, serverPort, ETHERNET_IF, localIp);
// Initiate non-blocking connection via specified interface
int fd = NoBlockConnectVia(serverIp, serverPort, ETHERNET_IF);
if (fd < 0)
{
printf("Failed to initiate connection: %d\r\n", fd);
return;
}
// Poll for connection establishment
uint32_t startTime = Secs;
bool connected = false;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
connected = true;
printf("Connection established via interface %d!\r\n", ETHERNET_IF);
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection failed (state: %d)\r\n", state);
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (!connected)
{
printf("Connection timeout\r\n");
close(fd);
return;
}
// Send data and receive response
const char *message = "Hello via Ethernet!\r\n";
write(fd, message, strlen(message));
close(fd);
}
int NoBlockConnectVia(const IPADDR &ipAddress, uint16_t remotePort, const IPADDR &interfaceIpAddress=IPADDR::NullIP())
Initiate a non-blocking TCP connection via a specific interface.
Definition tcp.h:7919
Multi-Interface Redundancy - Try Primary, Fallback to Secondary
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
int ConnectWithFailover(const IPADDR &serverIp, uint16_t serverPort,
int primaryIf, int secondaryIf)
{
int fd = -1;
// Try primary interface first
if (primaryIf < GetNumInterfaces() && GetIPAddress(primaryIf) != IPADDR_ANY)
{
printf("Attempting connection via primary interface %d\r\n", primaryIf);
fd = NoBlockConnectVia(serverIp, serverPort, primaryIf);
if (fd > 0)
{
// Wait up to 5 seconds for primary connection
uint32_t startTime = Secs;
while ((Secs - startTime) < 5)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
printf("Connected via primary interface %d\r\n", primaryIf);
return fd;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Primary interface connection failed\r\n");
close(fd);
fd = -1;
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (fd > 0)
{
printf("Primary interface connection timeout\r\n");
close(fd);
fd = -1;
}
}
}
// Primary failed, try secondary interface
if (secondaryIf < GetNumInterfaces() && GetIPAddress(secondaryIf) != IPADDR_ANY)
{
printf("Attempting connection via secondary interface %d\r\n", secondaryIf);
fd = NoBlockConnectVia(serverIp, serverPort, secondaryIf);
if (fd > 0)
{
uint32_t startTime = Secs;
while ((Secs - startTime) < 5)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
printf("Connected via secondary interface %d\r\n", secondaryIf);
return fd;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Secondary interface connection failed\r\n");
close(fd);
return -1;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
printf("Secondary interface connection timeout\r\n");
close(fd);
}
}
return -1;
}
void FailoverExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Try Ethernet (0) first, fallback to WiFi (1)
int fd = ConnectWithFailover(serverIp, serverPort, 0, 1);
if (fd > 0)
{
const char *message = "Connected with failover!\r\n";
write(fd, message, strlen(message));
close(fd);
}
else
{
printf("All connection attempts failed\r\n");
}
}
Simultaneous Connections via Different Interfaces
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
void DualInterfaceConnectionTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
const int ETHERNET_IF = 0;
const int WIFI_IF = 1;
// Verify both interfaces are available
if (GetNumInterfaces() < 2)
{
printf("Need at least 2 interfaces for this example\r\n");
return;
}
IPADDR ethernetIp = GetIPAddress(ETHERNET_IF);
IPADDR wifiIp = GetIPAddress(WIFI_IF);
if (ethernetIp == IPADDR_ANY || wifiIp == IPADDR_ANY)
{
printf("Both interfaces must have valid IP addresses\r\n");
return;
}
printf("Initiating connections via both interfaces:\r\n");
printf(" Ethernet (%d): %I\r\n", ETHERNET_IF, ethernetIp);
printf(" WiFi (%d): %I\r\n", WIFI_IF, wifiIp);
// Start both connections simultaneously
int ethernetFd = NoBlockConnectVia(serverIp, serverPort, ETHERNET_IF);
int wifiFd = NoBlockConnectVia(serverIp, serverPort, WIFI_IF);
if (ethernetFd < 0 && wifiFd < 0)
{
printf("Failed to initiate any connections\r\n");
return;
}
// Wait for at least one connection to establish
uint32_t startTime = Secs;
bool ethernetConnected = false;
bool wifiConnected = false;
while ((Secs - startTime) < 10 && !(ethernetConnected && wifiConnected))
{
if (ethernetFd > 0 && !ethernetConnected)
{
TcpState state = TcpGetSocketState(ethernetFd);
if (state == TCP_STATE_ESTABLISHED)
{
ethernetConnected = true;
printf("Ethernet connection established!\r\n");
write(ethernetFd, "Via Ethernet\r\n", 14);
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
close(ethernetFd);
ethernetFd = -1;
}
}
if (wifiFd > 0 && !wifiConnected)
{
TcpState state = TcpGetSocketState(wifiFd);
if (state == TCP_STATE_ESTABLISHED)
{
wifiConnected = true;
printf("WiFi connection established!\r\n");
write(wifiFd, "Via WiFi\r\n", 10);
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
close(wifiFd);
wifiFd = -1;
}
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
// Report results
printf("Connection results:\r\n");
printf(" Ethernet: %s\r\n", ethernetConnected ? "Connected" : "Failed");
printf(" WiFi: %s\r\n", wifiConnected ? "Connected" : "Failed");
// Clean up
if (ethernetFd > 0) close(ethernetFd);
if (wifiFd > 0) close(wifiFd);
}
Interface Selection Based on Network Conditions
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
// Select best interface based on link status and speed
int SelectBestInterface(void)
{
int bestInterface = -1;
uint32_t bestSpeed = 0;
for (int i = 0; i < GetNumInterfaces(); i++)
{
// Check if interface has valid IP
IPADDR ip = GetIPAddress(i);
if (ip == IPADDR_ANY)
continue;
// Check link status
if (ib == nullptr || !ib->IsLinkActive())
continue;
// Get interface speed (if available)
uint32_t speed = ib->GetSpeed();
if (speed > bestSpeed)
{
bestSpeed = speed;
bestInterface = i;
}
}
return bestInterface;
}
void SmartConnectionTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Automatically select best interface
int ifnum = SelectBestInterface();
if (ifnum < 0)
{
printf("No suitable interface available\r\n");
return;
}
IPADDR localIp = GetIPAddress(ifnum);
printf("Selected interface %d (%I) for connection\r\n", ifnum, localIp);
int fd = NoBlockConnectVia(serverIp, serverPort, ifnum);
if (fd < 0)
{
printf("Connection initiation failed: %d\r\n", fd);
return;
}
// Wait for connection
uint32_t startTime = Secs;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
printf("Connected successfully!\r\n");
// Use connection...
const char *msg = "Hello from smart interface selection!\r\n";
write(fd, msg, strlen(msg));
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection failed\r\n");
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
close(fd);
}
Network interface configuration block class for interface control and configuration.
Definition netinterface.h:245
InterfaceBlock * GetInterfaceBlock(int interface=0)
Get an InterfaceBlock control and configuration object.

◆ NoBlockConnectwlocal()

int NoBlockConnectwlocal ( const IPADDR & ipAddress,
uint16_t localPort,
uint16_t remotePort,
IPADDR interfaceIpAddress = IPADDR::NullIP(),
int ifn = -1 )
inline

#include <tcp.h>

Initiate a non-blocking TCP connection with full local parameter control.

Creates a TCP socket with complete control over connection parameters and initiates a connection to the remote host. The function returns immediately without waiting for the connection to complete. The application must poll the socket state using TcpGetSocketState() to determine when the connection is established (TCP_STATE_ESTABLISHED).

Parameters
ipAddressIP address of the remote host
localPortLocal port number to bind (recommend 0 for automatic assignment). Warning: Non-zero values can cause connection failures with half-open sockets on the remote side
remotePortPort number on the remote host
interfaceIpAddressIP address of local interface (use IPADDR::NullIP() if using ifn)
ifnNetwork interface number (use -1 if using interfaceIpAddress)
Returns
Positive file descriptor on success, negative TCP Socket Status error code on failure

Notes: This function provides the most control over connection parameters but is rarely needed. For most applications, use NoBlockConnect() or NoBlockConnectVia() instead.

  • You can specify the interface either by IP address (interfaceIpAddress) or by interface number (ifn), but not both. If both are specified, the interface number takes precedence.
Warning
  • Always call close() to free system resources, even if the socket enters the TCP_STATE_CLOSING state. Failure to close will cause a resource leak.
  • Specifying a local port number is not recommended. Using a fixed local port can cause connection failures when the remote host has a half-open socket remaining from a previous connection. Always use 0 for automatic port assignment unless you have a specific protocol requirement.
See also
TcpGetSocketState(), NoBlockConnect(), NoBlockConnectVia(), writeavail(), close()

Expand for Example Usage

Examples

Basic Usage - Let System Assign Local Port (Recommended)
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
void RecommendedUsageTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t remotePort = 8080;
// Get local interface IP
IPADDR localIp = GetIPAddress(0);
// Connect with automatic local port assignment (recommended)
// localPort = 0 means system will choose an available ephemeral port
int fd = NoBlockConnectwlocal(serverIp, 0, remotePort, localIp);
if (fd < 0)
{
printf("Connection initiation failed: %d\r\n", fd);
return;
}
printf("Connecting to %I:%d from %I:<auto>\r\n",
serverIp, remotePort, localIp);
// Wait for connection to establish
uint32_t startTime = Secs;
bool connected = false;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
connected = true;
printf("Connection established!\r\n");
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection failed (state: %d)\r\n", state);
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (connected)
{
const char *message = "Hello, Server!\r\n";
write(fd, message, strlen(message));
}
close(fd);
}
int NoBlockConnectwlocal(const IPADDR &ipAddress, uint16_t localPort, uint16_t remotePort, IPADDR interfaceIpAddress=IPADDR::NullIP(), int ifn=-1)
Initiate a non-blocking TCP connection with full local parameter control.
Definition tcp.h:8810
Using Interface Number Instead of IP Address
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
void ConnectViaInterfaceNumberTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t remotePort = 8080;
const int ETHERNET_IF = 0;
// Verify interface exists
if (ETHERNET_IF >= GetNumInterfaces())
{
printf("Interface %d does not exist\r\n", ETHERNET_IF);
return;
}
// Connect using interface number instead of IP address
// Pass IPADDR::NullIP() for interfaceIpAddress when using ifn
int fd = NoBlockConnectwlocal(serverIp, 0, remotePort,
IPADDR::NullIP(), ETHERNET_IF);
if (fd < 0)
{
printf("Connection initiation failed: %d\r\n", fd);
return;
}
IPADDR localIp = GetIPAddress(ETHERNET_IF);
printf("Connecting to %I:%d via interface %d (%I)\r\n",
serverIp, remotePort, ETHERNET_IF, localIp);
// Wait for connection
uint32_t startTime = Secs;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
printf("Connected via interface %d!\r\n", ETHERNET_IF);
const char *msg = "Hello from specific interface!\r\n";
write(fd, msg, strlen(msg));
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection failed\r\n");
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
close(fd);
}
Fixed Local Port (Not Recommended - Shows Potential Issues)
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
void FixedLocalPortExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t remotePort = 8080;
uint16_t fixedLocalPort = 5000; // WARNING: Not recommended!
IPADDR localIp = GetIPAddress(0);
// Attempt 1: Use fixed local port
printf("Attempting connection with fixed local port %d...\r\n", fixedLocalPort);
int fd = NoBlockConnectwlocal(serverIp, fixedLocalPort, remotePort, localIp);
if (fd < 0)
{
printf("Connection with fixed port failed: %d\r\n", fd);
if (fd == TCP_ERR_PORT_IN_USE)
{
printf("Local port %d is already in use\r\n", fixedLocalPort);
}
// Retry with automatic port assignment (recommended approach)
printf("Retrying with automatic port assignment...\r\n");
fd = NoBlockConnectwlocal(serverIp, 0, remotePort, localIp);
if (fd < 0)
{
printf("Connection still failed: %d\r\n", fd);
return;
}
}
// Wait for connection
uint32_t startTime = Secs;
bool connected = false;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
connected = true;
printf("Connection established\r\n");
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection failed after initiation\r\n");
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (connected)
{
const char *msg = "Connection succeeded\r\n";
write(fd, msg, strlen(msg));
}
close(fd);
// Demonstrate the half-open socket problem
printf("\r\nDemonstrating half-open socket issue...\r\n");
printf("If server still has half-open socket, reconnection with\r\n");
printf("same local port will fail. This is why automatic port\r\n");
printf("assignment (localPort=0) is strongly recommended.\r\n");
}
Protocol Requiring Specific Local Port (Rare Use Case)
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
// Example: Some legacy protocols require client to use specific port
void LegacyProtocolClient(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t remotePort = 8080;
uint16_t requiredLocalPort = 6000; // Protocol requirement
IPADDR localIp = GetIPAddress(0);
printf("Legacy protocol requires local port %d\r\n", requiredLocalPort);
// First, ensure port is not already in use
// In production, implement proper port cleanup and retry logic
int fd = NoBlockConnectwlocal(serverIp, requiredLocalPort, remotePort, localIp);
if (fd < 0)
{
if (fd == TCP_ERR_PORT_IN_USE)
{
printf("Required port %d is in use. Wait for TIME_WAIT...\r\n",
requiredLocalPort);
// In real application, you might:
// 1. Wait for TIME_WAIT to expire (typically 2*MSL = 240s)
// 2. Use SO_REUSEADDR if available
// 3. Inform user of the conflict
return;
}
else
{
printf("Connection failed: %d\r\n", fd);
return;
}
}
printf("Initiated connection from %I:%d to %I:%d\r\n",
localIp, requiredLocalPort, serverIp, remotePort);
// Wait for connection with timeout
uint32_t startTime = Secs;
bool connected = false;
while ((Secs - startTime) < 10)
{
TcpState state = TcpGetSocketState(fd);
if (state == TCP_STATE_ESTABLISHED)
{
connected = true;
printf("Connection established with required local port\r\n");
// Implement protocol-specific communication
const char *protocolMsg = "LEGACY_PROTOCOL_HANDSHAKE\r\n";
write(fd, protocolMsg, strlen(protocolMsg));
break;
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection failed during establishment\r\n");
break;
}
OSTimeDly(TICKS_PER_SECOND / 10);
}
if (!connected)
{
printf("Connection timeout\r\n");
}
close(fd);
// Important: After close(), port enters TIME_WAIT state
// It cannot be reused immediately (typically 240 seconds)
printf("Port %d now in TIME_WAIT - cannot reuse immediately\r\n",
requiredLocalPort);
}
Advanced: Multiple Connections with Interface and Port Control
#include <tcp.h>
#include <netinterface.h>
#include <nbrtos.h>
struct ManagedConnection
{
int fd;
IPADDR serverIp;
uint16_t serverPort;
int interface;
bool established;
};
void AdvancedMultiConnectionTask(void *pd)
{
const int NUM_CONNECTIONS = 3;
ManagedConnection connections[NUM_CONNECTIONS];
// Initialize connection parameters
const char *servers[] = {
"192.168.1.100",
"192.168.1.101",
"192.168.1.102"
};
// Use different interfaces for load balancing
int interfaces[] = {0, 1, 0}; // Alternate between interfaces
// Initiate all connections
for (int i = 0; i < NUM_CONNECTIONS; i++)
{
connections[i].serverIp = AsciiToIp(servers[i]);
connections[i].serverPort = 8080;
connections[i].interface = interfaces[i];
connections[i].established = false;
// Verify interface is valid
if (interfaces[i] >= GetNumInterfaces())
{
printf("Interface %d not available for connection %d\r\n",
interfaces[i], i);
connections[i].fd = -1;
continue;
}
IPADDR localIp = GetIPAddress(interfaces[i]);
if (localIp == IPADDR_ANY)
{
printf("Interface %d has no IP for connection %d\r\n",
interfaces[i], i);
connections[i].fd = -1;
continue;
}
// Connect with automatic local port, specific interface
connections[i].fd = NoBlockConnectwlocal(
connections[i].serverIp,
0, // Automatic local port (recommended)
connections[i].serverPort,
connections[i].interface
);
if (connections[i].fd < 0)
{
printf("Failed to initiate connection %d: %d\r\n",
i, connections[i].fd);
}
else
{
printf("Connection %d initiated to %I:%d via interface %d\r\n",
i, connections[i].serverIp, connections[i].serverPort,
connections[i].interface);
}
}
// Wait for all connections to establish or fail
uint32_t startTime = Secs;
int establishedCount = 0;
while ((Secs - startTime) < 10 && establishedCount < NUM_CONNECTIONS)
{
for (int i = 0; i < NUM_CONNECTIONS; i++)
{
if (connections[i].fd < 0 || connections[i].established)
continue;
TcpState state = TcpGetSocketState(connections[i].fd);
if (state == TCP_STATE_ESTABLISHED)
{
connections[i].established = true;
establishedCount++;
printf("Connection %d established!\r\n", i);
// Send initial data
char msg[64];
snprintf(msg, sizeof(msg), "Connection %d via interface %d\r\n",
i, connections[i].interface);
write(connections[i].fd, msg, strlen(msg));
}
else if (state == TCP_STATE_CLOSED || state == TCP_STATE_CLOSING)
{
printf("Connection %d failed\r\n", i);
close(connections[i].fd);
connections[i].fd = -1;
establishedCount++;
}
}
OSTimeDly(TICKS_PER_SECOND / 20);
}
// Report final status
printf("\r\nFinal connection status:\r\n");
for (int i = 0; i < NUM_CONNECTIONS; i++)
{
printf(" Connection %d: %s\r\n", i,
connections[i].established ? "Established" : "Failed");
}
// Clean up all connections
for (int i = 0; i < NUM_CONNECTIONS; i++)
{
if (connections[i].fd > 0)
{
close(connections[i].fd);
}
}
}

◆ SetOutOfOrderBuffers()

uint8_t SetOutOfOrderBuffers ( int fd,
uint8_t max )
inline

#include <tcp.h>

Configure the maximum number of out-of-order buffers for a TCP socket.

Sets the maximum number of out-of-order TCP receive buffers for the socket. TCP may receive packets out of sequence, which must be stored until earlier packets arrive to maintain correct data ordering. Each buffer is approximately 1500 bytes.

The default value is 5 buffers. The maximum is 43 buffers. Increasing this value can improve bulk data throughput on fast networks but may increase TCP latency if connection problems (such as resets) occur.

Parameters
fdSocket file descriptor
maxMaximum number of out-of-order buffers (1-43, default: 5)
Returns
Status code: 0 on success, negative TCP Socket Status error code on failure

Notes:

  • This setting should be configured before significant data transfer begins, ideally right after the connection is established.
  • Higher values improve performance on high-bandwidth, high-latency networks where packet reordering is common, but consume more memory.
  • Lower values reduce memory usage but may cause TCP to request retransmissions more frequently when packets arrive out of order.
Warning
Setting this value too high may waste system resources. Setting it too low may reduce throughput on networks with significant packet reordering.
See also
setsockoption(), getsockoption(), clrsockoption(), SetSocketRxBuffers(), SetSocketTxBuffers()

Expand for Example Usage

Examples

Basic Configuration for High-Speed Transfer
#include <tcp.h>
#include <nbrtos.h>
void HighSpeedFileTransfer(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
// Connect to server
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected to %I:%d\r\n", serverIp, serverPort);
// Configure for high-speed transfer - increase out-of-order buffers
uint8_t result = SetOutOfOrderBuffers(fd, 20);
if (result != 0)
{
printf("Failed to set out-of-order buffers: %d\r\n", result);
}
else
{
printf("Out-of-order buffers set to 20 (30KB buffer space)\r\n");
}
// Receive large file
char buffer[4096];
uint32_t totalBytes = 0;
uint32_t startTime = Secs;
while (1)
{
int bytesRead = read(fd, buffer, sizeof(buffer), TICKS_PER_SECOND * 30);
if (bytesRead <= 0)
{
break;
}
totalBytes += bytesRead;
}
uint32_t duration = Secs - startTime;
if (duration > 0)
{
uint32_t throughputKBps = (totalBytes / 1024) / duration;
printf("Transfer complete: %lu bytes in %lu sec (%lu KB/s)\r\n",
totalBytes, duration, throughputKBps);
}
close(fd);
}
uint8_t SetOutOfOrderBuffers(int fd, uint8_t max)
Configure the maximum number of out-of-order buffers for a TCP socket.
Definition tcp.h:11303
Adaptive Buffer Configuration Based on Network Conditions
#include <tcp.h>
#include <nbrtos.h>
void ConfigureBuffersForNetwork(int fd, const char *networkType)
{
uint8_t bufferCount;
if (strcmp(networkType, "local") == 0)
{
// Local network - low latency, minimal reordering
bufferCount = 5; // Default
printf("Local network: using %d out-of-order buffers\r\n", bufferCount);
}
else if (strcmp(networkType, "wan") == 0)
{
// WAN - higher latency, more reordering
bufferCount = 15;
printf("WAN network: using %d out-of-order buffers\r\n", bufferCount);
}
else if (strcmp(networkType, "wireless") == 0)
{
// Wireless - potentially high packet reordering
bufferCount = 25;
printf("Wireless network: using %d out-of-order buffers\r\n", bufferCount);
}
else if (strcmp(networkType, "satellite") == 0)
{
// Satellite - very high latency, significant reordering
bufferCount = 43; // Maximum
printf("Satellite network: using %d out-of-order buffers (max)\r\n",
bufferCount);
}
else
{
bufferCount = 10; // Conservative default
printf("Unknown network type: using %d out-of-order buffers\r\n",
bufferCount);
}
uint8_t result = SetOutOfOrderBuffers(fd, bufferCount);
if (result != 0)
{
printf("WARNING: Failed to set out-of-order buffers: %d\r\n", result);
}
}
void AdaptiveNetworkTransfer(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Configure based on detected network type
ConfigureBuffersForNetwork(fd, "wireless");
// Proceed with data transfer
const char *message = "Data transfer request\r\n";
write(fd, message, strlen(message));
close(fd);
}
Memory-Constrained Configuration
#include <tcp.h>
#include <nbrtos.h>
void LowMemoryConnection(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Reduce buffers to minimum for memory-constrained environment
uint8_t result = SetOutOfOrderBuffers(fd, 2);
if (result == 0)
{
printf("Out-of-order buffers reduced to 2 (~3KB)\r\n");
printf("Memory saved, but throughput may be reduced\r\n");
}
else
{
printf("Failed to set buffers: %d\r\n", result);
}
// Use connection with reduced buffers
char buffer[256];
int bytesRead = read(fd, buffer, sizeof(buffer) - 1, TICKS_PER_SECOND * 10);
if (bytesRead > 0)
{
buffer[bytesRead] = '\0';
printf("Received: %s\r\n", buffer);
}
close(fd);
}
Performance Testing with Different Buffer Sizes
#include <tcp.h>
#include <nbrtos.h>
struct PerformanceResult
{
uint8_t bufferCount;
uint32_t bytesReceived;
uint32_t durationSeconds;
uint32_t throughputKBps;
int retransmissions;
};
PerformanceResult TestBufferConfiguration(uint8_t bufferCount)
{
PerformanceResult result = {0};
result.bufferCount = bufferCount;
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed for buffer test %d: %d\r\n",
bufferCount, fd);
return result;
}
// Configure buffers
if (SetOutOfOrderBuffers(fd, bufferCount) != 0)
{
printf("Failed to set buffers to %d\r\n", bufferCount);
close(fd);
return result;
}
printf("Testing with %d out-of-order buffers...\r\n", bufferCount);
// Request data transfer
const char *request = "SEND_TEST_DATA\r\n";
write(fd, request, strlen(request));
// Receive data
char buffer[4096];
uint32_t startTime = Secs;
int initialRtx = GetTcpRtxCount(fd);
while ((Secs - startTime) < 30) // 30 second test
{
int bytesRead = read(fd, buffer, sizeof(buffer), TICKS_PER_SECOND * 5);
if (bytesRead <= 0)
{
break;
}
result.bytesReceived += bytesRead;
}
result.durationSeconds = Secs - startTime;
result.retransmissions = GetTcpRtxCount(fd) - initialRtx;
if (result.durationSeconds > 0)
{
result.throughputKBps = (result.bytesReceived / 1024) / result.durationSeconds;
}
close(fd);
return result;
}
void OptimalBufferFinderTask(void *pd)
{
printf("=== Out-of-Order Buffer Performance Test ===\r\n\r\n");
uint8_t testSizes[] = {2, 5, 10, 20, 30, 43};
PerformanceResult results[6];
for (int i = 0; i < 6; i++)
{
results[i] = TestBufferConfiguration(testSizes[i]);
printf("Buffer size %d results:\r\n", results[i].bufferCount);
printf(" Bytes: %lu\r\n", results[i].bytesReceived);
printf(" Duration: %lu sec\r\n", results[i].durationSeconds);
printf(" Throughput: %lu KB/s\r\n", results[i].throughputKBps);
printf(" Retransmits: %d\r\n\r\n", results[i].retransmissions);
// Wait between tests
OSTimeDly(TICKS_PER_SECOND * 5);
}
// Find optimal configuration
uint32_t bestThroughput = 0;
int bestIndex = 0;
for (int i = 0; i < 6; i++)
{
if (results[i].throughputKBps > bestThroughput)
{
bestThroughput = results[i].throughputKBps;
bestIndex = i;
}
}
printf("=== Optimal Configuration ===\r\n");
printf("Buffer count: %d\r\n", results[bestIndex].bufferCount);
printf("Throughput: %lu KB/s\r\n", results[bestIndex].throughputKBps);
printf("Retransmits: %d\r\n", results[bestIndex].retransmissions);
}
Server Configuration for Different Client Types
#include <tcp.h>
#include <nbrtos.h>
void ConfigureClientSocket(int clientFd, const IPADDR &clientAddr)
{
// Determine client type based on IP range or other criteria
uint8_t bufferCount = 5; // Default
// Example: Different config for different subnets
if ((clientAddr.ip4_addr & 0xFF) == 10) // 10.x.x.x subnet
{
// Local network client
bufferCount = 5;
printf("Local client %I: using default buffers (%d)\r\n",
clientAddr, bufferCount);
}
else if ((clientAddr.ip4_addr & 0xFF) == 192) // 192.x.x.x
{
// Remote client via VPN or similar
bufferCount = 20;
printf("Remote client %I: increased buffers (%d)\r\n",
clientAddr, bufferCount);
}
else
{
// Internet client - maximize buffers
bufferCount = 43;
printf("Internet client %I: maximum buffers (%d)\r\n",
clientAddr, bufferCount);
}
uint8_t result = SetOutOfOrderBuffers(clientFd, bufferCount);
if (result != 0)
{
printf("WARNING: Failed to configure buffers for %I: %d\r\n",
clientAddr, result);
}
}
void SmartServerTask(void *pd)
{
const uint16_t SERVER_PORT = 8080;
int listenFd = listen(INADDR_ANY, SERVER_PORT, 5);
if (listenFd < 0)
{
printf("Failed to create listening socket: %d\r\n", listenFd);
return;
}
printf("Smart server listening on port %d\r\n", SERVER_PORT);
while (1)
{
IPADDR clientAddr;
uint16_t clientPort;
int clientFd = accept(listenFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
printf("Client connected: %I:%d\r\n", clientAddr, clientPort);
// Configure socket based on client characteristics
ConfigureClientSocket(clientFd, clientAddr);
// Handle client...
const char *welcome = "Connection configured\r\n";
write(clientFd, welcome, strlen(welcome));
close(clientFd);
}
}
close(listenFd);
}

◆ SetSocketRxBuffers()

int SetSocketRxBuffers ( int fd,
int n )

#include <tcp.h>

Configure the number of TCP receive buffers.

Sets the maximum number of receive buffers allocated to the socket. Each buffer is approximately 1548 bytes. The available space in these buffers determines the TCP window size advertised to the remote host, which controls how much data they can send.

As data is read from the socket, buffer space is freed, allowing the remote host to send more data. Since the maximum TCP window size is 65536 bytes, increasing this value beyond 43 buffers (approximately 66KB) provides no additional benefit.

The system default is 5 buffers (defined in constants.h) to conserve network buffer resources. This default is sufficient for most applications unless transferring large amounts of bulk data.

Parameters
fdSocket file descriptor
nNumber of receive buffers to allocate
Returns
Status code: TCP Socket Status
See also
setsockoption(), getsockoption(), clrsockoption(), SetSocketUnackBuffers(), SetSocketTxBuffers()

Expand for Example Usage

Examples

Basic Usage - Setting Receive Buffers
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Allocate 10 receive buffers (~15KB window)
int result = SetSocketRxBuffers(fd, 10);
if (result == TCP_ERR_NONE) {
printf("Receive buffers configured successfully\n");
}
}
int SetSocketRxBuffers(int fd, int n)
Configure the number of TCP receive buffers.
Maximum Window Size Configuration
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Set to maximum useful value (43 buffers equals approx. 66KB)
// Beyond this provides no benefit due to 64KB TCP window limit
bind(fd, ...);
listen(fd, 5);
}
Server Socket with Custom Receive Buffer
int listenFd = socket(AF_INET, SOCK_STREAM, 0);
SetSocketRxBuffers(listenFd, 20); // Configure before accepting connections
bind(listenFd, (struct sockaddr*)&addr, sizeof(addr));
listen(listenFd, 5);
int clientFd = accept(listenFd, NULL, NULL);
// clientFd inherits the buffer settings from listenFd
Memory-Constrained Application
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Use minimal buffers to conserve memory
SetSocketRxBuffers(fd, 3); // ~4.6KB receive window
}

◆ SetSocketTxBuffers()

int SetSocketTxBuffers ( int fd,
int n )

#include <tcp.h>

Configure the number of TCP transmit buffers.

Sets the maximum number of buffers allocated to the transmit queue. Each buffer is approximately 1548 bytes. The transmit queue accumulates outgoing data up to this limit regardless of the current state of unacknowledged buffers or the remote host's window size. This value effectively sets the maximum size for a single write() operation.

Note
Always check the return value of write functions to determine how many bytes were actually written to the transmit queue.
Parameters
fdSocket file descriptor
nNumber of transmit buffers to allocate
Returns
Status code: TCP Socket Status
See also
setsockoption(), getsockoption(), clrsockoption(), SetSocketRxBuffers(), SetSocketUnackBuffers(), write(), writeall()

Expand for Example Usage

Examples

Basic Usage - Setting Transmit Buffers
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Allocate 15 transmit buffers (~23KB queue)
int result = SetSocketTxBuffers(fd, 15);
if (result == TCP_ERR_NONE) {
printf("Transmit buffers configured successfully\n");
}
}
int SetSocketTxBuffers(int fd, int n)
Configure the number of TCP transmit buffers.
Large Data Transfer Setup
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Configure for sending large chunks of data
SetSocketTxBuffers(fd, 30); // ~46KB transmit queue
connect(fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
// Now we can write larger amounts in a single call
char largeBuffer[40000];
int bytesWritten = write(fd, largeBuffer, sizeof(largeBuffer));
printf("Wrote %d bytes\n", bytesWritten);
}
Checking Write Return Values
int fd = socket(AF_INET, SOCK_STREAM, 0);
SetSocketTxBuffers(fd, 10); // ~15KB transmit queue
connect(fd, ...);
char data[20000];
int bytesWritten = write(fd, data, sizeof(data));
if (bytesWritten < sizeof(data)) {
printf("Warning: Only wrote %d of %d bytes\n",
bytesWritten, sizeof(data));
// Transmit queue is full, need to wait or use writeall()
}
Complete Socket Configuration
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Configure all buffer settings for optimal performance
SetSocketTxBuffers(fd, 20); // Transmit queue: ~31KB
SetSocketRxBuffers(fd, 15); // Receive window: ~23KB
SetSocketUnackBuffers(fd, 10); // Unacknowledged: 10 buffers
// Socket is now ready for high-performance communication
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
}
int SetSocketUnackBuffers(int fd, uint8_t val)
Configure the maximum number of unacknowledged transmit buffers.
Definition tcp.h:12335

◆ SetSocketUnackBuffers()

int SetSocketUnackBuffers ( int fd,
uint8_t val )
inline

#include <tcp.h>

Configure the maximum number of unacknowledged transmit buffers.

Sets the maximum number of TCP transmit buffers that can remain unacknowledged by the remote host. When data is sent, it moves from the transmit queue to the unacknowledged list. Buffers remain in this list until the remote host sends an acknowledgment (ACK), at which point they are freed. The actual number of unacknowledged buffers is also limited by the remote host's TCP window size.

Increasing this value can improve bulk data throughput on fast networks. However, on lossy networks without selective acknowledgment (SACK), higher values may reduce performance. Note: Most modern PCs support SACK, but many NAT routers do not.

Parameters
fdSocket file descriptor
valMaximum number of unacknowledged buffers
Returns
Status code: TCP Socket Status
See also
setsockoption(), getsockoption(), clrsockoption(), SetSocketRxBuffers(), SetSocketTxBuffers()

Expand for Example Usage

Examples

Basic Usage - Setting Unacknowledged Buffers
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Set to 10 unacknowledged buffers for better throughput
int result = SetSocketUnackBuffers(fd, 10);
if (result == TCP_ERR_NONE) {
printf("Successfully configured unack buffers\n");
}
}
Optimizing for High-Speed Bulk Transfer
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Configure socket for high-throughput data transfer
SetSocketTxBuffers(fd, 20); // Large transmit queue
SetSocketUnackBuffers(fd, 15); // Allow more unacknowledged data
// Now ready for bulk transfer
connect(fd, ...);
write(fd, largeDataBuffer, largeDataSize);
}
Conservative Setting for Lossy Networks
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd > 0) {
// Lower value for networks with packet loss
SetSocketUnackBuffers(fd, 3); // Conservative for lossy/NAT environments
}

◆ setsockoption()

int setsockoption ( int fd,
int option )

#include <tcp.h>

Enable TCP socket options.

Sets one or more option flags for the specified socket. Socket options control various aspects of TCP behavior such as the Nagle algorithm and PUSH flag handling. Multiple options can be combined using bitwise OR.

Parameters
fdSocket file descriptor
optionSocket option flags to enable: TCP Socket Options
Returns
Bitmask of all currently enabled options for the socket, or negative value on error

Notes:

  • Common options include:
    • SO_NODELAY: Disable Nagle algorithm for low-latency transmission
    • SO_PUSH: Set TCP PUSH flag on transmitted data
    • SO_KEEPALIVE: Enable TCP keepalive probes
  • Multiple options can be set simultaneously using bitwise OR: setsockoption(fd, SO_NODELAY | SO_PUSH);
  • This function does not clear existing options - it only adds new ones. Use clrsockoption() to disable options.
See also
clrsockoption(), getsockoption(), SetSocketUnackBuffers(), SetSocketRxBuffers(), SetSocketTxBuffers()

Expand for Example Usage

Examples

Disable Nagle Algorithm for Low Latency
#include <tcp.h>
#include <nbrtos.h>
void LowLatencyClient(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Disable Nagle algorithm for immediate transmission
int result = setsockoption(fd, SO_NODELAY);
if (result >= 0)
{
printf("SO_NODELAY enabled - options mask: 0x%X\r\n", result);
}
else
{
printf("Failed to set SO_NODELAY: %d\r\n", result);
}
// Send small messages that will be transmitted immediately
const char *msg1 = "A";
const char *msg2 = "B";
const char *msg3 = "C";
write(fd, msg1, 1); // Sent immediately (no Nagle delay)
write(fd, msg2, 1); // Sent immediately
write(fd, msg3, 1); // Sent immediately
printf("Small messages sent without Nagle delay\r\n");
close(fd);
}
Enable Multiple Options
#include <tcp.h>
#include <nbrtos.h>
void ConfigureOptimalSocket(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Enable multiple options for optimal real-time performance
int options = SO_NODELAY | SO_PUSH;
int result = setsockoption(fd, options);
if (result >= 0)
{
printf("Socket configured for low-latency:\r\n");
printf(" SO_NODELAY: %s\r\n", (result & SO_NODELAY) ? "ON" : "OFF");
printf(" SO_PUSH: %s\r\n", (result & SO_PUSH) ? "ON" : "OFF");
}
else
{
printf("Failed to configure socket: %d\r\n", result);
}
// Send time-critical data
const char *message = "Real-time control command\r\n";
write(fd, message, strlen(message));
close(fd);
}
Interactive Terminal Application
#include <tcp.h>
#include <nbrtos.h>
void InteractiveTerminal(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 23; // Telnet port
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected to telnet server\r\n");
// Configure for interactive use - disable Nagle for keystroke echo
int result = setsockoption(fd, SO_NODELAY);
if (result < 0)
{
printf("Warning: Failed to set SO_NODELAY\r\n");
}
else
{
printf("SO_NODELAY enabled - keystrokes will be sent immediately\r\n");
}
// Simulate sending individual keystrokes
const char *keystrokes = "ls -la\r\n";
for (int i = 0; keystrokes[i] != '\0'; i++)
{
// Each keystroke sent immediately (no buffering delay)
write(fd, &keystrokes[i], 1);
OSTimeDly(TICKS_PER_SECOND / 10); // Simulate typing speed
}
// Read response
char buffer[1024];
int bytesRead = read(fd, buffer, sizeof(buffer) - 1, TICKS_PER_SECOND * 5);
if (bytesRead > 0)
{
buffer[bytesRead] = '\0';
printf("Server response:\r\n%s\r\n", buffer);
}
close(fd);
}
Compare Performance With and Without Nagle
#include <tcp.h>
#include <nbrtos.h>
void TestNagleImpact(bool disableNagle)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
if (disableNagle)
{
setsockoption(fd, SO_NODELAY);
printf("Testing with SO_NODELAY (Nagle disabled)\r\n");
}
else
{
printf("Testing with Nagle algorithm enabled (default)\r\n");
}
// Send 100 small messages
uint32_t startTime = TimeTick;
for (int i = 0; i < 100; i++)
{
char msg[16];
snprintf(msg, sizeof(msg), "MSG%d\r\n", i);
write(fd, msg, strlen(msg));
}
uint32_t elapsedTicks = TimeTick - startTime;
uint32_t elapsedMs = (elapsedTicks * 1000) / TICKS_PER_SECOND;
printf("100 messages sent in %lu ms\r\n", elapsedMs);
int rtxCount = GetTcpRtxCount(fd);
printf("Retransmissions: %d\r\n", rtxCount);
close(fd);
}
void NagleComparisonTask(void *pd)
{
printf("=== Nagle Algorithm Performance Comparison ===\r\n\r\n");
printf("Test 1: With Nagle (default)\r\n");
TestNagleImpact(false);
OSTimeDly(TICKS_PER_SECOND * 2);
printf("\r\nTest 2: Without Nagle (SO_NODELAY)\r\n");
TestNagleImpact(true);
printf("\r\nConclusion:\r\n");
printf(" - Nagle enabled: Better bandwidth efficiency, higher latency\r\n");
printf(" - Nagle disabled: Lower latency, more packets sent\r\n");
}
Server-Side Socket Configuration
#include <tcp.h>
#include <nbrtos.h>
void ConfiguredServerTask(void *pd)
{
const uint16_t SERVER_PORT = 8080;
int listenFd = listen(INADDR_ANY, SERVER_PORT, 5);
if (listenFd < 0)
{
printf("Failed to create listening socket: %d\r\n", listenFd);
return;
}
printf("Server listening on port %d\r\n", SERVER_PORT);
while (1)
{
IPADDR clientAddr;
uint16_t clientPort;
int clientFd = accept(listenFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
printf("Client connected: %I:%d\r\n", clientAddr, clientPort);
// Configure client socket for optimal performance
int options = SO_NODELAY | SO_PUSH;
int result = setsockoption(clientFd, options);
if (result >= 0)
{
printf("Client socket configured: 0x%X\r\n", result);
}
// Handle client with optimized socket
char buffer[256];
int bytesRead = read(clientFd, buffer, sizeof(buffer) - 1,
if (bytesRead > 0)
{
buffer[bytesRead] = '\0';
// Echo response will be sent immediately due to SO_NODELAY
write(clientFd, buffer, bytesRead);
}
close(clientFd);
}
}
close(listenFd);
}

◆ SocketPeek()

char SocketPeek ( int fd)

#include <tcp.h>

Peek at the next available byte without removing it from the receive buffer.

Examines the next byte that would be read from the socket without actually removing it from the receive buffer. The byte remains available for subsequent read operations. If no data is available, returns 0.

Parameters
fdSocket file descriptor
Returns
The next byte that would be read, or 0 if no data is available
See also
read(), dataavail()

Expand for Example Usage

Examples

Basic Usage - Peeking at Next Byte
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
char nextByte = SocketPeek(fd);
if (nextByte != 0) {
printf("Next byte is: 0x%02X ('%c')\n", nextByte,
isprint(nextByte) ? nextByte : '.');
// Byte is still in buffer, can read it normally
char actualByte;
read(fd, &actualByte, 1);
// actualByte == nextByte
}
char SocketPeek(int fd)
Peek at the next available byte without removing it from the receive buffer.
Protocol Detection - Checking Message Type
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// Peek at message type without consuming it
char msgType = SocketPeek(fd);
if (msgType == 0x01) {
HandleDataMessage(fd);
} else if (msgType == 0x02) {
HandleControlMessage(fd);
} else if (msgType == 0x03) {
HandleErrorMessage(fd);
} else if (msgType == 0) {
printf("No data available\n");
} else {
printf("Unknown message type: 0x%02X\n", msgType);
}
Waiting for Specific Start Byte
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
const char START_MARKER = 0xAA;
// Wait for start marker
while (1) {
char nextByte = SocketPeek(fd);
if (nextByte == START_MARKER) {
// Found start marker, now read the full message
char buffer[256];
int n = read(fd, buffer, sizeof(buffer));
ProcessMessage(buffer, n);
break;
} else if (nextByte != 0) {
// Discard unexpected byte
char discard;
read(fd, &discard, 1);
printf("Discarded unexpected byte: 0x%02X\n", discard);
} else {
// No data yet, wait
OSTimeDly(TICKS_PER_SECOND / 10);
}
}
Non-Destructive Buffer Inspection
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// Check if data looks like ASCII text or binary
char firstByte = SocketPeek(fd);
if (firstByte == 0) {
printf("No data available\n");
} else if (isprint(firstByte) || firstByte == '\n' || firstByte == '\r') {
printf("Data appears to be ASCII text\n");
// Process as text
char textBuffer[512];
int n = read(fd, textBuffer, sizeof(textBuffer) - 1);
textBuffer[n] = '\0';
printf("Text: %s\n", textBuffer);
} else {
printf("Data appears to be binary (first byte: 0x%02X)\n", firstByte);
// Process as binary
uint8_t binaryBuffer[512];
int n = read(fd, binaryBuffer, sizeof(binaryBuffer));
ProcessBinaryData(binaryBuffer, n);
}
Checking Data Availability Before Blocking Read
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// Use peek to check if data is available before potentially blocking
if (SocketPeek(fd) != 0) {
char buffer[256];
int n = read(fd, buffer, sizeof(buffer));
printf("Read %d bytes\n", n);
} else {
printf("No data available, skipping read\n");
}

◆ SockReadWithTimeout()

int SockReadWithTimeout ( int fd,
char * buf,
int nbytes,
uint32_t timeout )

#include <tcp.h>

Read from a TCP socket with a timeout.

Attempts to read data from a TCP socket, waiting up to the specified timeout period. The function returns when at least 1 byte of data becomes available or the timeout expires. The nbytes parameter specifies the maximum number of bytes to read, but the actual number read may be less. Always check the return value to determine how many bytes were actually read.

Note
This function works with standard TCP sockets only; it does not work with TLS sockets.
Parameters
fdSocket file descriptor
bufBuffer to store received data
nbytesMaximum number of bytes to read
timeoutTimeout duration in system ticks. Recommended usage: TICKS_PER_SECOND * n where n is the number of seconds. For example: TICKS_PER_SECOND * 5 for a 5 second timeout
Returns
Number of bytes read on success, negative TCP Socket Status error code on failure
See also
ReadWithTimeout()

Expand for Example Usage

Examples

Basic Usage - Read with 5 Second Timeout
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
char buffer[256];
int bytesRead = SockReadWithTimeout(fd, buffer, sizeof(buffer), TICKS_PER_SECOND * 5);
if (bytesRead > 0) {
printf("Received %d bytes: %.*s\n", bytesRead, bytesRead, buffer);
} else if (bytesRead == TCP_ERR_TIMEOUT) {
printf("Read timeout after 5 seconds\n");
} else {
printf("Read error: %d\n", bytesRead);
}
int SockReadWithTimeout(int fd, char *buf, int nbytes, uint32_t timeout)
Read from a TCP socket with a timeout.
Request-Response Pattern with Timeout
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// Send request
const char *request = "GET /data HTTP/1.1\r\n\r\n";
write(fd, request, strlen(request));
// Wait up to 10 seconds for response
char response[1024];
int n = SockReadWithTimeout(fd, response, sizeof(response), TICKS_PER_SECOND * 10);
if (n > 0) {
response[n] = '\0';
printf("Server response: %s\n", response);
} else if (n == TCP_ERR_TIMEOUT) {
printf("Server did not respond within 10 seconds\n");
}
Multiple Read Attempts with Variable Timeout
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
char buffer[512];
int totalBytes = 0;
int attempts = 0;
const int maxAttempts = 3;
while (attempts < maxAttempts) {
int n = SockReadWithTimeout(fd, buffer + totalBytes,
sizeof(buffer) - totalBytes,
if (n > 0) {
totalBytes += n;
printf("Attempt %d: read %d bytes (total: %d)\n",
attempts + 1, n, totalBytes);
break; // Success
} else if (n == TCP_ERR_TIMEOUT) {
attempts++;
printf("Timeout on attempt %d\n", attempts);
} else {
printf("Read error: %d\n", n);
break;
}
}
if (attempts >= maxAttempts) {
printf("Failed after %d attempts\n", maxAttempts);
}
Polling Loop with Short Timeout
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
bool running = true;
char data[128];
while (running) {
// Short timeout allows checking other conditions frequently
int n = SockReadWithTimeout(fd, data, sizeof(data), TICKS_PER_SECOND / 2);
if (n > 0) {
ProcessData(data, n);
} else if (n == TCP_ERR_TIMEOUT) {
// No data yet, check other conditions
if (ShouldShutdown()) {
running = false;
}
} else {
printf("Socket error, exiting\n");
running = false;
}
}

◆ TcpAllDataAcked()

BOOL TcpAllDataAcked ( int socket)

#include <tcp.h>

Check if all transmitted data has been acknowledged.

Determines whether all data sent on this socket has been acknowledged by the remote host. This is useful for ensuring data has been successfully delivered before closing a connection or performing other operations.

Parameters
socketSocket file descriptor
Return values
TRUEAll sent data has been acknowledged by the remote host
FALSESome data remains unacknowledged
See also
WaitForSocketFlush()

◆ TcpGetLastRxInterval()

uint32_t TcpGetLastRxInterval ( int fd)

#include <tcp.h>

Get the time elapsed since the last received packet.

Calculates the number of system ticks that have elapsed between the current time and when the last packet was received on this socket. This is a convenience function that computes the difference between the current system time (TimeTick) and the socket's lastRxTime value.

Parameters
fdSocket file descriptor
Returns
Number of system ticks since the last packet was received, or 0 if socket is invalid

Notes:

  • This function handles one rollover of the system tick counter (approximately 6 years of uptime at typical tick rates) but not multiple rollovers. Given typical usage patterns and connection lifetimes, this limitation should not present problems in practice.
  • The returned value is in system ticks. Use TICKS_PER_SECOND to convert to seconds: uint32_t seconds = TcpGetLastRxInterval(fd) / TICKS_PER_SECOND;
  • This function is useful for detecting idle connections or implementing timeout logic without needing to manually track timestamps.
See also
TcpGetLastRxTime(), TimeTick, TICKS_PER_SECOND

Expand for Example Usage

Examples

Basic Idle Time Detection
#include <tcp.h>
#include <nbrtos.h>
#define IDLE_TIMEOUT_SEC 60
void CheckIdleConnection(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - monitoring idle time\r\n");
while (1)
{
// Check idle time every 5 seconds
OSTimeDly(TICKS_PER_SECOND * 5);
uint32_t idleTicks = TcpGetLastRxInterval(fd);
uint32_t idleSeconds = idleTicks / TICKS_PER_SECOND;
printf("Connection idle for %lu seconds\r\n", idleSeconds);
if (idleSeconds > IDLE_TIMEOUT_SEC)
{
printf("Idle timeout - closing connection\r\n");
break;
}
// Check connection state
TcpState state = TcpGetSocketState(fd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Connection closed (state: %d)\r\n", state);
break;
}
}
close(fd);
}
Server with Client Idle Monitoring
#include <tcp.h>
#include <nbrtos.h>
#define MAX_IDLE_TIME_SEC 120
void HandleClientWithTimeout(int clientFd, const IPADDR &clientAddr)
{
printf("Client %I connected\r\n", clientAddr);
while (1)
{
// Check for incoming data with timeout
char buffer[256];
int bytesRead = read(clientFd, buffer, sizeof(buffer) - 1,
if (bytesRead > 0)
{
buffer[bytesRead] = '\0';
printf("Client %I: %s\r\n", clientAddr, buffer);
// Echo back
write(clientFd, buffer, bytesRead);
}
// Check idle time
uint32_t idleTicks = TcpGetLastRxInterval(clientFd);
uint32_t idleSeconds = idleTicks / TICKS_PER_SECOND;
if (idleSeconds > MAX_IDLE_TIME_SEC)
{
printf("Client %I idle timeout (%lu seconds)\r\n",
clientAddr, idleSeconds);
const char *msg = "Idle timeout - disconnecting\r\n";
write(clientFd, msg, strlen(msg));
break;
}
// Check connection state
TcpState state = TcpGetSocketState(clientFd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Client %I disconnected (state: %d)\r\n",
clientAddr, state);
break;
}
}
close(clientFd);
printf("Client %I connection closed\r\n", clientAddr);
}
void IdleMonitorServerTask(void *pd)
{
const uint16_t SERVER_PORT = 8080;
int listenFd = listen(INADDR_ANY, SERVER_PORT, 5);
if (listenFd < 0)
{
printf("Failed to create listening socket: %d\r\n", listenFd);
return;
}
printf("Idle monitor server listening on port %d\r\n", SERVER_PORT);
printf("Client idle timeout: %d seconds\r\n", MAX_IDLE_TIME_SEC);
while (1)
{
IPADDR clientAddr;
uint16_t clientPort;
int clientFd = accept(listenFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
HandleClientWithTimeout(clientFd, clientAddr);
}
}
close(listenFd);
}
Progressive Idle Warnings
#include <tcp.h>
#include <nbrtos.h>
void ConnectionWithWarnings(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - idle warning system active\r\n");
bool warning30 = false;
bool warning60 = false;
bool warning90 = false;
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 10);
uint32_t idleSeconds = TcpGetLastRxInterval(fd) / TICKS_PER_SECOND;
if (idleSeconds >= 90 && !warning90)
{
printf("WARNING: Connection idle for 90+ seconds!\r\n");
warning90 = true;
// Final warning - send keepalive
}
else if (idleSeconds >= 60 && !warning60)
{
printf("WARNING: Connection idle for 60+ seconds\r\n");
warning60 = true;
}
else if (idleSeconds >= 30 && !warning30)
{
printf("INFO: Connection idle for 30+ seconds\r\n");
warning30 = true;
}
else if (idleSeconds < 30)
{
// Reset warnings if activity resumes
if (warning30 || warning60 || warning90)
{
printf("Activity resumed - warnings cleared\r\n");
warning30 = warning60 = warning90 = false;
}
}
if (idleSeconds >= 120)
{
printf("TIMEOUT: Connection idle for 120+ seconds - disconnecting\r\n");
break;
}
// Check connection validity
TcpState state = TcpGetSocketState(fd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Connection closed (state: %d)\r\n", state);
break;
}
}
close(fd);
}
void TcpSendKeepAlive(int fd)
Send a TCP keepalive probe packet.
Adaptive Timeout Based on Activity
#include <tcp.h>
#include <nbrtos.h>
void AdaptiveTimeoutConnection(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
uint32_t baseTimeoutSec = 60;
uint32_t currentTimeoutSec = baseTimeoutSec;
uint32_t maxTimeoutSec = 300; // 5 minutes max
printf("Connected - adaptive timeout starting at %lu seconds\r\n",
currentTimeoutSec);
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 10);
uint32_t idleSeconds = TcpGetLastRxInterval(fd) / TICKS_PER_SECOND;
if (idleSeconds > currentTimeoutSec)
{
printf("Idle timeout (%lu > %lu seconds) - checking connection\r\n",
idleSeconds, currentTimeoutSec);
uint32_t rxBefore = TcpGetLastRxTime(fd);
OSTimeDly(TICKS_PER_SECOND * 3);
uint32_t rxAfter = TcpGetLastRxTime(fd);
if (rxAfter != rxBefore)
{
// Connection alive but idle - increase timeout
currentTimeoutSec = currentTimeoutSec * 2;
if (currentTimeoutSec > maxTimeoutSec)
{
currentTimeoutSec = maxTimeoutSec;
}
printf("Connection alive - timeout increased to %lu seconds\r\n",
currentTimeoutSec);
}
else
{
printf("Connection dead - no response\r\n");
break;
}
}
else if (idleSeconds < (baseTimeoutSec / 2))
{
// Recent activity - reset timeout
if (currentTimeoutSec != baseTimeoutSec)
{
currentTimeoutSec = baseTimeoutSec;
printf("Activity detected - timeout reset to %lu seconds\r\n",
currentTimeoutSec);
}
}
// Check connection state
TcpState state = TcpGetSocketState(fd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Connection closed (state: %d)\r\n", state);
break;
}
}
close(fd);
}
uint32_t TcpGetLastRxTime(int fd)
Get the system tick count when the last packet was received.

◆ TcpGetLastRxTime()

uint32_t TcpGetLastRxTime ( int fd)

#include <tcp.h>

Get the system tick count when the last packet was received.

Returns the timestamp (in system ticks) of the last received packet on this connection. Each TCP socket maintains a lastRxTime value that is updated whenever a packet arrives. This function is primarily used with TcpSendKeepAlive() to implement TCP keepalive functionality and detect stale connections.

To detect a lost connection:

  1. Record lastRxTime before sending a keepalive packet
  2. Send the keepalive packet with TcpSendKeepAlive()
  3. Wait sufficient time for a response
  4. Check if lastRxTime has changed
  5. If unchanged, the remote host has not responded and the connection may be lost
Parameters
fdSocket file descriptor
Returns
System tick count when the last packet was received, or 0 if socket is invalid

Notes:

  • The returned value is in system ticks. Use TICKS_PER_SECOND to convert to seconds.
  • This timestamp is updated on any received packet, including ACKs, data packets, and keepalive responses.
Warning
Do not call this function more frequently than once per second to avoid unnecessary overhead.
See also
TcpSendKeepAlive(), TcpGetLastRxInterval(), TimeTick, TICKS_PER_SECOND

Expand for Example Usage

Examples

Basic Keepalive Detection
#include <tcp.h>
#include <nbrtos.h>
bool IsConnectionAlive(int fd, uint32_t timeoutSeconds)
{
// Get last RX time before sending keepalive
uint32_t lastRxTimeBefore = TcpGetLastRxTime(fd);
// Send keepalive packet
printf("Keepalive sent, waiting for response...\r\n");
// Wait for response (convert timeout to ticks)
OSTimeDly(timeoutSeconds * TICKS_PER_SECOND);
// Check if we received a response
uint32_t lastRxTimeAfter = TcpGetLastRxTime(fd);
if (lastRxTimeAfter != lastRxTimeBefore)
{
printf("Connection alive - received response\r\n");
return true;
}
else
{
printf("Connection dead - no response to keepalive\r\n");
return false;
}
}
void ConnectionMonitorTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected to %I:%d\r\n", serverIp, serverPort);
// Monitor connection with keepalives every 30 seconds
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 30);
if (!IsConnectionAlive(fd, 5))
{
printf("Connection lost, reconnecting...\r\n");
close(fd);
fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Reconnection failed: %d\r\n", fd);
break;
}
printf("Reconnected successfully\r\n");
}
}
if (fd > 0) close(fd);
}
Display Last Packet Receive Time
#include <tcp.h>
#include <nbrtos.h>
void DisplayLastPacketInfo(int fd)
{
uint32_t lastRxTime = TcpGetLastRxTime(fd);
uint32_t currentTime = TimeTick;
// Calculate elapsed time in ticks
uint32_t elapsedTicks = currentTime - lastRxTime;
// Convert to seconds
uint32_t elapsedSeconds = elapsedTicks / TICKS_PER_SECOND;
printf("Last packet received:\r\n");
printf(" Timestamp: %lu ticks\r\n", lastRxTime);
printf(" Current time: %lu ticks\r\n", currentTime);
printf(" Time since RX: %lu seconds\r\n", elapsedSeconds);
}
void PacketTimingExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
// Initial display
DisplayLastPacketInfo(fd);
// Send some data
const char *message = "Test message\r\n";
write(fd, message, strlen(message));
// Read response
char buffer[256];
int bytesRead = read(fd, buffer, sizeof(buffer) - 1, TICKS_PER_SECOND * 5);
if (bytesRead > 0)
{
buffer[bytesRead] = '\0';
printf("Received: %s\r\n", buffer);
// Display timing after receiving data
DisplayLastPacketInfo(fd);
}
close(fd);
}
Advanced Keepalive with Retry Logic
#include <tcp.h>
#include <nbrtos.h>
#define MAX_KEEPALIVE_RETRIES 3
#define KEEPALIVE_INTERVAL_SEC 30
#define KEEPALIVE_TIMEOUT_SEC 5
typedef enum
{
CONN_ALIVE,
CONN_SUSPECT,
CONN_DEAD
} ConnectionState;
ConnectionState CheckConnectionHealth(int fd)
{
int failedProbes = 0;
for (int i = 0; i < MAX_KEEPALIVE_RETRIES; i++)
{
uint32_t lastRxBefore = TcpGetLastRxTime(fd);
printf("Keepalive probe %d/%d sent\r\n", i + 1, MAX_KEEPALIVE_RETRIES);
OSTimeDly(KEEPALIVE_TIMEOUT_SEC * TICKS_PER_SECOND);
uint32_t lastRxAfter = TcpGetLastRxTime(fd);
if (lastRxAfter != lastRxBefore)
{
printf("Response received on probe %d\r\n", i + 1);
return CONN_ALIVE;
}
else
{
failedProbes++;
printf("No response on probe %d\r\n", i + 1);
}
// Small delay between retries
if (i < MAX_KEEPALIVE_RETRIES - 1)
{
OSTimeDly(TICKS_PER_SECOND);
}
}
if (failedProbes >= MAX_KEEPALIVE_RETRIES)
{
return CONN_DEAD;
}
return CONN_SUSPECT;
}
void RobustConnectionTask(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - starting keepalive monitoring\r\n");
while (1)
{
// Wait before next check
OSTimeDly(KEEPALIVE_INTERVAL_SEC * TICKS_PER_SECOND);
ConnectionState state = CheckConnectionHealth(fd);
switch (state)
{
case CONN_ALIVE:
printf("Connection healthy\r\n");
break;
case CONN_SUSPECT:
printf("Connection suspect - some probes failed\r\n");
break;
case CONN_DEAD:
printf("Connection dead - all probes failed\r\n");
close(fd);
// Attempt reconnection
printf("Attempting reconnection...\r\n");
OSTimeDly(TICKS_PER_SECOND * 5);
fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Reconnection failed: %d\r\n", fd);
return;
}
printf("Reconnected successfully\r\n");
break;
}
}
if (fd > 0) close(fd);
}
Server-Side Connection Monitoring
#include <tcp.h>
#include <nbrtos.h>
#define CLIENT_TIMEOUT_SEC 60
void MonitorClientConnection(int clientFd, const IPADDR &clientAddr)
{
uint32_t lastCheckTime = Secs;
while (1)
{
// Check every 10 seconds
OSTimeDly(TICKS_PER_SECOND * 10);
// Get time since last packet
uint32_t lastRxTime = TcpGetLastRxTime(clientFd);
uint32_t currentTime = TimeTick;
uint32_t idleTimeSeconds = (currentTime - lastRxTime) / TICKS_PER_SECOND;
printf("Client %I idle for %lu seconds\r\n", clientAddr, idleTimeSeconds);
if (idleTimeSeconds > CLIENT_TIMEOUT_SEC)
{
printf("Client %I timeout - checking if alive\r\n", clientAddr);
uint32_t rxBefore = TcpGetLastRxTime(clientFd);
TcpSendKeepAlive(clientFd);
OSTimeDly(TICKS_PER_SECOND * 5);
uint32_t rxAfter = TcpGetLastRxTime(clientFd);
if (rxAfter == rxBefore)
{
printf("Client %I not responding - closing connection\r\n",
clientAddr);
close(clientFd);
return;
}
else
{
printf("Client %I responded to keepalive\r\n", clientAddr);
}
}
// Check if socket is still valid
TcpState state = TcpGetSocketState(clientFd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Client %I connection closed (state: %d)\r\n",
clientAddr, state);
close(clientFd);
return;
}
}
}
void TimeoutServerTask(void *pd)
{
const uint16_t SERVER_PORT = 8080;
int listenFd = listen(INADDR_ANY, SERVER_PORT, 5);
if (listenFd < 0)
{
printf("Failed to create listening socket: %d\r\n", listenFd);
return;
}
printf("Timeout server listening on port %d\r\n", SERVER_PORT);
printf("Client timeout: %d seconds\r\n", CLIENT_TIMEOUT_SEC);
while (1)
{
IPADDR clientAddr;
uint16_t clientPort;
int clientFd = accept(listenFd, &clientAddr, &clientPort, 0);
if (clientFd > 0)
{
printf("Client connected: %I:%d\r\n", clientAddr, clientPort);
// Monitor this client (in real app, spawn a task)
MonitorClientConnection(clientFd, clientAddr);
printf("Client %I monitoring ended\r\n", clientAddr);
}
}
close(listenFd);
}

◆ TcpGetRxBufferSpaceUsed()

uint16_t TcpGetRxBufferSpaceUsed ( int fd)

#include <tcp.h>

Get the number of bytes currently in the receive buffer.

Returns the amount of received data waiting to be read from the socket's receive buffer.

Parameters
fdSocket file descriptor
Returns
Number of bytes available to read
See also
TcpGetTxBufferAvailSpace(), TcpGetTxDataWaiting()

◆ TcpGetSocketInterface()

int TcpGetSocketInterface ( int fd)

#include <tcp.h>

Get the network interface number associated with a TCP socket.

Retrieves the network interface number being used by an established TCP connection.

Note
The return value is undefined for listening sockets.
Parameters
fdSocket file descriptor
Returns
Network interface number
See also
GetInterfaceBlock(), InterfaceBlock

Expand for Example Usage

Examples

Basic Usage - Getting Socket Interface
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
int ifNum = TcpGetSocketInterface(fd);
printf("Socket is using interface number: %d\n", ifNum);
close(fd);
Multi-Interface System - Identifying Active Interface
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(8080);
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.100");
if (connect(fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == 0) {
int ifNum = TcpGetSocketInterface(fd);
InterfaceBlock *pIfBlock = GetInterfaceBlock(ifNum);
if (pIfBlock != NULL) {
printf("Connected via interface %d\n", ifNum);
printf("Interface IP: %I\n", pIfBlock->ip4.cur_addr.i4);
printf("Interface name: %s\n", pIfBlock->GetInterfaceName());
}
}
close(fd);
virtual const char * GetInterfaceName()
Returns the interface name network interface.
I4Record ip4
IPv4 configuration for "this" interface, see config_netobj.h for details.
Definition netinterface.h:247
Routing Verification - Check Expected Interface
int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
int actualInterface = TcpGetSocketInterface(fd);
int expectedInterface = 0; // Expected to use eth0
if (actualInterface == expectedInterface) {
printf("Connection using correct interface\n");
} else {
printf("Warning: Using interface %d, expected %d\n",
actualInterface, expectedInterface);
}
close(fd);
Server Connection Logging
void HandleClient(int clientFd) {
int ifNum = TcpGetSocketInterface(clientFd);
InterfaceBlock *pIfBlock = GetInterfaceBlock(ifNum);
struct sockaddr_in clientAddr;
socklen_t addrLen = sizeof(clientAddr);
getpeername(clientFd, (struct sockaddr*)&clientAddr, &addrLen);
printf("Client %I connected via interface %d (%s)\n",
clientAddr.sin_addr.s_addr,
ifNum,
pIfBlock ? pIfBlock->GetInterfaceName() : "unknown");
// Process client request...
close(clientFd);
}
Load Balancing - Track Interface Usage
struct InterfaceStats {
int connectionCount;
uint32_t bytesTransferred;
};
InterfaceStats ifStats[2] = {0}; // Track 2 interfaces
void TrackConnection(int fd, int bytesTransferred) {
int ifNum = TcpGetSocketInterface(fd);
if (ifNum >= 0 && ifNum < 2) {
ifStats[ifNum].connectionCount++;
ifStats[ifNum].bytesTransferred += bytesTransferred;
printf("Interface %d stats: %d connections, %lu bytes\n",
ifNum,
ifStats[ifNum].connectionCount,
ifStats[ifNum].bytesTransferred);
}
}
Failover Detection
int fd = socket(AF_INET, SOCK_STREAM, 0);
int primaryInterface = 0;
connect(fd, (struct sockaddr*)&addr, sizeof(addr));
int activeInterface = TcpGetSocketInterface(fd);
if (activeInterface != primaryInterface) {
printf("WARNING: Connection failed over to backup interface %d\n",
activeInterface);
// Log failover event
LogFailoverEvent(primaryInterface, activeInterface);
} else {
printf("Connection established on primary interface %d\n",
primaryInterface);
}
Diagnostic Output for All Connections
void DiagnoseConnections(int *fdArray, int fdCount) {
printf("\n=== Connection Diagnostics ===\n");
for (int i = 0; i < fdCount; i++) {
int fd = fdArray[i];
int ifNum = TcpGetSocketInterface(fd);
struct sockaddr_in peerAddr;
socklen_t addrLen = sizeof(peerAddr);
getpeername(fd, (struct sockaddr*)&peerAddr, &addrLen);
printf("FD %d: Peer %I via interface %d\n",
fd, peerAddr.sin_addr.s_addr, ifNum);
}
printf("==============================\n\n");
}

◆ TcpGetSocketState()

uint8_t TcpGetSocketState ( int fd)

#include <tcp.h>

Get the current TCP state of a socket.

Queries the current state of a TCP socket connection. The returned value corresponds to one of the states in the TCP state machine as defined in RFC 793.

Parameters
fdSocket file descriptor
Returns
Current socket state: TCP Socket State

◆ TcpGetTxBufferAvailSpace()

uint16_t TcpGetTxBufferAvailSpace ( int fd)

#include <tcp.h>

Get the available space in the transmit buffer.

Returns the number of bytes that can be written to the socket's transmit buffer before it becomes full.

Parameters
fdSocket file descriptor
Returns
Number of bytes available for writing
See also
TcpGetRxBufferSpaceUsed(), TcpGetTxDataWaiting()

◆ TcpGetTxDataWaiting()

uint16_t TcpGetTxDataWaiting ( int fd)

#include <tcp.h>

Get the number of bytes queued for transmission.

Returns the number of bytes currently in the transmit buffer waiting to be sent to the remote host. This includes both data that has not yet been transmitted and data that has been transmitted but not yet acknowledged.

Parameters
fdSocket file descriptor
Returns
Number of bytes queued for transmission
See also
TcpGetTxBufferAvailSpace(), TcpGetRxBufferSpaceUsed()

◆ TcpSendKeepAlive()

void TcpSendKeepAlive ( int fd)

#include <tcp.h>

Send a TCP keepalive probe packet.

Transmits a TCP keepalive packet to the remote host to verify the connection is still active. The keepalive packet is an empty segment with a sequence number one less than the last sent packet. If the remote host is still connected, it will respond with a TCP ACK packet, which will update the socket's lastRxTime.

This function is used with TcpGetLastRxTime() to implement TCP keepalive functionality and detect stale or dead connections.

Parameters
fdSocket file descriptor

Notes:

  • The keepalive probe does not contain any data - it's purely a mechanism to elicit an ACK response from the remote host.
  • If the remote host is unreachable or the connection is dead, no response will be received and the lastRxTime will not change.
  • This is a lightweight operation that generates minimal network traffic (typically just the TCP header with no payload).
See also
TcpGetLastRxTime(), TcpGetLastRxInterval()

Expand for Example Usage

Examples

Basic Keepalive Usage
#include <tcp.h>
#include <nbrtos.h>
void SimpleKeepaliveExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - sending keepalive every 30 seconds\r\n");
while (1)
{
// Wait 30 seconds
OSTimeDly(TICKS_PER_SECOND * 30);
// Send keepalive
printf("Keepalive sent at %lu seconds\r\n", Secs);
// Check if connection is still valid
TcpState state = TcpGetSocketState(fd);
if (state != TCP_STATE_ESTABLISHED)
{
printf("Connection lost (state: %d)\r\n", state);
break;
}
}
close(fd);
}
Keepalive with Response Verification
#include <tcp.h>
#include <nbrtos.h>
void VerifiedKeepaliveExample(void *pd)
{
IPADDR serverIp = AsciiToIp("192.168.1.100");
uint16_t serverPort = 8080;
int fd = connect(serverIp, serverPort, TICKS_PER_SECOND * 10);
if (fd < 0)
{
printf("Connection failed: %d\r\n", fd);
return;
}
printf("Connected - monitoring with keepalives\r\n");
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 30);
// Get RX time before keepalive
uint32_t rxBefore = TcpGetLastRxTime(fd);
// Send keepalive
printf("Keepalive sent, waiting for ACK...\r\n");
// Wait for response (typically very quick)
OSTimeDly(TICKS_PER_SECOND * 3);
// Check if we got a response
uint32_t rxAfter = TcpGetLastRxTime(fd);
if (rxAfter != rxBefore)
{
uint32_t responseTimeMs = ((rxAfter - rxBefore) * 1000) / TICKS_PER_SECOND;
printf("Keepalive ACK received (RTT: %lu ms)\r\n", responseTimeMs);
}
else
{
printf("WARNING: No response to keepalive!\r\n");
// Retry once more
rxBefore = TcpGetLastRxTime(fd);
OSTimeDly(TICKS_PER_SECOND * 5);
rxAfter = TcpGetLastRxTime(fd);
if (rxAfter == rxBefore)
{
printf("Connection dead - no response to keepalive retry\r\n");
break;
}
}
}
close(fd);
}
Multiple Connections with Coordinated Keepalives
#include <tcp.h>
#include <nbrtos.h>
#define MAX_CONNECTIONS 5
struct ManagedConnection
{
int fd;
IPADDR serverIp;
uint32_t lastKeepaliveTime;
bool alive;
};
void SendKeepalivesToAll(ManagedConnection *connections, int count)
{
uint32_t currentTime = Secs;
for (int i = 0; i < count; i++)
{
if (connections[i].fd > 0 && connections[i].alive)
{
// Check if it's time for keepalive (every 30 seconds)
if ((currentTime - connections[i].lastKeepaliveTime) >= 30)
{
uint32_t rxBefore = TcpGetLastRxTime(connections[i].fd);
TcpSendKeepAlive(connections[i].fd);
printf("Keepalive sent to %I\r\n", connections[i].serverIp);
connections[i].lastKeepaliveTime = currentTime;
// Quick check for response
OSTimeDly(TICKS_PER_SECOND);
uint32_t rxAfter = TcpGetLastRxTime(connections[i].fd);
if (rxAfter == rxBefore)
{
printf("No keepalive response from %I\r\n",
connections[i].serverIp);
connections[i].alive = false;
}
}
}
}
}
void MultiConnectionKeepaliveTask(void *pd)
{
ManagedConnection connections[MAX_CONNECTIONS];
// Initialize connections
const char *servers[] = {
"192.168.1.100",
"192.168.1.101",
"192.168.1.102",
"192.168.1.103",
"192.168.1.104"
};
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
connections[i].serverIp = AsciiToIp(servers[i]);
connections[i].fd = connect(connections[i].serverIp, 8080,
connections[i].lastKeepaliveTime = Secs;
connections[i].alive = (connections[i].fd > 0);
if (connections[i].alive)
{
printf("Connected to %I\r\n", connections[i].serverIp);
}
}
// Monitor all connections
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 5);
SendKeepalivesToAll(connections, MAX_CONNECTIONS);
}
// Cleanup
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (connections[i].fd > 0)
{
close(connections[i].fd);
}
}
}

◆ WaitForSocketFlush()

BOOL WaitForSocketFlush ( int fd,
uint32_t ticks )

#include <tcp.h>

Wait for all transmitted data to be acknowledged.

Blocks until all data sent on the socket has been acknowledged by the remote host or until the specified timeout expires. A socket is considered "flushed" when all transmitted data has been acknowledged.

Parameters
fdSocket file descriptor
ticksMaximum wait time in system ticks
Return values
TRUEAll sent data has been acknowledged
FALSETimeout occurred before all data was acknowledged
See also
TcpAllDataAcked()