Example3: udpecho_client.c

Description

This example implements a simple UDP echo client.  It connects to a 
UDP echo server, periodically sends echo requests and then validates 
that the data in the received response exactly matches the data sent. 
If it is linked into the DEBUG version of embTCP and is run on a 
system with a console, it will print status messages.  Otherwise, you 
will only be able to see what there are doing by looking at a 
WireShark trace.

The initialization routine for all of the embTCP example programs is 
called example_init. For this reason, you can only link with one 
example at a time on an embTCP system.  When example_init is called, 
it will create and initialize a task and begin running.

Example3 was intended as a simple example of a UDP client program.  
It is not a robust UDP echo client.  It starts immediately once it 
has been initialized, sends 10 echo requests of 255 bytes each at a 
fixed rate, listens for responses and then exits by deleting its task.  

Note:  The target UDP echo server needs to be running when 
udpecho_client is initialized. Once initialized, the udpecho_client  
immediately attempts to connect.  If the server is not running, the 
connection request will timeout and the task will return to its task 
loop where it will be deleted.  

Configuration Parameters

You must change the 'svraddrstr' parameter to be the IP address of a 
UDP echo server. The other parameters should not be changed for the 
initial tests.

Most Windows and Linux systems have a running UDP echo server that 
will respond to echo requests. You could also send the requests to 
another system running embTCP with example 4, a UDP echo server. 

Code Walkthrough

The UDPCLIENT structure holds the input and output buffers and the 
variables that are maintained across all of the echo requests.  

The next section defines the UDP task info structure and calls 
TK_CREATE to create the UDP echo client task.

The function examle_init() creates udp echo client task.
Task body tk_uc_echo waits until the network is ready 
and then calls udp_ceho_init(). udp_cecho_init() calls the main loop of the echo 
client. Most tasks run for the life of the system.  However, the UDP 
echo task runs only long enough to send the configured number of echo 
requests.  When it returns to the task loop, the task is deleted.      

The udp_cecho_init() routine does the following:
* Converts the IP address string to a binary number
* Sets its own address structure and calls t_bind in order to listen 
  for UDP echo responses addressed to it from any address. It lets 
  the OS pick the local port number.
* Fills out the address structure for the remote server.
* Opens a socket and calls t_connect().  The connect routine blocks 
  and will not return until either the connection has been made or it 
  times out. Note: If the server is not running, when the t_connect() 
  times out it will print a connection error message and return to the 
  task loop where the task will be deleted.
* Calls t_setsockopt() to put the socket in non-blocking mode.
* Calls udp_send_an_echo to send the first echo request.  
* If there is no error, it calls udp_cecho_loop() to send the rest of the 
  requests.
* Call udp_cehco_close when udp_cecho_loop returns.
* Returns to the main task loop where the task will be deleted. 

The udp_cecho_loop does the following:
* Goes into a loop.  The "for(;;)" expression means it will only exit 
  when "return" is called. 
* Calls t_select() to see if there are any responses ready to be read.  
  It sets the timeout value for t_select to 200 ms. This allows it to 
  test to see if it is time to send another echo request.
* Calls t_recv() to read any available echo response.  
* If the return from t_recv ('len') is < 0 it calls t_errno to determine 
  the error number. If the return is anything other the EWOULDBLOCK, it 
  will print an error message.
* If 'len' is greater than 0, then we read an echo response. Note if the 
  system were congested, the full response may not be read in a single 
  t_recv() call.  
* Loops to validate each byte of the received data. The variable 
  'uec->nextrcvbyte' hold the value of the next expected byte.  When 
  uec->nextrcvbyte increments to ECHODFTLEN, it is reset to 0.  If we find 
  an unexpected character, we print and error message and return.
* After a successful read,  the number of replies is incremented and 'len' 
  is added to the cumulative total number of bytes read.
* When the number of requests sent equals the configured number of requests 
  to send, udp echo has completed and will return.  
* Otherwise, if it is time to send another request, it calls udp_send_an_echo.

The udp_send_an_echo() routine does the following:
* Fills each byte of the outgoing buffer with values incrementing from 0 
  to ECHODFTLEN - 1.  
* The tcp_send_an_echo routine will loop until all bytes in the request 
  are sent. If the system is congested, then t_send may return EWOULDBLOCK 
  or a t_send it may send only part of the data. 
* If the t_send call blocks, we call taskYIELD() to let other tasks run. 
  On return we continue in the send loop.  
* If t_send return a positive value, then we add that value to the number 
  of bytes sent.  If only part of the data was sent, we advance the buffer 
  pointer and reduce bytestosend by the number of bytes sent.
* Once the full echo request has been sent, we increment the statistics 
  variables and set the timer for when the next request should be sent.

The udp_cecho_close() routine does the following:
* If there is a valid socket, it closes it.
* Prints a completion status message.


