Appendix C. UICI Implementation

This appendix contains source code for the UICI implementation. UICI has three parts: TCP, UDP and name resolution. The TCP and UDP UICI are implemented with sockets. Several different implementations of the name resolution functions are given. The name resolution functions are used by both UICI TCP and UICI UDP, but UICI TCP and UICI UDP are independent of each other. Section C.1 gives the UICI TCP implementation, Section C.2 gives the name resolution implementations, and Section C.3 gives the UICI UDP implementation.

Connection-Oriented UICI TCP Implementation

This section gives a complete implementation of the UICI TCP functions in terms of sockets.

Program C.1 shows the header file containing the prototypes for the UICI TCP functions. This file should be included in all application code that calls any of the public UICI functions.

Example C.1. uici.h

The header file containing prototypes of the UICI functions.

/*********************************** uici.h **************************/
/*   Prototypes for the three public UICI functions                  */
/*********************************************************************/
#define UPORT
typedef unsigned short u_port_t;
int u_open(u_port_t port);
int u_accept(int fd, char *hostn, int hostnsize);
int u_connect(u_port_t port, char *hostn);

The u_accept and u_connect functions call the name resolution functions addr2name and name2addr, respectively. Several implementations of these name resolution functions are discussed in Section C.2.1, Section C.2.2 and Section C.2.3.

Writing to a network socket that has no readers generates a SIGPIPE signal. If an application does not handle this signal, the remote host can cause the application to terminate by prematurely closing the connection. Both u_open and u_connect call u_ignore_sigpipe, which ignores the SIGPIPE signal if the default action for SIGPIPE (termination of the process) is in effect.

The u_open function also sets the SO_REUSEADDR option of the socket so that a server can immediately reuse a port number when it is not in use. This option is useful during debugging, for otherwise after terminating a server, you must wait (possibly several minutes) before starting the server listening again on the same port. The maximum backlog is set to 50 by default, but you can change this value either by modifying the uici.c file or by setting a compiler option (usually -D).

The u_accept function calls addr2name with three parameters. The first parameter is an address of type struct in_addr, which is converted to an ASCII string. The second parameter is a pointer to a buffer for storing the string, and the third parameter is the length of the buffer. If the buffer is not long enough to contain the host name string, addr2name silently truncates the string without producing an error. If name2addr cannot determine the host name, it uses the dotted-decimal notation address.

The u_connect function calls name2addr to convert an ASCII host name to an Internet address. If the name2addr call is not successful, u_connect returns –1 with errno set to EINVAL. The ASCII host name can be either a traditional name or an address in dotted-decimal notation. In the latter case, all the implementations of name2addr use inet_addr to convert the name to an address. The u_connect function must be handled in a special way when it is interrupted by a signal. If interrupted by a signal, u_connect continues to establish the connection asynchronously and it should not be called again. Instead, u_connect calls select to wait until the socket is available for writing. At this point the connection is established.

Example C.2. uici.c

The complete uici library.

/* uici.c  sockets implementation */

#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include "uici.h"
#include "uiciname.h"

#ifndef MAXBACKLOG
#define MAXBACKLOG 50
#endif

/*
 *                           u_igniore_sigpipe
 * Ignore SIGPIPE if the default action is in effect.
 *
 * returns: 0 if successful
 *          -1 on error and sets errno
 */
static int u_ignore_sigpipe() {
   struct sigaction act;

   if (sigaction(SIGPIPE, (struct sigaction *)NULL, &act) == -1)
      return -1;
   if (act.sa_handler == SIG_DFL) {
      act.sa_handler = SIG_IGN;
      if (sigaction(SIGPIPE, &act, (struct sigaction *)NULL) == -1)
         return -1;
   }
   return 0;
}

/*
 *                           u_open
 * Return a file descriptor, which is bound to the given port.
 *
 * parameter:
 *        s = number of port to bind to
 * returns:  file descriptor if successful
 *           -1 on error and sets errno
 */
int u_open(u_port_t port) {
   int error;
   struct sockaddr_in server;
   int sock;
   int true = 1;

   if ((u_ignore_sigpipe() == -1) ||
        ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
      return -1;

   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&true,
                  sizeof(true)) == -1) {
      error = errno;
      while ((close(sock) == -1) && (errno == EINTR));
      errno = error;
      return -1;
   }

   server.sin_family = AF_INET;
   server.sin_addr.s_addr = htonl(INADDR_ANY);
   server.sin_port = htons((short)port);
   if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) ||
        (listen(sock, MAXBACKLOG) == -1)) {
      error = errno;
      while ((close(sock) == -1) && (errno == EINTR));
      errno = error;
      return -1;
   }
   return sock;
}

/*
 *                           u_accept
 * Wait for a connection request from a host on a specified port.
 *
 * parameters:
 *      fd = file descriptor previously bound to listening port
 *      hostn = a buffer that will hold the name of the remote host
 *      hostnsize = size of hostn buffer
 * returns:  a communication file descriptor on success
 *              hostn is filled with the name of the remote host.
 *           -1 on error with errno set
 *
 * comments: This function is used by the server to wait for a
 * communication.  It blocks until a remote request is received
 * from the port bound to the given file descriptor.
 * hostn is filled with an ASCII string containing the remote
 * host name.  It must point to a buffer of size at least hostnsize.
 * If the name does not fit, as much of the name as is possible is put
 * into the buffer.
 * If hostn is NULL or hostnsize <= 0, no hostname is copied.
 */
int u_accept(int fd, char *hostn, int hostnsize) {
   int len = sizeof(struct sockaddr);
   struct sockaddr_in netclient;
   int retval;

   while (((retval =
           accept(fd, (struct sockaddr *)(&netclient), &len)) == -1) &&
          (errno == EINTR))
      ;
   if ((retval == -1) || (hostn == NULL) || (hostnsize <= 0))
      return retval;
   addr2name(netclient.sin_addr, hostn, hostnsize);
   return retval;
}

/*
 *                           u_connect
 * Initiate communication with a remote server.
 *
 * parameters:
 *     port  = well-known port on remote server
 *     hostn = character string giving the Internet name of remote host
 * returns:  a communication file descriptor if successful
 *           -1 on error with errno set
 */
int u_connect(u_port_t port, char *hostn) {
   int error;
   int retval;
   struct sockaddr_in server;
   int sock;
   fd_set sockset;

   if (name2addr(hostn,&(server.sin_addr.s_addr)) == -1) {
      errno = EINVAL;
      return -1;
   }
   server.sin_port = htons((short)port);
   server.sin_family = AF_INET;

   if ((u_ignore_sigpipe() == -1) ||
        ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1))
      return -1;

   if (((retval =
       connect(sock, (struct sockaddr *)&server, sizeof(server))) == -1) &&
       ((errno == EINTR) || (errno == EALREADY))) {
       FD_ZERO(&sockset);
       FD_SET(sock, &sockset);
       while ( ((retval = select(sock+1, NULL, &sockset, NULL, NULL)) == -1) &&
               (errno == EINTR) ) {
          FD_ZERO(&sockset);
          FD_SET(sock, &sockset);
       }
   }
   if (retval == -1) {
        error = errno;
        while ((close(sock) == -1) && (errno == EINTR));
        errno = error;
        return -1;
   }
   return sock;
}

Name Resolution Implementations

The socket functions are both standardized and generally available. Unfortunately, several options are available for converting between host name and address, and none is optimal for all situations. The functions that are robust and thread-safe are not yet readily available on all systems. We offer several options controlled by compile-time definitions. The two UICI name resolution functions are addr2name and name2addr. Prototypes for these are in uiciname.h, shown in Program C.3.

Example C.3. uiciname.h

The header file for the UICI name resolution functions.

/* uiciname.h name resolution functions */

#include <netinet/in.h>
#define REENTRANT_NONE 0
#define REENTRANT_R 1
#define REENTRANT_MUTEX 2
#define REENTRANT_POSIX 3

int name2addr(char *name, in_addr_t *addrp);
void addr2name(struct in_addr addr, char *name, int namelen);

The addr2name function never returns an error. If the name cannot be resolved, the address is converted to a dotted-decimal notation format. The name2addr function returns 0 on success and –1 on failure. The UICI TCP and UDP functions that call the name resolution functions handle this error by returning –1 and setting errno to EINVAL.

Program C.4 contains four implementations of the name resolution functions addr2name and name2addr. Conditional compilation enables the constant REENTRANCY to determine which implementation is picked. If this constant is not defined, the default value of REENTRANT_NONE is used, giving an implementation with gethostbyname and gethostbyaddr. The value of REENTRANCY can be set either by adding a #define in the uiciname.h file or with a compile-time option.

Implementation with gethostbyaddr and gethostbyname

The first implementation of name resolution presented here uses gethostbyname and gethostbyaddr. These functions should be available on all UNIX implementations. Their main drawback is that they are not thread-safe, so they cannot be directly used by more than one thread. These implementations are used by default or when the constant REENTRANCY is set to REENTRANT_NONE.

Reentrant versions of name resolution functions

If REENTRANCY is equal to REENTRANT_R, the implementations use gethostbyaddr_r and gethostbyname_r. These functions were part of the X/OPEN standard, but when this standard was merged with POSIX, these functions were omitted. However, they are still available on some systems. These functions require a user-supplied buffer, but the documentation does not specify how large this buffer should be. Stevens [115] suggests 8192 for this value, since that is what is commonly used in the implementations of the non-thread-safe forms.

If REENTRANCY is equal to REENTRANT_POSIX, then the implementation uses the newer getnameinfo and getaddrinfo functions. These thread-safe functions can also be used with IPv6. Unfortunately, they are not yet available on many systems. Section 18.8 describes getnameinfo and getaddrinfo.

Reentrant name resolution with mutex locks

If neither group of reentrant name resolution functions is available, you can use gethostbyname and gethostbyaddr by protecting them with mutex locks. Set REENTRANCY to REENTRANT_MUTEX to use this implementation. The implementation uses a single mutex lock to protect calls to gethostbyname and gethostbyaddr.

Example C.4. uiciname.c

Four implementations of the UICI name resolution functions.

/* uiciname.c  name resolution functions */

#include <ctype.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "uiciname.h"

#ifndef REENTRANCY
#define REENTRANCY REENTRANT_NONE
#endif

#if REENTRANCY==REENTRANT_MUTEX
#include <pthread.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

#if REENTRANCY==REENTRANT_NONE
/* Convert struct in_addr to a host name */
void addr2name(struct in_addr addr, char *name, int namelen) {
   struct hostent *hostptr;
   hostptr = gethostbyaddr((char *)&addr, 4, AF_INET);
   if (hostptr == NULL)
      strncpy(name, inet_ntoa(addr), namelen-1);
   else
      strncpy(name, hostptr->h_name, namelen-1);
   name[namelen-1] = 0;
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   struct hostent *hp;

   if (isdigit((int)(*name)))
      *addrp = inet_addr(name);
   else {
      hp = gethostbyname(name);
      if (hp == NULL)
         return -1;
      memcpy((char *)addrp, hp->h_addr_list[0], hp->h_length);
   }
   return 0;
}
#elif REENTRANCY==REENTRANT_R
#define GETHOST_BUFSIZE 8192
void addr2name(struct in_addr addr, char *name, int namelen) {
   char buf[GETHOST_BUFSIZE];
   int h_error;
   struct hostent *hp;
   struct hostent result;

   hp = gethostbyaddr_r((char *)&addr, 4, AF_INET, &result, buf,
                         GETHOST_BUFSIZE, &h_error);
   if (hp == NULL)
      strncpy(name, inet_ntoa(addr), namelen-1);
   else
      strncpy(name, hp->h_name, namelen-1);
   name[namelen-1] = 0;
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   char buf[GETHOST_BUFSIZE];
   int h_error;
   struct hostent *hp;
   struct hostent result;

   if (isdigit((int)(*name)))
      *addrp = inet_addr(name);
   else {
      hp = gethostbyname_r(name, &result, buf, GETHOST_BUFSIZE, &h_error);
      if (hp == NULL)
         return -1;
      memcpy((char *)addrp, hp->h_addr_list[0], hp->h_length);
   }
   return 0;
}
#elif REENTRANCY==REENTRANT_MUTEX
/* Convert struct in_addr to a host name */
void addr2name(struct in_addr addr, char *name, int namelen) {
   struct hostent *hostptr;

   if (pthread_mutex_lock(&mutex) == -1) {
      strncpy(name, inet_ntoa(addr), namelen-1);
      name[namelen-1] = 0;
      return;
   }
   hostptr = gethostbyaddr((char *)&addr, 4, AF_INET);
   if (hostptr == NULL)
      strncpy(name, inet_ntoa(addr), namelen-1);
   else
      strncpy(name, hostptr->h_name, namelen-1);
   pthread_mutex_unlock(&mutex);
   name[namelen-1] = 0;
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   struct hostent *hp;

   if (isdigit((int)(*name)))
      *addrp = inet_addr(name);
   else {
      if (pthread_mutex_lock(&mutex) == -1)
         return -1;
      hp = gethostbyname(name);
      if (hp == NULL) {
         pthread_mutex_unlock(&mutex);
         return -1;
      }
      memcpy((char *)addrp, hp->h_addr_list[0], hp->h_length);
      pthread_mutex_unlock(&mutex);
   }
   return 0;
}
#elif REENTRANCY==REENTRANT_POSIX
/* Convert struct in_addr to a host name */
void addr2name(struct in_addr addr, char *name, int namelen) {
   struct sockaddr_in saddr;
   saddr.sin_family = AF_INET;
   saddr.sin_port = 0;
   saddr.sin_addr = addr;
   if (getnameinfo((struct sockaddr *)&saddr, sizeof(saddr), name, namelen,
         NULL, 0, 0) != 0) {
      strncpy(name, inet_ntoa(addr), namelen-1);
      name[namelen-1] = 0;
   }
}

/* Return -1 on error, 0 on success */
int name2addr(char *name, in_addr_t *addrp) {
   struct addrinfo hints;
   struct addrinfo *res;
   struct sockaddr_in *saddrp;

   hints.ai_flags = AI_PASSIVE;
   hints.ai_family = PF_INET;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = 0;
   hints.ai_addrlen = 0;
   hints.ai_canonname = NULL;
   hints.ai_addr = NULL;
   hints.ai_next = NULL;

   if (getaddrinfo(name, NULL, &hints, &res) != 0)
      return -1;
   saddrp = (struct sockaddr_in *)(res->ai_addr);
   memcpy(addrp, &saddrp->sin_addr.s_addr, 4);
   freeaddrinfo(res);
   return 0;
}

#endif

Connectionless UICI UDP Implementation

Program C.5 shows the header file containing the prototypes for the UICI UDP functions. This file should be included in all applications that call any of these public functions. The details of the implementation have already been given in Section 20.7, so we just present the complete code in Program C.6.

Example C.5. uiciudp.h

The header file for the UICI UDP functions.

#include <netinet/in.h>

#ifndef UPORT
typedef unsigned short u_port_t;
#endif
#define UPORT

#ifndef ETIME
#define ETIME ETIMEDOUT
#endif

typedef struct sockaddr_in u_buf_t;
int u_openudp(u_port_t port);
void u_gethostname(u_buf_t *ubufp, char *hostn, int hostnsize);
void u_gethostinfo(u_buf_t *ubufp, char *info, int infosize);
int u_comparehost(u_buf_t *ubufp, char *hostn, u_port_t port);
ssize_t u_sendtohost(int fd, void *buf, size_t nbyte, char *hostn,
                     u_port_t port);
ssize_t u_sendto(int fd, void *buf, size_t nbyte, u_buf_t *ubufp);
ssize_t u_recvfrom(int fd, void *buf, size_t nbyte, u_buf_t *ubufp);
ssize_t u_recvfromtimed(int fd, void *buf, size_t nbyte, u_buf_t *ubufp,
                         double time);
int u_join(char *IP_address, u_port_t port, u_buf_t *ubufp);
int u_leave(int mcastfd, u_buf_t *ubufp);

Example C.6. uiciudp.c

An implementation of UICI UDP using sockets.

/* uiciudp.c udp sockets implementation */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "restart.h"
#include "uiciname.h"
#include "uiciudp.h"

/*
 *                           u_openudp
 * Return a file descriptor.
 *  It is bound to the given port if the port is positive.
 *
 * parameter:
 *        port = number of port to bind to
 * returns:  file descriptor if successful
 *           -1 on error and sets errno
 */
int u_openudp(u_port_t port) {
   int error;
   int one = 1;
   struct sockaddr_in server;
   int sock;

   if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
      return -1;

   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
      error = errno;
      r_close(sock);
      errno = error;
      return -1;
   }

   if (port > 0) {
      server.sin_family = AF_INET;
      server.sin_addr.s_addr = htonl(INADDR_ANY);
      server.sin_port = htons((short)port);

      if (bind(sock, (struct sockaddr *)&server, sizeof(server)) == -1) {
         error = errno;
         r_close(sock);
         errno = error;
         return -1;
      }
   }
   return sock;
}

/*
 *                           u_recvfrom
 *
 * Retrieve information from a file descriptor.
 *
 * parameters:
 *       fd = socket file descriptor
 *       buf = buffer that receives the data
 *       nbytes = number of bytes to retrieve
 *       ubufp = a pointer to a buffer of type u_buf_t
 * returns:
 *      the number of bytes read if successful.
 *         ubufp is filled with information about the sending host and port
 *      -1 on error and sets errno
 */

ssize_t u_recvfrom(int fd, void *buf, size_t nbytes, u_buf_t *ubufp) {
   int len;
   struct sockaddr *remote;
   int retval;

   len = sizeof (struct sockaddr_in);
   remote = (struct sockaddr *)ubufp;
   while (((retval = recvfrom(fd, buf, nbytes, 0, remote, &len)) == -1) &&
           (errno == EINTR)) ;
   return retval;
}

/*
 *                           u_recvfromtimed
 *
 * Retrieve information from a file descriptor with a timeout.
 *
 * parameters:
 *       fd = socket file descriptor
 *       buf = buffer to receive the data
 *       nbytes = number of bytes to retrieve
 *       ubufp = a pointer to a buffer of type u_buf_t
 *       seconds = timeout in seconds
 * returns:
 *      number of bytes received if successful
 *      -1 on error and sets errno
 */

ssize_t u_recvfromtimed(int fd, void *buf, size_t nbytes, u_buf_t *ubufp,
                         double seconds) {
   int len;
   struct sockaddr *remote;
   int retval;
   struct timeval timedone;

   timedone = add2currenttime(seconds);
   if (waitfdtimed(fd, timedone) == -1)
      return (ssize_t)(-1);
   len = sizeof (struct sockaddr_in);
   remote = (struct sockaddr *)ubufp;
   while (((retval = recvfrom(fd, buf, nbytes, 0, remote, &len)) == -1) &&
           (errno == EINTR)) ;
   return retval;
}

/*
 *                           u_gethostname
 *
 * Get the host name from a buffer of type u_buf_t
 *
 * parameters:
 *       ubufp = a pointer to a buffer of type u_buf_t that was
 *          filled by u_recvfrom
 *       hostn = a buffer of size hostnsize
 *       hostsize = the size of the hostn buffer
 * returns:
 *      hostn is filled with the name of the host, possibly truncated.
 */

void u_gethostname(u_buf_t *ubufp, char *hostn, int hostnsize) {
   struct sockaddr_in *remotep;

   remotep = (struct sockaddr_in *)ubufp;
   addr2name(remotep->sin_addr, hostn, hostnsize);
}

/*
 *                           u_gethostinfo
 *
 * Get a printable string containing the host name and port
 *
 * parameters:
 *       ubufp = a pointer to a buffer of type u_buf_t that was
 *          filled by u_recvfrom
 *       info = a buffer to hold the returned string
 *       infosize = the size of the info buffer
 * returns:
 *      a string is put in info, possibly truncated
 */
void u_gethostinfo(u_buf_t *ubufp, char *info, int infosize) {
   int len;
   int portnumber;

   portnumber = ntohs(ubufp->sin_port);
   len = snprintf(info, infosize, "port number is %d on host ", portnumber);
   info[infosize-1] = 0;                              /* in case name not fit */
   if (len >= infosize) return;
   u_gethostname(ubufp, info+len, infosize-len);
}


/*
 *                           u_comparehost
 *
 * Compare the given host and port with the info in a u_buf_t structure
 *
 * parameters:
 *       ubufp = a pointer to a buffer of type u_buf_t that was
 *          filled by u_recvfrom
 *       hostn = a string representing the host name
 *       port  = a port number
 * returns:
 *      1 if match
 *      0 if no match
 */

int u_comparehost(u_buf_t *ubufp, char *hostn, u_port_t port) {
   in_addr_t addr;
   struct sockaddr_in *remotep;

   remotep = (struct sockaddr_in *)ubufp;
   if ((port != ntohs(remotep->sin_port)) ||
       (name2addr(hostn, &addr) == -1) ||
       (memcmp(&(remotep->sin_addr.s_addr), &addr, sizeof(in_addr_t)) != 0))
      return 0;
   return 1;
}


/*
 *                           u_sendto
 *
 * Send information atomically to a remote host, using the buffer filled in
 * by recvfrom
 *
 * This is almost the same as sendto except that
 *   it retries if interrupted by a signal and
 *   the length of the buffer indicating the destination is not passed
 *
 * parameters:
 *       fd = file descriptor
 *       buf = buffer to be output
 *       nbytes = number of bytes to send
 *       ubufp = a pointer to a buffer of type u_buf_t that was
 *          filled by u_recvfrom
 * returns:
 *      the number of bytes that were sent (may not have been received)
 *      -1 on error and sets errno
 */

ssize_t u_sendto(int fd, void *buf, size_t nbytes, u_buf_t *ubufp) {
   int len;
   struct sockaddr *remotep;
   int retval;

   len = sizeof(struct sockaddr_in);
   remotep = (struct sockaddr *)ubufp;
   while (((retval = sendto(fd, buf, nbytes, 0, remotep, len)) == -1) &&
           (errno == EINTR)) ;
   return retval;
}

/*
 *                           u_sendtohost
 *
 * Send information atomically to a remote host given the host name and port
 *
 * parameters:
 *       fd = file descriptor
 *       buf = buffer to be output
 *       nbyte = number of bytes to send
 *       port = the port number to send to
 *       hostn = a string containing the name of the destination host
 * returns:
 *      the number of bytes that were sent (may not have been received)
 *      -1 on error and sets errno
 */

ssize_t u_sendtohost(int fd, void *buf, size_t nbytes, char *hostn,
                     u_port_t port) {
   struct sockaddr_in remote;

   if (name2addr(hostn, &(remote.sin_addr.s_addr)) == -1) {
      errno = EINVAL;
      return -1;
   }
   remote.sin_port = htons((short)port);
   remote.sin_family = AF_INET;
   return u_sendto(fd, buf, nbytes, &remote);
}

/*
 *                           u_join
 *
 * Join a multicast group
 *
 * parameters:
 *       IP_address = string representing the IP address of the group
 *       port = port number of multicast group
 *       ubufp = buffer to be filled in u_join
 * returns:
 *      a file descriptor on success
 *      -1 on error and sets errno
*/
int u_join(char *IP_address, u_port_t port, u_buf_t *ubufp) {
   int mcastfd;
   struct ip_mreq tempaddress;

   if ((mcastfd = u_openudp(port)) == -1)
      return mcastfd;

   tempaddress.imr_multiaddr.s_addr = inet_addr(IP_address);
   tempaddress.imr_interface.s_addr = htonl(INADDR_ANY);

        /* Join the multicast group. Let kernel choose the interface */
   if (setsockopt(mcastfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                   &tempaddress, sizeof(tempaddress)) == -1)
      return -1;
   ubufp->sin_family = AF_INET;
   ubufp->sin_addr.s_addr = inet_addr(IP_address);
   ubufp->sin_port = htons((short)port);
   return mcastfd;
}

/* This version leaves the group but keeps the file descriptor open and
   still bound to the same port.  It can still receive messages on the port,
   but only those addressed directly to the given host.
*/
/*
 *                           u_leave
 *
 * Leave a multicast group.  Messages can still be received on the port
 * if they are directly addressed to the host.
 *
 * parameters:
 *       mcastfd = previously opened file descriptor returned by u_join
 *       ubufp = buffer filled in by previous u_join
 * returns:
 *      0 on success
 *      -1 on error with errno set
*/
int u_leave(int mcastfd, u_buf_t *ubufp) {
   struct ip_mreq tempaddress;

   memcpy(&(tempaddress.imr_multiaddr),
         &(ubufp->sin_addr), sizeof(struct in_addr));
   tempaddress.imr_interface.s_addr = htonl(INADDR_ANY);
   return setsockopt(mcastfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
                   &tempaddress, sizeof(tempaddress));
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset