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