C.1 Connection-Oriented UICI TCP Implementation

Team-FLY

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.

Program 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.

Program 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; } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net