NetBurner 3.5.6
PDF Version
TCP Prococol

TCP Protocol

TCP establishes a reliable byte-stream connection between two network hosts. The listening host is the server, and the connecting host is the client. Unlike UDP, TCP transmits data as a continuous stream without automatic message boundaries.

TCP Stream Behavior

Data Transmission Without Delimiters:
┌────────────────────────────────────────────┐
│ Sender: "9827" "3129" "3234" "2498"
│ [send] [send] [send] [send] │
└────────────────┬───────────────────────────┘
v TCP Stream
┌────────────────────────────────────────────┐
│ Receiver sees: "98273129323424498..."
│ Problem: Where does one message end? │
└────────────────────────────────────────────┘
Solution: Application must add delimiters/framing

TCP Connection Requirements

Every TCP connection requires four parameters:

  • Source IP address
  • Source port number
  • Destination IP address
  • Destination port number

Well-Known Port Numbers

┌────────────┬────────┬─────────────────────┐
│ Protocol │ Port │ Description │
├────────────┼────────┼─────────────────────┤
│ FTP │ 21 │ File Transfer │
│ Telnet │ 23 │ Remote Terminal │
│ SMTP │ 25 │ Email Sending │
│ DNS │ 53 │ Name Resolution │
│ TFTP │ 69 │ Trivial FTP │
│ HTTP │ 80 │ Web Traffic │
│ POP3 │ 110 │ Email Retrieval │
│ NTP │ 123 │ Time Sync
└────────────┴────────┴─────────────────────┘
@ Sync
Synchronous mode. All signals synchronized to SEMC clock. Supports burst transfers....

TCP Server Implementation

A TCP server listens for incoming connections on a specified port, accepts connection requests, and communicates with connected clients.

TCP Server Flow

Server Lifecycle:
┌─────────────────────────────────────────────────────┐
│ │
│ 1. listen(port) │
│ │ │
│ v │
│ 2. accept() ───> [BLOCKING] │
│ │ │
│ v │
│ 3. Client connects │
│ │ │
│ v │
│ 4. Send/Receive data │
│ │ │
│ v │
│ 5. close() │
│ │ │
│ └──> Loop back to accept() │
│ │
└─────────────────────────────────────────────────────┘
int close(int fd)
Close the specified file descriptor and free the associated resources.
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

TCP Server Functions

Core functions for TCP server implementation:

Basic TCP Server Example

A NetBurner embedded TCP server application that creates a listening socket on port 23 (Telnet) and accepts client connections for communication. Location**: \nburn\examples\TCP

Overview

This application demonstrates how to implement a basic TCP server on NetBurner hardware. The server listens for incoming connections and provides a simple echo-style communication interface where it receives data from clients and displays it locally.

Features

  • TCP Server: Creates a listening socket on port 23 (standard Telnet port)
  • Client Connection Handling: Accepts incoming TCP connections from clients
  • Data Reception: Reads data from connected clients using a simple read() function
  • Connection Management: Handles client disconnections gracefully
  • Multi-tasking: Uses RTOS tasks for concurrent operation

Technical Details

Configuration

  • Listen Port: 23 (Telnet)
  • Receive Buffer Size: 4096 bytes
  • Maximum Pending Connections: 5
  • Task Priority: MAIN_PRIO - 1 (higher than UserMain)

Key Components

TcpServerTask

The main server task that:

  1. Creates a listening socket bound to INADDR_ANY on the specified port
  2. Waits for client connections using accept()
  3. Sends welcome messages to connected clients
  4. Continuously reads data from clients until disconnection
  5. Closes connections and waits for new ones

Buffer Management

  • Uses a global receive buffer (RXBuffer) of 4096 bytes
  • Null-terminates received data for string processing
  • Displays received data length and content via printf()

Usage

Testing with Telnet

To test the TCP server, use a Telnet client from any system on the same network:

telnet <netburner_ip_address>

Where <netburner_ip_address> is the IP address of your NetBurner device.

Expected Behavior

  1. The server displays "Waiting for connection on port 23..."
  2. When a client connects, it shows the client's IP address
  3. The client receives welcome messages:
    • "Welcome to the NetBurner TCP Server"
    • Connection details with server IP and port
  4. Any data sent by the client is echoed to the server console
  5. When the client disconnects, the server closes the connection and waits for new ones

Implementation Notes

Connection Lifecycle

  • The server uses a blocking accept() call to wait for connections
  • Each client connection is handled sequentially (single client at a time)
  • The read() function blocks until data is received or connection closes
  • Connection closure is detected when read() returns 0 or negative value

Limitations

  • Single Client: This example handles one client connection at a time
  • Sequential Processing: New connections must wait until the current client disconnects
  • No Timeout: Connections remain open indefinitely until client closes

For Multiple Clients

This example uses a simple read() approach for single client connections. For handling multiple simultaneous client connections, refer to the "TCP Multi Socket Server" example.

#include <init.h>
#include <tcp.h>
#include <iosys.h>
#include <fdprintf.h>
const char *AppName = "Simple TCP Server Example";
#define TCP_LISTEN_PORT 23 // Telnet port number
#define RX_BUFSIZE (4096)
char RXBuffer[RX_BUFSIZE];
// Allocate task stack for TCP listen task
uint32_t TcpServerTaskStack[USER_TASK_STK_SIZE];
/*-------------------------------------------------------------------
TCP Server Task
*------------------------------------------------------------------*/
void TcpServerTask(void *pd)
{
int listenPort = (int)pd;
// Set up the listening TCP socket
int fdListen = listen(INADDR_ANY, listenPort, 5);
if (fdListen > 0)
{
IPADDR clientAddress;
uint16_t clientPort;
while (1)
{
/* The accept() function will block the current task until a TCP client
requests a connection. Once a client connection is accepting, the
file descriptor fdAccept is used to read/write to it.
*/
printf("Waiting for connection on port %d...\n", listenPort);
int fdAccept = accept(fdListen, &clientAddress, &clientPort, 0);
printf("Connected to: %I\r\n", GetSocketRemoteAddr(fdAccept));
writestring(fdAccept, "Welcome to the NetBurner TCP Server\r\n");
fdprintf(fdAccept, "You are connected to IP Address %I:%d\r\n", GetSocketRemoteAddr(fdAccept), GetSocketRemotePort(fdAccept));
while (fdAccept > 0)
{
/* Loop while connection is valid. The read() function will return 0 or a negative number if the
client closes the connection, so we test the return value in the loop. Note: you can also use
ReadWithTimout() in place of read to enable the connection to terminate after a period of inactivity.
*/
int n = 0;
do
{
n = read(fdAccept, RXBuffer, RX_BUFSIZE);
RXBuffer[n] = '\0';
printf("Read %d bytes: %s\n", n, RXBuffer);
} while (n > 0);
printf("Closing client connection: %I\r\n", GetSocketRemoteAddr(fdAccept));
close(fdAccept);
fdAccept = 0;
}
} // while(1)
} // while listen
}
/*-------------------------------------------------------------------
User Main
------------------------------------------------------------------*/
void UserMain(void *pd)
{
init();
//Enable system diagnostics. Probably should remove for production code.
// Create TCP Server task
OSTaskCreatewName(TcpServerTask,
(void *)TCP_LISTEN_PORT,
&TcpServerTaskStack[USER_TASK_STK_SIZE],
TcpServerTaskStack,
MAIN_PRIO - 1, /* higher priority than UserMain */
"TCP Server");
while (1)
{
OSTimeDly(TICKS_PER_SECOND * 5);
}
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition ipv6_addr.h:41
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
#define MAIN_PRIO
Recommend UserMain priority.
Definition constants.h:130
int fdprintf(int fd, const char *format,...)
Print formatted output to a file descriptor.
int read(int fd, char *buf, int nbytes)
Read data from a file descriptor (fd).
int writestring(int fd, const char *str)
Write a null terminated ascii string to the stream associated with a file descriptor (fd)....
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
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...
void EnableSystemDiagnostics()
Turn on the diagnostic reports from the config page.
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.

Basic Server Limitations

This simple example demonstrates core TCP server concepts but has limitations:

  • Listens on only one port
  • Handles only one connection at a time
  • No graceful connection termination from server side
  • Client must close connection

Multi-Connection Server Example

For production applications, use select() to handle multiple simultaneous connections efficiently.

Overview

This application demonstrates a TCP server implementation that can handle multiple simultaneous client connections using the NetBurner embedded platform. The server uses the select() function to efficiently manage multiple TCP connections concurrently without blocking.

Features

  • Multi-client support: Handles up to 10 simultaneous TCP connections
  • Non-blocking I/O: Uses select() to efficiently manage multiple file descriptors
  • Connection management: Automatically accepts new connections and manages client disconnections
  • Simple protocol: Clients can send 'Q' to quit their connection
  • Debug output: Status messages displayed on debug serial port

Configuration

The application uses the following configurable parameters:

  • Listen Port: 23 (Telnet port)
  • Maximum Connections: 10 simultaneous clients
  • Read Buffer Size: 1024 bytes per connection

These values can be modified by changing the corresponding #define statements in main.cpp.

How It Works

Multi-Connection Architecture

Select() Multiplexing Pattern:
┌──────────────────────────────────────────────────┐
select() │
│ [Blocks until activity] │
└───────────┬──────────────────────────────────────┘
v
┌───────────────────────────────────────────────────┐
│ Check listen socket for new connections │
│ ├─> New connection? -> accept() -> add to array │
│ └─> Error? -> close and reopen │
└───────────────────────────────────────────────────┘
v
┌───────────────────────────────────────────────────┐
│ Check each active connection fd: │
│ ├─> Data ready? -> read() and process │
│ ├─> 'Q' received? -> close connection │
│ └─> Error? -> close and free slot │
└───────────────────────────────────────────────────┘
v
Loop back to select()
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)...

Server Initialization

  1. Initializes the NetBurner system and waits for network connectivity
  2. Creates a listening socket on port 23
  3. Displays the device's IP addresses for client connection reference

Connection Management

The server uses a file descriptor array (fdArray) to track active client connections. The main loop:

  1. Sets up file descriptor sets for select() monitoring
  2. Calls select() to block until activity occurs on any socket
  3. Processes new connections when clients connect to the listening port
  4. Handles client data when existing connections have data to read
  5. Manages errors by closing problematic connections

Client Interaction

  • Welcome message: New clients receive a greeting upon connection
  • Quit command: Clients can send 'Q' to cleanly disconnect
  • Echo behavior: The server reads client data and logs it to the debug port
  • Connection limits: If the server is full (10 connections), new clients are rejected with an error message

Testing the Application

Using Telnet

The easiest way to test this application is using multiple Telnet sessions:

telnet <netburner_ip_address> 23

You can open up to 10 simultaneous Telnet connections to test the multi-client functionality.

Expected Behavior

  1. Successful connection: You'll see "Welcome to the NetBurner Multi-Socket TCP Server! 'Q' to quit."
  2. Server full: If you try to connect when 10 clients are already connected, you'll see "I am sorry, but the server is full"
  3. Quit command: Type 'Q' to cleanly disconnect
  4. Debug output: Connection status, received data, and errors are logged to the serial debug port

Code Structure

Key Functions

  • **UserMain()**: Main application entry point and event loop
  • **select()**: Monitors multiple file descriptors for activity
  • **accept()**: Accepts new client connections
  • **read()**: Reads data from client connections
  • **close()**: Closes file descriptors and cleans up connections

File Descriptor Management

The application maintains an array of file descriptors (fdArray) where:

  • Index 0-9: Active client connections (0 = unused slot)
  • Separate fdListen: The listening socket for new connections

Error Handling

  • Connection errors: Automatically detected and connections are closed
  • Read errors: Treated as connection problems and handled gracefully
  • Listen socket errors: The listening socket is closed and reopened

Troubleshooting

  • Cannot connect: Verify the NetBurner device has network connectivity and check IP address
  • Connection refused: Ensure no other service is using port 23
  • Unexpected disconnections: Check debug serial output for error messages
  • Server appears full: Existing connections may not have closed properly; restart the application

Source Code

#include <init.h>
#include <iosys.h>
#include <tcp.h>
#include <ipshow.h>
const char *AppName = "TCP Multisocket Server";
#define listenPort (23) // TCP port number to listen on
#define maxConnections (10) // Max number of file descriptors/connections
#define readBufferSize (1024) // Connection read buffer size
int fdArray[maxConnections]; // Array of TCP file descriptors
/*-----------------------------------------------------------------------------
User Main
*------------------------------------------------------------------------------*/
void UserMain(void *pd)
{
init();
//Enable system diagnostics. Probably should remove for production code.
// Listen for incoming TCP connections. You only need to call listen() one time.
// Any incoming IP address is allowed, queue up to 5 connection requests at one time
int32_t fdListen = listen(INADDR_ANY, listenPort, 5);
printf("Listening for incoming connections on port %d\r\n", listenPort);
while (1)
{
// Declare file descriptor sets for select()
fd_set readFds;
fd_set errorFds;
// Init the fd sets
FD_ZERO(&readFds);
FD_ZERO(&errorFds);
// Configure the fd sets so select() knows what to process. In this case any fd data to be read, or an error
for (int32_t i = 0; i < maxConnections; i++)
{
if (fdArray[i]) // The fd in the array will be > 0 if open and valid, so reset the file descriptor sets
{
FD_SET(fdArray[i], &readFds);
FD_SET(fdArray[i], &errorFds);
}
}
// select() should also process the listen fd
FD_SET(fdListen, &readFds);
FD_SET(fdListen, &errorFds);
/* select() will block until any fd has data to be read, or has an error. When select() returns,
readFds and/or errorFds variables will have been modified to reflect the events.
*/
select(FD_SETSIZE, &readFds, (fd_set *)0, &errorFds, 0);
// If the listen fd has a connection request, accept it.
if (FD_ISSET(fdListen, &readFds))
{
IPADDR clientIp;
uint16_t clientPort;
int fdAccept = accept(fdListen, &clientIp, &clientPort, 0);
// If accept() returned, find an open fd array slot
if (fdAccept > 0)
{
for (int i = 0; i < maxConnections; i++)
{
if (fdArray[i] == 0)
{
fdArray[i] = fdAccept;
writestring(fdAccept, "Welcome to the NetBurner Multi-Socket TCP Server! 'Q' to quit.");
printf("Added connection on fd[%d] = %d, Client IP: %I:%d\r\n", i, fdAccept,
fdAccept = 0;
break;
}
}
}
// If no array positions are open, close the connection
if (fdAccept)
{
writestring(fdAccept, "I am sorry, but the server is full\r\n");
printf("Server Full\r\n");
close(fdAccept);
}
}
// If the listen fd has an error, close it and reopen
if (FD_ISSET(fdListen, &errorFds))
{
close(fdListen);
fdListen = listen(INADDR_ANY, listenPort, 5);
}
// Process each fd array element and check it against readFds and errorFds.
for (int i = 0; i < maxConnections; i++)
{
if (fdArray[i])
{
// Check for data to be read
if (FD_ISSET(fdArray[i], &readFds))
{
char buffer[readBufferSize];
int rv = read(fdArray[i], buffer, readBufferSize);
if (rv > 0)
{
buffer[rv] = 0;
if (buffer[0] == 'Q')
{
printf("Closing connection fd[%d]\r\n", i);
writestring(fdArray[i], "Bye\r\n");
close(fdArray[i]);
fdArray[i] = 0;
}
else
{
printf("Read \"%s\" from fd[%d]\r\n", buffer, i);
// snprintf( buffer, readBufferSize, "Server read %d byte(s)\r\n", rv );
// writestring( fdArray[i], buffer );
}
}
else
{
printf("Read Error on fd[%d]\r\n", fdArray[i]);
FD_SET(fdArray[i], &errorFds);
}
} // data available to read
// Check for errors
if (FD_ISSET(fdArray[i], &errorFds))
{
printf("Error on fd[%d], closing connection\r\n", i);
close(fdArray[i]);
fdArray[i] = 0;
}
} // if fd is valid
} // process each connection in the array
} // while (1)
} // UserMain
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...
void FD_ZERO(fd_set *pfds)
Clear (set to 0) a fd_set (file descriptor set) so no file descriptors (fds) are selected.
void showIpAddresses()
Print system IP addresses to stdout.

TCP Client Implementation

A TCP client initiates connections to TCP servers using the connect() function. This section demonstrates a web-based TCP client interface.

This is a simple TCP client application built for NetBurner hardware that demonstrates how to create and use a TCP client connection. The application provides a web-based interface that allows users to send messages to any TCP server by specifying the destination IP address, port number, and message content.

Features

  • Web-based Interface: Complete interaction through a web page interface
  • Configurable Connection: Set destination IP address and port number
  • Message Transmission: Send custom messages to TCP servers
  • Auto-fill Functionality: Automatically fills in the requesting client's IP address as default destination
  • Error Handling: Comprehensive error reporting and logging
  • Real-time Feedback: Connection status and transmission results displayed

User Main (main.cpp)

#include <init.h>
#include <nbrtos.h>
#include <ipshow.h>
const char *AppName = "Simple TCP Client Example";
/*-------------------------------------------------------------------
User Main
------------------------------------------------------------------*/
void UserMain(void *pd)
{
init();
//Enable system diagnostics. Probably should remove for production code.
while (1)
{
OSTimeDly(TICKS_PER_SECOND);
}
}
void StartHttp(uint16_t port, bool RunConfigMirror)
Start the HTTP web server. Further documentation in the Initialization section Initialization - Syste...

Client Web Page User Interface to Connect (clientweb.cpp)

/*NB_REVISION*/
/*NB_COPYRIGHT*/
/*-------------------------------------------------------------------
This code implements the web page entries for the message,
destination IP address and destination port number. When the
web page first loads it will automatically fill in the IP
address from the source requesting the web page, because in
most cases it will also be the address of the TCP Server.
The web page is a form, and when a user presses the submit
button the SendMsg() function will open a TCP connection to
the server, send the message, and close the connection.
Any error messages will be sent to stdout and can be viewed
with MTTTY.
A TCP server program must already be listening at the specified
IP address and port number for the message to be sent. A simple
TCP Server called TcpServerWin.exe is located in the
\nburn\pctools directory of your NetBurner installation.
-------------------------------------------------------------------*/
#include <iosys.h>
#include <tcp.h>
#include <fdprintf.h>
#include <httppost.h>
#define APP_VERSION "Version 1.3 7/29/2025"
#define MAX_MSG_SIZE 1024
int gDestPort;
IPADDR gDestIp;
char gMessage[MAX_MSG_SIZE];
/*-------------------------------------------------------------------
Sends a message to the specified host.
------------------------------------------------------------------*/
void SendMsg(IPADDR destIp, int destPort, char *msg)
{
printf("Connecting to: %I:%d\r\n", destIp, destPort);
int fd = connect(destIp, destPort, TICKS_PER_SECOND * 5);
if (fd < 0) { printf("Error: Connection failed, return code: %d\r\n", fd); }
else
{
printf("Attempting to write: \"%s\" \r\n", msg);
int n = write(fd, msg, strlen(msg));
printf("Wrote %d bytes\r\n", n);
close(fd);
}
}
/*-------------------------------------------------------------------
Show destination port number on web page
----------------------------------------------------------------*/
void WebDestPort(int sock, PCSTR url)
{
if (gDestPort == 0) // If no dest port is specified, use a default
gDestPort = 2000;
fdprintf(sock, "VALUE=\"%d\" ", gDestPort);
}
/*-------------------------------------------------------------------
Show destination ip address on web page
------------------------------------------------------------------*/
void WebDestIp(int sock, PCSTR url)
{
if (gDestIp.IsNull()) // If no dest ip address has been entered, use the one that requested the web page.
fdprintf(sock, "VALUE=\"%I\" ", GetSocketRemoteAddr(sock));
else
fdprintf(sock, "VALUE=\"%I\" ", gDestIp);
}
/*-------------------------------------------------------------------
Show destination ip address on web page
*------------------------------------------------------------------*/
void WebShowClientIp(int sock, PCSTR url)
{
fdprintf(sock, "%I", GetSocketRemoteAddr(sock));
}
/*-------------------------------------------------------------------
Parse form post variables.
*------------------------------------------------------------------*/
void processPostVariables(const char *pName, const char *pValue)
{
printf("Processing: %s\r\n", pName);
if (strcmp(pName, "tfDestPortNum") == 0)
{
gDestPort = (uint16_t)atoi(pValue);
printf("Destination port set to: %d\r\n", gDestPort);
}
else if (strcmp(pName, "tfDestIpAddr") == 0)
{
printf("DestIpAddr set to: %s\r\n", pValue);
gDestIp = AsciiToIp(pValue);
}
else if (strcmp(pName, "tfMessage") == 0)
{
strncpy(gMessage, pValue, MAX_MSG_SIZE - 1);
}
else if (strcmp(pName, "SendMessage") == 0)
{
SendMsg(gDestIp, gDestPort, (char *)pValue);
}
else
{
printf("Error processing %s\r\n", pName);
}
}
/*-------------------------------------------------------------------
Form post callback function
*------------------------------------------------------------------*/
int PostCallBack(int sock, PostEvents event, const char *pName, const char *pValue)
{
// Received a call back with an event, check for event type
switch (event)
{
case eStartingPost: // Called at the beginning of the post before any data is sent
break;
case eVariable: // Called once for each variable in the form
processPostVariables(pName, pValue);
break;
// Called back with a file handle if the post had a file
case eFile:
break; // No file type here so we do nothing
// Called back when the post is complete. You should send your response here.
case eEndOfPost:
{
printf("\r\n\r\n"); // just some new lines for easier console reading
RedirectResponse(sock, "INDEX.HTML"); // Our response is to redirect to the index page
}
break;
} // Switch
return 0;
}
// Create a global static post handling object that responds to the specified html page.
// A separate post handler can be created for each form in your application.
HtmlPostVariableListCallback poster("index.html", PostCallBack);
Implements the HtmlPostVariableListHandler class as a function pointer callback for HTTP POST submiss...
Definition httppost.h:131
bool IsNull() const
Check if the IP address is null.
Definition ipv6_addr.h:133
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,...
int connect(const IPADDR &ipAddress, uint16_t remotePort, uint32_t timeout)
Establish a TCP connection to a remote host.
Definition tcp.h:1547
void RedirectResponse(int sock, PCSTR new_page)
Redirect a HTTP request to a different page.

TCP Error Handling

Status codes and error values returned by TCP socket operations These error codes are returned by TCP socket functions such as listen(), accept(), connect(), read(), write(), and other socket operations. Understanding these codes is essential for proper error handling and debugging network issues.

Return Value Convention

TCP socket functions follow this convention:

  • Positive values: Valid file descriptor (socket successfully created/connected)
  • Zero: Success for non-FD operations (e.g., TCP_ERR_NORMAL)
  • Negative values: Error condition (use these constants to identify the error)

Error Handling Pattern

int sock = connect("example.com", 80, TICKS_PER_SECOND * 10);
if (sock < 0) {
// Error occurred - check which one
switch (sock) {
printf("Connection timed out\r\n");
break;
printf("No sockets available\r\n");
break;
default:
printf("Connection error: %d\r\n", sock);
break;
}
} else {
// Success - sock is a valid file descriptor
printf("Connected on socket %d\r\n", sock);
}
#define TCP_ERR_TIMEOUT
Operation timed out before completion.
Definition tcp.h:355
#define TCP_ERR_NONE_AVAIL
No sockets available in the system pool.
Definition tcp.h:359

Common Usage Scenarios

Client Connections

  • TCP_ERR_TIMEOUT: Server unreachable or not responding
  • TCP_ERR_NONE_AVAIL: Too many open connections
  • TCP_ERR_CON_RESET: Server rejected connection

Server Operations

  • TCP_ERR_TIMEOUT: accept() timeout (not necessarily an error)
  • TCP_ERR_NONE_AVAIL: Socket pool exhausted

Data Transfer

  • TCP_ERR_NOCON: Connection closed before operation
  • TCP_ERR_CLOSING: Connection in teardown state
  • TCP_ERR_CON_RESET: Remote host reset connection

Expand for Example Usage

Examples

Example 1: Basic Error Handling in Client Connection
int ConnectToServer(const char *host, uint16_t port) {
printf("Connecting to %s:%d...\r\n", host, port);
int sock = connect(host, port, TICKS_PER_SECOND * 10);
if (sock == TCP_ERR_TIMEOUT) {
printf("ERROR: Connection timed out\r\n");
return -1;
} else if (sock == TCP_ERR_NONE_AVAIL) {
printf("ERROR: No sockets available\r\n");
return -1;
} else if (sock < 0) {
printf("ERROR: Connection failed with code %d\r\n", sock);
return -1;
}
printf("Successfully connected (socket %d)\r\n", sock);
return sock;
}
Example 2: Server Accept with Timeout Handling
void ServerAcceptLoop(int listenSock) {
while (1) {
// Accept with 5 second timeout
int clientSock = accept(listenSock, NULL, NULL, TICKS_PER_SECOND * 5);
if (clientSock == TCP_ERR_TIMEOUT) {
// Timeout is normal - just loop again
continue;
} else if (clientSock == TCP_ERR_NONE_AVAIL) {
printf("WARNING: No sockets available for new connection\r\n");
OSTimeDly(TICKS_PER_SECOND); // Wait before retry
continue;
} else if (clientSock < 0) {
printf("ERROR: Accept failed with code %d\r\n", clientSock);
break;
}
// Valid connection
printf("New client connected on socket %d\r\n", clientSock);
HandleClient(clientSock);
}
}
Example 3: Comprehensive Error Reporting
const char* GetTCPErrorString(int errorCode) {
switch (errorCode) {
return "Success";
return "Operation timed out";
return "No active connection";
return "Socket is closing";
return "Socket does not exist";
return "No sockets available";
return "Connection reset by peer";
return "Connection aborted";
default:
return "Unknown error";
}
}
void ReportConnectionError(int errorCode, const char *operation) {
printf("TCP Error during %s: %s (code: %d)\r\n",
operation, GetTCPErrorString(errorCode), errorCode);
}
// Usage
int sock = connect("server.com", 80, TICKS_PER_SECOND * 10);
if (sock < 0) {
ReportConnectionError(sock, "connect");
}
#define TCP_ERR_NOCON
No active connection exists on this socket.
Definition tcp.h:356
#define TCP_ERR_NORMAL
Operation completed successfully with no errors.
Definition tcp.h:354
#define TCP_ERR_CON_RESET
Connection was reset by remote host.
Definition tcp.h:360
#define TCP_ERR_NOSUCH_SOCKET
The specified socket does not exist.
Definition tcp.h:358
#define TCP_ERR_CLOSING
Socket is currently in the closing state.
Definition tcp.h:357
#define TCP_ERR_CON_ABORT
Connection was aborted.
Definition tcp.h:361
Example 4: Read with Connection Error Detection
int ReadWithErrorHandling(int sock, char *buffer, int bufSize) {
int bytesRead = read(sock, buffer, bufSize);
if (bytesRead > 0) {
// Data received successfully
return bytesRead;
} else if (bytesRead == 0) {
// Connection closed gracefully
printf("Connection closed by remote host\r\n");
return 0;
} else {
// Error occurred
if (bytesRead == TCP_ERR_NOCON) {
printf("ERROR: No active connection\r\n");
} else if (bytesRead == TCP_ERR_CLOSING) {
printf("ERROR: Socket is closing\r\n");
} else if (bytesRead == TCP_ERR_CON_RESET) {
printf("ERROR: Connection reset by peer\r\n");
} else if (bytesRead == TCP_ERR_TIMEOUT) {
printf("ERROR: Read timeout\r\n");
} else {
printf("ERROR: Read failed with code %d\r\n", bytesRead);
}
return -1;
}
}
Example 5: Socket Pool Management
#define MAX_RETRY_ATTEMPTS 3
int ConnectWithRetry(const char *host, uint16_t port) {
for (int attempt = 1; attempt <= MAX_RETRY_ATTEMPTS; attempt++) {
printf("Connection attempt %d/%d...\r\n", attempt, MAX_RETRY_ATTEMPTS);
int sock = connect(host, port, TICKS_PER_SECOND * 5);
if (sock >= 0) {
// Success
return sock;
}
if (sock == TCP_ERR_NONE_AVAIL) {
printf("No sockets available, waiting for one to free up...\r\n");
OSTimeDly(TICKS_PER_SECOND * 2); // Wait for sockets to free
} else if (sock == TCP_ERR_TIMEOUT) {
printf("Timeout, retrying...\r\n");
OSTimeDly(TICKS_PER_SECOND); // Brief delay before retry
} else {
// Other error - don't retry
printf("Fatal error %d, aborting\r\n", sock);
return sock;
}
}
printf("Failed to connect after %d attempts\r\n", MAX_RETRY_ATTEMPTS);
}
Example 6: Connection State Monitoring
typedef struct {
int sock;
bool isConnected;
uint32_t lastActivity;
int lastError;
} ConnectionState;
void UpdateConnectionState(ConnectionState *conn) {
// Try a zero-length read to check connection status
char dummy;
int result = read(conn->sock, &dummy, 0);
if (result == TCP_ERR_NOCON || result == TCP_ERR_CON_RESET ||
result == TCP_ERR_CON_ABORT) {
if (conn->isConnected) {
printf("Connection lost: %s\r\n", GetTCPErrorString(result));
conn->isConnected = false;
conn->lastError = result;
}
} else if (result == TCP_ERR_CLOSING) {
printf("Connection closing...\r\n");
conn->isConnected = false;
conn->lastError = result;
} else {
// Connection still active
conn->lastActivity = Secs;
}
}
Example 7: Graceful Shutdown on Error
void CloseConnectionGracefully(int sock) {
if (sock < 0) {
return; // Invalid socket
}
// Try to shutdown gracefully
printf("Closing socket %d...\r\n", sock);
// Attempt to send any pending data with timeout
OSTimeDly(TICKS_PER_SECOND / 10); // 100ms grace period
close(sock);
printf("Socket closed\r\n");
}
void HandleConnectionError(int sock, int errorCode) {
printf("Handling error: %s\r\n", GetTCPErrorString(errorCode));
switch (errorCode) {
// Connection already gone, just close FD
close(sock);
break;
// Wait briefly for close to complete
OSTimeDly(TICKS_PER_SECOND / 2);
close(sock);
break;
default:
CloseConnectionGracefully(sock);
break;
}
}
Example 8: Diagnostic Logging
void LogSocketOperation(const char *operation, int result) {
if (result >= 0) {
printf("[OK] %s: fd=%d\r\n", operation, result);
} else {
printf("[ERROR] %s: %s (code=%d)\r\n",
operation, GetTCPErrorString(result), result);
}
}
// Usage
int sock = connect("example.com", 80, TICKS_PER_SECOND * 10);
LogSocketOperation("connect", sock);
if (sock >= 0) {
int bytes = write(sock, "GET /", 5);
LogSocketOperation("write", bytes);
}

Functions that return TCP Status Codes:

Function Description
connect() Establish TCP client connection
listen() Create listening TCP socket
accept() Accept incoming TCP connection
read() Read data from TCP socket
write() Write data to TCP socket
close() Close TCP socket

TCP Return Codes

TCP Socket Status and Error Codes are defined here: TCP Socket Status. A summary is provided below and the following sections detail each error code as well as possible causes and corrective measures.

#define TCP_ERR_NORMAL (0) // Operation completed successfully with no errors
#define TCP_ERR_TIMEOUT (-1) // Operation timed out before completion
#define TCP_ERR_NOCON (-2) // No active connection exists on this socket
#define TCP_ERR_CLOSING (-3) // Socket is currently in the closing state
#define TCP_ERR_NOSUCH_SOCKET (-4) // The specified socket does not exist
#define TCP_ERR_NONE_AVAIL (-5) // No sockets available in the system pool
#define TCP_ERR_CON_RESET (-6) // Connection was reset by remote host
#define TCP_ERR_CON_ABORT (-7) // Connection was aborted

Operation completed successfully with no errors

#define TCP_ERR_NORMAL (0)

Indicates that a socket operation completed without any error conditions. This is the expected return value for successful non-FD operations.


Operation timed out before completion

#define TCP_ERR_TIMEOUT (-1)

The socket operation did not complete within the specified timeout period. Common causes:

  • Remote host unreachable or not responding
  • Network congestion or packet loss
  • Timeout value too short for operation
  • Firewall blocking connection

For accept() with timeout, this is not necessarily an error - it just means no connection arrived within the timeout period.

Note
When this occurs during connect(), the remote host is likely down or unreachable
For read() operations, this may indicate the peer stopped sending data

No active connection exists on this socket

#define TCP_ERR_NOCON (-2)

Attempted to perform an operation on a socket that has no active connection. Common causes:

  • Trying to read/write on a socket that was never connected
  • Connection was closed by remote peer
  • Connection attempt failed but socket was still used
  • Using a socket after close() was called
Note
Always check connection establishment before attempting I/O operations
This error indicates the socket exists but has no connection

Socket is currently in the closing state

#define TCP_ERR_CLOSING (-3)

The socket is in the process of closing and cannot accept new operations. This is a transitional state during connection teardown.

Common causes:

  • close() was called and TCP is performing graceful shutdown
  • FIN packet sent but waiting for acknowledgment
  • TCP TIME_WAIT or CLOSE_WAIT state
Note
Wait briefly and the socket will complete closing
Do not attempt further I/O on this socket

The specified socket does not exist

#define TCP_ERR_NOSUCH_SOCKET (-4)

The file descriptor does not correspond to a valid socket in the system. Common causes:

  • Using an invalid file descriptor number
  • Socket was already closed
  • File descriptor number was never allocated
  • Corruption of the socket handle
Note
This indicates a programming error - verify FD validity before use
Check that socket creation succeeded before using the FD

No sockets available in the system pool

#define TCP_ERR_NONE_AVAIL (-5)

The system has exhausted its pool of available socket resources and cannot create new connections. This is a resource limitation error.

Common causes:

  • Too many simultaneous connections open
  • Sockets not being closed properly (resource leak)
  • Application exceeding design limits
  • System configuration limits too low

Solutions:

  • Close unused sockets promptly
  • Implement connection pooling or limiting
  • Increase system socket pool size if possible
  • Check for socket leaks in application code
Warning
This error indicates a serious resource constraint
Note
Monitor socket usage to prevent this condition

Connection was reset by remote host

#define TCP_ERR_CON_RESET (-6)

The remote peer forcibly closed the connection, typically by sending a TCP RST (reset) packet. This indicates an abnormal connection termination.

Common causes:

  • Remote application crashed
  • Remote host rebooted
  • Firewall or security device terminated connection
  • Protocol violation or invalid data sent
  • Remote application explicitly reset the socket
Note
This is different from a graceful close (FIN packet)
Data may have been lost when this occurs
Warning
Connection cannot be recovered - must establish new connection

Connection was aborted

#define TCP_ERR_CON_ABORT (-7)

The connection was terminated abnormally, typically due to a local or network error condition. This is a general abort condition.

Common causes:

  • Local TCP stack detected fatal error
  • Network path broken
  • Excessive retransmission failures
  • Local application requested abort
  • System resources exhausted during transfer
Note
Similar to TCP_ERR_CON_RESET but indicates local-side abort
Warning
Connection cannot be recovered - must establish new connection