18.9 Thread-Safe UICI

Team-FLY

The UNIX functions that use errno were originally unsafe for threads. When errno was an external integer shared by all threads, one thread could set errno and have another thread change it before the first thread used the value. Multithreaded systems solve this problem by using thread-specific data for errno , thus preserving the syntax for the standard UNIX library functions. This same problem exists with any function that returns values in variables with static storage class.

The TCP socket implementation of UICI in Section 18.7 is thread-safe provided that the underlying implementations of socket , bind , listen , accept , connect , read , write and close are thread-safe and that the name resolution is thread-safe. The POSIX standard states that all functions defined by POSIX and the C standard are thread-safe, except the ones shown in Table 12.2 on page 432. The list is short and mainly includes functions, such as strtok and ctime , that require the use of static data.

The gethostbyname , gethostbyaddr and inet_ntoa functions, which are used in some versions of UICI name resolution, appear on the POSIX list of functions that might not be thread-safe. Some implementations of inet_ntoa (such as that of Sun Solaris) are thread-safe because they use thread-specific data. These possibly unsafe functions are used only in name2addr and addr2name , so the issue of thread safety of UICI is reduced to whether these functions are thread-safe.

Since getnameinfo and getaddrinfo are thread-safe, then if inet_ntoa is threadsafe, the implementations of name2addr and addr2name that use these are also threadsafe. Unfortunately, as stated earlier, getnameinfo and getaddrinfo are not yet available on many systems.

On some systems, thread-safe versions of gethostbyname and gethostbyaddr , called gethostbyname_r and gethostbyaddr_r , are available.

  SYNOPSIS  #include <netdb.h>   struct hostent *gethostbyname_r(const char *name,        struct hostent *result, char *buffer, int buflen,        int *h_errnop);   struct hostent *gethostbyaddr_r(const char *addr,        int length, int type, struct hostent *result,        char *buffer, int buflen, int *h_errnop); 

These functions perform the same tasks as their unsafe counterparts but do not use static storage. The user supplies a pointer to a struct hostent in the result parameter. Pointers in this structure point into the user-supplied buffer , which has length buflen . The supplied buffer array must be large enough for the generated data. When the gethostbyname_r and gethostbyaddr_r functions return NULL , they supply an error code in the integer pointed to by *h_errnop . Program 18.13 shows a threadsafe implementation of addr2name , assuming that inet_ntoa is thread-safe. Section C.2.2 contains a complete implementation of UICI, using gethostbyname_r and gethostbyaddress_r .

Unfortunately, gethostbyname_r and gethostbyaddress_r were part of the X/OPEN standard, but when this standard was merged with POSIX, these functions were omitted. Another problem associated with Program 18.13 is that it does not specify how large the user-supplied buffer should be. Stevens [115] suggests 8192 for this value, since that is what is commonly used in the implementations of the traditional forms.

An alternative for enforcing thread safety is to protect the sections that use static storage with mutual exclusion. POSIX:THR mutex locks provide a simple method of doing this. Program 18.14 is an implementation of addr2name that uses mutex locks. Section C.2.3 contains a complete implementation of UICI using mutex locks. This implementation does not require inet_ntoa to be thread-safe, since its static storage is protected also.

Program 18.13 addr2name_gethostbyaddr_r.c

A version of addr2name using gethostbyaddr_r .

 #include <ctype.h> #include <netdb.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #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; } 
Program 18.14 addr2name_mutex.c

A thread-safe version of addr2name using POSIX mutex locks .

 #include <ctype.h> #include <netdb.h> #include <pthread.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void addr2name(struct in_addr addr, char *name, int namelen) {     struct hostent *hostptr;     pthread_mutex_lock(&mutex);     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; } 
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