Source File modules/sk/sk_socket.c

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