Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers chargen.c Source File

chargen.c

Go to the documentation of this file.
00001 /**
00002  * @file chargen.c
00003  * @brief Character generator 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 character generator service is a useful debugging and measurement
00028  * tool. The service simply sends data until the calling user terminates
00029  * the connection. Refer to RFC 864 for complete details
00030  *
00031  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00032  * @version 1.7.6
00033  **/
00034 
00035 //Switch to the appropriate trace level
00036 #define TRACE_LEVEL STD_SERVICES_TRACE_LEVEL
00037 
00038 //Dependencies
00039 #include "core/net.h"
00040 #include "std_services/chargen.h"
00041 #include "debug.h"
00042 
00043 //Character pattern (from RFC 864)
00044 const char_t pattern[190] =
00045 {
00046    '!', '"', '#',  '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3',
00047    '4', '5', '6',  '7', '8', '9', ':',  ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
00048    'G', 'H', 'I',  'J', 'K', 'L', 'M',  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
00049    'Z', '[', '\\', ']', '^', '_', '`',  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
00050    'm', 'n', 'o',  'p', 'q', 'r', 's',  't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', ' ',
00051    '!', '"', '#',  '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3',
00052    '4', '5', '6',  '7', '8', '9', ':',  ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
00053    'G', 'H', 'I',  'J', 'K', 'L', 'M',  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
00054    'Z', '[', '\\', ']', '^', '_', '`',  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
00055    'm', 'n', 'o',  'p', 'q', 'r', 's',  't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', ' '
00056 };
00057 
00058 
00059 /**
00060  * @brief Start TCP chargen service
00061  * @return Error code
00062  **/
00063 
00064 error_t tcpChargenStart(void)
00065 {
00066    error_t error;
00067    Socket *socket;
00068    OsTask *task;
00069 
00070    //Debug message
00071    TRACE_INFO("Starting TCP chargen service...\r\n");
00072 
00073    //Open a TCP socket
00074    socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
00075    //Failed to open socket?
00076    if(socket == NULL)
00077       return ERROR_OPEN_FAILED;
00078 
00079    //Start of exception handling block
00080    do
00081    {
00082       //Bind the newly created socket to port 19
00083       error = socketBind(socket, &IP_ADDR_ANY, CHARGEN_PORT);
00084       //Failed to bind the socket to the desired port?
00085       if(error)
00086          break;
00087 
00088       //Place the socket into listening mode
00089       error = socketListen(socket, 0);
00090       //Any error to report?
00091       if(error)
00092          break;
00093 
00094       //Create a task to handle incoming connection requests
00095       task = osCreateTask("TCP Chargen Listener", tcpChargenListenerTask,
00096          socket, CHARGEN_SERVICE_STACK_SIZE, CHARGEN_SERVICE_PRIORITY);
00097 
00098       //Unable to create the task?
00099       if(task == OS_INVALID_HANDLE)
00100       {
00101          //Report an error to the calling function
00102          error = ERROR_OUT_OF_RESOURCES;
00103          break;
00104       }
00105 
00106       //End of exception handling block
00107    } while(0);
00108 
00109    //Any error to report?
00110    if(error)
00111    {
00112       //Clean up side effects...
00113       socketClose(socket);
00114    }
00115 
00116    //Return status code
00117    return error;
00118 }
00119 
00120 
00121 /**
00122  * @brief Task handling connection requests
00123  * @param[in] param Pointer to the chargen service context
00124  **/
00125 
00126 void tcpChargenListenerTask(void *param)
00127 {
00128    error_t error;
00129    uint16_t clientPort;
00130    IpAddr clientIpAddr;
00131    Socket *serverSocket;
00132    Socket *clientSocket;
00133    ChargenServiceContext *context;
00134    OsTask *task;
00135 
00136    //Point to the listening socket
00137    serverSocket = (Socket *) param;
00138 
00139    //Main loop
00140    while(1)
00141    {
00142       //Accept an incoming connection
00143       clientSocket = socketAccept(serverSocket, &clientIpAddr, &clientPort);
00144       //Check whether a valid connection request has been received
00145       if(!clientSocket) continue;
00146 
00147       //Debug message
00148       TRACE_INFO("Chargen service: connection established with client %s port %" PRIu16 "\r\n",
00149          ipAddrToString(&clientIpAddr, NULL), clientPort);
00150 
00151       //Adjust timeout
00152       error = socketSetTimeout(clientSocket, CHARGEN_TIMEOUT);
00153 
00154       //Any error to report?
00155       if(error)
00156       {
00157          //Close socket
00158          socketClose(clientSocket);
00159          //Wait for an incoming connection attempt
00160          continue;
00161       }
00162 
00163       //Allocate resources for the new connection
00164       context = osAllocMem(sizeof(ChargenServiceContext));
00165 
00166       //Failed to allocate memory?
00167       if(context == NULL)
00168       {
00169          //Close socket
00170          socketClose(clientSocket);
00171          //Wait for an incoming connection attempt
00172          continue;
00173       }
00174 
00175       //Record the handle of the newly created socket
00176       context->socket = clientSocket;
00177 
00178       //Create a task to service the current connection
00179       task = osCreateTask("TCP Chargen Connection", tcpChargenConnectionTask,
00180          context, CHARGEN_SERVICE_STACK_SIZE, CHARGEN_SERVICE_PRIORITY);
00181 
00182       //Did we encounter an error?
00183       if(task == OS_INVALID_HANDLE)
00184       {
00185          //Close socket
00186          socketClose(clientSocket);
00187          //Release resources
00188          osFreeMem(context);
00189       }
00190    }
00191 }
00192 
00193 
00194 /**
00195  * @brief TCP chargen service implementation
00196  * @param[in] param Pointer to the chargen service context
00197  **/
00198 
00199 void tcpChargenConnectionTask(void *param)
00200 {
00201    error_t error;
00202    //size_t i;
00203    size_t n;
00204    //size_t offset;
00205    size_t byteCount;
00206    systime_t startTime;
00207    systime_t duration;
00208    ChargenServiceContext *context;
00209 
00210    //Get a pointer to the context
00211    context = (ChargenServiceContext *) param;
00212    //Get current time
00213    startTime = osGetSystemTime();
00214 
00215    //Initialize counters
00216    byteCount = 0;
00217    //offset = 0;
00218 
00219    //Once a connection is established a stream of data is sent out
00220    //the connection (and any data received is thrown away). This
00221    //continues until the calling user terminates the connection
00222    while(1)
00223    {
00224       //Format output data
00225       /*for(i = 0; i < CHARGEN_BUFFER_SIZE; i += 95)
00226       {
00227          //Calculate the length of the current line
00228          n = MIN(CHARGEN_BUFFER_SIZE - i, 95);
00229          //Copy character pattern
00230          memcpy(context->buffer + i, pattern + offset, n);
00231       }
00232 
00233       //Update offset
00234       offset += CHARGEN_BUFFER_SIZE + 95 - i;
00235       //Wrap around if necessary
00236       if(offset >= 95) offset = 0;*/
00237 
00238       //Send data
00239       error = socketSend(context->socket, context->buffer, CHARGEN_BUFFER_SIZE, &n, 0);
00240       //Any error to report?
00241       if(error)
00242          break;
00243 
00244       //Total number of bytes sent
00245       byteCount += n;
00246    }
00247 
00248    //Graceful shutdown
00249    socketShutdown(context->socket, SOCKET_SD_BOTH);
00250    //Compute total duration
00251    duration = osGetSystemTime() - startTime;
00252    //Avoid division by zero...
00253    if(!duration) duration = 1;
00254 
00255    //Debug message
00256    TRACE_INFO("Chargen service: %" PRIuSIZE " bytes "
00257       "sent in %" PRIu32 " ms (%" PRIu32 " kBps, %" PRIu32 " kbps)\r\n",
00258       byteCount, duration, byteCount / duration, (byteCount * 8) / duration);
00259 
00260    //Close socket
00261    socketClose(context->socket);
00262    //Release previously allocated memory
00263    osFreeMem(context);
00264 
00265    //Kill ourselves
00266    osDeleteTask(NULL);
00267 }
00268 
00269 
00270 /**
00271  * @brief Start UDP chargen service
00272  * @return Error code
00273  **/
00274 
00275 error_t udpChargenStart(void)
00276 {
00277    error_t error;
00278    ChargenServiceContext *context;
00279    OsTask *task;
00280 
00281    //Debug message
00282    TRACE_INFO("Starting UDP chargen service...\r\n");
00283 
00284    //Allocate a memory block to hold the context
00285    context = osAllocMem(sizeof(ChargenServiceContext));
00286    //Failed to allocate memory?
00287    if(context == NULL)
00288       return ERROR_OUT_OF_MEMORY;
00289 
00290    //Start of exception handling block
00291    do
00292    {
00293       //Open a UDP socket
00294       context->socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
00295 
00296       //Failed to open socket?
00297       if(!context->socket)
00298       {
00299          //Report an error
00300          error = ERROR_OPEN_FAILED;
00301          //Exit immediately
00302          break;
00303       }
00304 
00305       //The server listens for incoming datagrams on port 19
00306       error = socketBind(context->socket, &IP_ADDR_ANY, CHARGEN_PORT);
00307       //Unable to bind the socket to the desired port?
00308       if(error)
00309          break;
00310 
00311       //Create a task to handle incoming datagrams
00312       task = osCreateTask("UDP Chargen", udpChargenTask,
00313          context, CHARGEN_SERVICE_STACK_SIZE, CHARGEN_SERVICE_PRIORITY);
00314 
00315       //Unable to create the task?
00316       if(task == OS_INVALID_HANDLE)
00317       {
00318          //Report an error to the calling function
00319          error = ERROR_OUT_OF_RESOURCES;
00320          break;
00321       }
00322 
00323       //End of exception handling block
00324    } while(0);
00325 
00326    //Any error to report?
00327    if(error)
00328    {
00329       //Clean up side effects...
00330       socketClose(context->socket);
00331       osFreeMem(context);
00332    }
00333 
00334    //Return status code
00335    return error;
00336 }
00337 
00338 
00339 /**
00340  * @brief UDP chargen service implementation
00341  * @param[in] param Pointer to the chargen service context
00342  **/
00343 
00344 void udpChargenTask(void *param)
00345 {
00346    error_t error;
00347    size_t i;
00348    size_t k;
00349    size_t n;
00350    size_t length;
00351    uint16_t port;
00352    IpAddr ipAddr;
00353    ChargenServiceContext *context;
00354 
00355    //Get a pointer to the context
00356    context = (ChargenServiceContext *) param;
00357 
00358    //Main loop
00359    while(1)
00360    {
00361       //Wait for an incoming datagram
00362       error = socketReceiveFrom(context->socket, &ipAddr, &port,
00363          context->buffer, CHARGEN_BUFFER_SIZE, &n, 0);
00364 
00365       //Any datagram received?
00366       if(!error)
00367       {
00368          //When a datagram is received, an answering datagram is sent
00369          //containing a random number (between 0 and 512) of characters
00370          length = netGetRand() % 513;
00371 
00372          //Reset line counter
00373          n = 0;
00374 
00375          //Format output data
00376          for(i = 0; i < length; i += 74)
00377          {
00378             //Calculate the length of the current line
00379             k = MIN(length - i, 74);
00380             //Copy character pattern
00381             memcpy(context->buffer + i, pattern + n, k);
00382 
00383             //End each line with carriage return and line feed
00384             if(k == 74)
00385             {
00386                context->buffer[i + 72] = '\r';
00387                context->buffer[i + 73] = '\n';
00388             }
00389 
00390             //Increment line counter
00391             if(++n >= 95) n = 0;
00392          }
00393 
00394          //Send data to the remote host
00395          error = socketSendTo(context->socket, &ipAddr, port,
00396             context->buffer, length, &n, 0);
00397 
00398          //Debug message
00399          TRACE_INFO("Chargen service: %" PRIuSIZE " bytes sent to %s port %" PRIu16 "\r\n",
00400             n, ipAddrToString(&ipAddr, NULL), port);
00401       }
00402    }
00403 }
00404