2 FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\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
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
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
25 ***************************************************************************
\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
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
37 ***************************************************************************
\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
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
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
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
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
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
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
70 /* Standard includes. */
\r
73 #include <WinSock2.h>
\r
74 #include <Mswsock.h>
\r
76 /* FreeRTOS includes. */
\r
77 #include "FreeRTOS.h"
\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
86 #include "SimpleTCPEchoServer.h" /* For prvSimpleTcpServerClientTask */
\r
89 #define tcpechoNUMBER_OF_CLIENTS 0
\r
91 void tcpWinShowEvent( BaseType_t aDoLog );
\r
94 * Listens for incoming echo connections. Creates a task to handle each
\r
97 static void prvConnectionListeningTask( void *pvParameters );
\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
103 /*-----------------------------------------------------------*/
\r
105 void vStartSelectTCPServerTasks( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority )
\r
107 WORD wVersionRequested;
\r
109 BaseType_t xClient;
\r
110 //extern void prvSimpleTCPClientTask( void *pvParameters );
\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
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
120 /* Prepare to use WinSock library. */
\r
121 wVersionRequested = MAKEWORD( 2, 2 );
\r
122 configASSERT( WSAStartup( wVersionRequested, &xWSAData ) == ( WORD ) 0 );
\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
129 #define SEND_BUFFER_SIZE ( 8 * ipconfigTCP_MSS )
\r
131 typedef struct xTCP_SERVER {
\r
133 struct xTCP_SERVER *pxNext;
\r
134 SSimpleBuf *pxSendData;
\r
135 BaseType_t bHasSendRequest;
\r
138 static uint8_t cReceivedString[ ipconfigTCP_MSS ];
\r
140 static void prvTcpInit( TCPServer_t *pxTcpServer )
\r
142 struct freertos_sockaddr addr;
\r
143 BaseType_t xReceiveTimeOut = 0;
\r
144 BaseType_t xSendTimeOut = 0;
\r
146 pxTcpServer->pxSendData = ( SSimpleBuf * )pvPortMalloc( sizeof( *pxTcpServer->pxSendData ) - sizeof( pxTcpServer->pxSendData->array ) + SEND_BUFFER_SIZE + 1 );
\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
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
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
160 static void prvTcpClose( TCPServer_t *pxThisServer )
\r
162 FreeRTOS_closesocket( pxThisServer->xSocket );
\r
163 vPortFree( pxThisServer->pxSendData );
\r
164 vPortFree( pxThisServer );
\r
167 static BaseType_t prvTcpSend( TCPServer_t *pxTcpServer )
\r
169 BaseType_t lBytes, lReturned, xReturn = 0;
\r
171 lBytes = sbGet( pxTcpServer->pxSendData, 0, cReceivedString, sizeof( cReceivedString ), pdTRUE );
\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
178 xReturn = sbGet( pxTcpServer->pxSendData, 0, NULL, lReturned, pdFALSE );
\r
184 static BaseType_t prvTcpHasSendData( TCPServer_t *pxTcpServer )
\r
186 return ( sbGetSize( pxTcpServer->pxSendData ) > 0 ) ? 1 : 0;
\r
189 static BaseType_t prvTcpWork( TCPServer_t *pxTcpServer )
\r
191 BaseType_t lBytes, lReturned, lMayWrite;
\r
193 lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket );
\r
194 if( lMayWrite < 0 )
\r
196 while( lMayWrite > 0 )
\r
198 lReturned = prvTcpSend( pxTcpServer );
\r
199 if( lReturned < 0 )
\r
201 if( lReturned == 0 )
\r
203 lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket );
\r
204 if( lMayWrite < 0 )
\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
213 /* Receive data on the socket. */
\r
214 lBytes = FreeRTOS_recv( pxTcpServer->xSocket, cReceivedString, sizeof( cReceivedString ), 0 );
\r
217 /* Return the received characters. */
\r
218 if( lMayWrite > 0 && sbGetSize( pxTcpServer->pxSendData ) == 0 )
\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
226 if( lBytes > lReturned )
\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
232 lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket );
\r
233 if( lMayWrite < 0 )
\r
237 sbAdd( pxTcpServer->pxSendData, 0, cReceivedString, lBytes );
\r
242 static TickType_t lastTickTime;
\r
243 static BaseType_t xTaskCount = 0, xConfirmedCount = 0;
\r
244 static void prvConnectionListeningTask( void *pvParameters )
\r
246 struct freertos_sockaddr xClient, xBindAddress;
\r
247 Socket_t xListeningSocket;
\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
256 WinProperties_t winProps;
\r
258 /* Just to prevent compiler warnings. */
\r
259 ( void ) pvParameters;
\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
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
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
273 winProps.lRxBufSize = 2 * 1460;
\r
274 winProps.lRxWinSize = 2;
\r
276 FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &winProps, sizeof( winProps ) );
\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
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
288 pxServerList = NULL;
\r
290 xSocketSet = FreeRTOS_createsocketset( );
\r
291 configASSERT( xSocketSet != NULL );
\r
292 FreeRTOS_FD_SET( xListeningSocket, xSocketSet, eSELECT_READ );
\r
296 TickType_t xMask = FreeRTOS_select( xSocketSet, 3000 );
\r
298 if( FreeRTOS_FD_ISSET( xListeningSocket, xSocketSet ) )
\r
300 Socket_t xNewSocket;
\r
302 xNewSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize );
\r
303 if ( xNewSocket && xNewSocket != FREERTOS_INVALID_SOCKET )
\r
305 TCPServer_t *pxServer;
\r
307 FreeRTOS_debug_printf( ( "prvConnectionListeningTask: new connection %xip:%u\n",
\r
308 FreeRTOS_ntohl( xClient.sin_addr ), FreeRTOS_ntohs( xClient.sin_port ) ) );
\r
310 pxServer = (TCPServer_t *)pvPortMalloc( sizeof( *pxServer ) );
\r
311 memset( pxServer, '\0', sizeof( *pxServer ));
\r
313 pxServer->xSocket = xNewSocket;
\r
314 FreeRTOS_FD_SET( xNewSocket, xSocketSet, eSELECT_READ | eSELECT_EXCEPT );
\r
315 if( pxServerList == NULL )
\r
317 /* This is the first server */
\r
318 pxServerList = pxServer;
\r
322 /* Attach it to the end of the list */
\r
323 for( pxIterator = pxServerList; pxIterator->pxNext != NULL; pxIterator = pxIterator->pxNext )
\r
326 pxIterator->pxNext = pxServer;
\r
328 prvTcpInit( pxServer );
\r
332 TCPServer_t *pxThisServer = NULL;
\r
334 for( pxIterator = pxServerList; pxIterator != NULL; )
\r
337 pxThisServer = pxIterator;
\r
338 /* Move to the next one before the current gets deleted */
\r
339 pxIterator = pxIterator->pxNext;
\r
341 if( FreeRTOS_FD_ISSET( pxThisServer->xSocket, xSocketSet ) == 0 )
\r
346 rc = prvTcpWork( pxThisServer );
\r
350 FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_ALL );
\r
352 if( pxServerList = pxThisServer )
\r
354 pxServerList = pxThisServer->pxNext;
\r
358 struct xTCP_SERVER *pxOther;
\r
359 for( pxOther = pxServerList; pxOther->pxNext != NULL; pxOther = pxOther->pxNext )
\r
361 if( pxOther->pxNext == pxThisServer )
\r
363 pxOther->pxNext == pxThisServer->pxNext;
\r
368 /* Close the socket and free the space */
\r
369 prvTcpClose( pxThisServer );
\r
372 pxThisServer->bHasSendRequest = prvTcpHasSendData( pxThisServer );
\r
373 if( pxThisServer->bHasSendRequest )
\r
374 FreeRTOS_FD_SET( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE );
\r
376 FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE );
\r
377 //FreeRTOS_debug_printf( ( "SET_FD WRITE %d\n", pxServerFound->bHasSendRequest != 0 ) );
\r
381 if( ( xTaskGetTickCount () - lastTickTime ) > 30000 )
\r
383 lastTickTime = xTaskGetTickCount ();
\r
384 //plusPrintf( "ListeningTask %ld,%ld tasks\n", xTaskCount, xConfirmedCount );
\r
388 /*-----------------------------------------------------------*/
\r
390 static BaseType_t prvCreateTxData( uint8_t *ucBuffer, uint32_t ulBufferLength )
\r
392 BaseType_t lCharactersToAdd, lCharacter;
\r
393 uint8_t ucChar = '0';
\r
395 /* Randomise the number of characters that will be sent. */
\r
398 lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL );
\r
399 } while ( lCharactersToAdd == 0 );
\r
401 /* Fill the buffer. */
\r
402 for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ )
\r
404 ucBuffer[ lCharacter ] = ucChar;
\r
413 return lCharactersToAdd;
\r
415 /*-----------------------------------------------------------*/
\r