Source File modules/sk/sk_socket.c

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