PServer.c

PServer.c example details

This program installs a concurrent TCP echo server on port 5031.

To verify this program, first 'ping' the DSP:

>ping 192.168.168.200

If the settings and network connections are correct, the pings will be replied.

The TCP Echo server will re-send (echo) anything it receives. To verify this, start Netcat (nc) with the following command

>nc 192.168.168.200 5031
           |        |
           |        +-- port 5031 = User Echo Port
           +----------- the DSP's IP address

Any characters you type in the console window will be returned. Netcat doesn't send the characters immediately, it will send the entire string following a terminating CR. Please note that the maximum length of the character string is limited by the size of the buffer used for TCP echo (MAX_DATA = 1024).

Using parallel servers:

The user defined function 'init_parallel_echo_server()' must be called once to have at least one listening socket. After connecting this socket, the callback function tcp_echo() is called from TCP stack with error code SO_CONNECTION_ESTABLISHED. The next 'init_parallel_echo_server()' function call increases the server list. The new opened server socket is automatically in listening state and can be connected from the next client. After disconnecting one client, the TCP stack calls the user callback function again. This time with error code SO_CONNECTION_CLOSED (or SO_CONNECTION_RESET ). Call 'close_parallel_echo_server()' to decrease the server list and free all associated memory.

See also
Concurrent Server
/***************************************************************************//**
@file PServer.c
@brief Concurrent Server Example
@verbatim
_ _ _
__| | ___(_) ____ _ __ | |_
/ _` | / __| |/ _` | '_ \| __|
| (_| | _ \__ \ | (_| | | | | |_
\__,_|(_) ___/_|\__, |_| |_|\__|
Signalprocessing |___/ Technology
@endverbatim
@author D.SignT GmbH & Co. KG, Claus Hermbusche
@date 2019-06-03
@anchor PSERVEREX
@details
This program installs a concurrent TCP echo server on port 5031.
To verify this program, first 'ping' the DSP:
>ping 192.168.168.200
or
>ping mydemo
If the settings and network connections are correct, the pings
will be replied.
The TCP Echo server will re-send (echo) anything it receives.
To verify this, start NetCat (nc) with the following command
>nc 192.168.168.200 5031
| |
| +-- port 5031 = User Echo Port
+----------- the DSP's IP address
or
>nc mydemo 5031
| |
| +----- port 5031 = User Echo Port
+----------- the DSP hostname
Any characters you type in the console window will be returned.
NetCat doesn't send the characters immediately, it will send
the entire string following a terminating CR. Please note that
the maximum length of the character string is limited by the
size of the buffer used for TCP echo (MAX_DATA = 1024).
Using parallel servers:
The user defined function 'init_parallel_echo_server()' must be called once
to have at least one listening socket. After connecting this socket, the
callback function tcp_echo() is called from TCP stack with error code
SO_CONNECTION_ESTABLISHED. The next 'init_parallel_echo_server()' function
call increases the server list. The new opened server socket is auto-
matically in listening state and can be connected from the next client.
After disconnecting one client, the TCP stack calls the user callback
function again. This time with error code SO_CONNECTION_CLOSED (or
SO_CONNECTION_RESET ). Call 'close_parallel_echo_server()' to decrease
the server list and free all associated memory.
@cond Software License Agreement
Copyright (C) 2001-2019 D.SignT GmbH & Co. KG - http://www.dsignt.de
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
Neither the name of D.SignT GmbH & Co. KG nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
Disclaimer
THIS SOFTWARE IS PROVIDED BY D.SIGNT GMBH & CO. KG "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL D.SIGNT GMBH & CO. KG BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@endcond
*******************************************************************************/
/*******************************************************************************
include stdtypes.h to avoid data type mismatch
*******************************************************************************/
/*******************************************************************************
include Runtime Source
*******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>
#include <time.h>
#include <string.h>
/*******************************************************************************
network support functions
*******************************************************************************/
#include <Libs/Netlib/net.h> /* D.Module network support */
#include <Libs/Netlib/pserver.h> /* concurrent server support */
/*******************************************************************************
board specific functions
*******************************************************************************/
#include <BoardSupport/inc/BoardSpecific.h> /* board support functions */
/*******************************************************************************
common support functions
*******************************************************************************/
#include <Common/Common.h> /* on exit function */
#include <Common/uartio.h> /* UART support */
#include <Common/timer.h> /* timer setting */
#include <Common/CPrintf.h> /* CPrintf defines */
/*******************************************************************************
network configuration
*******************************************************************************/
#include <BoardSupport/config/netconfig.c> /* network configuration */
#ifdef __cplusplus
extern "C" {
#endif /* !__cplusplus */
/*******************************************************************************
local prototypes
*******************************************************************************/
#pragma CODE_SECTION(tcp_echo , ".commontext")
int32_t tcp_echo (SOCKET *so, void *data, uint32_t len, uint32_t ec);
#pragma CODE_SECTION(close_parallel_echo_server , ".commontext")
int close_parallel_echo_server (SOCKET *so);
#pragma CODE_SECTION(init_parallel_echo_server , ".commontext")
int init_parallel_echo_server(SOCKET *so);
#ifdef __cplusplus
} // extern "C"
#endif
/*******************************************************************************
* *
* DEFINES *
* *
*******************************************************************************/
#define _ECHO_RECEIVE_BUFFER 1460L
/*******************************************************************************
define different states for server state machine
*******************************************************************************/
#define _ECHO_LISTENING 0
#define _ECHO_ESTABLISHED 1
/*******************************************************************************
echoserv_type: used for information about current connection and protocol
specific data.
*******************************************************************************/
typedef struct _echoserv
{
SOCKET *control; // connected socket
char *control_buffer; // buffer for incoming data
int len; // received length
/*******************************************************************************
* *
* GLOBALS *
* *
*******************************************************************************/
/*******************************************************************************
program name
*******************************************************************************/
char *program_name = "pserver";
/*******************************************************************************
head of double linked list of concurrent servers
*******************************************************************************/
_PARALLEL_SERVER *_ECHO_SERVER_HEAD = NULL;
/*******************************************************************************
a pointer to double linked list of concurrent servers
*******************************************************************************/
_PARALLEL_SERVER *echo_pserver = NULL;
/*******************************************************************************
for statistical purpose
*******************************************************************************/
unsigned int echo_socket_counter = 0;
/*******************************************************************************
* *
* FUNCTIONS *
* *
*******************************************************************************/
/*******************************************************************************
@brief This function is called each time new data is received or the
error status has changed (MSB set in error code)
@param so - socket
@param data - pointer to received data
@param len - received data length
@param ec - error code
@return SOCKET_CB_OK - if message processed
@return SOCKET_CB_CLOSED - if socket was closed
*******************************************************************************/
int32_t tcp_echo (SOCKET *so, void *data, uint32_t len, uint32_t ec)
{
/***************************************************************************
it's safe to use ec unmasked, because the event flag (MSB) is reset before
this callback function is called
***************************************************************************/
switch (ec)
{
/*******************************************************************
send echo
*******************************************************************/
net_send (so, data, (uint16_t)len);
break;
/*******************************************************************
get a new listening server
*******************************************************************/
{
/***************************************************************
print error code
***************************************************************/
CPuts ("\r ");
net_print_error (ec, CPrintf);
CPrintf (" %d concurrent sockets\r\n", echo_socket_counter);
}
else
{
/***************************************************************
print error code
***************************************************************/
CPuts ("\r Out of memory\r\n");
shutdown (so, 100L);
}
break;
/*******************************************************************
close the server
*******************************************************************/
/*******************************************************************
print error code
*******************************************************************/
CPuts ("\r ");
net_print_error (ec, CPrintf);
CPrintf (" %d concurrent sockets\r\n", echo_socket_counter);
/*******************************************************************
return -1 signals socket is invalid
*******************************************************************/
return (SOCKET_CB_CLOSED);
default:
/*******************************************************************
else print error code
*******************************************************************/
CPuts ("\r ");
net_print_error (ec, CPrintf);
break;
}
/***************************************************************************
return true, if message processed
***************************************************************************/
return (SOCKET_CB_OK);
}
/*******************************************************************************
@brief Maintain parallel server
@param so - socket to close
@return TRUE
*******************************************************************************/
{
/***************************************************************************
Locals
***************************************************************************/
_PARALLEL_SERVER *echo_pserver = NULL;
echoserv_type *echo_info; // used for protocol information for
// each connection
/***************************************************************************
get control information for current server
***************************************************************************/
echo_pserver = get_current_pserver (so, &_ECHO_SERVER_HEAD);
echo_info = (echoserv_type *)(echo_pserver-> info);
echo_pserver-> close = TRUE;
if ( echo_pserver-> state > _ECHO_LISTENING )
{
/***********************************************************************
connection closed or terminated:
free all protocol specific buffers
***********************************************************************/
if ( echo_info-> control_buffer != NULL )
{
free (echo_info-> control_buffer);
echo_info-> control_buffer = NULL;
free (echo_info);
echo_pserver-> info = NULL;
}
/***********************************************************************
use close() method to delete the terminated or closed server
***********************************************************************/
echo_pserver = close_pserver (echo_pserver, &_ECHO_SERVER_HEAD);
/***********************************************************************
correct current connection counter
***********************************************************************/
}
/***************************************************************************
return true, if message processed
***************************************************************************/
return (1);
}
/*******************************************************************************
@brief Generate a new listening server with individual protocol information
@param socket
@return FALSE - out of memory
@return TRUE - success
*******************************************************************************/
{
/***************************************************************************
Locals
***************************************************************************/
_PARALLEL_SERVER *pserver = NULL;
echoserv_type *echo_info; // used for protocol information for
// each connection
/***************************************************************************
add a new pserver to server list
first parameter: Port to listen on
second parameter: user defined head of server list
***************************************************************************/
pserver = add_pserver (5031, &_ECHO_SERVER_HEAD);
if ( pserver == NULL )
{
/***********************************************************************
out of memory
***********************************************************************/
return (FALSE);
}
/***************************************************************************
create a protocol info and link it to the parallel server
echoserv_type is a user defined structure type containing all
information needed for protocol handling
***************************************************************************/
pserver-> info = (echoserv_type *) malloc ( sizeof( echoserv_type));
if ( pserver-> info == NULL )
{
/***********************************************************************
out of memory, use close() method to delete the listening server
***********************************************************************/
return (FALSE);
}
/***************************************************************************
initialize protocol specific information
***************************************************************************/
echo_info = (echoserv_type *)(pserver-> info);
echo_info-> control = INVALID_SOCKET;
/***************************************************************************
get buffer space for control data
***************************************************************************/
echo_info-> control_buffer = (char *) malloc (_ECHO_RECEIVE_BUFFER * sizeof (char));
if ( echo_info-> control_buffer == NULL )
{
/***********************************************************************
out of memory, use close() method to delete the listening server
***********************************************************************/
free (echo_info);
pserver = close_pserver (pserver, &_ECHO_SERVER_HEAD);
return (FALSE); // out of memory
} // if
/***************************************************************************
define callback function for received TCP packets
***************************************************************************/
socket_define_callback (pserver-> server, /* socket */
tcp_echo, /* call back function */
echo_info-> control_buffer, /* data buffer */
_ECHO_RECEIVE_BUFFER); /* data buffer size */
/***************************************************************************
count the current sockets
***************************************************************************/
if (so != INVALID_SOCKET)
{
/***********************************************************************
switch to established state
***********************************************************************/
pserver-> state = _ECHO_ESTABLISHED;
pserver-> close = FALSE;
}
return (TRUE);
}
/*******************************************************************************
@brief Main application
@param -
@return never
*******************************************************************************/
#pragma CODE_SECTION(main , ".commontext");
int main ( void )
{
/***************************************************************************
locals
***************************************************************************/
int main_loop = 1; /* main loop switch, set to 0 to exit */
timeval stamp1, stamp2, delta; /* used to determine startup time */
/***************************************************************************
initialize application (e.g. timer clocks, PLL settings, EMIF etc.)
(ref. \Common\Common.c)
***************************************************************************/
/***************************************************************************
select output device for CPrintf (ref. \Common\cprintf.c)
possible settings:
CPRINTF_UART_OUTPUT -> output to UART
CPRINTF_CCS_OUTPUT -> output to CCS
CPRINTF_UART_OUTPUT | CPRINTF_CCS_OUTPUT -> output to UART and CCS
***************************************************************************/
/***************************************************************************
print a start up message
***************************************************************************/
/**************************************************************************/
// CPrintfProgress (" Heap check ");
// at least 0x2000 bytes required for this app
/**************************************************************************/
// CPrintfProgressSuccess();
/**************************************************************************/
CPrintfProgress (" Setup system time ");
// 1 milli seconds resolution
/**************************************************************************/
CPrintf (" *** timer %d mapped to CPU int %d ***\r\n",
/**************************************************************************/
CPrintfProgress (" Enable interrupts ");
/**************************************************************************/
/**************************************************************************/
CPrintfProgress (" Start system timer ");
/**************************************************************************/
CPrintf (" *** timer %d running at %"PRId32" Hz ***\r\n", SystemTimerDev, RES_SECONDS/GetSystemTimerRes());
/***************************************************************************
measure network initialization time
***************************************************************************/
stamp1 = GetTimeStamp();
/**************************************************************************/
CPrintfProgress (" Initialize network ");
/**************************************************************************/
InitializeNetwork ( 64); // 64 bytes for ping
/***************************************************************************
the first call to init_parallel_echo_server() creates a listening socket
***************************************************************************/
stamp2 = GetTimeStamp();
tv_interval (&delta, &stamp1, &stamp2);
CPuts (" network startup time [sec]: ");
"%"PRId32".%03"PRId32"\r\n"
delta.tv_sec,
delta.tv_usec/1000);
/***************************************************************************
loop forever
***************************************************************************/
CPrintf (" %s running on address %s\r\n", program_name, eth.ip);
CPuts ("\r\n Entering main loop ...\r\n");
/***************************************************************************
main program loop: set main_loop to 0 to exit loop
***************************************************************************/
while ( main_loop )
{
/***********************************************************************
process net_isq()
***********************************************************************/
net_isq (); // process ISQ
/***********************************************************************
monitor link status
***********************************************************************/
/***********************************************************************
try to detect IP assignment
if DHCP is used, the assigned IP address may change
***********************************************************************/
/***********************************************************************
show that the program is running, perform symbol animation
***********************************************************************/
}
/***************************************************************************
exit program, shut down peripherals
***************************************************************************/
return (0);
}