Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
echo.c
00001 /** 00002 * @file echo.c 00003 * @brief Echo protocol 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @section Description 00026 * 00027 * The echo service simply sends back to the originating source 00028 * any data it receives. Refer to RFC 862 for complete details 00029 * 00030 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00031 * @version 1.7.6 00032 **/ 00033 00034 //Switch to the appropriate trace level 00035 #define TRACE_LEVEL STD_SERVICES_TRACE_LEVEL 00036 00037 //Dependencies 00038 #include "core/net.h" 00039 #include "std_services/echo.h" 00040 #include "debug.h" 00041 00042 //Check TCP/IP stack configuration 00043 #if (NET_STATIC_OS_RESOURCES == ENABLED) 00044 00045 //UDP Echo service 00046 static OsTask udpEchoTaskStruct; 00047 static uint_t udpEchoTaskStack[ECHO_SERVICE_STACK_SIZE]; 00048 00049 #endif 00050 00051 00052 /** 00053 * @brief Start TCP echo service 00054 * @return Error code 00055 **/ 00056 00057 error_t tcpEchoStart(void) 00058 { 00059 error_t error; 00060 Socket *socket; 00061 OsTask *task; 00062 00063 //Debug message 00064 TRACE_INFO("Starting TCP echo service...\r\n"); 00065 00066 //Open a TCP socket 00067 socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); 00068 //Failed to open socket? 00069 if(socket == NULL) 00070 return ERROR_OPEN_FAILED; 00071 00072 //Start of exception handling block 00073 do 00074 { 00075 //Bind the newly created socket to port 7 00076 error = socketBind(socket, &IP_ADDR_ANY, ECHO_PORT); 00077 //Failed to bind the socket to the desired port? 00078 if(error) 00079 break; 00080 00081 //Place the socket into listening mode 00082 error = socketListen(socket, 0); 00083 //Any error to report? 00084 if(error) 00085 break; 00086 00087 //Create a task to handle incoming connection requests 00088 task = osCreateTask("TCP Echo Listener", tcpEchoListenerTask, 00089 socket, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY); 00090 00091 //Unable to create the task? 00092 if(task == OS_INVALID_HANDLE) 00093 { 00094 //Report an error to the calling function 00095 error = ERROR_OUT_OF_RESOURCES; 00096 break; 00097 } 00098 00099 //End of exception handling block 00100 } while(0); 00101 00102 //Any error to report? 00103 if(error) 00104 { 00105 //Clean up side effects... 00106 socketClose(socket); 00107 } 00108 00109 //Return status code 00110 return error; 00111 } 00112 00113 00114 /** 00115 * @brief Task handling connection requests 00116 * @param[in] param Pointer to the echo service context 00117 **/ 00118 00119 void tcpEchoListenerTask(void *param) 00120 { 00121 error_t error; 00122 uint16_t clientPort; 00123 IpAddr clientIpAddr; 00124 Socket *serverSocket; 00125 Socket *clientSocket; 00126 EchoServiceContext *context; 00127 OsTask *task; 00128 00129 //Point to the listening socket 00130 serverSocket = (Socket *) param; 00131 00132 //Main loop 00133 while(1) 00134 { 00135 //Accept an incoming connection 00136 clientSocket = socketAccept(serverSocket, &clientIpAddr, &clientPort); 00137 //Check whether a valid connection request has been received 00138 if(!clientSocket) continue; 00139 00140 //Debug message 00141 TRACE_INFO("Echo service: connection established with client %s port %" PRIu16 "\r\n", 00142 ipAddrToString(&clientIpAddr, NULL), clientPort); 00143 00144 //The socket operates in non-blocking mode 00145 error = socketSetTimeout(clientSocket, 0); 00146 00147 //Any error to report? 00148 if(error) 00149 { 00150 //Close socket 00151 socketClose(clientSocket); 00152 //Wait for an incoming connection attempt 00153 continue; 00154 } 00155 00156 //Allocate resources for the new connection 00157 context = osAllocMem(sizeof(EchoServiceContext)); 00158 00159 //Failed to allocate memory? 00160 if(context == NULL) 00161 { 00162 //Close socket 00163 socketClose(clientSocket); 00164 //Wait for an incoming connection attempt 00165 continue; 00166 } 00167 00168 //Record the handle of the newly created socket 00169 context->socket = clientSocket; 00170 00171 //Create a task to service the current connection 00172 task = osCreateTask("TCP Echo Connection", tcpEchoConnectionTask, 00173 context, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY); 00174 00175 //Did we encounter an error? 00176 if(task == OS_INVALID_HANDLE) 00177 { 00178 //Close socket 00179 socketClose(clientSocket); 00180 //Release resources 00181 osFreeMem(context); 00182 } 00183 } 00184 } 00185 00186 00187 /** 00188 * @brief TCP echo service implementation 00189 * @param[in] param Pointer to the echo service context 00190 **/ 00191 00192 void tcpEchoConnectionTask(void *param) 00193 { 00194 error_t error; 00195 size_t n; 00196 size_t writeIndex; 00197 size_t readIndex; 00198 size_t bufferLength; 00199 size_t rxByteCount; 00200 size_t txByteCount; 00201 systime_t startTime; 00202 systime_t duration; 00203 SocketEventDesc eventDesc; 00204 EchoServiceContext *context; 00205 00206 //Get a pointer to the context 00207 context = (EchoServiceContext *) param; 00208 //Get current time 00209 startTime = osGetSystemTime(); 00210 00211 //Initialize variables 00212 writeIndex = 0; 00213 readIndex = 0; 00214 bufferLength = 0; 00215 rxByteCount = 0; 00216 txByteCount = 0; 00217 00218 //Main loop 00219 while(1) 00220 { 00221 //Buffer is empty? 00222 if(!bufferLength) 00223 { 00224 //Get notified when the socket is readable 00225 eventDesc.socket = context->socket; 00226 eventDesc.eventMask = SOCKET_EVENT_RX_READY; 00227 } 00228 //Buffer is not empty of full? 00229 else if(bufferLength < ECHO_BUFFER_SIZE) 00230 { 00231 //Get notified when the socket is readable or writable 00232 eventDesc.socket = context->socket; 00233 eventDesc.eventMask = SOCKET_EVENT_RX_READY | SOCKET_EVENT_TX_READY; 00234 } 00235 //Buffer is full? 00236 else 00237 { 00238 //Get notified when the socket is writable 00239 eventDesc.socket = context->socket; 00240 eventDesc.eventMask = SOCKET_EVENT_TX_READY; 00241 } 00242 00243 //Wait for an event to be fired 00244 error = socketPoll(&eventDesc, 1, NULL, ECHO_TIMEOUT); 00245 //Timeout error or any other exception to report? 00246 if(error) 00247 break; 00248 00249 //The socket is available for reading 00250 if(eventDesc.eventFlags & SOCKET_EVENT_RX_READY) 00251 { 00252 //Read as much data as possible 00253 n = MIN(ECHO_BUFFER_SIZE - writeIndex, ECHO_BUFFER_SIZE - bufferLength); 00254 00255 //Read incoming data 00256 error = socketReceive(context->socket, context->buffer + writeIndex, n, &n, 0); 00257 //Any error to report? 00258 if(error) 00259 break; 00260 00261 //Increment write index 00262 writeIndex += n; 00263 //Wrap around if necessary 00264 if(writeIndex >= ECHO_BUFFER_SIZE) 00265 writeIndex = 0; 00266 00267 //Increment buffer length 00268 bufferLength += n; 00269 //Total number of bytes received 00270 rxByteCount += n; 00271 } 00272 00273 //The socket is available for writing? 00274 if(eventDesc.eventFlags & SOCKET_EVENT_TX_READY) 00275 { 00276 //Write as much data as possible 00277 n = MIN(ECHO_BUFFER_SIZE - readIndex, bufferLength); 00278 00279 //Send data back to the client 00280 error = socketSend(context->socket, context->buffer + readIndex, n, &n, 0); 00281 //Any error to report? 00282 if(error && error != ERROR_TIMEOUT) 00283 break; 00284 00285 //Increment read index 00286 readIndex += n; 00287 //Wrap around if necessary 00288 if(readIndex >= ECHO_BUFFER_SIZE) 00289 readIndex = 0; 00290 00291 //Update buffer length 00292 bufferLength -= n; 00293 //Total number of bytes sent 00294 txByteCount += n; 00295 } 00296 } 00297 00298 //Adjust timeout value 00299 socketSetTimeout(context->socket, ECHO_TIMEOUT); 00300 //Graceful shutdown 00301 socketShutdown(context->socket, SOCKET_SD_BOTH); 00302 //Compute total duration 00303 duration = osGetSystemTime() - startTime; 00304 00305 //Debug message 00306 TRACE_INFO("Echo service: %" PRIuSIZE " bytes received, %" PRIuSIZE " bytes sent in %" PRIu32 " ms\r\n", 00307 rxByteCount, txByteCount, duration); 00308 00309 //Close socket 00310 socketClose(context->socket); 00311 //Release previously allocated memory 00312 osFreeMem(context); 00313 00314 //Kill ourselves 00315 osDeleteTask(NULL); 00316 } 00317 00318 00319 /** 00320 * @brief Start UDP echo service 00321 * @return Error code 00322 **/ 00323 00324 error_t udpEchoStart(void) 00325 { 00326 error_t error; 00327 EchoServiceContext *context; 00328 00329 #if (NET_STATIC_OS_RESOURCES == DISABLED) 00330 OsTask *task; 00331 #endif 00332 00333 //Debug message 00334 TRACE_INFO("Starting UDP echo service...\r\n"); 00335 00336 //Allocate a memory block to hold the context 00337 context = osAllocMem(sizeof(EchoServiceContext)); 00338 //Failed to allocate memory? 00339 if(context == NULL) 00340 return ERROR_OUT_OF_MEMORY; 00341 00342 //Start of exception handling block 00343 do 00344 { 00345 //Open a UDP socket 00346 context->socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP); 00347 00348 //Failed to open socket? 00349 if(!context->socket) 00350 { 00351 //Report an error 00352 error = ERROR_OPEN_FAILED; 00353 //Exit immediately 00354 break; 00355 } 00356 00357 //The server listens for incoming datagrams on port 7 00358 error = socketBind(context->socket, &IP_ADDR_ANY, ECHO_PORT); 00359 //Unable to bind the socket to the desired port? 00360 if(error) 00361 break; 00362 00363 #if (NET_STATIC_OS_RESOURCES == ENABLED) 00364 //Create a task to handle incoming datagrams 00365 osCreateStaticTask(&udpEchoTaskStruct, "UDP Echo", udpEchoTask, context, 00366 udpEchoTaskStack, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY); 00367 #else 00368 //Create a task to handle incoming datagrams 00369 task = osCreateTask("UDP Echo", udpEchoTask, 00370 context, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY); 00371 00372 //Unable to create the task? 00373 if(task == OS_INVALID_HANDLE) 00374 { 00375 //Report an error to the calling function 00376 error = ERROR_OUT_OF_RESOURCES; 00377 break; 00378 } 00379 #endif 00380 00381 //End of exception handling block 00382 } while(0); 00383 00384 //Any error to report? 00385 if(error) 00386 { 00387 //Clean up side effects... 00388 socketClose(context->socket); 00389 osFreeMem(context); 00390 } 00391 00392 //Return status code 00393 return error; 00394 } 00395 00396 00397 /** 00398 * @brief UDP echo service implementation 00399 * @param[in] param Pointer to the echo service context 00400 **/ 00401 00402 void udpEchoTask(void *param) 00403 { 00404 error_t error; 00405 size_t length; 00406 uint16_t port; 00407 IpAddr ipAddr; 00408 EchoServiceContext *context; 00409 00410 //Get a pointer to the context 00411 context = (EchoServiceContext *) param; 00412 00413 //Main loop 00414 while(1) 00415 { 00416 //Wait for an incoming datagram 00417 error = socketReceiveFrom(context->socket, &ipAddr, &port, 00418 context->buffer, ECHO_BUFFER_SIZE, &length, 0); 00419 00420 //Any datagram received? 00421 if(!error) 00422 { 00423 //Debug message 00424 TRACE_INFO("Echo service: %" PRIuSIZE " bytes received from %s port %" PRIu16 "\r\n", 00425 length, ipAddrToString(&ipAddr, NULL), port); 00426 00427 //Send the data back to the source 00428 error = socketSendTo(context->socket, &ipAddr, port, 00429 context->buffer, length, NULL, 0); 00430 } 00431 } 00432 } 00433
Generated on Tue Jul 12 2022 17:10:13 by
1.7.2