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  | }