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