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