]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoSelectServer.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Demo / FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator / DemoTasks / TCPEchoSelectServer.c
1 /*\r
2     FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
12 \r
13     ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18     ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40     the FAQ page "My application does not run, what could be wrong?".  Have you\r
41     defined configASSERT()?\r
42 \r
43     http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44     embedded software for free we request you assist our global community by\r
45     participating in the support forum.\r
46 \r
47     http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48     be as productive as possible as early as possible.  Now you can receive\r
49     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50     Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 /* Standard includes. */\r
71 #include <stdint.h>\r
72 #include <stdio.h>\r
73 #include <WinSock2.h>\r
74 #include <Mswsock.h>\r
75 \r
76 /* FreeRTOS includes. */\r
77 #include "FreeRTOS.h"\r
78 #include "task.h"\r
79 #include "semphr.h"\r
80 \r
81 /* FreeRTOS+TCP includes. */\r
82 #include "FreeRTOS_IP.h"\r
83 #include "FreeRTOS_Sockets.h"\r
84 #include "FreeRTOS_char_buf.h"\r
85 \r
86 #include "SimpleTCPEchoServer.h"        /* For prvSimpleTcpServerClientTask */\r
87 \r
88 \r
89 #define tcpechoNUMBER_OF_CLIENTS                0\r
90 \r
91 void tcpWinShowEvent( BaseType_t aDoLog );\r
92 \r
93 /*\r
94  * Listens for incoming echo connections.  Creates a task to handle each\r
95  * connection.\r
96  */\r
97 static void prvConnectionListeningTask( void *pvParameters );\r
98 \r
99 /* Stores the stack size passed into vStartSimpleTCPServerTasks() so it can be\r
100 reused when the server listening task creates tasks to handle connections. */\r
101 static unsigned short usUsedStackSize = 0;\r
102 \r
103 /*-----------------------------------------------------------*/\r
104 \r
105 void vStartSelectTCPServerTasks( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority )\r
106 {\r
107 WORD wVersionRequested;\r
108 WSADATA xWSAData;\r
109 BaseType_t xClient;\r
110 //extern void prvSimpleTCPClientTask( void *pvParameters );\r
111 \r
112         /* The clients use non-blocking Winsock sockets and must therefore run at\r
113         the idle priority. */\r
114         configASSERT( uxPriority == tskIDLE_PRIORITY );\r
115 \r
116         /* Create the TCP echo server.  The echo server uses FreeRTOS+TCP through\r
117         the spoofed IP and MAC address. */\r
118         xTaskCreate( prvConnectionListeningTask, "ServerListener", usStackSize, ( void * ) ulPort, uxPriority + 1, NULL );\r
119 \r
120         /* Prepare to use WinSock library. */\r
121         wVersionRequested = MAKEWORD( 2, 2 );\r
122         configASSERT( WSAStartup( wVersionRequested, &xWSAData ) == ( WORD ) 0 );\r
123 \r
124         /* Remember the requested stack size so it can be re-used by the server\r
125         listening task when it creates tasks to handle connections. */\r
126         usUsedStackSize = usStackSize;\r
127 }\r
128 \r
129 #define SEND_BUFFER_SIZE        ( 8 * ipconfigTCP_MSS )\r
130 \r
131 typedef struct xTCP_SERVER {\r
132         Socket_t xSocket;\r
133         struct xTCP_SERVER *pxNext;\r
134         SSimpleBuf *pxSendData;\r
135         BaseType_t bHasSendRequest;\r
136 } TCPServer_t;\r
137 \r
138 static uint8_t cReceivedString[ ipconfigTCP_MSS ];\r
139 \r
140 static void prvTcpInit( TCPServer_t *pxTcpServer )\r
141 {\r
142 struct freertos_sockaddr addr;\r
143 BaseType_t xReceiveTimeOut = 0;\r
144 BaseType_t xSendTimeOut = 0;\r
145 \r
146         pxTcpServer->pxSendData = ( SSimpleBuf * )pvPortMalloc( sizeof( *pxTcpServer->pxSendData ) - sizeof( pxTcpServer->pxSendData->array ) + SEND_BUFFER_SIZE + 1 );\r
147 \r
148         configASSERT( pxTcpServer->pxSendData != NULL );\r
149         memset( pxTcpServer->pxSendData, '\0', sizeof( *pxTcpServer->pxSendData ) );\r
150         pxTcpServer->pxSendData->LENGTH = SEND_BUFFER_SIZE + 1;\r
151 \r
152         FreeRTOS_GetRemoteAddress( pxTcpServer->xSocket, &addr );\r
153         FreeRTOS_debug_printf( ( "prvTcpInit: serving %xip:%u\n",\r
154                 FreeRTOS_ntohl( addr.sin_addr ), addr.sin_port) );\r
155 \r
156         FreeRTOS_setsockopt( pxTcpServer->xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );\r
157         FreeRTOS_setsockopt( pxTcpServer->xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) );\r
158 }\r
159 \r
160 static void prvTcpClose( TCPServer_t *pxThisServer )\r
161 {\r
162         FreeRTOS_closesocket( pxThisServer->xSocket );\r
163         vPortFree( pxThisServer->pxSendData );\r
164         vPortFree( pxThisServer );\r
165 }\r
166 \r
167 static BaseType_t prvTcpSend( TCPServer_t *pxTcpServer )\r
168 {\r
169 BaseType_t lBytes, lReturned, xReturn = 0;\r
170 \r
171         lBytes = sbGet( pxTcpServer->pxSendData, 0, cReceivedString, sizeof( cReceivedString ), pdTRUE );\r
172         if( lBytes )\r
173         {\r
174                 /* Send as much as possible, non-blocking */\r
175                 lReturned = FreeRTOS_send( pxTcpServer->xSocket, cReceivedString, lBytes, 0 );\r
176                 if( lReturned > 0 )\r
177                 {\r
178                         xReturn = sbGet( pxTcpServer->pxSendData, 0, NULL, lReturned, pdFALSE );\r
179                 }\r
180         }\r
181         return xReturn;\r
182 }\r
183 \r
184 static BaseType_t prvTcpHasSendData( TCPServer_t *pxTcpServer )\r
185 {\r
186         return ( sbGetSize( pxTcpServer->pxSendData ) > 0 ) ? 1 : 0;\r
187 }\r
188 \r
189 static BaseType_t prvTcpWork( TCPServer_t *pxTcpServer )\r
190 {\r
191 BaseType_t lBytes, lReturned, lMayWrite;\r
192 \r
193         lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket );\r
194         if( lMayWrite < 0 )\r
195                 return lMayWrite;\r
196         while( lMayWrite > 0 )\r
197         {\r
198                 lReturned = prvTcpSend( pxTcpServer );\r
199                 if( lReturned < 0 )\r
200                         return lReturned;\r
201                 if( lReturned == 0 )\r
202                         break;\r
203                 lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket );\r
204                 if( lMayWrite < 0 )\r
205                         return lMayWrite;\r
206         }\r
207         for( ; ; )\r
208         {\r
209                 /* Zero out the receive array so there is NULL at the end of the string\r
210                 when it is printed out. */\r
211                 memset( cReceivedString, 0x00, sizeof( cReceivedString ) );\r
212 \r
213                 /* Receive data on the socket. */\r
214                 lBytes = FreeRTOS_recv( pxTcpServer->xSocket, cReceivedString, sizeof( cReceivedString ), 0 );\r
215                 if( lBytes <= 0 )\r
216                                 return lBytes;\r
217                 /* Return the received characters. */\r
218                 if( lMayWrite > 0 && sbGetSize( pxTcpServer->pxSendData ) == 0 )\r
219                 {\r
220                         /* The cirular buffer is empty, send the received data directly */\r
221                         lReturned = FreeRTOS_send( pxTcpServer->xSocket, cReceivedString, lBytes, 0 );\r
222                         if( lReturned < 0 )\r
223                         {\r
224                                 return -1;\r
225                         }\r
226                         if( lBytes > lReturned )\r
227                         {\r
228                                 /* Not all dta could be delivered, save them for later\r
229                                         * FD_SET( eSELECT_WRITE ) will be called */\r
230                                 sbAdd( pxTcpServer->pxSendData, 0, cReceivedString + lReturned, lBytes - lReturned );\r
231                         }\r
232                         lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket );\r
233                         if( lMayWrite < 0 )\r
234                                 return lMayWrite;\r
235                 } else\r
236                 {\r
237                         sbAdd( pxTcpServer->pxSendData, 0, cReceivedString, lBytes );\r
238                 }\r
239         }\r
240 }\r
241 \r
242 static TickType_t lastTickTime;\r
243 static BaseType_t xTaskCount = 0, xConfirmedCount = 0;\r
244 static void prvConnectionListeningTask( void *pvParameters )\r
245 {\r
246 struct freertos_sockaddr xClient, xBindAddress;\r
247 Socket_t xListeningSocket;\r
248 \r
249 socklen_t xSize = sizeof( xClient );\r
250 static const TickType_t xReceiveTimeOut = 0; //portMAX_DELAY;\r
251 const BaseType_t xBacklog = 10;\r
252 SocketSet_t xSocketSet;\r
253 struct xTCP_SERVER *pxServerList = NULL;\r
254 struct xTCP_SERVER *pxIterator;\r
255 \r
256 WinProperties_t winProps;\r
257 \r
258         /* Just to prevent compiler warnings. */\r
259         ( void ) pvParameters;\r
260 \r
261         /* Attempt to open the socket. */\r
262         xListeningSocket = FreeRTOS_socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );\r
263         configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET );\r
264 \r
265         /* Set a time out so accept() will just wait for a connection. */\r
266         FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );\r
267 \r
268         memset(&winProps, '\0', sizeof( winProps ) );\r
269         // Size in units of MSS\r
270         winProps.lTxBufSize   = 1 * 1460;//1000;\r
271         winProps.lTxWinSize   = 2;\r
272 \r
273         winProps.lRxBufSize   = 2 * 1460;\r
274         winProps.lRxWinSize   =  2;\r
275 \r
276         FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &winProps, sizeof( winProps ) );\r
277 \r
278         /* The strange casting is to remove compiler errors. */\r
279         xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL;\r
280         xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port );\r
281 \r
282         /* Bind the socket to the port that the client task will send to, then\r
283         listen for incoming connections. */\r
284         while( FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ) != 0 );\r
285         FreeRTOS_listen( xListeningSocket, xBacklog );\r
286         lastTickTime = xTaskGetTickCount ();\r
287 \r
288         pxServerList = NULL;\r
289 \r
290         xSocketSet = FreeRTOS_createsocketset( );\r
291         configASSERT( xSocketSet != NULL );\r
292         FreeRTOS_FD_SET( xListeningSocket, xSocketSet, eSELECT_READ );\r
293 \r
294         for( ;; )\r
295         {\r
296                 TickType_t xMask = FreeRTOS_select( xSocketSet, 3000 );\r
297 \r
298                 if( FreeRTOS_FD_ISSET( xListeningSocket, xSocketSet ) )\r
299                 {\r
300                         Socket_t xNewSocket;\r
301 \r
302                         xNewSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );\r
303                         if ( xNewSocket && xNewSocket != FREERTOS_INVALID_SOCKET )\r
304                         {\r
305                                 TCPServer_t *pxServer;\r
306 \r
307                                 FreeRTOS_debug_printf( ( "prvConnectionListeningTask: new connection %xip:%u\n",\r
308                                         FreeRTOS_ntohl( xClient.sin_addr ), FreeRTOS_ntohs( xClient.sin_port ) ) );\r
309 \r
310                                 pxServer = (TCPServer_t *)pvPortMalloc( sizeof( *pxServer ) );\r
311                                 memset( pxServer, '\0', sizeof( *pxServer ));\r
312 \r
313                                 pxServer->xSocket = xNewSocket;\r
314                                 FreeRTOS_FD_SET( xNewSocket, xSocketSet, eSELECT_READ | eSELECT_EXCEPT );\r
315                                 if( pxServerList == NULL )\r
316                                 {\r
317                                         /* This is the first server */\r
318                                         pxServerList = pxServer;\r
319                                 }\r
320                                 else\r
321                                 {\r
322                                         /* Attach it to the end of the list */\r
323                                         for( pxIterator = pxServerList; pxIterator->pxNext != NULL; pxIterator = pxIterator->pxNext )\r
324                                         {\r
325                                         }\r
326                                         pxIterator->pxNext = pxServer;\r
327                                 }\r
328                                 prvTcpInit( pxServer );\r
329                         }\r
330                 }\r
331                 {\r
332                         TCPServer_t *pxThisServer = NULL;\r
333 \r
334                         for( pxIterator = pxServerList; pxIterator != NULL;  )\r
335                         {\r
336                                 BaseType_t rc;\r
337                                 pxThisServer = pxIterator;\r
338                                 /* Move to the next one before the current gets deleted */\r
339                                 pxIterator = pxIterator->pxNext;\r
340 \r
341                                 if( FreeRTOS_FD_ISSET( pxThisServer->xSocket, xSocketSet )  == 0 )\r
342                                 {\r
343                                         continue;\r
344                                 }\r
345 \r
346                                 rc = prvTcpWork( pxThisServer );\r
347 \r
348                                 if( rc < 0)\r
349                                 {\r
350                                         FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_ALL );\r
351 \r
352                                         if( pxServerList = pxThisServer )\r
353                                         {\r
354                                                 pxServerList = pxThisServer->pxNext;\r
355                                         }\r
356                                         else\r
357                                         {\r
358                                                 struct xTCP_SERVER *pxOther;\r
359                                                 for( pxOther = pxServerList; pxOther->pxNext != NULL; pxOther = pxOther->pxNext )\r
360                                                 {\r
361                                                         if( pxOther->pxNext == pxThisServer )\r
362                                                         {\r
363                                                                 pxOther->pxNext == pxThisServer->pxNext;\r
364                                                                 break;\r
365                                                         }\r
366                                                 }\r
367                                         }\r
368                                         /* Close the socket and free the space */\r
369                                         prvTcpClose( pxThisServer );\r
370                                 } else\r
371                                 {\r
372                                         pxThisServer->bHasSendRequest = prvTcpHasSendData( pxThisServer );\r
373                                         if( pxThisServer->bHasSendRequest )\r
374                                                 FreeRTOS_FD_SET( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE );\r
375                                         else\r
376                                                 FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE );\r
377                                         //FreeRTOS_debug_printf( ( "SET_FD WRITE %d\n", pxServerFound->bHasSendRequest != 0 ) );\r
378                                 }\r
379                         }\r
380                 }\r
381                 if( ( xTaskGetTickCount () - lastTickTime ) > 30000 )\r
382                 {\r
383                         lastTickTime = xTaskGetTickCount ();\r
384                         //plusPrintf( "ListeningTask %ld,%ld tasks\n", xTaskCount, xConfirmedCount );\r
385                 }\r
386         }\r
387 }\r
388 /*-----------------------------------------------------------*/\r
389 \r
390 static BaseType_t prvCreateTxData( uint8_t *ucBuffer, uint32_t ulBufferLength )\r
391 {\r
392 BaseType_t lCharactersToAdd, lCharacter;\r
393 uint8_t ucChar = '0';\r
394 \r
395         /* Randomise the number of characters that will be sent. */\r
396         do\r
397         {\r
398                 lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL );\r
399         } while ( lCharactersToAdd == 0 );\r
400 \r
401         /* Fill the buffer. */\r
402         for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ )\r
403         {\r
404                 ucBuffer[ lCharacter ] = ucChar;\r
405                 ucChar++;\r
406 \r
407                 if( ucChar > '~' )\r
408                 {\r
409                         ucChar = '0';\r
410                 }\r
411         }\r
412 \r
413         return lCharactersToAdd;\r
414 }\r
415 /*-----------------------------------------------------------*/\r