]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c
Update version numbers in preparation for a new release.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / protocols / Common / FreeRTOS_TCP_server.c
1 /*\r
2  * FreeRTOS+TCP V2.0.3\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\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
11  *\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
14  *\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
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 \r
27 /* Standard includes. */\r
28 #include <stdint.h>\r
29 #include <stdio.h>\r
30 #include <stdlib.h>\r
31 \r
32 /* FreeRTOS includes. */\r
33 #include "FreeRTOS.h"\r
34 #include "task.h"\r
35 \r
36 /* FreeRTOS+TCP includes. */\r
37 #include "FreeRTOS_IP.h"\r
38 #include "FreeRTOS_Sockets.h"\r
39 #include "FreeRTOS_TCP_server.h"\r
40 #include "FreeRTOS_server_private.h"\r
41 \r
42 /* Remove the entire file if TCP is not being used. */\r
43 #if( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) )\r
44 \r
45 #if !defined( ARRAY_SIZE )\r
46         #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )\r
47 #endif\r
48 \r
49 \r
50 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket );\r
51 static char *strnew( const char *pcString );\r
52 /* Remove slashes at the end of a path. */\r
53 static void prvRemoveSlash( char *pcDir );\r
54 \r
55 TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount )\r
56 {\r
57 TCPServer_t *pxServer;\r
58 SocketSet_t xSocketSet;\r
59 \r
60         /* Create a new server.\r
61         xPort / xPortAlt : Make the service available on 1 or 2 public port numbers. */\r
62         xSocketSet = FreeRTOS_CreateSocketSet();\r
63 \r
64         if( xSocketSet != NULL )\r
65         {\r
66         BaseType_t xSize;\r
67 \r
68                 xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] );\r
69 \r
70                 pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize );\r
71                 if( pxServer != NULL )\r
72                 {\r
73                 struct freertos_sockaddr xAddress;\r
74                 BaseType_t xNoTimeout = 0;\r
75                 BaseType_t xIndex;\r
76 \r
77                         memset( pxServer, '\0', xSize );\r
78                         pxServer->xServerCount = xCount;\r
79                         pxServer->xSocketSet = xSocketSet;\r
80 \r
81                         for( xIndex = 0; xIndex < xCount; xIndex++ )\r
82                         {\r
83                         BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber;\r
84 \r
85                                 if( xPortNumber > 0 )\r
86                                 {\r
87                                 Socket_t xSocket;\r
88 \r
89                                         xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );\r
90                                         FreeRTOS_printf( ( "TCP socket on port %d\n", ( int )xPortNumber ) );\r
91 \r
92                                         if( xSocket != FREERTOS_NO_SOCKET )\r
93                                         {\r
94                                                 xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used\r
95                                                 xAddress.sin_port = FreeRTOS_htons( xPortNumber );\r
96 \r
97                                                 FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );\r
98                                                 FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog );\r
99 \r
100                                                 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );\r
101                                                 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) );\r
102 \r
103                                                 #if( ipconfigHTTP_RX_BUFSIZE > 0 )\r
104                                                 {\r
105                                                         if( pxConfigs[ xIndex ].eType == eSERVER_HTTP )\r
106                                                         {\r
107                                                         WinProperties_t xWinProps;\r
108 \r
109                                                                 memset( &xWinProps, '\0', sizeof( xWinProps ) );\r
110                                                                 /* The parent socket itself won't get connected.  The properties below\r
111                                                                 will be inherited by each new child socket. */\r
112                                                                 xWinProps.lTxBufSize = ipconfigHTTP_TX_BUFSIZE;\r
113                                                                 xWinProps.lTxWinSize = ipconfigHTTP_TX_WINSIZE;\r
114                                                                 xWinProps.lRxBufSize = ipconfigHTTP_RX_BUFSIZE;\r
115                                                                 xWinProps.lRxWinSize = ipconfigHTTP_RX_WINSIZE;\r
116 \r
117                                                                 /* Set the window and buffer sizes. */\r
118                                                                 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps,     sizeof( xWinProps ) );\r
119                                                         }\r
120                                                 }\r
121                                                 #endif\r
122 \r
123                                                 FreeRTOS_FD_SET( xSocket, xSocketSet, eSELECT_READ|eSELECT_EXCEPT );\r
124                                                 pxServer->xServers[ xIndex ].xSocket = xSocket;\r
125                                                 pxServer->xServers[ xIndex ].eType = pxConfigs[ xIndex ].eType;\r
126                                                 pxServer->xServers[ xIndex ].pcRootDir = strnew( pxConfigs[ xIndex ].pcRootDir );\r
127                                                 prvRemoveSlash( ( char * ) pxServer->xServers[ xIndex ].pcRootDir );\r
128                                         }\r
129                                 }\r
130                         }\r
131                 }\r
132                 else\r
133                 {\r
134                         /* Could not allocate the server, delete the socket set */\r
135                         FreeRTOS_DeleteSocketSet( xSocketSet );\r
136                 }\r
137         }\r
138         else\r
139         {\r
140                 /* Could not create a socket set, return NULL */\r
141                 pxServer = NULL;\r
142         }\r
143 \r
144         return pxServer;\r
145 }\r
146 /*-----------------------------------------------------------*/\r
147 \r
148 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket )\r
149 {\r
150 TCPClient_t *pxClient = NULL;\r
151 BaseType_t xSize = 0;\r
152 FTCPWorkFunction fWorkFunc = NULL;\r
153 FTCPDeleteFunction fDeleteFunc = NULL;\r
154 const char *pcType = "Unknown";\r
155 \r
156         /*_RB_ Can the work and delete functions be part of the xSERVER_CONFIG structure\r
157         becomes generic, with no pre-processing required? */\r
158         #if( ipconfigUSE_HTTP != 0 )\r
159         {\r
160                 if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP )\r
161                 {\r
162                         xSize = sizeof( HTTPClient_t );\r
163                         fWorkFunc = xHTTPClientWork;\r
164                         fDeleteFunc = vHTTPClientDelete;\r
165                         pcType = "HTTP";\r
166                 }\r
167         }\r
168         #endif /* ipconfigUSE_HTTP != 0 */\r
169 \r
170         #if( ipconfigUSE_FTP != 0 )\r
171         {\r
172                 if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP )\r
173                 {\r
174                         xSize = sizeof( FTPClient_t );\r
175                         fWorkFunc = xFTPClientWork;\r
176                         fDeleteFunc = vFTPClientDelete;\r
177                         pcType = "FTP";\r
178                 }\r
179         }\r
180         #endif /* ipconfigUSE_FTP != 0 */\r
181 \r
182         /* Malloc enough space for a new HTTP-client */\r
183         if( xSize )\r
184         {\r
185                 pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize );\r
186         }\r
187 \r
188         if( pxClient != NULL )\r
189         {\r
190                 memset( pxClient, '\0', xSize );\r
191 \r
192                 /* Put the new client in front of the list. */\r
193                 pxClient->eType = pxServer->xServers[ xIndex ].eType;\r
194                 pxClient->pcRootDir = pxServer->xServers[ xIndex ].pcRootDir;\r
195                 pxClient->pxParent = pxServer;\r
196                 pxClient->xSocket = xNexSocket;\r
197                 pxClient->pxNextClient = pxServer->pxClients;\r
198                 pxClient->fWorkFunction = fWorkFunc;\r
199                 pxClient->fDeleteFunction = fDeleteFunc;\r
200                 pxServer->pxClients = pxClient;\r
201 \r
202                 FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT );\r
203         }\r
204         else\r
205         {\r
206                 pcType = "closed";\r
207                 FreeRTOS_closesocket( xNexSocket );\r
208         }\r
209         {\r
210         struct freertos_sockaddr xRemoteAddress;\r
211                 FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress );\r
212                 FreeRTOS_printf( ( "TPC-server: new %s client %xip\n", pcType, (unsigned)FreeRTOS_ntohl( xRemoteAddress.sin_addr ) ) );\r
213         }\r
214 \r
215         /* Remove compiler warnings in case FreeRTOS_printf() is not used. */\r
216         ( void ) pcType;\r
217 }\r
218 /*-----------------------------------------------------------*/\r
219 \r
220 void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime )\r
221 {\r
222 TCPClient_t **ppxClient;\r
223 BaseType_t xIndex;\r
224 BaseType_t xRc;\r
225 \r
226         /* Let the server do one working cycle */\r
227         xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime );\r
228 \r
229         if( xRc != 0 )\r
230         {\r
231                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
232                 {\r
233                 struct freertos_sockaddr xAddress;\r
234                 Socket_t xNexSocket;\r
235                 socklen_t xSocketLength;\r
236 \r
237                         if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET )\r
238                         {\r
239                                 continue;\r
240                         }\r
241 \r
242                         xSocketLength = sizeof( xAddress );\r
243                         xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength);\r
244 \r
245                         if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) )\r
246                         {\r
247                                 prvReceiveNewClient( pxServer, xIndex, xNexSocket );\r
248                         }\r
249                 }\r
250         }\r
251 \r
252         ppxClient = &pxServer->pxClients;\r
253 \r
254         while( ( * ppxClient ) != NULL )\r
255         {\r
256         TCPClient_t *pxThis = *ppxClient;\r
257 \r
258                 /* Almost C++ */\r
259                 xRc = pxThis->fWorkFunction( pxThis );\r
260 \r
261                 if (xRc < 0 )\r
262                 {\r
263                         *ppxClient = pxThis->pxNextClient;\r
264                         /* Close handles, resources */\r
265                         pxThis->fDeleteFunction( pxThis );\r
266                         /* Free the space */\r
267                         vPortFreeLarge( pxThis );\r
268                 }\r
269                 else\r
270                 {\r
271                         ppxClient = &( pxThis->pxNextClient );\r
272                 }\r
273         }\r
274 }\r
275 /*-----------------------------------------------------------*/\r
276 \r
277 static char *strnew( const char *pcString )\r
278 {\r
279 BaseType_t xLength;\r
280 char *pxBuffer;\r
281 \r
282         xLength = strlen( pcString ) + 1;\r
283         pxBuffer = ( char * ) pvPortMalloc( xLength );\r
284         if( pxBuffer != NULL )\r
285         {\r
286                 memcpy( pxBuffer, pcString, xLength );\r
287         }\r
288 \r
289         return pxBuffer;\r
290 }\r
291 /*-----------------------------------------------------------*/\r
292 \r
293 static void prvRemoveSlash( char *pcDir )\r
294 {\r
295 BaseType_t xLength = strlen( pcDir );\r
296 \r
297         while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) )\r
298         {\r
299                 pcDir[ --xLength ] = '\0';\r
300         }\r
301 }\r
302 /*-----------------------------------------------------------*/\r
303 \r
304 #if( ipconfigSUPPORT_SIGNALS != 0 )\r
305 \r
306         /* FreeRTOS_TCPServerWork() calls select().\r
307         The two functions below provide a possibility to interrupt\r
308         the call to select(). After the interruption, resume\r
309         by calling FreeRTOS_TCPServerWork() again. */\r
310         BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer )\r
311         {\r
312         BaseType_t xIndex;\r
313         BaseType_t xResult = pdFALSE;\r
314                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
315                 {\r
316                         if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )\r
317                         {\r
318                                 FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket );\r
319                                 xResult = pdTRUE;\r
320                                 break;\r
321                         }\r
322                 }\r
323 \r
324                 return xResult;\r
325         }\r
326 \r
327 #endif /* ipconfigSUPPORT_SIGNALS */\r
328 /*-----------------------------------------------------------*/\r
329 \r
330 #if( ipconfigSUPPORT_SIGNALS != 0 )\r
331 \r
332         /* Same as above: this function may be called from an ISR,\r
333         for instance a GPIO interrupt. */\r
334         BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken )\r
335         {\r
336         BaseType_t xIndex;\r
337         BaseType_t xResult = pdFALSE;\r
338                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
339                 {\r
340                         if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )\r
341                         {\r
342                                 FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken );\r
343                                 xResult = pdTRUE;\r
344                                 break;\r
345                         }\r
346                 }\r
347 \r
348                 return xResult;\r
349         }\r
350 #endif /* ipconfigSUPPORT_SIGNALS */\r
351 /*-----------------------------------------------------------*/\r
352 \r
353 #endif /* ( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) */\r