7.2   BSD Sockets

A socket is a communications end-point that is bound to a UDP or TCP port within the node. Under VxWorks, your application can use the sockets interface to access features of the Internet Protocol suite (features such as multicasting). Depending on the bound port type, a socket is referred to either as a stream socket or a datagram socket. VxWorks sockets are UNIX BSD 4.4 compatible. However, VxWorks does not support signal functionality for sockets.

Stream sockets use TCP to bind to a particular port number. Another process, on any host in the network, can then create another stream socket and request that it be connected to the first socket by specifying its host Internet address and port number. After the two TCP sockets are connected, there is a virtual circuit set up between them, allowing reliable socket-to-socket communications. This style of communication is conversational.

Datagram sockets use UDP to bind to a particular port number. Other processes, on any host in the network, can then send messages to that socket by specifying the host Internet address and the port number. Compared to TCP, UDP provides a simpler but less robust communication method. In a UDP communication, data is sent between sockets in separate, unconnected, individually addressed packets called datagrams. There is no sense of conversation with a datagram socket. The communication is in the style of a letter. Each packet carries the address of both the destination and the sender. Compared to TCP, UDP is unreliable. Like the mail, packets that are lost or out-of-sequence are not reported.

There are a number of complex network programming issues that are beyond the scope of this guide. For additional information, consult a socket-programming book, such as one of the following:

7.2.1   Stream Sockets (TCP)

The Transmission Control Protocol (TCP) provides reliable, two-way transmission of data. In a TCP communication, two sockets are connected, allowing a reliable byte-stream to flow between them in either direction. TCP is referred to as a virtual circuit protocol, because it behaves as though a circuit is created between the two sockets.

A good analogy for TCP communications is a telephone system. Connecting two sockets is similar to calling from one phone to another. After the connection is established, you can write and read data (talk and listen).

Table 7-1 shows the steps in establishing socket communications with TCP, and the analogy of each step with telephone communications.

Table 7-1:  TCP Analogy to Telephone Communication


Task 1
Waits
 
Task 2
Calls
 
Function
 
Analogy
 

socket( )
 
socket( )
 
Create sockets.
 
Hook up telephones.
 
bind( )
   
Assign address to socket.
 
Assign phone numbers.
 
listen( )
   
Allow others to connect to socket.
 
Allow others to call.
 
 
connect( )
 
Request connection to another socket.
 
Dial another phone's number.
 
accept( )
   
Complete connection between sockets.
 
Answer phone and establish connection.
 
write( )
 
write( )
 
Send data to other socket.
 
Talk.
 
read( )
 
read( )
 
Receive data from other socket.
 
Listen.
 
close( )
 
close( )
 
Close sockets.
 
Hang up.
 

Example 7-1:  Stream Sockets (TCP)

The following code example uses a client-server communication model. The server communicates with clients using stream-oriented (TCP) sockets. The main server loop, in tcpServerWorkTask( ), reads requests, prints the client's message to the console, and, if requested, sends a reply back to the client. The client builds the request by prompting for input. It sends a message to the server and, optionally, waits for a reply to be sent back. To simplify the example, we assume that the code is executed on machines that have the same data sizes and alignment.

/* tcpExample.h - header used by both TCP server and client examples */  
 
/* defines */ 
#define SERVER_PORT_NUM         5001   /* server's port number for bind() */ 
#define SERVER_WORK_PRIORITY    100    /* priority of server's work task */ 
#define SERVER_STACK_SIZE       10000  /* stack size of server's work task */ 
#define SERVER_MAX_CONNECTIONS  4      /* max clients connected at a time */ 
#define REQUEST_MSG_SIZE        1024   /* max size of request message */ 
#define REPLY_MSG_SIZE          500    /* max size of reply message */ 
 
/* structure for requests from clients to server */ 
struct request 
    { 
    int reply;                         /* TRUE = request reply from server */  
    int msgLen;                        /* length of message text */ 
    char message[REQUEST_MSG_SIZE];    /* message buffer */  
    };

/* tcpClient.c - TCP client example */ 
 
/* 
DESCRIPTION 
This file contains the client-side of the VxWorks TCP example code. 
The example code demonstrates the usage of several BSD 4.4-style 
socket routine calls. 
*/ 
 
/* includes */ 
 
#include "vxWorks.h" 
#include "sockLib.h" 
#include "inetLib.h" 
#include "stdioLib.h" 
#include "strLib.h" 
#include "hostLib.h" 
#include "ioLib.h" 
#include "tcpExample.h" 
 
/**************************************************************************** 
* 
* tcpClient - send requests to server over a TCP socket 
* 
* This routine connects over a TCP socket to a server, and sends a 
* user-provided message to the server.  Optionally, this routine 
* waits for the server's reply message. 
* 
* This routine may be invoked as follows: 
*       -> tcpClient "remoteSystem" 
*       Message to send: 
*       Hello out there 
*       Would you like a reply (Y or N): 
*       y 
*       value = 0 = 0x0 
*       -> MESSAGE FROM SERVER: 
*       Server received your message 
* 
* RETURNS: OK, or ERROR if the message could not be sent to the server. 
*/ 
 
STATUS tcpClient 
    ( 
    char *              serverName     /* name or IP address of server */ 
    ) 
    { 
    struct request      myRequest;     /* request to send to server */ 
    struct sockaddr_in  serverAddr;    /* server's socket address */ 
    char                replyBuf[REPLY_MSG_SIZE]; /* buffer for reply */ 
    char                reply;         /* if TRUE, expect reply back */ 
    int                 sockAddrSize;  /* size of socket address structure */ 
    int                 sFd;           /* socket file descriptor */ 
    int                 mlen;          /* length of message */ 
 
    /* create client's socket */ 
    if ((sFd = socket (AF_INET, SOCK_STREAM, 0)) == ERROR) 
        { 
        perror ("socket"); 
        return (ERROR); 
        } 
 
    /* bind not required - port number is dynamic */ 
    /* build server socket address */ 
    sockAddrSize = sizeof (struct sockaddr_in); 
    bzero ((char *) &serverAddr, sockAddrSize); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sa_len = (u_char) sockAddrSize; 
    serverAddr.sin_port = htons (SERVER_PORT_NUM); 
 
    if (((serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && 
        ((serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) 
        { 
        perror ("unknown server name"); 
        close (sFd); 
        return (ERROR); 
        } 
 
    /* connect to server */ 
    if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR) 
        { 
        perror ("connect"); 
        close (sFd); 
        return (ERROR); 
        } 
 
    /* build request, prompting user for message */ 
    printf ("Message to send: \n"); 
    mlen = read (STD_IN, myRequest.message, REQUEST_MSG_SIZE); 
    myRequest.msgLen = mlen; 
    myRequest.message[mlen - 1] = '\0'; 
    printf ("Would you like a reply (Y or N): \n"); 
    read (STD_IN, &reply, 1); 
    switch (reply) 
        { 
        case 'y': 
        case 'Y': myRequest.reply = TRUE; 
            break; 
        default: myRequest.reply = FALSE; 
            break; 
        } 
 
    /* send request to server */ 
 
    if (write (sFd, (char *) &myRequest, sizeof (myRequest)) == ERROR) 
        { 
        perror ("write"); 
        close (sFd); 
        return (ERROR); 
        } 
 
    if (myRequest.reply)        /* if expecting reply, read and display it */  
        { 
        if (read (sFd, replyBuf, REPLY_MSG_SIZE) < 0) 
            { 
            perror ("read"); 
            close (sFd); 
            return (ERROR); 
            }
printf ("MESSAGE FROM SERVER:\n%s\n", replyBuf); }
close (sFd); return (OK); }

/* tcpServer.c - TCP server example */
/* DESCRIPTION This file contains the server-side of the VxWorks TCP example code. The example code demonstrates the useage of several BSD 4.4-style socket routine calls. */
/* includes */ #include "vxWorks.h" #include "sockLib.h" #include "inetLib.h" #include "taskLib.h" #include "stdioLib.h" #include "strLib.h" #include "ioLib.h" #include "fioLib.h" #include "tcpExample.h"
/* function declarations */
VOID tcpServerWorkTask (int sFd, char * address, u_short port);
/**************************************************************************** * * tcpServer - accept and process requests over a TCP socket * * This routine creates a TCP socket, and accepts connections over the socket * from clients. Each client connection is handled by spawning a separate * task to handle client requests. * * This routine may be invoked as follows: * -> sp tcpServer * task spawned: id = 0x3a6f1c, name = t1 * value = 3829532 = 0x3a6f1c * -> MESSAGE FROM CLIENT (Internet Address 150.12.0.10, port 1027): * Hello out there * * RETURNS: Never, or ERROR if a resources could not be allocated. */
STATUS tcpServer (void) { struct sockaddr_in serverAddr; /* server's socket address */ struct sockaddr_in clientAddr; /* client's socket address */ int sockAddrSize; /* size of socket address structure */ int sFd; /* socket file descriptor */ int newFd; /* socket descriptor from accept */ int ix = 0; /* counter for work task names */ char workName[16]; /* name of work task */
/* set up the local address */
sockAddrSize = sizeof (struct sockaddr_in); bzero ((char *) &serverAddr, sockAddrSize); serverAddr.sin_family = AF_INET; serverAddr.sa_len = (u_char) sockAddrSize; serverAddr.sin_port = htons (SERVER_PORT_NUM); serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
/* create a TCP-based socket */
if ((sFd = socket (AF_INET, SOCK_STREAM, 0)) == ERROR) { perror ("socket"); return (ERROR); }
/* bind socket to local address */
if (bind (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR) { perror ("bind"); close (sFd); return (ERROR); }
/* create queue for client connection requests */
if (listen (sFd, SERVER_MAX_CONNECTIONS) == ERROR) { perror ("listen"); close (sFd); return (ERROR); }
/* accept new connect requests and spawn tasks to process them */
FOREVER { if ((newFd = accept (sFd, (struct sockaddr *) &clientAddr, &sockAddrSize)) == ERROR) { perror ("accept"); close (sFd); return (ERROR); }
sprintf (workName, "tTcpWork%d", ix++); if (taskSpawn(workName, SERVER_WORK_PRIORITY, 0, SERVER_STACK_SIZE, (FUNCPTR) tcpServerWorkTask, newFd, (int) inet_ntoa (clientAddr.sin_addr), ntohs (clientAddr.sin_port), 0, 0, 0, 0, 0, 0, 0) == ERROR) { /* if taskSpawn fails, close fd and return to top of loop */ perror ("taskSpawn"); close (newFd); } } } /**************************************************************************** * * tcpServerWorkTask - process client requests * * This routine reads from the server's socket, and processes client * requests. If the client requests a reply message, this routine * will send a reply to the client. * * RETURNS: N/A. */ VOID tcpServerWorkTask ( int sFd, /* server's socket fd */ char * address, /* client's socket address */ u_short port /* client's socket port */ ) { struct request clientRequest; /* request/message from client */ int nRead; /* number of bytes read */ static char replyMsg[] = "Server received your message"; /* read client request, display message */ while ((nRead = fioRead (sFd, (char *) &clientRequest, sizeof (clientRequest))) > 0) { printf ("MESSAGE FROM CLIENT (Internet Address %s, port %d):\n%s\n", address, port, clientRequest.message); free (address); /* free malloc from inet_ntoa() */ if (clientRequest.reply) if (write (sFd, replyMsg, sizeof (replyMsg)) == ERROR) perror ("write"); } if (nRead == ERROR) /* error from read() */ perror ("read"); close (sFd); /* close server socket connection */ }

7.2.2   Datagram Sockets (UDP)

You can use datagram (UDP) sockets to implement a simple client-server communication system. You can also use UDP sockets to handle multicasting.

Using a Datagram Socket to Implement a Client-Server Communication System

The following code example uses a client-server communication model. The server communicates with clients using datagram-oriented (UDP) sockets. The main server loop, in udpServer( ), reads requests and optionally displays the client's message. The client builds the request by prompting the user for input. Note that this code assumes that it executes on machines that have the same data sizes and alignment.

Example 7-2:  Datagram Sockets (UDP)


/* udpExample.h - header used by both UDP server and client examples */ 
 
#define SERVER_PORT_NUM         5002    /* server's port number for bind() */ 
#define REQUEST_MSG_SIZE        1024    /* max size of request message */ 
 
/* structure used for client's request */ 
 
struct request 
    { 
    int  display;                       /* TRUE = display message */ 
    char message[REQUEST_MSG_SIZE];     /* message buffer */ 
    };

/* udpClient.c - UDP client example */ 
 
/* 
DESCRIPTION 
This file contains the client-side of the VxWorks UDP example code. 
The example code demonstrates the useage of several BSD 4.4-style 
socket routine calls. 
*/ 
 
 
/* includes */ 
 
#include "vxWorks.h" 
#include "sockLib.h" 
#include "inetLib.h" 
#include "stdioLib.h" 
#include "strLib.h" 
#include "hostLib.h" 
#include "ioLib.h" 
#include "udpExample.h" 
 
/**************************************************************************** 
* 
* udpClient - send a message to a server over a UDP socket 
* 
* This routine sends a user-provided message to a server over a UDP socket. 
* Optionally, this routine can request that the server display the message. 
* This routine may be invoked as follows: 
*       -> udpClient "remoteSystem" 
*       Message to send: 
*       Greetings from UDP client 
*       Would you like server to display your message (Y or N):  
*       y 
*       value = 0 = 0x0 
* 
* RETURNS: OK, or ERROR if the message could not be sent to the server. 
*/ 
 
STATUS udpClient 
    ( 
    char *              serverName     /* name or IP address of server */ 
    ) 
    { 
    struct request      myRequest;     /* request to send to server */ 
    struct sockaddr_in  serverAddr;    /* server's socket address */ 
    char                display;       /* if TRUE, server prints message */ 
    int                 sockAddrSize;  /* size of socket address structure */ 
    int                 sFd;           /* socket file descriptor */  
    int                 mlen;          /* length of message */  
 
    /* create client's socket */ 
 
    if ((sFd = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR) 
        { 
        perror ("socket"); 
        return (ERROR); 
        } 
 
    /* bind not required - port number is dynamic */ 
 
    /* build server socket address */ 
 
    sockAddrSize = sizeof (struct sockaddr_in); 
    bzero ((char *) &serverAddr, sockAddrSize); 
    serverAddr.sa_len = (u_char) sockAddrSize; 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons (SERVER_PORT_NUM); 
 
    if (((serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && 
        ((serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) 
        { 
        perror ("unknown server name"); 
        close (sFd); 
        return (ERROR); 
        } 
 
    /* build request, prompting user for message */ 
 
    printf ("Message to send: \n"); 
    mlen = read (STD_IN, myRequest.message, REQUEST_MSG_SIZE); 
    myRequest.message[mlen - 1] = '\0'; 
 
    printf ("Would you like the server to display your message (Y or N): \n"); 
    read (STD_IN, &display, 1); 
    switch (display) 
        { 
        case 'y': 
        case 'Y': myRequest.display = TRUE; 
            break; 
        default: myRey = FALSE; 
            break; 
        } 
 
    /* send request to server */ 
 
    if (sendto (sFd, (caddr_t) &myRequest, sizeof (myRequest), 0, 
        (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR) 
        { 
        perror ("sendto"); 
        close (sFd); 
        return (ERROR); 
        } 
 
    close (sFd); 
    return (OK); 
    }

/* udpServer.c - UDP server example */ 
 
/* 
DESCRIPTION 
This file contains the server-side of the VxWorks UDP example code. 
The example code demonstrates the useage of several BSD 4.4-style 
socket routine calls. 
*/ 
 
/* includes */ 
#include "vxWorks.h" 
#include "sockLib.h" 
#include "inetLib.h" 
#include "stdioLib.h" 
#include "strLib.h" 
#include "ioLib.h" 
#include "fioLib.h" 
#include "udpExample.h" 
 
 
/********************************************************************* 
* 
* udpServer - read from UDP socket and display client's message if requested  
* 
* Example of VxWorks UDP server: 
*       -> sp udpServer 
*       task spawned: id = 0x3a1f6c, name = t2 
*       value = 3809132 = 0x3a1f6c 
*       -> MESSAGE FROM CLIENT (Internet Address 150.12.0.11, port 1028): 
*       Greetings from UDP client 
* 
* RETURNS: Never, or ERROR if a resources could not be allocated. 
*/ 
 
STATUS udpServer (void) 
    { 
    struct sockaddr_in  serverAddr;    /* server's socket address */ 
    struct sockaddr_in  clientAddr;    /* client's socket address */ 
    struct request      clientRequest; /* request/Message from client */ 
    int                 sockAddrSize;  /* size of socket address structure */ 
    int                 sFd;           /* socket file descriptor */ 
    char                inetAddr[INET_ADDR_LEN]; 
                                       /* buffer for client's inet addr */ 
 
    /* set up the local address */ 
 
    sockAddrSize = sizeof (struct sockaddr_in); 
    bzero ((char *) &serverAddr, sockAddrSize); 
    serverAddr.sa_len = (u_char) sockAddrSize; 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons (SERVER_PORT_NUM); 
    serverAddr.sin_addr.s_addr = htonl (INADDR_ANY); 
 
    /* create a UDP-based socket */ 
 
    if ((sFd = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR) 
        { 
        perror ("socket"); 
        return (ERROR); 
        } 
 
    /* bind socket to local address */ 
 
    if (bind (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR) 
        { 
        perror ("bind"); 
        close (sFd); 
        return (ERROR); 
        } 
 
    /* read data from a socket and satisfy requests */ 
 
    FOREVER 
        { 
        if (recvfrom (sFd, (char *) &clientRequest, sizeof (clientRequest), 0, 
            (struct sockaddr *) &clientAddr, &sockAddrSize) == ERROR) 
            { 
            perror ("recvfrom"); 
            close (sFd); 
            return (ERROR); 
            } 
 
        /* if client requested that message be displayed, print it */ 
 
        if (clientRequest.display) 
            { 
            /* convert inet address to dot notation */ 
 
            inet_ntoa_b (clientAddr.sin_addr, inetAddr); 
            printf ("MSG FROM CLIENT (Internet Address %s, port %d):\n%s\n", 
                inetAddr, ntohs (clientAddr.sin_port), clientRequest.message); 
            } 
        } 
    } 

Using a Datagram (UDP) Socket to Access IP Multicasting

Multicasting is the delivery of the same packets to multiple IP addresses. Typical multicasting applications include audio and video conferencing, resource discovery tools, and shared white boards. Multicasting is a feature of the IP layer, but to access this function, an application uses a UDP socket.

A VxWorks process must multicast on a network interface driver that supports multicasting (many do not). To review the capabilities of all attached network drivers, use ifShow( ). If a network interface supports multicasting, IFF_MULTICAST is listed among the flags for that network interface.

Multicast IP addresses range from 224.0.0.0 to 239.255.255.255. These addresses are also called class D addresses or multicast groups. A datagram with a class D destination address is delivered to every process that has joined the corresponding multicast group.

To multicast a packet, a VxWorks process need do nothing special. The process just sends to the appropriate multicast address. The process can use any normal UDP socket. To set the route to the destination multicast address, use routeAdd( ).

To receive a multicast packet, a VxWorks process must join a multicast group. To do this, the VxWorks process must set the appropriate socket options on the socket (see Table 7-2).

Table 7-2:  Multicasting Socket Options1


Command
 
Argument
 
Description
 

IP_MULTICAST_IF
 
struct in_addr
 
Select default interface for outgoing multicasts.
 
IP_MULTICAST_TTL
 
CHAR
 
Select default time to live (TTL) for outgoing multicast packets.
 
IP_MULTICAST_LOOP
 
CHAR
 
Enable or disable loopback of outgoing multicasts.
 
IP_ADD_MEMBERSHIP
 
struct ip_mreq
 
Join a multicast group.
 
IP_DROP_MEMBERSHIP
 
struct ip_mreq
 
Leave a multicast group.
 

1:  For more on multicasting socket options, see the setsockopt( ) reference entry.

When choosing an address upon which to multicast, remember that certain addresses and address ranges are already registered to specific uses and protocols. For example, 244.0.0.1 multicasts to all systems on the local subnet. The Internet Assigned Numbers Authority (IANA) maintains a list of registered IP multicast groups. The current list can be found in RFC 1700. For more information about the IANA, see RFC 1700. Table 7-3 lists some of the well-known multicast groups.

Table 7-3:  Well-Known Multicast Groups


Group
 
VxWorks constant
 
Description
 

224.0.0.0
 
INADDR_UNSPEC_GROUP
 
Reserved for protocols that implement IP unicast and multicast routing mechanisms. Datagrams sent to any of these groups are not forwarded beyond the local network by multicast routers.
 
224.0.0.1
 
INADDR_ALLHOSTS_GROUP
 
All systems on this subnet. This value is automatically added to all network drivers at initialization.
 
224.0.0.2
   
All routers on this subnet.
 
224.0.0.3
   
Unassigned.
 
224.0.0.4
   
DVMRP routers.
 
224.0.0.5
   
OSPF routers.
 
224.0.0.6
   
OSPF designated routers.
 
224.0.0.9
   
All RIP routers.
 
224.0.0.255
 
INADDR_MAX_LOCAL_GROUP
 
Unassigned.
 
224.0.1.1
   
NTP (Network Time Protocol).
 

The following code samples define two routines, mcastSend( ) and mcastRcv( ). These routines demonstrate how to use UDP sockets to handle sending and receiving multicast traffic.

mcastSend( ) transmits a buffer to the specified multicast address. As input, this routine expects a multicast destination, a port number, a buffer pointer, and a buffer length. For example:

status = mcastSend ("224.1.0.1", 7777, bufPtr, 100);

mcastRcv( )receives any packet sent to a specified multicast address. As input, this routine expects the interface address from which the packet is coming, a multicast address, a port number, and the number of bytes to read from the packet. The returned value of the function is a pointer a buffer containing the read bytes. For example:

buf = mcastRcv (ifAddress, "224.1.0.1", 7777, 100) ;

Example 7-3:  Datagram Sockets (UDP) and Multicasting


/* includes */ 
#include "vxWorks.h" 
#include "taskLib.h" 
#include "socket.h" 
#include "netinet/in.h" 
#include "stdio.h" 
#include "stdlib.h" 
#include "string.h" 
#include "sockLib.h" 
#include "inetLib.h" 
#include "ioLib.h" 
#include "routeLib.h" 
  
/* defines */ 
/* globals */ 
/* forward declarations */ 
 
 
STATUS mcastSend (char * mcastAddr, USHORT mcastPort, char * sendBuf, 
                  int sendLen);  
char * mcastRcv (char * ifAddr, char * mcastAddr, USHORT mcastPort,  
                 int numRead);  
 
/************************************************************************ 
* mcastSend - send a message to the multicast address 
* This function sends a message to the multicast address 
* The multicast group address to send, the port number, the pointer to the  
* send buffer and the send buffer length are given as input parameters. 
* RETURNS: OK if sucessful or ERROR 
*/ 
 
STATUS mcastSend 
    ( 
    char *      mcastAddr,      /* multicast address  */ 
    USHORT      mcastPort,      /* udp port number */ 
    char *      sendBuf,        /* send Buffer */ 
    int         sendLen         /* length of send buffer */ 
    ) 
    { 
    struct sockaddr_in  sin;  
    struct sockaddr_in  toAddr;  
    int                 toAddrLen; 
    int                 sockDesc; 
    char *              bufPtr; 
    int                 len; 
 
    /* create a send and recv socket */ 
 
    if ((sockDesc = socket (AF_INET, SOCK_DGRAM, 0)) < 0 ) 
        { 
        printf (" cannot open send socket\n");  
        return (ERROR);  
        } 
 
    /* zero out the structures */ 
    bzero ((char *)&sin, sizeof (sin)); 
    bzero ((char *)&toAddr, sizeof (toAddr)); 
 
    sin.sa_len = (u_char) sizeof(sin);  
    sin.sin_family = AF_INET;  
    sin.sin_addr.s_addr = INADDR_ANY; 
    sin.sin_port = htons(0); 
 
    if (bind(sockDesc, (struct sockaddr *)&sin, sizeof(sin)) != 0) 
        { 
        perror("bind"); 
        if (sockDesc) 
            close (sockDesc); 
        return (ERROR);  
        } 
 
    toAddrLen = sizeof(struct sockaddr_in); 
    toAddr.sa_len      = (u_char) toAddrLen; 
    toAddr.sin_family      = AF_INET; 
 
 
    /* initialize the address to the send */ 
    toAddr.sin_addr.s_addr = inet_addr (mcastAddr); 
 
    /* initialize the port to send */ 
    toAddr.sin_port        = htons(mcastPort); 
 
    bufPtr = sendBuf;           /* initialize the buffer pointer */ 
 
    /* send the buffer */ 
    while (sendLen > 0) 
        { 
        if ((len = sendto (sockDesc, bufPtr, sendLen, 0,  
                           (struct sockaddr *)&toAddr, toAddrLen)) < 0 ) 
            { 
            printf("mcastSend sendto errno:0x%x\n", errno );  
            break; 
            } 
 
        sendLen -= len; 
        bufPtr += len; 
 
        taskDelay (1);          /* give  a taskDelay */ 
        } 
 
    if (sockDesc != ERROR) 
        close (sockDesc);  
 
    return (OK); 
    } 
 
/************************************************************************ 
 * mcastRcv - receive a message from a  multicast address 
 * This function receives a message from a  multicast address  
 * The interface address from which to receive the multicast packet, 
 * the multicast address to recv from, the port number and the number of  
 * bytes to read are given as input parameters to this routine. 
 * RETURNS: Pointer to the Buffer or NULL if error. 
 */ 
 
char * mcastRcv 
    ( 
    char *      ifAddr,         /* interface address to recv mcast packets */ 
    char *      mcastAddr,      /* multicast address  */ 
    USHORT      mcastPort,      /* udp port number to recv */ 
    int         numRead         /* number of bytes to read */ 
    ) 
    { 
    struct sockaddr_in  fromAddr;  
    struct sockaddr_in  sin;  
    int                 fromLen;  
    struct ip_mreq      ipMreq;  
    int                 recvLen; 
    int                 sockDesc; 
    char *              bufPtr;  
    int                 status  = OK; 
    char *              recvBuf = NULL; 
 
    if ((sockDesc = socket (AF_INET, SOCK_DGRAM, 0)) < 0)  
        { 
        printf (" cannot open recv socket\n");  
        return (NULL); 
        } 
 
    bzero ((char *)&sin, sizeof (sin)); 
    bzero ((char *) &fromAddr, sizeof(fromAddr)); 
    fromLen = sizeof(fromAddr);  
 
    if ((recvBuf = calloc (numRead, sizeof (char))) == NULL) 
        { 
        printf (" calloc error, cannot allocate memory\n");  
        status = ERROR; 
        goto cleanUp; 
        } 
 
    sin.sa_len = (u_char) sizeof(sin);  
    sin.sin_family = AF_INET;  
    sin.sin_addr.s_addr = INADDR_ANY;  
 
    /* UDP port number to match for the received packets */ 
    sin.sin_port = htons (mcastPort); 
 
    /* bind a port number to the socket */ 
    if (bind(sockDesc, (struct sockaddr *)&sin, sizeof(sin)) != 0) 
        { 
        perror("bind"); 
        status = ERROR; 
        goto cleanUp; 
        } 
     
    /* fill in the argument structure to join the multicast group */ 
    /* initialize the multicast address to join */ 
 
    ipMreq.imr_multiaddr.s_addr = inet_addr (mcastAddr); 
 
    /* unicast interface addr from which to receive the multicast packets */ 
    ipMreq.imr_interface.s_addr = inet_addr (ifAddr); 
     
    /* set the socket option to join the MULTICAST group */ 
    if (setsockopt (sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,  
                (char *)&ipMreq,  
                sizeof (ipMreq)) < 0) 
        {  
        printf ("setsockopt IP_ADD_MEMBERSHIP error:\n");  
        status = ERROR; 
        goto cleanUp; 
        } 
 
    /* get the data destined to the above multicast group */ 
    bufPtr = recvBuf; 
 
 
 
    while (numRead > 0) 
      { 
      if ((recvLen = recvfrom (sockDesc, bufPtr, numRead, 0,  
                             (struct sockaddr *)&fromAddr, &fromLen)) < 0) 
          { 
          perror("recvfrom");  
          status = ERROR; 
          break; 
          } 
       numRead -= recvLen;       /* decrement number of bytes to read */ 
      bufPtr  += recvLen;       /* increment the buffer pointer */ 
      } 
     
    /* set the socket option to leave the MULTICAST group */ 
    if (setsockopt (sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP,  
                    (char *)&ipMreq,  
                    sizeof (ipMreq)) < 0)  
        printf ("setsockopt IP_DROP_MEMBERSHIP error:\n");  
 
    cleanUp: 
        { 
        if (sockDesc != ERROR) 
            close (sockDesc); 
         if ((status != OK) && (recvBuf != NULL)) 
            { 
            free (recvBuf); 
            recvBuf = NULL; 
            } 
        } 
     return (recvBuf); 
    }