2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
59 /* Standard includes. */
\r
64 /* FreeRTOS includes. */
\r
65 #include "FreeRTOS.h"
\r
68 /* FreeRTOS+TCP includes. */
\r
69 #include "FreeRTOS_IP.h"
\r
70 #include "FreeRTOS_Sockets.h"
\r
71 #include "FreeRTOS_TCP_server.h"
\r
72 #include "FreeRTOS_server_private.h"
\r
74 /* Remove the entire file if TCP is not being used. */
\r
75 #if( ipconfigUSE_TCP == 1 )
\r
77 #if !defined( ARRAY_SIZE )
\r
78 #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )
\r
82 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket );
\r
83 static char *strnew( const char *pcString );
\r
84 /* Remove slashes at the end of a path. */
\r
85 static void prvRemoveSlash( char *pcDir );
\r
87 TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount )
\r
89 TCPServer_t *pxServer;
\r
90 SocketSet_t xSocketSet;
\r
92 /* Create a new server.
\r
93 xPort / xPortAlt : Make the service available on 1 or 2 public port numbers. */
\r
94 xSocketSet = FreeRTOS_CreateSocketSet();
\r
96 if( xSocketSet != NULL )
\r
100 xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] );
\r
102 pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize );
\r
103 if( pxServer != NULL )
\r
105 struct freertos_sockaddr xAddress;
\r
106 BaseType_t xNoTimeout = 0;
\r
109 memset( pxServer, '\0', xSize );
\r
110 pxServer->xServerCount = xCount;
\r
111 pxServer->xSocketSet = xSocketSet;
\r
113 for( xIndex = 0; xIndex < xCount; xIndex++ )
\r
115 BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber;
\r
117 if( xPortNumber > 0 )
\r
121 xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
122 FreeRTOS_printf( ( "TCP socket on port %d\n", ( int )xPortNumber ) );
\r
124 if( xSocket != FREERTOS_NO_SOCKET )
\r
126 xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used
\r
127 xAddress.sin_port = FreeRTOS_htons( xPortNumber );
\r
129 FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
\r
130 FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog );
\r
132 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );
\r
133 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );
\r
135 #if( ipconfigHTTP_RX_BUFSIZE > 0 )
\r
137 if( pxConfigs[ xIndex ].eType == eSERVER_HTTP )
\r
139 WinProperties_t xWinProps;
\r
141 memset( &xWinProps, '\0', sizeof( xWinProps ) );
\r
142 /* The parent socket itself won't get connected. The properties below
\r
143 will be inherited by each new child socket. */
\r
144 xWinProps.lTxBufSize = ipconfigHTTP_TX_BUFSIZE;
\r
145 xWinProps.lTxWinSize = ipconfigHTTP_TX_WINSIZE;
\r
146 xWinProps.lRxBufSize = ipconfigHTTP_RX_BUFSIZE;
\r
147 xWinProps.lRxWinSize = ipconfigHTTP_RX_WINSIZE;
\r
149 /* Set the window and buffer sizes. */
\r
150 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) );
\r
155 FreeRTOS_FD_SET( xSocket, xSocketSet, eSELECT_READ|eSELECT_EXCEPT );
\r
156 pxServer->xServers[ xIndex ].xSocket = xSocket;
\r
157 pxServer->xServers[ xIndex ].eType = pxConfigs[ xIndex ].eType;
\r
158 pxServer->xServers[ xIndex ].pcRootDir = strnew( pxConfigs[ xIndex ].pcRootDir );
\r
159 prvRemoveSlash( ( char * ) pxServer->xServers[ xIndex ].pcRootDir );
\r
166 /* Could not allocate the server, delete the socket set */
\r
167 FreeRTOS_DeleteSocketSet( xSocketSet );
\r
172 /* Could not create a socket set, return NULL */
\r
178 /*-----------------------------------------------------------*/
\r
180 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket )
\r
182 TCPClient_t *pxClient = NULL;
\r
183 BaseType_t xSize = 0;
\r
184 FTCPWorkFunction fWorkFunc = NULL;
\r
185 FTCPDeleteFunction fDeleteFunc = NULL;
\r
186 const char *pcType = "Unknown";
\r
188 /*_RB_ Can the work and delete functions be part of the xSERVER_CONFIG structure
\r
189 becomes generic, with no pre-processing required? */
\r
190 #if( ipconfigUSE_HTTP != 0 )
\r
192 if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP )
\r
194 xSize = sizeof( HTTPClient_t );
\r
195 fWorkFunc = xHTTPClientWork;
\r
196 fDeleteFunc = vHTTPClientDelete;
\r
200 #endif /* ipconfigUSE_HTTP != 0 */
\r
202 #if( ipconfigUSE_FTP != 0 )
\r
204 if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP )
\r
206 xSize = sizeof( FTPClient_t );
\r
207 fWorkFunc = xFTPClientWork;
\r
208 fDeleteFunc = vFTPClientDelete;
\r
212 #endif /* ipconfigUSE_FTP != 0 */
\r
214 /* Malloc enough space for a new HTTP-client */
\r
217 pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize );
\r
220 if( pxClient != NULL )
\r
222 memset( pxClient, '\0', xSize );
\r
224 /* Put the new client in front of the list. */
\r
225 pxClient->eType = pxServer->xServers[ xIndex ].eType;
\r
226 pxClient->pcRootDir = pxServer->xServers[ xIndex ].pcRootDir;
\r
227 pxClient->pxParent = pxServer;
\r
228 pxClient->xSocket = xNexSocket;
\r
229 pxClient->pxNextClient = pxServer->pxClients;
\r
230 pxClient->fWorkFunction = fWorkFunc;
\r
231 pxClient->fDeleteFunction = fDeleteFunc;
\r
232 pxServer->pxClients = pxClient;
\r
234 FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT );
\r
239 FreeRTOS_closesocket( xNexSocket );
\r
242 FreeRTOS_printf( ( "TPC-server: new %s client\n", pcType ) );
\r
244 /* Remove compiler warnings in case FreeRTOS_printf() is not used. */
\r
247 /*-----------------------------------------------------------*/
\r
249 void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime )
\r
251 TCPClient_t **ppxClient;
\r
255 /* Let the server do one working cycle */
\r
256 xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime );
\r
260 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
\r
262 struct freertos_sockaddr xAddress;
\r
263 Socket_t xNexSocket;
\r
264 socklen_t xSocketLength;
\r
266 if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET )
\r
271 xSocketLength = sizeof( xAddress );
\r
272 xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength);
\r
274 if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) )
\r
276 prvReceiveNewClient( pxServer, xIndex, xNexSocket );
\r
281 ppxClient = &pxServer->pxClients;
\r
283 while( ( * ppxClient ) != NULL )
\r
285 TCPClient_t *pxThis = *ppxClient;
\r
288 xRc = pxThis->fWorkFunction( pxThis );
\r
292 *ppxClient = pxThis->pxNextClient;
\r
293 /* Close handles, resources */
\r
294 pxThis->fDeleteFunction( pxThis );
\r
295 /* Free the space */
\r
296 vPortFreeLarge( pxThis );
\r
300 ppxClient = &( pxThis->pxNextClient );
\r
304 /*-----------------------------------------------------------*/
\r
306 static char *strnew( const char *pcString )
\r
308 BaseType_t xLength;
\r
311 xLength = strlen( pcString ) + 1;
\r
312 pxBuffer = ( char * ) pvPortMalloc( xLength );
\r
313 if( pxBuffer != NULL )
\r
315 memcpy( pxBuffer, pcString, xLength );
\r
320 /*-----------------------------------------------------------*/
\r
322 static void prvRemoveSlash( char *pcDir )
\r
324 BaseType_t xLength = strlen( pcDir );
\r
326 while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) )
\r
328 pcDir[ --xLength ] = '\0';
\r
331 /*-----------------------------------------------------------*/
\r
333 #if( ipconfigSUPPORT_SIGNALS != 0 )
\r
335 /* FreeRTOS_TCPServerWork() calls select().
\r
336 The two functions below provide a possibility to interrupt
\r
337 the call to select(). After the interruption, resume
\r
338 by calling FreeRTOS_TCPServerWork() again. */
\r
339 BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer )
\r
342 BaseType_t xResult = pdFALSE;
\r
343 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
\r
345 if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )
\r
347 FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket );
\r
356 #endif /* ipconfigSUPPORT_SIGNALS */
\r
357 /*-----------------------------------------------------------*/
\r
359 #if( ipconfigSUPPORT_SIGNALS != 0 )
\r
361 /* Same as above: this function may be called from an ISR,
\r
362 for instance a GPIO interrupt. */
\r
363 BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken )
\r
366 BaseType_t xResult = pdFALSE;
\r
367 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
\r
369 if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )
\r
371 FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken );
\r
379 #endif /* ipconfigSUPPORT_SIGNALS */
\r
380 /*-----------------------------------------------------------*/
\r
382 #endif /* ipconfigUSE_TCP != 1 */
\r