modules/sk/sk_socket.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- SK_atoport
- SK_close
- SK_getsock
- SK_accept_connection
- SK_read
- SK_write
- SK_gets
- SK_puts
- SK_putc
- SK_getc
- SK_getpeername
- SK_getpeerip
- SK_cd_puts
- SK_cd_gets
- SK_cd_close
- SK_cd_printf
- sk_real_init
- SK_init
- func_sigusr
- sk_watchdog
- SK_watchstart
- SK_watchstop
- SK_watch_setkill
- SK_watch_setexec
- SK_watch_setclear
- SK_watchexec
- SK_watchkill
- SK_watchtrigger
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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, ...)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
679 {
680 dieif( pthread_key_create( &sk_watch_tsd, NULL) != 0 );
681 }
682
683 void SK_init(void)
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
849 {
850 condat->killthis = killthis;
851 }
852
853 void
854 SK_watch_setexec( sk_conn_st *condat, void *(*function)(void *) , void *args)
/* [<][>][^][v][top][bottom][index][help] */
855 {
856 condat->execthis = function;
857 condat->execargs = args;
858 }
859
860 void
861 SK_watch_setclear(sk_conn_st *condat)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
896 {
897 SK_watchkill(condat);
898 SK_watchexec(condat);
899
900 }