2 * FreeRTOS+TCP V2.0.1
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
29 /* Standard includes. */
\r
34 /* FreeRTOS includes. */
\r
35 #include "FreeRTOS.h"
\r
38 /* FreeRTOS+TCP includes. */
\r
39 #include "FreeRTOS_IP.h"
\r
40 #include "FreeRTOS_Sockets.h"
\r
41 #include "FreeRTOS_TCP_server.h"
\r
42 #include "FreeRTOS_server_private.h"
\r
44 /* Remove the entire file if TCP is not being used. */
\r
45 #if( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) )
\r
47 #if !defined( ARRAY_SIZE )
\r
48 #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )
\r
52 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket );
\r
53 static char *strnew( const char *pcString );
\r
54 /* Remove slashes at the end of a path. */
\r
55 static void prvRemoveSlash( char *pcDir );
\r
57 TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount )
\r
59 TCPServer_t *pxServer;
\r
60 SocketSet_t xSocketSet;
\r
62 /* Create a new server.
\r
63 xPort / xPortAlt : Make the service available on 1 or 2 public port numbers. */
\r
64 xSocketSet = FreeRTOS_CreateSocketSet();
\r
66 if( xSocketSet != NULL )
\r
70 xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] );
\r
72 pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize );
\r
73 if( pxServer != NULL )
\r
75 struct freertos_sockaddr xAddress;
\r
76 BaseType_t xNoTimeout = 0;
\r
79 memset( pxServer, '\0', xSize );
\r
80 pxServer->xServerCount = xCount;
\r
81 pxServer->xSocketSet = xSocketSet;
\r
83 for( xIndex = 0; xIndex < xCount; xIndex++ )
\r
85 BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber;
\r
87 if( xPortNumber > 0 )
\r
91 xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
\r
92 FreeRTOS_printf( ( "TCP socket on port %d\n", ( int )xPortNumber ) );
\r
94 if( xSocket != FREERTOS_NO_SOCKET )
\r
96 xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used
\r
97 xAddress.sin_port = FreeRTOS_htons( xPortNumber );
\r
99 FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );
\r
100 FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog );
\r
102 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );
\r
103 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );
\r
105 #if( ipconfigHTTP_RX_BUFSIZE > 0 )
\r
107 if( pxConfigs[ xIndex ].eType == eSERVER_HTTP )
\r
109 WinProperties_t xWinProps;
\r
111 memset( &xWinProps, '\0', sizeof( xWinProps ) );
\r
112 /* The parent socket itself won't get connected. The properties below
\r
113 will be inherited by each new child socket. */
\r
114 xWinProps.lTxBufSize = ipconfigHTTP_TX_BUFSIZE;
\r
115 xWinProps.lTxWinSize = ipconfigHTTP_TX_WINSIZE;
\r
116 xWinProps.lRxBufSize = ipconfigHTTP_RX_BUFSIZE;
\r
117 xWinProps.lRxWinSize = ipconfigHTTP_RX_WINSIZE;
\r
119 /* Set the window and buffer sizes. */
\r
120 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) );
\r
125 FreeRTOS_FD_SET( xSocket, xSocketSet, eSELECT_READ|eSELECT_EXCEPT );
\r
126 pxServer->xServers[ xIndex ].xSocket = xSocket;
\r
127 pxServer->xServers[ xIndex ].eType = pxConfigs[ xIndex ].eType;
\r
128 pxServer->xServers[ xIndex ].pcRootDir = strnew( pxConfigs[ xIndex ].pcRootDir );
\r
129 prvRemoveSlash( ( char * ) pxServer->xServers[ xIndex ].pcRootDir );
\r
136 /* Could not allocate the server, delete the socket set */
\r
137 FreeRTOS_DeleteSocketSet( xSocketSet );
\r
142 /* Could not create a socket set, return NULL */
\r
148 /*-----------------------------------------------------------*/
\r
150 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket )
\r
152 TCPClient_t *pxClient = NULL;
\r
153 BaseType_t xSize = 0;
\r
154 FTCPWorkFunction fWorkFunc = NULL;
\r
155 FTCPDeleteFunction fDeleteFunc = NULL;
\r
156 const char *pcType = "Unknown";
\r
158 /*_RB_ Can the work and delete functions be part of the xSERVER_CONFIG structure
\r
159 becomes generic, with no pre-processing required? */
\r
160 #if( ipconfigUSE_HTTP != 0 )
\r
162 if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP )
\r
164 xSize = sizeof( HTTPClient_t );
\r
165 fWorkFunc = xHTTPClientWork;
\r
166 fDeleteFunc = vHTTPClientDelete;
\r
170 #endif /* ipconfigUSE_HTTP != 0 */
\r
172 #if( ipconfigUSE_FTP != 0 )
\r
174 if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP )
\r
176 xSize = sizeof( FTPClient_t );
\r
177 fWorkFunc = xFTPClientWork;
\r
178 fDeleteFunc = vFTPClientDelete;
\r
182 #endif /* ipconfigUSE_FTP != 0 */
\r
184 /* Malloc enough space for a new HTTP-client */
\r
187 pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize );
\r
190 if( pxClient != NULL )
\r
192 memset( pxClient, '\0', xSize );
\r
194 /* Put the new client in front of the list. */
\r
195 pxClient->eType = pxServer->xServers[ xIndex ].eType;
\r
196 pxClient->pcRootDir = pxServer->xServers[ xIndex ].pcRootDir;
\r
197 pxClient->pxParent = pxServer;
\r
198 pxClient->xSocket = xNexSocket;
\r
199 pxClient->pxNextClient = pxServer->pxClients;
\r
200 pxClient->fWorkFunction = fWorkFunc;
\r
201 pxClient->fDeleteFunction = fDeleteFunc;
\r
202 pxServer->pxClients = pxClient;
\r
204 FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT );
\r
209 FreeRTOS_closesocket( xNexSocket );
\r
212 struct freertos_sockaddr xRemoteAddress;
\r
213 FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress );
\r
214 FreeRTOS_printf( ( "TPC-server: new %s client %xip\n", pcType, (unsigned)FreeRTOS_ntohl( xRemoteAddress.sin_addr ) ) );
\r
217 /* Remove compiler warnings in case FreeRTOS_printf() is not used. */
\r
220 /*-----------------------------------------------------------*/
\r
222 void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime )
\r
224 TCPClient_t **ppxClient;
\r
228 /* Let the server do one working cycle */
\r
229 xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime );
\r
233 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
\r
235 struct freertos_sockaddr xAddress;
\r
236 Socket_t xNexSocket;
\r
237 socklen_t xSocketLength;
\r
239 if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET )
\r
244 xSocketLength = sizeof( xAddress );
\r
245 xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength);
\r
247 if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) )
\r
249 prvReceiveNewClient( pxServer, xIndex, xNexSocket );
\r
254 ppxClient = &pxServer->pxClients;
\r
256 while( ( * ppxClient ) != NULL )
\r
258 TCPClient_t *pxThis = *ppxClient;
\r
261 xRc = pxThis->fWorkFunction( pxThis );
\r
265 *ppxClient = pxThis->pxNextClient;
\r
266 /* Close handles, resources */
\r
267 pxThis->fDeleteFunction( pxThis );
\r
268 /* Free the space */
\r
269 vPortFreeLarge( pxThis );
\r
273 ppxClient = &( pxThis->pxNextClient );
\r
277 /*-----------------------------------------------------------*/
\r
279 static char *strnew( const char *pcString )
\r
281 BaseType_t xLength;
\r
284 xLength = strlen( pcString ) + 1;
\r
285 pxBuffer = ( char * ) pvPortMalloc( xLength );
\r
286 if( pxBuffer != NULL )
\r
288 memcpy( pxBuffer, pcString, xLength );
\r
293 /*-----------------------------------------------------------*/
\r
295 static void prvRemoveSlash( char *pcDir )
\r
297 BaseType_t xLength = strlen( pcDir );
\r
299 while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) )
\r
301 pcDir[ --xLength ] = '\0';
\r
304 /*-----------------------------------------------------------*/
\r
306 #if( ipconfigSUPPORT_SIGNALS != 0 )
\r
308 /* FreeRTOS_TCPServerWork() calls select().
\r
309 The two functions below provide a possibility to interrupt
\r
310 the call to select(). After the interruption, resume
\r
311 by calling FreeRTOS_TCPServerWork() again. */
\r
312 BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer )
\r
315 BaseType_t xResult = pdFALSE;
\r
316 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
\r
318 if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )
\r
320 FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket );
\r
329 #endif /* ipconfigSUPPORT_SIGNALS */
\r
330 /*-----------------------------------------------------------*/
\r
332 #if( ipconfigSUPPORT_SIGNALS != 0 )
\r
334 /* Same as above: this function may be called from an ISR,
\r
335 for instance a GPIO interrupt. */
\r
336 BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken )
\r
339 BaseType_t xResult = pdFALSE;
\r
340 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )
\r
342 if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )
\r
344 FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken );
\r
352 #endif /* ipconfigSUPPORT_SIGNALS */
\r
353 /*-----------------------------------------------------------*/
\r
355 #endif /* ( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) */
\r