modules/sk/sk_socket.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- SK_atoport
- func_sigusr
- 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_watchdog
- SK_watchstart
- SK_watchstop
- SK_watchkill
- SK_watchexec
- SK_watchclear
1 /***************************************
2 $Revision: 1.4 $
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) {
/* [<][>][^][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 /* 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) {
/* [<][>][^][v][top][bottom][index][help] */
110 ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigusr(%d) called", n);
111 }
112
113 int SK_close(int socket) {
/* [<][>][^][v][top][bottom][index][help] */
114 ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
115
116 return 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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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 return res;
559 } /* SK_cd_puts() */
560
561 /* SK_cd_gets() */
562 /*++++++++++++++++++++++++++++++++++++++
563
564 Wrapper around SK_gets.
565
566 int SK_cd_gets The total_count of bytes read,
567 or errors (represented as negative numbers)
568
569 sk_conn_st *condat connection data
570
571 char *str The buffer to be written from the socket.
572
573 More:
574 if the connection structure has bad status for this connection
575 from previous calls, no write will be attempted.
576
577 +html+ <PRE>
578 Authors:
579 marek
580
581 Side Effects:
582 broken connections get registered
583 in the connection structure within the query environment
584
585 +html+ </PRE>
586
587 ++++++++++++++++++++++++++++++++++++++*/
588 int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
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 return readcount;
624
625 } /* SK_cd_gets() */
626
627
628 int SK_cd_close(sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
629 return SK_close(condat->sock);
630 } /* SK_cd_close() */
631
632
633 /* print to condat like printf
634
635 by marek
636 */
637 int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
/* [<][>][^][v][top][bottom][index][help] */
638 {
639 #define SKBUFLEN 2047
640 va_list ap;
641 char buffer[SKBUFLEN+1];
642 int len;
643 char *newbuf = NULL;
644 char *finalbuf = buffer; /* points to where the text REALLY is */
645
646 /* vsnprintf returns the number of character it WOULD write if it could.
647 So we assume the buffer to be of adequate size for most cases,
648 and if it isn't, then we allocate to newbuf and call v*printf again
649 */
650 va_start(ap, txt);
651 len = vsnprintf(buffer, SKBUFLEN, txt, ap);
652 va_end(ap);
653
654 if( len > SKBUFLEN ) {
655 dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1)));
656
657 va_start(ap, txt);
658 vsnprintf(newbuf, len, txt, ap);
659 va_end(ap);
660
661 finalbuf = newbuf;
662 }
663 /* terminate */
664 finalbuf[len] = 0;
665
666 /* reuse len */
667 len = SK_cd_puts(condat, finalbuf);
668
669 if(newbuf != NULL) {
670 wr_free(newbuf);
671 }
672
673 return len;
674 }
675
676
677 /* sk_watchdog - started as a separate thread.
678
679 selects on the given socket; discards all input.
680 whenever it sees end of file (socket closed), it
681 * sets a corresponding flag in the condat structure,
682 * kills a thread designated to be killed (by SK_watchkill)
683
684 by marek;
685 */
686 static
687 void *sk_watchdog(void *arg)
/* [<][>][^][v][top][bottom][index][help] */
688 {
689 sk_conn_st *condat = (sk_conn_st *) arg;
690 int nready;
691 int n;
692 fd_set rset;
693 char buff[STR_S];
694 int socket = condat->sock;
695 sigset_t sset;
696 struct sigaction act;
697
698 FD_ZERO(&rset);
699 FD_SET(socket, &rset);
700
701 sigemptyset(&sset);
702 sigaddset(&sset, SIGUSR1);
703
704 act.sa_handler = func_sigusr;
705 act.sa_flags = 0;
706 dieif(sigaction(SIGUSR1, &act, NULL) != 0);
707
708 dieif(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) != 0);
709
710 pthread_mutex_unlock( & condat->watchmutex ); /* now ready for signal */
711
712 while ((nready=select(socket+1, &rset, NULL, NULL, NULL))!=-1) {
713
714 /* don't even try to read if we have been killed */
715 if( errno == EINTR ) {
716 break;
717 }
718
719 /* There was some input or client half of connection was closed */
720 /* Check for the latter */
721 if (( n=read(socket, buff, sizeof(buff))) == 0) {
722 /* Connection was closed by client */
723 /* Now send a cancellation request to the whois thread. */
724 /* mysql thread will be terminated by thread cleanup routine */
725
726 /* set the reason-to-close flag on this connection */
727 condat->rtc |= SK_INTERRUPT;
728
729 /* cancel the thread to be cancelled if defined */
730 if( condat->killthis != 0 ) {
731 pthread_cancel(condat->killthis);
732 /* The only possible error is ESRCH, so we do not care about it*/
733 }
734
735 /* call the function to be called if defined */
736 if( condat->execthis != NULL ) {
737 condat->execthis(condat->execargs);
738 }
739
740 /* quit */
741 break;
742 }
743 /* Otherwise dump input and continue */
744
745 }
746
747 /* Exit the watchdog thread, passing NULL as we don't expect a join */
748 pthread_exit(NULL);
749
750 /* oh yes. Shouldn't compilers _analyze_ library functions ? */
751 return NULL;
752 }
753
754 /* SK_watchstart
755
756 starts sk_watchdog thread unless already started,
757 and registers its threadid in the condat structure
758
759 dies if watchdog already running
760 */
761 er_ret_t
762 SK_watchstart(sk_conn_st *condat)
/* [<][>][^][v][top][bottom][index][help] */
763 {
764 dieif( condat->watchdog != 0 );
765
766 /* init the mutex in locked state, watchdog will unlock it when
767 it's ready for signal */
768 pthread_mutex_init( & condat->watchmutex, NULL );
769 pthread_mutex_lock( & condat->watchmutex );
770
771 pthread_create(&condat->watchdog, NULL, sk_watchdog, (void *) condat );
772
773 return SK_OK;
774 }
775
776
777 /* SK_watchstop
778
779 stops sk_watchdog thread if it is registered in the connection struct
780 */
781 er_ret_t
782 SK_watchstop(sk_conn_st *condat)
/* [<][>][^][v][top][bottom][index][help] */
783 {
784 void *res;
785
786 if(condat->watchdog > 0) {
787 int ret;
788
789 /* wait until the watchdog is ready for signal */
790 pthread_mutex_lock( & condat->watchmutex );
791
792 ret = pthread_kill(condat->watchdog, SIGUSR1);
793
794 ret = pthread_join(condat->watchdog, &res);
795
796 pthread_mutex_destroy( & condat->watchmutex );
797 condat->watchdog = 0;
798 }
799 return SK_OK;
800 }
801
802 /* SK_watchkill
803
804 sets the threadid of the thread to be killed by watchdog
805 0 means dont kill anything
806 */
807 void
808 SK_watchkill(sk_conn_st *condat, pthread_t killthis)
/* [<][>][^][v][top][bottom][index][help] */
809 {
810 condat->killthis = killthis;
811 }
812
813 void
814 SK_watchexec( sk_conn_st *condat, void *(*function)(void *) , void *args)
/* [<][>][^][v][top][bottom][index][help] */
815 {
816 condat->execthis = function;
817 condat->execargs = args;
818 }
819
820 void
821 SK_watchclear(sk_conn_st *condat)
/* [<][>][^][v][top][bottom][index][help] */
822 {
823 condat->execthis = NULL;
824 condat->execargs = NULL;
825 condat->killthis = 0;
826 }