]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c
Roll up the minor changes checked into svn since V10.0.0 into new V10.0.1 ready for...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / protocols / Common / FreeRTOS_TCP_server.c
1 /*\r
2  * FreeRTOS+TCP V2.0.1\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://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 \r
29 /* Standard includes. */\r
30 #include <stdint.h>\r
31 #include <stdio.h>\r
32 #include <stdlib.h>\r
33 \r
34 /* FreeRTOS includes. */\r
35 #include "FreeRTOS.h"\r
36 #include "task.h"\r
37 \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
43 \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
46 \r
47 #if !defined( ARRAY_SIZE )\r
48         #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )\r
49 #endif\r
50 \r
51 \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
56 \r
57 TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount )\r
58 {\r
59 TCPServer_t *pxServer;\r
60 SocketSet_t xSocketSet;\r
61 \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
65 \r
66         if( xSocketSet != NULL )\r
67         {\r
68         BaseType_t xSize;\r
69 \r
70                 xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] );\r
71 \r
72                 pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize );\r
73                 if( pxServer != NULL )\r
74                 {\r
75                 struct freertos_sockaddr xAddress;\r
76                 BaseType_t xNoTimeout = 0;\r
77                 BaseType_t xIndex;\r
78 \r
79                         memset( pxServer, '\0', xSize );\r
80                         pxServer->xServerCount = xCount;\r
81                         pxServer->xSocketSet = xSocketSet;\r
82 \r
83                         for( xIndex = 0; xIndex < xCount; xIndex++ )\r
84                         {\r
85                         BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber;\r
86 \r
87                                 if( xPortNumber > 0 )\r
88                                 {\r
89                                 Socket_t xSocket;\r
90 \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
93 \r
94                                         if( xSocket != FREERTOS_NO_SOCKET )\r
95                                         {\r
96                                                 xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used\r
97                                                 xAddress.sin_port = FreeRTOS_htons( xPortNumber );\r
98 \r
99                                                 FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );\r
100                                                 FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog );\r
101 \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
104 \r
105                                                 #if( ipconfigHTTP_RX_BUFSIZE > 0 )\r
106                                                 {\r
107                                                         if( pxConfigs[ xIndex ].eType == eSERVER_HTTP )\r
108                                                         {\r
109                                                         WinProperties_t xWinProps;\r
110 \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
118 \r
119                                                                 /* Set the window and buffer sizes. */\r
120                                                                 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps,     sizeof( xWinProps ) );\r
121                                                         }\r
122                                                 }\r
123                                                 #endif\r
124 \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
130                                         }\r
131                                 }\r
132                         }\r
133                 }\r
134                 else\r
135                 {\r
136                         /* Could not allocate the server, delete the socket set */\r
137                         FreeRTOS_DeleteSocketSet( xSocketSet );\r
138                 }\r
139         }\r
140         else\r
141         {\r
142                 /* Could not create a socket set, return NULL */\r
143                 pxServer = NULL;\r
144         }\r
145 \r
146         return pxServer;\r
147 }\r
148 /*-----------------------------------------------------------*/\r
149 \r
150 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket )\r
151 {\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
157 \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
161         {\r
162                 if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP )\r
163                 {\r
164                         xSize = sizeof( HTTPClient_t );\r
165                         fWorkFunc = xHTTPClientWork;\r
166                         fDeleteFunc = vHTTPClientDelete;\r
167                         pcType = "HTTP";\r
168                 }\r
169         }\r
170         #endif /* ipconfigUSE_HTTP != 0 */\r
171 \r
172         #if( ipconfigUSE_FTP != 0 )\r
173         {\r
174                 if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP )\r
175                 {\r
176                         xSize = sizeof( FTPClient_t );\r
177                         fWorkFunc = xFTPClientWork;\r
178                         fDeleteFunc = vFTPClientDelete;\r
179                         pcType = "FTP";\r
180                 }\r
181         }\r
182         #endif /* ipconfigUSE_FTP != 0 */\r
183 \r
184         /* Malloc enough space for a new HTTP-client */\r
185         if( xSize )\r
186         {\r
187                 pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize );\r
188         }\r
189 \r
190         if( pxClient != NULL )\r
191         {\r
192                 memset( pxClient, '\0', xSize );\r
193 \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
203 \r
204                 FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT );\r
205         }\r
206         else\r
207         {\r
208                 pcType = "closed";\r
209                 FreeRTOS_closesocket( xNexSocket );\r
210         }\r
211         {\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
215         }\r
216 \r
217         /* Remove compiler warnings in case FreeRTOS_printf() is not used. */\r
218         ( void ) pcType;\r
219 }\r
220 /*-----------------------------------------------------------*/\r
221 \r
222 void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime )\r
223 {\r
224 TCPClient_t **ppxClient;\r
225 BaseType_t xIndex;\r
226 BaseType_t xRc;\r
227 \r
228         /* Let the server do one working cycle */\r
229         xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime );\r
230 \r
231         if( xRc != 0 )\r
232         {\r
233                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
234                 {\r
235                 struct freertos_sockaddr xAddress;\r
236                 Socket_t xNexSocket;\r
237                 socklen_t xSocketLength;\r
238 \r
239                         if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET )\r
240                         {\r
241                                 continue;\r
242                         }\r
243 \r
244                         xSocketLength = sizeof( xAddress );\r
245                         xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength);\r
246 \r
247                         if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) )\r
248                         {\r
249                                 prvReceiveNewClient( pxServer, xIndex, xNexSocket );\r
250                         }\r
251                 }\r
252         }\r
253 \r
254         ppxClient = &pxServer->pxClients;\r
255 \r
256         while( ( * ppxClient ) != NULL )\r
257         {\r
258         TCPClient_t *pxThis = *ppxClient;\r
259 \r
260                 /* Almost C++ */\r
261                 xRc = pxThis->fWorkFunction( pxThis );\r
262 \r
263                 if (xRc < 0 )\r
264                 {\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
270                 }\r
271                 else\r
272                 {\r
273                         ppxClient = &( pxThis->pxNextClient );\r
274                 }\r
275         }\r
276 }\r
277 /*-----------------------------------------------------------*/\r
278 \r
279 static char *strnew( const char *pcString )\r
280 {\r
281 BaseType_t xLength;\r
282 char *pxBuffer;\r
283 \r
284         xLength = strlen( pcString ) + 1;\r
285         pxBuffer = ( char * ) pvPortMalloc( xLength );\r
286         if( pxBuffer != NULL )\r
287         {\r
288                 memcpy( pxBuffer, pcString, xLength );\r
289         }\r
290 \r
291         return pxBuffer;\r
292 }\r
293 /*-----------------------------------------------------------*/\r
294 \r
295 static void prvRemoveSlash( char *pcDir )\r
296 {\r
297 BaseType_t xLength = strlen( pcDir );\r
298 \r
299         while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) )\r
300         {\r
301                 pcDir[ --xLength ] = '\0';\r
302         }\r
303 }\r
304 /*-----------------------------------------------------------*/\r
305 \r
306 #if( ipconfigSUPPORT_SIGNALS != 0 )\r
307 \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
313         {\r
314         BaseType_t xIndex;\r
315         BaseType_t xResult = pdFALSE;\r
316                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
317                 {\r
318                         if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )\r
319                         {\r
320                                 FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket );\r
321                                 xResult = pdTRUE;\r
322                                 break;\r
323                         }\r
324                 }\r
325 \r
326                 return xResult;\r
327         }\r
328 \r
329 #endif /* ipconfigSUPPORT_SIGNALS */\r
330 /*-----------------------------------------------------------*/\r
331 \r
332 #if( ipconfigSUPPORT_SIGNALS != 0 )\r
333 \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
337         {\r
338         BaseType_t xIndex;\r
339         BaseType_t xResult = pdFALSE;\r
340                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
341                 {\r
342                         if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )\r
343                         {\r
344                                 FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken );\r
345                                 xResult = pdTRUE;\r
346                                 break;\r
347                         }\r
348                 }\r
349 \r
350                 return xResult;\r
351         }\r
352 #endif /* ipconfigSUPPORT_SIGNALS */\r
353 /*-----------------------------------------------------------*/\r
354 \r
355 #endif /* ( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) */\r