network/tcp_echo_server/main.c

/*******************************************************************************
* # License
* Copyright 2019 Silicon Laboratories Inc. www.silabs.com
*******************************************************************************
*
* The licensor of this software is Silicon Laboratories Inc. Your use of this
* software is governed by the terms of Silicon Labs Master Software License
* Agreement (MSLA) available at
* www.silabs.com/about-us/legal/master-software-license-agreement. This
* software is distributed to you in Source Code format and is governed by the
* sections of the MSLA applicable to Source Code.
*
******************************************************************************/
/*
* Documentation for this app is available online.
* See https://docs.silabs.com/gecko-os/4/standard/latest/sdk/examples/network/tcp-echo-server
*/
#include "gos.h"
#include "example_app_util.h"
// Maximum of bytes to read per RX event
// We don't want this to be too large as it will block the app thread
// and starve other client streams
#define MAX_READ_LENGTH_PER_RX_EVENT 3000
#define TCP_SEVER_DEFAULT_PORT 3000
#define APPLICATION_START_LINE "Starting TCP Echo Server example ..."
#define CLIENT_LOG(handle, msg, ...) GOS_LOG("[Stream:%u] " msg, handle, ## __VA_ARGS__);
char rx_buffer[4096];
// NOTE: Stream handles start a 1.
// To make the logic easier just add an extra element to this array
static uint32_t client_connection_times[GOS_MAX_STREAMS + 1];
/*************************************************************************************************/
void gos_app_init(void)
{
GOS_LOG(APPLICATION_START_LINE);
if (gos_load_app_settings("settings.ini") == GOS_SUCCESS)
{
example_app_util_network_up(GOS_INTERFACE_ANY, true, network_event_handler);
}
else
{
GOS_LOG("Failed to load settings");
}
}
/*************************************************************************************************/
static void network_event_handler(bool is_up)
{
if(is_up == true)
{
gos_result_t result;
uint32_t port;
GOS_LOG("Network up");
if(GOS_FAILED(result, gos_settings_get_uint32("tcp.server.port", &port)))
{
GOS_LOG("Failed to get TCP server port, err:%d", result);
port = TCP_SEVER_DEFAULT_PORT;
GOS_LOG("Default to port: %d", port);
}
gos_tcp_register_server_event_handlers(tcp_client_connect_handler,
tcp_client_disconnect_handler,
tcp_client_receive_handler);
{
GOS_LOG("Failed to start TCP server, err:%d", result);
}
else
{
GOS_LOG("TCP Echo Server listening on: %s:%u", example_app_util_get_network_interface_ip_address_str(), port);
GOS_LOG("- All data clients send to the server will be echoed back");
}
}
else
{
GOS_LOG("Network down");
}
}
/*************************************************************************************************/
static void tcp_client_connect_handler(gos_handle_t handle)
{
CLIENT_LOG(handle, "TCP client connected");
client_connection_times[handle] = gos_rtos_get_time();
}
/*************************************************************************************************/
static void tcp_client_disconnect_handler(gos_handle_t handle)
{
CLIENT_LOG(handle, "TCP client disconnected");
close_client_stream(handle);
}
/*************************************************************************************************/
static void tcp_client_receive_handler(gos_handle_t handle)
{
gos_result_t result;
uint32_t rx_bytes;
if(GOS_FAILED(result, gos_tcp_poll(handle, &rx_bytes, NULL)))
{
CLIENT_LOG(handle, "Failed to poll stream, err:%d", result);
close_client_stream(handle);
return;
}
CLIENT_LOG(handle, "Rx bytes pending:%d", rx_bytes);
rx_bytes = MIN(MAX_READ_LENGTH_PER_RX_EVENT, rx_bytes);
while(rx_bytes > 0)
{
uint32_t bytes_read = 0;
if(GOS_FAILED(result, gos_tcp_read(handle, rx_buffer, MIN(rx_bytes, sizeof(rx_buffer)-1), &bytes_read)))
{
CLIENT_LOG(handle, "Failed to read stream, err:%d", result);
break;
}
else if(GOS_FAILED(result, gos_tcp_write(handle, rx_buffer, bytes_read, false)))
{
CLIENT_LOG(handle, "Failed to echo data back to stream, err:%d", result);
break;
}
else
{
rx_bytes -= rx_bytes;
}
}
// if the above operations failed then close the connection
if(result != GOS_SUCCESS)
{
close_client_stream(handle);
}
}
/*************************************************************************************************/
static void close_client_stream(uint32_t handle)
{
const gos_result_t result = gos_tcp_disconnect(handle);
CLIENT_LOG(handle, "Manually closed client stream, result: %d", result)
if(result == GOS_SUCCESS)
{
const uint32_t time = gos_rtos_get_time() - client_connection_times[handle];
CLIENT_LOG(handle, "Total connection time: %u", time)
}
}