Author Topic: about the udp use!  (Read 38308 times)

Offline tr111

  • Jr. Member
  • **
  • Posts: 72
    • View Profile
about the udp use!
« on: August 28, 2007, 07:38:27 AM »
hello:
    I have download the uTaskerV1[1].3.0_M5223X_SP3!
    but i don't know how to use the udp to send and get!
     #define DEMO_UDP  but how it can work???
   

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3232
    • View Profile
    • uTasker
Re: about the udp use!
« Reply #1 on: August 28, 2007, 11:22:39 AM »
Hi

The UDP demo in the demo project shows the method of setting up a UDP socket on a particular port (which is necessary to receive UDP frames) and sending  data. The demo waits for a UDP frame to be received and then sends it back (echo). Although the demo doesn't generate any frames of its own, the method for sending is the same if it were to.

Here is a more complete guide to the use of UDP.

1. When no UDP socket is available
If there is no UDP socket opened on a particular port, all received UDP frames on that port are discarded. However it is possible to cause an ICMP DESTINATION UNREACHABLE to be returned (this happens irrespective of UDP support) by configuring #define ICMP_DEST_UNREACHABLE in the USE_ICMP configuration group in config.h.
Note that the ICMP destination unreachable is often disabled on PCs by default since it is considered a security risk - it confirms that there is a PC/device at the destination IP address, even if there is no UDP based service running on it.

2. Opening a UDP socket
A UDP socket must be set to listening state for UDP frames to be received.
When the UDP demo starts it creates a UDP socket and binds it as shown by the following code:

Code: [Select]
    if (!((MyUDP_Socket = fnGetUDP_socket(TOS_MINIMISE_DELAY, fnUDPListner, (UDP_OPT_SEND_CS | UDP_OPT_CHECK_CS))) < 0)) {
        fnBindSocket(MyUDP_Socket, MY_UDP_PORT);                         // Bind socket
        ptrUDP_Frame    = uMalloc(sizeof(UDP_MESSAGE));                  // get some memory for UDP frame
    }
    else {
    return;                                                          // no socket - this must never happen (ensure that enough user UDP sockets have been defined - USER_UDP_SOCKETS in config.h)!!
    }

USOCKET fnGetUDP_socket(unsigned char ucTOS, int (*fnListener)(USOCKET, unsigned char, unsigned char *, unsigned short, unsigned char *, unsigned short), unsigned char ucOpts);

the first parameter TOS_MINIMISE_DELAY can in fact be ignored - it is not used.
fnUDPListner() is the UDP call back routine which is called when a UDP frame is received or other event occur relevant to the socket.
(UDP_OPT_SEND_CS | UDP_OPT_CHECK_CS) are options which define whether the UDP checksum of transmitted frames is generated and whether the UDP check sum of received frames is checked. UDP allows frames to be sent with or without check sums.

static USOCKET MyUDP_Socket;  is the socket used for communicating

#define MY_UDP_PORT            9999                                  // Test UDP port
fnBindSocket(MyUDP_Socket, MY_UDP_PORT); This call binds the new socket to a port number.

In the demo project the port number is defined to be 9999, but it could of course be a variable value.

As the comment says, ensure that there are enough UDP sockets available in the UDP socket pool. For each socket required by the application increase the value of USER_UDP_SOCKETS in config.h.

From this point on, the UDP socket is in listening for received farmes and any activity will result in the call back being executed.

3. Receiving UDP events

Code: [Select]
// UDP data server - reception call back function
//
extern int fnUDPListner(USOCKET SocketNr, unsigned char ucEvent, unsigned char *ucIP, unsigned short usPortNr, unsigned char *data, unsigned short usLength)
{
switch (ucEvent) {
case UDP_EVENT_RXDATA:
//if (usPortNr != MY_UDP_PORT) break;                            // ignore false ports
//if (uMemcmp(ucIP, ucUDP_IP_Address, IPV4_LENGTH)) break;       // ignore if not from expected IP address

        //if (usLength <= UDP_BUFFER_SIZE) {                             // ignore frames which are too large
            //uMemcpy(&ptrUDP_Frame->ucUDP_Message, data, usLength);     // Send the received UDP frame back
            //fnSendUDP(MyUDP_Socket, ucUDP_IP_Address, MY_UDP_PORT, (unsigned char*)&ptrUDP_Frame->tUDP_Header, usLength, OWN_TASK);
        //}
        fnSendUDP(MyUDP_Socket, ucIP, usPortNr, (data - sizeof(UDP_HEADER)), usLength, OWN_TASK); // echo back from transmitting IP and port
break;

case UDP_EVENT_PORT_UNREACHABLE:                                     // we have received information that this port is not available at the destination so quit
break;
}
return 0;
}

There are in two possible events which can arrive:
UDP_EVENT_PORT_UNREACHABLE - this means that an ICMP DISTINATION UNREACHABLE frame was received which corresponds to the souce port of this UDP socket. Generally it will be returned if the user sends a UDP frame to a destination which does not (or no longer has) a listening UDP socket operating.

UDP_EVENT_RXDATA - this means that a UDP frame has been received.
 ucIP is a pointer to the IP address fo the sender
 usPortNr is the port number of the sender
 data is a pointer to the data in the UDP frame
 usLength is the length of the UDP data

As shown in the example (where the comments can be changed to suit) this allows various things to be quite simply performed:
if (usPortNr != MY_UDP_PORT) break; // this will reject UDP frames from destinations which are not using the same UDP port number as their source.

if (uMemcmp(ucIP, ucUDP_IP_Address, IPV4_LENGTH)) break; // this will reject any data from IP addresses not equal to
    static unsigned char ucUDP_IP_Address[IPV4_LENGTH] = {192, 168, 0, 102};
This is used as a form of trusted IP address.

fnSendUDP(MyUDP_Socket, ucIP, usPortNr, (data - sizeof(UDP_HEADER)), usLength, OWN_TASK); // This is the simplest form of echo message. It sends the received data back to the destination port and IP address without copying it from the receive Ethernet frame buffer. The reason for the pointer shift of sizeof(UDP_HEADER) is due to the fact that the data is passed with space for the UDP header which the UDP transmission routine uses when constructing the UDP frame. This should become clear in the next section.

4. Transmission of UDP frames

Code: [Select]
fnSendUDP(MyUDP_Socket, ucUDP_IP_Address, MY_UDP_PORT, (unsigned char*)&ptrUDP_Frame->tUDP_Header, usLength, OWN_TASK);
This is the general transmission method. The destintion UDP port number and destination IP address determine where the UDP frame will be sent to. MY_UDP_PORT is passed since it is also required in the UDP frame.
The data is passed in this example as a struct, where the data length is defined (usLength) and a reference to the sending task OWN_TASK is also given.

In the demo the following struct is defined for sending a UDP frame.
Code: [Select]
    typedef struct stUDP_MESSAGE
    {
        unsigned short usLength;
        UDP_HEADER     tUDP_Header;                                      // reserve header space
        unsigned char  ucUDP_Message[UDP_BUFFER_SIZE];                   // reserve message space
    } UDP_MESSAGE;
This defines the message buffer as consisting of a UDP_HEADER plus UDP data, where the buffer size UDP_BUFFER_SIZE is adequate for the application use.
When UDP data is sent, the data content is set to the buffer ucUDP_Message. When sent, the complete object is passed so that the UDP transmission routine can simply fill it out with the necessary UDP header and send it on to the IP layer. This results in improved efficiency since the UDP frame construction routine doesn't have to copy any UDP data content. It does however mean that the user must always pass the header buffer space - which is easily done when such a struct is used.

5. UDP frame retransmissions
UDP is a connectionless protocol and has also no retransmission at the UDP layer. This means that it is not a secure protocol unless a higher layer is responsible for resending lost data if it has detected a communication problem.
However there are cases where transmission is not possible and a repeat of the data must be foreseen. This is due to the ARP process and can be handled as follows - this is also built into the UDP demo code in application.c as reference.

Consider the following transmission case:

Code: [Select]
static UDP_MESSAGE *ptrUDP_Frame  = uMalloc(sizeof(UDP_MESSAGE));                  // get some memory for UDP frame
const unsigned char test_data[] = {1,2,3,4,5,6,7,8};

uMemcpy(&ptrUDP_Frame->ucUDP_Message, test_data, sizeof(test_data));     // Send the received UDP frame back
fnSendUDP(MyUDP_Socket, ucUDP_IP_Address, MY_UDP_PORT, (unsigned char*)&ptrUDP_Frame->tUDP_Header, sizeof(test_data), OWN_TASK);


Here a test frame is put to the UDP buffer and send using fnSendUDP().
Note that the UDP frame buffer has been created on the heap and maintains a backup of this frame. This is important if the data is to be retransmitted at a later point in time.
Although the return value of fnSendUDP() is not being checked, it can have the following values:
0 means that no data could be transmitted due to a problem with the Ethernet interface. In this case the data has been lost - it is an exceptional case which is generally not expected.
> 0 means that this amount of data was transmitted (including IP and UDP headers). It means that the transmission to the destination address via the Ethernet interface was successful but it doesn't mean that the UDP frame will ever arrive. However, if there is no higher level protocol being executed the job has in fact been completed.

INVALID_SOCKET_HANDLE will be returned if the socket is invalid or
SOCKET_CLOSED if the socket is not bound.
INVALID_DEST_IP will be returned if the user tries to send to the IP address 0.0.0.0.
INVALID_REMOTE_PORT if the user tries to send to the destination UDP port number 0 or
ZERO_PORT if the user source port is declared as 0.

NO_ARP_ENTRY will be returned if the IP frame (consisting of IP and UDP header plus UDP data) could not be sent due to a missing MAC <-> IP entry in the ARP table. This is not an error but a natural occurance in an Ethernet LAN, which starts the ARP resolve process. ARP sends a broadcast request to attempt to resolve the destination IP address in the local network, which can be either successful or fail. Since this ARP resolve process can take some time the result is sent to the sending task (remember the parameter OWN_TASK) as soon as it is known. In the case of the fail it can take several seconds until ARP actually gives up and declares the process as a failed attempt.

The demo project example shows how the ARP result messages are processed:

Code: [Select]
        case  TASK_ARP:
            fnRead( PortIDInternal, ucInputMessage, ucInputMessage[MSG_CONTENT_LENGTH]); // read the contents
            switch (ucInputMessage[ 0 ]) {                               // ARP sends us either ARP resolution success or failed
            case ARP_RESOLUTION_SUCCESS:                                 // IP address has been resolved (repeat UDP frame).
                fnSendUDP(MyUDP_Socket, ucUDP_IP_Address, MY_UDP_PORT, (unsigned char*)&ptrUDP_Frame->tUDP_Header, UDP_BUFFER_SIZE, OWN_TASK);
                break;

            case ARP_RESOLUTION_FAILED:                                  // IP address could not be resolved...
                break;
            }
            break;

This is in the task's input queue read, where the ARP task is identified as the message source.
The message type ARP_RESOLUTION_FAILED informs that the destination IP address is not reachable on the network. In this demo example nothing is undertaken but the message could be of interest in an application to generate a user message informing of the reason for the failure.

The ARP_RESOLUTION_SUCCESS message informs that the destination IP address has now been resolved and a retransmission of the original message should now be performed. This retransmission is not necessarily an application layer retranmission but is rather necessary to be performed due to the ARP process which can and will take place in practice. This means that its handling MUST be resolved if UDP transmission is to operate correctly.
As can be seen the backed up UDP frame is simply resent, which will in this case almost certainly be successful.

Note that in an application where a lot of UDP data is to be transmitted it is probably best to not allow further transmissions to be attempted until the ARP resolution process has completed. This will avoid having to back up lots of UDP data frames. If several tasks are sending UDP frames, each task can use the same mechanism but will have to back up its own message in each case.

If you have studied the TCP implementation you will see that the handling of the ARP RESOLUTION is resolved by the TCP_EVENT_REGENERATE event in the TCP call back routine, This call back routine has however been dispatched from the same ARP message reception in the TCP task.


That is about all that is needed to be known to be able to successfully use UDP in the project.

Good luck!!

Regards

Mark






Offline tr111

  • Jr. Member
  • **
  • Posts: 72
    • View Profile
Re: about the udp use!
« Reply #2 on: August 29, 2007, 01:30:24 AM »
Thank you very much ! mark !

Offline Tino

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: about the udp use!
« Reply #3 on: January 23, 2008, 05:07:00 PM »
Hi,
Now I have a problem with UDP:

static USOCKET UDP_data_socket = -1;

static int fnUDPListner(USOCKET SocketNr, unsigned char ucEvent, unsigned char *ucIP, unsigned short usPortNr, unsigned char *data, unsigned short usLength);

void StartListen(void) {
   if (((UDP_data_socket = fnGetUDP_socket(TOS_MINIMISE_DELAY, fnUDPListner, (UDP_OPT_SEND_CS | UDP_OPT_CHECK_CS))) >= 0)) {
        fnBindSocket(UDP_data_socket, RECEIVE_DATA_PORT_NUMBER);                         // Bind socket
    }
    else {
       return;
    }
}

static int fnUDPListner(USOCKET SocketNr, unsigned char ucEvent, unsigned char *ucIP, unsigned short usPortNr, unsigned char *data, unsigned short usLength) {
...
}


When I comment
fnBindSocket(UDP_data_socket, RECEIVE_DATA_PORT_NUMBER);                         // Bind socket
it works.
But if it is uncommented, the mcu crashes and resets.
Strange things is, that this worked before.
I have enough udp sockets reserved (10).

Help :)
Tino

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3232
    • View Profile
    • uTasker
Re: about the udp use!
« Reply #4 on: January 23, 2008, 05:47:00 PM »
Tino

Do you know where the code is crashing? - I don't see that fnBindSocket() itself can be the cause of the crash. This routine only fills out variables when the socket and its internal pointers are valid.

Is it possible that the crash occurs when data has been received? In this case the problem may be in the listener call-back routine. If the socket if not bound it will not be listening and so the call back will not be executed.

Regards

Mark

Offline Tino

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: about the udp use!
« Reply #5 on: January 23, 2008, 07:54:30 PM »
Someday I will go nuts...
Now it works again.
I will try to make it not work again and then debug.

Thanks for your reply,
Tino

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: about the udp use!
« Reply #6 on: March 14, 2008, 12:38:40 PM »
Hi,
  I am new to UDP, and have always used TCP. I understand (well, think), that UDP is connectionless, but that is as far as it goes.
The application I need is not being a server, but connecting to a server device. I simply want to connect to a server, send/receve data and close (well, dont know if there is a close command in UDP).

Thanks
Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3232
    • View Profile
    • uTasker
Re: about the udp use!
« Reply #7 on: March 14, 2008, 01:07:42 PM »
Hi Neil

Since UDP is connectionless there is no way to connect to a server - you can simply send data to the server whenever you want - either it arrives (no ack) or it doesn't (also no ack). If the server is not actually running but the PC it is on is, it may be possible that you receive an ICMP DESTINATION UNREACHABLE, but this is also not guarantied since this is often disabled at the PC (considered as a security weakness in some situations when activated).

If the application needs more reliability you can add a protocol layer above the UDP layer which then performs its own protocol (ACK,NACK etc.). If reliability is important the application must take over this responsibility - or change to TCP/IP as protocol where it is handled.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: about the udp use!
« Reply #8 on: April 03, 2008, 12:44:51 PM »
Hi Mark,
  I have an application where I will be communicating with 1 piece of hardware using UDP( It is local to the board, about 3 feet away). My application will not be a server but a client. I understand that a UDP cannot make a connection, but their documentation regarding the UDP does mention a connection first. I looked into my trusty book 'Network programming for microsoft windows', and it does mention a connection (even though it does nothing) , here is the details from the book:

'Another method of receiving and sending data on a connectionless socket is to establish a connection. This might seem strange, but its not quite what it sounds like. Once the socket is created, you can call connect. No actual connection is made, however. The socket address passed into a connect function is associated with the socket so recv can be used  instead of recvfrom because the datas origin is known. The capability to connect a datagram socket is handy if you intend to communicate with only one endpoint at a time.'

My application will only be communicating (well with one socket, might have a tcp socket on another connection to my application on a windows machine)with one endpoint. Is this the way to go for my UDP socket?

Thanks
Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3232
    • View Profile
    • uTasker
Re: about the udp use!
« Reply #9 on: April 03, 2008, 04:20:24 PM »
Hi Neil

I am not sure exactly what this connect does but it sounds like something conceptional rather than to acually do with the protocol. It may be sort of entering the port number for the UDP connection (does 'endpoint' mean a IP / Port pair?) so that it doesn't have to be passed each time it is read.

From the embedded side it probably doesn't have any real significance.

Regards

Mark

Offline thamanjd

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
Re: about the udp use!
« Reply #10 on: April 04, 2008, 06:07:40 AM »
May we ask what language/compiler you were going to use for the PC software?

Offline thamanjd

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
Re: about the udp use!
« Reply #11 on: May 06, 2008, 03:25:10 AM »
can you clarify for me what fnReleaseUDP_socket does please?
What actually gets freed - it looks like the socket handle is left alone?


Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3232
    • View Profile
    • uTasker
Re: about the udp use!
« Reply #12 on: May 06, 2008, 02:15:28 PM »
Hi

Rather than answering this here I have added the complete function description to the (new) on-line documentation.

To view this please go to: http://www.utasker.com/docs/Code.html

As you will see there are only a few functions which are presently documented and the layout needs some extra work to get it operating with all Browsers (Firefox works quite well when the screen is not too narrow). However I have just added the fnGetUDP_socket() and fnReleaseUDP_socket() descriptions which will hopefully clarify everthing!

Regards

Mark

Offline Marco

  • Newbie
  • *
  • Posts: 21
    • View Profile
Re: about the udp use!
« Reply #13 on: February 10, 2009, 01:48:43 PM »
Hi Mark

I have tried all day and gotten no where, this is the code I got so far.

#include "config.h"


extern void fnMyFirstTask(TTASKTABLE *ptrTaskTable)
{

  fnBindSocket(2, 1234);
  fnSendUDP(2, (192, 168, 0, 101) ,1234, (unsigned char*)"Hello World", 11, OWN_TASK);

}

The error I'm getting is that OWN_TASK is not defined, you wouldn't happen to have an example of sending a hello world from a new app?

cheers

Marco

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3232
    • View Profile
    • uTasker
Re: about the udp use!
« Reply #14 on: February 10, 2009, 05:48:06 PM »
Hi Marco

If you activate DEMO_UDP in application.c it will add a demo. There is a listener which echoes back received frames.

OWN_TASK is the name of the owner task which is informed of transmission errors and ARP resolution if the MAC address of the destination has first to be resolved. See the case ARP_RESOLUTION_SUCCESS in application.c where the UDP frame is repeated on ARP resolution success.

Eg. in application.c it is
#define OWN_TASK                  TASK_APPLICATION

In your own task you can just locally define
#define OWN_TASK                  MY_TASK         , for example.


  fnBindSocket(2, 1234);

Before you can bind a socket you need to get one from the UDP pool. Eg.
MyUDP_Socket = fnGetUDP_socket(TOS_MINIMISE_DELAY, fnUDPListner, (UDP_OPT_SEND_CS | UDP_OPT_CHECK_CS));

Then you can bind it - you need to pass the socket to be bound and not a fixed number.
  fnBindSocket(MyUDP_Socket, 1234);

Make sure that there are enough UDP sockets in the pool by incrementing USER_UDP_SOCKETS (in config.h) for each extra one your application needs.


  fnSendUDP(2, (192, 168, 0, 101) ,1234, (unsigned char*)"Hello World", 11, OWN_TASK);

Again you need to pass the socket and not a fixed number.

I am not sure about the (192, 168, 0, 101). I think that this is passing an array of ints - it should be an array of unsigned chars.
It is best to do
const unsigned char ucIP[] = {192,168,0,101}; and pass this.

Finally there is a mistake with passing the string. Here you need to pass a UDP struct which has space for the UDP header to be added to it. You are passing a const pointer and this will probably cause the code to crash when it tries to add the header (it would also overwrite some data).


You need to build and send your message (compare with the demo code), for example like this:

            uMemcpy(&ptrUDP_Frame->ucUDP_Message, "Hello World", 11);
            fnSendUDP(MyUDP_Socket, (unsigned char *)ucIP, 1234, (unsigned char*)&ptrUDP_Frame->tUDP_Header, 11, OWN_TASK);


Regards

Mark