]> begriffs open source - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/protocols/Common/FreeRTOS_TCP_server.c
Added +TCP code to main repo.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / protocols / Common / FreeRTOS_TCP_server.c
1 /*\r
2  * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.\r
3  * Authors include Hein Tibosch and Richard Barry\r
4  *\r
5  *******************************************************************************\r
6  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
7  ***                                                                         ***\r
8  ***                                                                         ***\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
11  ***   download):                                                            ***\r
12  ***                                                                         ***\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
18  ***                                                                         ***\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
23  ***                                                                         ***\r
24  ***                                                                         ***\r
25  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
26  *******************************************************************************\r
27  *\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
31  *\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
37  * licenses follow:\r
38  *\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
42  *\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
49  *\r
50  * 1 tab == 4 spaces!\r
51  *\r
52  * http://www.FreeRTOS.org\r
53  * http://www.FreeRTOS.org/plus\r
54  * http://www.FreeRTOS.org/labs\r
55  *\r
56  */\r
57 \r
58 \r
59 /* Standard includes. */\r
60 #include <stdint.h>\r
61 #include <stdio.h>\r
62 #include <stdlib.h>\r
63 \r
64 /* FreeRTOS includes. */\r
65 #include "FreeRTOS.h"\r
66 #include "task.h"\r
67 \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
73 \r
74 /* Remove the entire file if TCP is not being used. */\r
75 #if( ipconfigUSE_TCP == 1 )\r
76 \r
77 #if !defined( ARRAY_SIZE )\r
78         #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] )\r
79 #endif\r
80 \r
81 \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
86 \r
87 TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount )\r
88 {\r
89 TCPServer_t *pxServer;\r
90 SocketSet_t xSocketSet;\r
91 \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
95 \r
96         if( xSocketSet != NULL )\r
97         {\r
98         BaseType_t xSize;\r
99 \r
100                 xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] );\r
101 \r
102                 pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize );\r
103                 if( pxServer != NULL )\r
104                 {\r
105                 struct freertos_sockaddr xAddress;\r
106                 BaseType_t xNoTimeout = 0;\r
107                 BaseType_t xIndex;\r
108 \r
109                         memset( pxServer, '\0', xSize );\r
110                         pxServer->xServerCount = xCount;\r
111                         pxServer->xSocketSet = xSocketSet;\r
112 \r
113                         for( xIndex = 0; xIndex < xCount; xIndex++ )\r
114                         {\r
115                         BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber;\r
116 \r
117                                 if( xPortNumber > 0 )\r
118                                 {\r
119                                 Socket_t xSocket;\r
120 \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
123 \r
124                                         if( xSocket != FREERTOS_NO_SOCKET )\r
125                                         {\r
126                                                 xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used\r
127                                                 xAddress.sin_port = FreeRTOS_htons( xPortNumber );\r
128 \r
129                                                 FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) );\r
130                                                 FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog );\r
131 \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
134 \r
135                                                 #if( ipconfigHTTP_RX_BUFSIZE > 0 )\r
136                                                 {\r
137                                                         if( pxConfigs[ xIndex ].eType == eSERVER_HTTP )\r
138                                                         {\r
139                                                         WinProperties_t xWinProps;\r
140 \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
148 \r
149                                                                 /* Set the window and buffer sizes. */\r
150                                                                 FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps,     sizeof( xWinProps ) );\r
151                                                         }\r
152                                                 }\r
153                                                 #endif\r
154 \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
160                                         }\r
161                                 }\r
162                         }\r
163                 }\r
164                 else\r
165                 {\r
166                         /* Could not allocate the server, delete the socket set */\r
167                         FreeRTOS_DeleteSocketSet( xSocketSet );\r
168                 }\r
169         }\r
170         else\r
171         {\r
172                 /* Could not create a socket set, return NULL */\r
173                 pxServer = NULL;\r
174         }\r
175 \r
176         return pxServer;\r
177 }\r
178 /*-----------------------------------------------------------*/\r
179 \r
180 static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket )\r
181 {\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
187 \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
191         {\r
192                 if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP )\r
193                 {\r
194                         xSize = sizeof( HTTPClient_t );\r
195                         fWorkFunc = xHTTPClientWork;\r
196                         fDeleteFunc = vHTTPClientDelete;\r
197                         pcType = "HTTP";\r
198                 }\r
199         }\r
200         #endif /* ipconfigUSE_HTTP != 0 */\r
201 \r
202         #if( ipconfigUSE_FTP != 0 )\r
203         {\r
204                 if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP )\r
205                 {\r
206                         xSize = sizeof( FTPClient_t );\r
207                         fWorkFunc = xFTPClientWork;\r
208                         fDeleteFunc = vFTPClientDelete;\r
209                         pcType = "FTP";\r
210                 }\r
211         }\r
212         #endif /* ipconfigUSE_FTP != 0 */\r
213 \r
214         /* Malloc enough space for a new HTTP-client */\r
215         if( xSize )\r
216         {\r
217                 pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize );\r
218         }\r
219 \r
220         if( pxClient != NULL )\r
221         {\r
222                 memset( pxClient, '\0', xSize );\r
223 \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
233 \r
234                 FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT );\r
235         }\r
236         else\r
237         {\r
238                 pcType = "closed";\r
239                 FreeRTOS_closesocket( xNexSocket );\r
240         }\r
241 \r
242         FreeRTOS_printf( ( "TPC-server: new %s client\n", pcType ) );\r
243 \r
244         /* Remove compiler warnings in case FreeRTOS_printf() is not used. */\r
245         ( void ) pcType;\r
246 }\r
247 /*-----------------------------------------------------------*/\r
248 \r
249 void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime )\r
250 {\r
251 TCPClient_t **ppxClient;\r
252 BaseType_t xIndex;\r
253 BaseType_t xRc;\r
254 \r
255         /* Let the server do one working cycle */\r
256         xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime );\r
257 \r
258         if( xRc != 0 )\r
259         {\r
260                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
261                 {\r
262                 struct freertos_sockaddr xAddress;\r
263                 Socket_t xNexSocket;\r
264                 socklen_t xSocketLength;\r
265 \r
266                         if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET )\r
267                         {\r
268                                 continue;\r
269                         }\r
270 \r
271                         xSocketLength = sizeof( xAddress );\r
272                         xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength);\r
273 \r
274                         if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) )\r
275                         {\r
276                                 prvReceiveNewClient( pxServer, xIndex, xNexSocket );\r
277                         }\r
278                 }\r
279         }\r
280 \r
281         ppxClient = &pxServer->pxClients;\r
282 \r
283         while( ( * ppxClient ) != NULL )\r
284         {\r
285         TCPClient_t *pxThis = *ppxClient;\r
286 \r
287                 /* Almost C++ */\r
288                 xRc = pxThis->fWorkFunction( pxThis );\r
289 \r
290                 if (xRc < 0 )\r
291                 {\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
297                 }\r
298                 else\r
299                 {\r
300                         ppxClient = &( pxThis->pxNextClient );\r
301                 }\r
302         }\r
303 }\r
304 /*-----------------------------------------------------------*/\r
305 \r
306 static char *strnew( const char *pcString )\r
307 {\r
308 BaseType_t xLength;\r
309 char *pxBuffer;\r
310 \r
311         xLength = strlen( pcString ) + 1;\r
312         pxBuffer = ( char * ) pvPortMalloc( xLength );\r
313         if( pxBuffer != NULL )\r
314         {\r
315                 memcpy( pxBuffer, pcString, xLength );\r
316         }\r
317 \r
318         return pxBuffer;\r
319 }\r
320 /*-----------------------------------------------------------*/\r
321 \r
322 static void prvRemoveSlash( char *pcDir )\r
323 {\r
324 BaseType_t xLength = strlen( pcDir );\r
325 \r
326         while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) )\r
327         {\r
328                 pcDir[ --xLength ] = '\0';\r
329         }\r
330 }\r
331 /*-----------------------------------------------------------*/\r
332 \r
333 #if( ipconfigSUPPORT_SIGNALS != 0 )\r
334 \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
340         {\r
341         BaseType_t xIndex;\r
342         BaseType_t xResult = pdFALSE;\r
343                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
344                 {\r
345                         if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )\r
346                         {\r
347                                 FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket );\r
348                                 xResult = pdTRUE;\r
349                                 break;\r
350                         }\r
351                 }\r
352 \r
353                 return xResult;\r
354         }\r
355 \r
356 #endif /* ipconfigSUPPORT_SIGNALS */\r
357 /*-----------------------------------------------------------*/\r
358 \r
359 #if( ipconfigSUPPORT_SIGNALS != 0 )\r
360 \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
364         {\r
365         BaseType_t xIndex;\r
366         BaseType_t xResult = pdFALSE;\r
367                 for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ )\r
368                 {\r
369                         if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET )\r
370                         {\r
371                                 FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken );\r
372                                 xResult = pdTRUE;\r
373                                 break;\r
374                         }\r
375                 }\r
376 \r
377                 return xResult;\r
378         }\r
379 #endif /* ipconfigSUPPORT_SIGNALS */\r
380 /*-----------------------------------------------------------*/\r
381 \r
382 #endif /* ipconfigUSE_TCP != 1 */\r