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