Source File modules/sk/sk_socket.c

    1    | /***************************************
    2    |   $Revision: 1.3 $
    3    |
    4    |   Example code: A socket module.
    5    |
    6    |   Status: NOT REVUED, NOT TESTED
    7    |
    8    |   +html+ <DL COMPACT>
    9    |   +html+ <DT>Online References:
    10   |   +html+ <DD><UL>
    11   |   +html+   <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>.
    12   |   +html+ </UL>
    13   |   +html+ </DL>
    14   |   +html+ <PRE>
    15   |   +html+ </PRE>
    16   |
    17   |   ******************/ /******************
    18   |   Modification History:
    19   |         ottrey (08/03/1999) Created from sockhelp.c.
    20   |         ottrey (08/03/1998) Heavily butchered.
    21   |         joao   (22/06/1999) Modified socket creation and accepts.
    22   |   ******************/ /******************
    23   |  REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE
    24   |   ***************************************/
    25   | #include <arpa/inet.h>
    26   | #include "socket.h"
    27   | #include "constants.h"
    28   | #include "stubs.h"
    29   |
    30   | #include "iproutines.h"
    31   | #include "memwrap.h"
    32   |
    33   | #include <pthread.h>
    34   |
    35   | extern int h_errno;
    36   |
    37   |
    38   | /*+ String sizes +*/
    39   | #define STR_S   63
    40   | #define STR_M   255
    41   | #define STR_L   1023
    42   | #define STR_XL  4095
    43   | #define STR_XXL 16383
    44   |
    45   | /* SK_atoport() */
    46   | /*++++++++++++++++++++++++++++++++++++++
    47   |    Take a service name, and a service type, and return a port number.  If the
    48   |    service name is not found, it tries it as a decimal number.  The number
    49   |    returned is byte ordered for the network.
    50   |
    51   |   char *service   Service name (or port number).
    52   |
    53   |   char *proto     Protocol (eg "tcp").
    54   |
    55   |   More:
    56   |   +html+ <PRE>
    57   |   Authors:
    58   |         ottrey
    59   |
    60   |   +html+ </PRE><DL COMPACT>
    61   |   +html+ <DT>Online References:
    62   |   +html+ <DD><UL>
    63   |   +html+ </UL></DL>
    64   |
    65   |   ++++++++++++++++++++++++++++++++++++++*/
    66   | int SK_atoport(const char *service, const char *proto) {
    67   |   int port;
    68   |   long int lport;
    69   |   struct servent *serv;
    70   |   char *errpos;
    71   |   struct servent result;
    72   |   char buffer[STR_XXL];
    73   |
    74   |   /* First try to read it from /etc/services */
    75   |
    76   |   /*  serv = getservbyname(service, proto); */
    77   |   serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
    78   |   if (serv != NULL)
    79   |     port = serv->s_port;
    80   |   else { /* Not in services, maybe a number? */
    81   |     lport = strtol(service,&errpos,0);
    82   |     if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
    83   |       return -1; /* Invalid port address */
    84   |     port = htons(lport);
    85   |   }
    86   |   return port;
    87   | } /* SK_atoport() */
    88   |
    89   |
    90   | /* SK_close_listening_socket() */
    91   | /*++++++++++++++++++++++++++++++++++++++
    92   |   XXX Note: Not sure how long this function will last.  Shouldn't _really_ need it.
    93   |
    94   |   More:
    95   |   +html+ <PRE>
    96   |   Authors:
    97   |         ottrey
    98   |
    99   |   +html+ </PRE><DL COMPACT>
    100  |   +html+ <DT>Online References:
    101  |   +html+ <DD><UL>
    102  |   +html+ </UL></DL>
    103  |
    104  |   ++++++++++++++++++++++++++++++++++++++*/
    105  | /*void SK_close_listening_socket() {
    106  |   close(listening_socket);
    107  | } */ /* SK_close_listening_socket */
    108  |
    109  | static void func_sigusr(int n) {
    110  |   ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigusr(%d) called", n);
    111  | }
    112  |
    113  | void SK_close(int socket) {
    114  |   ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
    115  |
    116  |   close(socket);
    117  | }
    118  |
    119  | /* SK_getsock() */
    120  | /*++++++++++++++++++++++++++++++++++++++
    121  |
    122  |    This function creates a socket and binds to it
    123  |
    124  |    int      SK_getsock       The new socket
    125  |
    126  |    int      socket_type      SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
    127  |
    128  |    u_short  port             The port to listen on.  Remember that ports < 1024 are
    129  |                              reserved for the root user.  Must be passed in network byte
    130  |                              order (see "man htons").
    131  |
    132  |    uint32_t bind_address     Address to bind to, in network order.
    133  |   More:
    134  |   +html+ <PRE>
    135  |   Authors:
    136  |         ottrey
    137  | 	joao
    138  |
    139  |   +html+ </PRE><DL COMPACT>
    140  |   +html+ <DT>Online References:
    141  |   +html+ <DD><UL>
    142  |   +html+ </UL></DL>
    143  |
    144  |   ++++++++++++++++++++++++++++++++++++++*/
    145  | int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
    146  |   struct sockaddr_in address;
    147  |   int listening_socket;
    148  |   int reuse_addr = 1;
    149  |
    150  |   /* Setup internet address information.
    151  |      This is used with the bind() call */
    152  |   memset((char *) &address, 0, sizeof(address));
    153  |   address.sin_family = AF_INET;
    154  |   address.sin_port = port;
    155  |   address.sin_addr.s_addr = bind_address;
    156  |
    157  |   /* Map all of the signals and exit routine */
    158  |
    159  |   listening_socket = socket(AF_INET, socket_type, 0);
    160  |   if (listening_socket < 0) {
    161  |     perror("socket");
    162  |     exit(EXIT_FAILURE);
    163  |   }
    164  |
    165  |   setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
    166  |
    167  |   if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
    168  |     perror("bind");
    169  |     close(listening_socket);
    170  |     exit(EXIT_FAILURE);
    171  |   }
    172  |
    173  |
    174  |   if (socket_type == SOCK_STREAM) {
    175  |     listen(listening_socket, 5); /* Queue up to five connections before
    176  |                                   having them automatically rejected. */
    177  |   }
    178  |
    179  |   return listening_socket;
    180  | } /* SK_getsock() */
    181  |
    182  | /*++++++++++++++++++++++++++++++++++++++
    183  |
    184  |    Wait for an incoming connection on the specified socket
    185  |
    186  |    int	SK_accept_connection The socket for communicating to the client
    187  |
    188  |    int  listening_socket     The socket that the server is bound to
    189  |
    190  |   More:
    191  |   +html+ <PRE>
    192  |   Authors:
    193  | 	joao
    194  |   +html+ </PRE>
    195  |   ++++++++++++++++++++++++++++++++++++++*/
    196  | int SK_accept_connection(int listening_socket) {
    197  |   int connected_socket = -1;
    198  |
    199  |   while(connected_socket < 0) {
    200  |
    201  |     ER_dbg_va(FAC_SK, ASP_SK_GEN,
    202  | 	      "Going to accept connections on socket : %d",listening_socket);
    203  |
    204  | /* XXX joao - ? - why is this here?
    205  | fflush(NULL);
    206  | */
    207  |
    208  |     connected_socket = accept(listening_socket, NULL, NULL);
    209  |     if (connected_socket < 0) {
    210  |       /* Either a real error occured, or blocking was interrupted for
    211  |          some reason.  Only abort execution if a real error occured. */
    212  |       if (errno != EINTR) {
    213  |         perror("accept");
    214  |         close(listening_socket);
    215  |         return(-1);
    216  |      /* no exit, just return with error */
    217  |       } else {
    218  |         continue;    /* don't return - do the accept again */
    219  |       }
    220  |     }
    221  |   }
    222  |
    223  |   ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
    224  | 	    connected_socket
    225  | 	    );
    226  |
    227  |   return connected_socket;
    228  | }
    229  |
    230  | /* SK_read() */
    231  | /*++++++++++++++++++++++++++++++++++++++
    232  |
    233  |    This is just like the read() system call, except that it will make
    234  |    sure that all your data goes through the socket.
    235  |
    236  |    int    SK_read  The number of bytes read.
    237  |
    238  |    int    sockfd    The socket file descriptor.
    239  |
    240  |    char   *buf      The buffer to be read from the socket.
    241  |
    242  |    size_t count     The number of bytes in the buffer.
    243  |
    244  |   More:
    245  |   +html+ <PRE>
    246  |   Authors:
    247  |         ottrey
    248  |   +html+ </PRE>
    249  |   ++++++++++++++++++++++++++++++++++++++*/
    250  | int SK_read(int sockfd, char *buf, size_t count) {
    251  |   size_t bytes_read = 0;
    252  |   int this_read;
    253  |
    254  |   while (bytes_read < count) {
    255  |     do
    256  |       this_read = read(sockfd, buf, count - bytes_read);
    257  |     while ( (this_read < 0) && (errno == EINTR) );
    258  |     if (this_read < 0)
    259  |       return this_read;
    260  |     else if (this_read == 0)
    261  |       return bytes_read;
    262  |     bytes_read += this_read;
    263  |     buf += this_read;
    264  |   }
    265  |
    266  |   return count;
    267  |
    268  | } /* SK_read() */
    269  |
    270  |
    271  | /* SK_write() */
    272  | /*++++++++++++++++++++++++++++++++++++++
    273  |
    274  |    This is just like the write() system call, accept that it will
    275  |    make sure that all data is transmitted.
    276  |
    277  |    int    sockfd  The socket file descriptor.
    278  |
    279  |    char   *buf    The buffer to be written to the socket.
    280  |
    281  |    size_t count   The number of bytes in the buffer.
    282  |
    283  |   More:
    284  |   +html+ <PRE>
    285  |   Authors:
    286  |         ottrey
    287  |
    288  |   +html+ </PRE><DL COMPACT>
    289  |   +html+ <DT>Online References:
    290  |   +html+ <DD><UL>
    291  |   +html+ </UL></DL>
    292  |
    293  |   ++++++++++++++++++++++++++++++++++++++*/
    294  | int SK_write(int sockfd, const char *buf, size_t count) {
    295  |   size_t  bytes_sent = 0;
    296  |   int     this_write;
    297  |
    298  |
    299  |   ER_dbg_va(FAC_SK, ASP_SK_WRIT,
    300  | 	    "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
    301  | 	    sockfd, buf, count);
    302  |
    303  |   while (bytes_sent < count) {
    304  |     do
    305  |       this_write = write(sockfd, buf, count - bytes_sent);
    306  |     while ( (this_write < 0) && (errno == EINTR) );
    307  |     if (this_write <= 0)
    308  |       return this_write;
    309  |     bytes_sent += this_write;
    310  |     buf += this_write;
    311  |   }
    312  |   return count;
    313  | } /* SK_write() */
    314  |
    315  |
    316  | /* SK_gets() */
    317  | /*++++++++++++++++++++++++++++++++++++++
    318  |
    319  |    This function reads from a socket, until it recieves a linefeed
    320  |    character.  It fills the buffer "str" up to the maximum size "count".
    321  |
    322  |    int SK_gets  The total_count of bytes read.
    323  |
    324  |    int    sockfd    The socket file descriptor.
    325  |
    326  |    char   *str      The buffer to be written from the socket.
    327  |
    328  |    size_t count     The number of bytes in the buffer.
    329  |
    330  |   More:
    331  |   +html+ <PRE>
    332  |   Authors:
    333  |         ottrey
    334  |
    335  |   Side Effects:
    336  |         This function will return -1 if the socket is closed during the read operation.
    337  |
    338  |         Note that if a single line exceeds the length of count, the extra data
    339  |         will be read and discarded!  You have been warned.
    340  |
    341  |   To Do:
    342  |         Capture the control-c properly!
    343  |
    344  |   +html+ </PRE>
    345  |
    346  |   ++++++++++++++++++++++++++++++++++++++*/
    347  | int SK_gets(int sockfd, char *str, size_t count) {
    348  |   int bytes_read;
    349  |   int total_count = 0;
    350  |   char *current_position;
    351  |   char last_read = 0;
    352  |
    353  |   int control_c = 0;
    354  |
    355  |   current_position = str;
    356  |   while (last_read != 10) {
    357  |
    358  |
    359  |
    360  |     bytes_read = read(sockfd, &last_read, 1);
    361  |     if (bytes_read <= 0) {
    362  |       /* The other side may have closed unexpectedly */
    363  |       return SK_DISCONNECT;
    364  |       /* Is this effective on other platforms than linux? */
    365  |     }
    366  |     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
    367  |       *current_position = last_read;
    368  |       current_position++;
    369  |       total_count++;
    370  |     }
    371  |
    372  |     if (last_read == -1) {
    373  |       bytes_read = read(sockfd, &last_read, 1);
    374  |       if (last_read == -12) {
    375  |         ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
    376  |         control_c = 1;
    377  |         ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
    378  |         return SK_INTERRUPT;
    379  |       }
    380  |     }
    381  |   }
    382  |   if (count > 0) {
    383  |     *current_position = 0;
    384  |   }
    385  |
    386  |   return total_count;
    387  |
    388  | } /* SK_gets() */
    389  |
    390  |
    391  | /* SK_puts() */
    392  | /*++++++++++++++++++++++++++++++++++++++
    393  |
    394  |    This function writes a character string out to a socket.
    395  |
    396  |    int SK_puts  The total_count of bytes written,
    397  |                 or errors (represented as negative numbers)
    398  |
    399  |    int    sockfd    The socket file descriptor.
    400  |
    401  |    char   *str      The buffer to be written from the socket.
    402  |
    403  |   More:
    404  |   +html+ <PRE>
    405  |   Authors:
    406  |         ottrey
    407  |
    408  |   Side Effects:
    409  |         This function will return -1 if the socket is closed during the write operation.
    410  |
    411  |         Note that if a single line exceeds the length of count, the extra data
    412  |         will be read and discarded!  You have been warned.
    413  |
    414  |   +html+ </PRE>
    415  |
    416  |   ++++++++++++++++++++++++++++++++++++++*/
    417  | int SK_puts(int sockfd, const char *str) {
    418  |
    419  |   return SK_write(sockfd, str, strlen(str));
    420  |
    421  | } /* SK_puts() */
    422  |
    423  | /* SK_putc() */
    424  | /*++++++++++++++++++++++++++++++++++++++
    425  |
    426  |    int SK_putc This function writes a single character out to a socket.
    427  |
    428  |    int sockfd        socket
    429  |    char ch           character
    430  |
    431  |    return number of chars written
    432  |
    433  |   ++++++++++++++++++++++++++++++++++++++*/
    434  | int SK_putc(int sockfd, char ch) {
    435  |   return SK_write(sockfd, &ch, 1);
    436  | }/* SK_putc() */
    437  |
    438  | /*++++++++++++++++++++++++++++++++++++++
    439  |
    440  |    This function reads a single character from a socket.
    441  |
    442  |    returns EOF when no character can be read.
    443  |
    444  |   ++++++++++++++++++++++++++++++++++++++*/
    445  | int SK_getc(int sockfd) {
    446  |   char ch;
    447  |
    448  |   if( read(sockfd, &ch, 1) <= 0 ) {
    449  |     return EOF;
    450  |   }
    451  |   else {
    452  |     return ch;
    453  |   }
    454  | }/* SK_getc() */
    455  |
    456  | /* SK_getpeername() */
    457  | /*++++++++++++++++++++++++++++++++++++++
    458  |
    459  |    This function will tell you who is at the other end of a connected stream socket.
    460  |    XXX It's not working.
    461  |    XXX ? MB it is...
    462  |
    463  |    int    sockfd    The socket file descriptor.
    464  |
    465  |   More:
    466  |   +html+ <PRE>
    467  |   Authors:
    468  |         ottrey
    469  |   +html+ </PRE>
    470  |
    471  |   ++++++++++++++++++++++++++++++++++++++*/
    472  | char *SK_getpeername(int sockfd)
    473  | {
    474  |   char *hostaddress=NULL;
    475  |   struct sockaddr_in addr_in;
    476  |   int namelen=sizeof(addr_in);
    477  |
    478  |   if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) {
    479  |
    480  |     dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK);
    481  |
    482  |     strcpy(hostaddress, inet_ntoa(addr_in.sin_addr));  /* XXX MT-UNSAFE */
    483  |   }
    484  |
    485  |   return hostaddress;
    486  |
    487  | } /* SK_getpeername() */
    488  |
    489  | /* SK_getpeerip */
    490  | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
    491  |   struct sockaddr_in addr_in;
    492  |   int namelen=sizeof(addr_in);
    493  |   int ret=-1;
    494  |
    495  |   memset(& addr_in, 0, sizeof(struct sockaddr_in));
    496  |
    497  |   if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
    498  |     ret=0;
    499  |     IP_addr_s2b(ip, &addr_in, namelen);
    500  |   }
    501  |
    502  |   return ret;
    503  | }
    504  |
    505  | /*-------------------------------------------------------------------
    506  |  *   CD varieties of the functions: broken connections get registered
    507  |  *   in the connection structure within the query environment
    508  |  *   as side effects.
    509  |  * -----------------------------------------------------------------*/
    510  |
    511  | /* SK_cd_puts() */
    512  | /*++++++++++++++++++++++++++++++++++++++
    513  |
    514  |    This function writes a character string out to a socket.
    515  |
    516  |    int SK_qe_puts  The total_count of bytes written,
    517  |                 or errors (represented as negative numbers)
    518  |
    519  |    sk_conn_st *condat connection data
    520  |
    521  |    char   *str       The buffer to be written from the socket.
    522  |
    523  |   More:
    524  |        if the connection structure has bad status for this connection
    525  |        from previous calls, no write will be attempted.
    526  |
    527  |   +html+ <PRE>
    528  |   Authors:
    529  |         marek
    530  |
    531  |   Side Effects:
    532  |        broken connections get registered
    533  |        in the connection structure within the query environment
    534  |
    535  |   +html+ </PRE>
    536  |
    537  |   ++++++++++++++++++++++++++++++++++++++*/
    538  | int SK_cd_puts(sk_conn_st *condat, const char *str) {
    539  |   int res=SK_puts(condat->sock, str);
    540  |
    541  |   if( res < 0 ){
    542  |     /* set the corresponding rtc flag */
    543  |     condat->rtc |= (-res);
    544  |
    545  |     switch( - res ) {
    546  |       /* dont know what to do and how to log */
    547  |     case SK_DISCONNECT:
    548  |     case SK_INTERRUPT:
    549  |       /*("Thread received a control-c\n");*/
    550  |     case SK_TIMEOUT:
    551  |       /*("Reading timed out\n");*/
    552  |       break;
    553  |     default:
    554  |       /* unexpected error code. bail out */
    555  |       die;
    556  |     }
    557  |   }
    558  | } /* SK_cd_puts() */
    559  |
    560  | /* SK_cd_gets() */
    561  | /*++++++++++++++++++++++++++++++++++++++
    562  |
    563  |    Wrapper around SK_gets.
    564  |
    565  |    int SK_cd_gets  The total_count of bytes read,
    566  |                    or errors (represented as negative numbers)
    567  |
    568  |    sk_conn_st *condat connection data
    569  |
    570  |    char   *str       The buffer to be written from the socket.
    571  |
    572  |   More:
    573  |        if the connection structure has bad status for this connection
    574  |        from previous calls, no write will be attempted.
    575  |
    576  |   +html+ <PRE>
    577  |   Authors:
    578  |         marek
    579  |
    580  |   Side Effects:
    581  |        broken connections get registered
    582  |        in the connection structure within the query environment
    583  |
    584  |   +html+ </PRE>
    585  |
    586  |   ++++++++++++++++++++++++++++++++++++++*/
    587  | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) {
    588  |   int res;
    589  |   fd_set rset;
    590  |   struct timeval *ptm = & condat->rd_timeout;
    591  |   int readcount = 0;
    592  |
    593  |   memset( str, 0, count);
    594  |   FD_ZERO( &rset );
    595  |   FD_SET( condat->sock, &rset );
    596  |
    597  |   if( ptm->tv_sec == 0 && ptm->tv_usec == 0) { /* if timeout undefined,
    598  | 						  do blocking I/O */
    599  |     ptm = NULL;
    600  |   }
    601  |
    602  |   do {
    603  |     char buf[2];
    604  |     int sel = select( (condat->sock)+1, &rset, NULL, NULL, ptm);
    605  |
    606  |     dieif(sel < 0); /* we don't expect problems */
    607  |
    608  |     if( sel == 0 ) {
    609  |       condat->rtc |= SK_TIMEOUT;
    610  |       break;
    611  |     }
    612  |
    613  |     else {
    614  |       read( condat->sock, buf, 1 );
    615  |       str[readcount] = buf[0];
    616  |       readcount++;
    617  |       if( buf[0] == '\n' ) {
    618  | 	break;
    619  |       }
    620  |     }
    621  |   } while( readcount < count );
    622  |
    623  | } /* SK_cd_gets() */
    624  |
    625  |
    626  | int SK_cd_close(sk_conn_st *condat) {
    627  |   SK_close(condat->sock);
    628  | } /* SK_cd_close() */
    629  |
    630  |
    631  | /* print to condat like printf
    632  |
    633  |    by marek
    634  | */
    635  | int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
    636  | {
    637  | #define SKBUFLEN 2047
    638  |   va_list   ap;
    639  |   char      buffer[SKBUFLEN+1];
    640  |   int       len;
    641  |   char      *newbuf = NULL;
    642  |   char      *finalbuf = buffer; /* points to where the text REALLY is */
    643  |
    644  |   /* vsnprintf returns the number of character it WOULD write if it could.
    645  |      So we assume the buffer to be of adequate size for most cases,
    646  |      and if it isn't, then we allocate to newbuf and call v*printf again
    647  |   */
    648  |   va_start(ap, txt);
    649  |   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
    650  |   va_end(ap);
    651  |
    652  |   if( len > SKBUFLEN ) {
    653  |     dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1)));
    654  |
    655  |     va_start(ap, txt);
    656  |     vsnprintf(newbuf, len, txt, ap);
    657  |     va_end(ap);
    658  |
    659  |     finalbuf = newbuf;
    660  |   }
    661  |   /* terminate */
    662  |   finalbuf[len] = 0;
    663  |
    664  |   /* reuse len */
    665  |   len = SK_cd_puts(condat, finalbuf);
    666  |
    667  |   if(newbuf != NULL) {
    668  |     wr_free(newbuf);
    669  |   }
    670  |
    671  |   return len;
    672  | }
    673  |
    674  |
    675  | /* sk_watchdog - started as a separate thread.
    676  |
    677  |    selects on the given socket; discards all input.
    678  |    whenever it sees end of file (socket closed), it
    679  |    * sets a corresponding flag in the condat structure,
    680  |    * kills a thread designated to be killed (by SK_watchkill)
    681  |
    682  |    by marek;
    683  | */
    684  | static
    685  | void *sk_watchdog(void *arg)
    686  | {
    687  |   sk_conn_st *condat = (sk_conn_st *) arg;
    688  |   int nready;
    689  |   int n;
    690  |   fd_set rset;
    691  |   char buff[STR_S];
    692  |   int socket = condat->sock;
    693  |   sigset_t sset;
    694  |   struct sigaction act;
    695  |
    696  |   FD_ZERO(&rset);
    697  |   FD_SET(socket, &rset);
    698  |
    699  |   sigemptyset(&sset);
    700  |   sigaddset(&sset, SIGUSR1);
    701  |
    702  |   act.sa_handler = func_sigusr;
    703  |   act.sa_flags = 0;
    704  |   dieif(sigaction(SIGUSR1, &act, NULL) != 0);
    705  |
    706  |   dieif(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) != 0);
    707  |
    708  |   pthread_mutex_unlock( & condat->watchmutex ); /* now ready for signal */
    709  |
    710  |   while ((nready=select(socket+1, &rset, NULL, NULL, NULL))!=-1) {
    711  |
    712  |     /* don't even try to read if we have been killed */
    713  |     if( errno == EINTR ) {
    714  |       break;
    715  |     }
    716  |
    717  |    /* There was some input or client half of connection was closed */
    718  |    /* Check for the latter */
    719  |    if (( n=read(socket, buff, sizeof(buff))) == 0) {
    720  |    /* Connection was closed by client */
    721  |    /* Now send a cancellation request to the whois thread. */
    722  |    /* mysql thread will be terminated by thread cleanup routine */
    723  |
    724  |      /* set the reason-to-close flag on this connection */
    725  |      condat->rtc |= SK_INTERRUPT;
    726  |
    727  |      /* cancel the thread to be cancelled if defined */
    728  |      if( condat->killthis != 0 ) {
    729  |        pthread_cancel(condat->killthis);
    730  |        /* The only possible error is ESRCH, so we do not care about it*/
    731  |      }
    732  |
    733  |      /* call the function to be called if defined */
    734  |      if( condat->execthis != NULL ) {
    735  |        condat->execthis(condat->execargs);
    736  |      }
    737  |
    738  |      /* quit */
    739  |      break;
    740  |    }
    741  |    /* Otherwise dump input and continue */
    742  |
    743  |   }
    744  |
    745  |   /* Exit the watchdog thread, passing NULL as we don't expect a join */
    746  |   pthread_exit(NULL);
    747  | }
    748  |
    749  | /* SK_watchstart
    750  |
    751  |    starts sk_watchdog thread unless already started,
    752  |    and registers its threadid in the condat structure
    753  |
    754  |    dies if watchdog already running
    755  | */
    756  | er_ret_t
    757  | SK_watchstart(sk_conn_st *condat)
    758  | {
    759  |   dieif( condat->watchdog != 0 );
    760  |
    761  |   /* init the mutex in locked state, watchdog will unlock it when
    762  |      it's ready for signal */
    763  |   pthread_mutex_init( & condat->watchmutex, NULL );
    764  |   pthread_mutex_lock( & condat->watchmutex );
    765  |
    766  |   pthread_create(&condat->watchdog, NULL, sk_watchdog, (void *) condat );
    767  |
    768  |   return SK_OK;
    769  | }
    770  |
    771  |
    772  | /* SK_watchstop
    773  |
    774  |    stops sk_watchdog thread if it is registered in the connection struct
    775  | */
    776  | er_ret_t
    777  | SK_watchstop(sk_conn_st *condat)
    778  | {
    779  |   void *res;
    780  |
    781  |   if(condat->watchdog > 0) {
    782  |     int ret;
    783  |
    784  |     /* wait until the watchdog is ready for signal */
    785  |     pthread_mutex_lock( & condat->watchmutex );
    786  |
    787  |     ret = pthread_kill(condat->watchdog, SIGUSR1);
    788  |
    789  |     ret = pthread_join(condat->watchdog, &res);
    790  |
    791  |     pthread_mutex_destroy( & condat->watchmutex );
    792  |     condat->watchdog = 0;
    793  |   }
    794  |   return SK_OK;
    795  | }
    796  |
    797  | /* SK_watchkill
    798  |
    799  |    sets the threadid of the thread to be killed by watchdog
    800  |    0 means dont kill anything
    801  | */
    802  | void
    803  | SK_watchkill(sk_conn_st *condat, pthread_t killthis)
    804  | {
    805  |   condat->killthis = killthis;
    806  | }
    807  |
    808  | void
    809  | SK_watchexec( sk_conn_st *condat, void *(*function)(void *) , void *args)
    810  | {
    811  |   condat->execthis = function;
    812  |   condat->execargs = args;
    813  | }
    814  |
    815  | void
    816  | SK_watchclear(sk_conn_st *condat)
    817  | {
    818  |   condat->execthis = NULL;
    819  |   condat->execargs = NULL;
    820  |   condat->killthis = 0;
    821  | }