modules/sk/socket.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- SK_atoport
- func_atexit
- func_sighup
- func_sigint
- 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
1 /***************************************
2 $Revision: 1.16 $
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 extern int h_errno;
34
35
36 /*+ String sizes +*/
37 #define STR_S 63
38 #define STR_M 255
39 #define STR_L 1023
40 #define STR_XL 4095
41 #define STR_XXL 16383
42
43 /* SK_atoport() */
44 /*++++++++++++++++++++++++++++++++++++++
45 Take a service name, and a service type, and return a port number. If the
46 service name is not found, it tries it as a decimal number. The number
47 returned is byte ordered for the network.
48
49 char *service Service name (or port number).
50
51 char *proto Protocol (eg "tcp").
52
53 More:
54 +html+ <PRE>
55 Authors:
56 ottrey
57
58 +html+ </PRE><DL COMPACT>
59 +html+ <DT>Online References:
60 +html+ <DD><UL>
61 +html+ </UL></DL>
62
63 ++++++++++++++++++++++++++++++++++++++*/
64 int SK_atoport(const char *service, const char *proto) {
/* [<][>][^][v][top][bottom][index][help] */
65 int port;
66 long int lport;
67 struct servent *serv;
68 char *errpos;
69 struct servent result;
70 char buffer[STR_XXL];
71
72 /* First try to read it from /etc/services */
73
74 /* serv = getservbyname(service, proto); */
75 serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
76 if (serv != NULL)
77 port = serv->s_port;
78 else { /* Not in services, maybe a number? */
79 lport = strtol(service,&errpos,0);
80 if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
81 return -1; /* Invalid port address */
82 port = htons(lport);
83 }
84 return port;
85 } /* SK_atoport() */
86
87
88 /* SK_close_listening_socket() */
89 /*++++++++++++++++++++++++++++++++++++++
90 XXX Note: Not sure how long this function will last. Shouldn't _really_ need it.
91
92 More:
93 +html+ <PRE>
94 Authors:
95 ottrey
96
97 +html+ </PRE><DL COMPACT>
98 +html+ <DT>Online References:
99 +html+ <DD><UL>
100 +html+ </UL></DL>
101
102 ++++++++++++++++++++++++++++++++++++++*/
103 /*void SK_close_listening_socket() {
104 close(listening_socket);
105 } */ /* SK_close_listening_socket */
106
107 static void func_atexit(void) {
/* [<][>][^][v][top][bottom][index][help] */
108 ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_atexit() called");
109 }
110
111 static void func_sighup(int n) {
/* [<][>][^][v][top][bottom][index][help] */
112 ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sighup(%d) called", n);
113 }
114
115 static void func_sigint(int n) {
/* [<][>][^][v][top][bottom][index][help] */
116 ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigint(%d) called", n);
117 }
118
119
120 void SK_close(int socket) {
/* [<][>][^][v][top][bottom][index][help] */
121 ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
122
123 close(socket);
124 }
125
126 /* SK_getsock() */
127 /*++++++++++++++++++++++++++++++++++++++
128
129 This function creates a socket and binds to it
130
131 int SK_getsock The new socket
132
133 int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
134
135 u_short port The port to listen on. Remember that ports < 1024 are
136 reserved for the root user. Must be passed in network byte
137 order (see "man htons").
138
139 uint32_t bind_address Address to bind to, in network order.
140 More:
141 +html+ <PRE>
142 Authors:
143 ottrey
144 joao
145
146 +html+ </PRE><DL COMPACT>
147 +html+ <DT>Online References:
148 +html+ <DD><UL>
149 +html+ </UL></DL>
150
151 ++++++++++++++++++++++++++++++++++++++*/
152 int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
/* [<][>][^][v][top][bottom][index][help] */
153 struct sockaddr_in address;
154 int listening_socket;
155 int reuse_addr = 1;
156
157 /* Setup internet address information.
158 This is used with the bind() call */
159 memset((char *) &address, 0, sizeof(address));
160 address.sin_family = AF_INET;
161 address.sin_port = port;
162 address.sin_addr.s_addr = bind_address;
163
164 /* Map all of the signals and exit routine */
165 atexit(func_atexit);
166 /* signal.h has a full list of signal names */
167
168 listening_socket = socket(AF_INET, socket_type, 0);
169 if (listening_socket < 0) {
170 perror("socket");
171 exit(EXIT_FAILURE);
172 }
173
174 setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
175
176 if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
177 perror("bind");
178 close(listening_socket);
179 exit(EXIT_FAILURE);
180 }
181
182
183 if (socket_type == SOCK_STREAM) {
184 listen(listening_socket, 5); /* Queue up to five connections before
185 having them automatically rejected. */
186 }
187
188 return listening_socket;
189 } /* SK_getsock() */
190
191 /*++++++++++++++++++++++++++++++++++++++
192
193 Wait for an incoming connection on the specified socket
194
195 int SK_accept_connection The socket for communicating to the client
196
197 int listening_socket The socket that the server is bound to
198
199 More:
200 +html+ <PRE>
201 Authors:
202 joao
203 +html+ </PRE>
204 ++++++++++++++++++++++++++++++++++++++*/
205 int SK_accept_connection(int listening_socket) {
/* [<][>][^][v][top][bottom][index][help] */
206 int connected_socket = -1;
207
208 while(connected_socket < 0) {
209
210 ER_dbg_va(FAC_SK, ASP_SK_GEN,
211 "Going to accept connections on socket : %d",listening_socket);
212
213 /* XXX joao - ? - why is this here?
214 fflush(NULL);
215 */
216
217 connected_socket = accept(listening_socket, NULL, NULL);
218 if (connected_socket < 0) {
219 /* Either a real error occured, or blocking was interrupted for
220 some reason. Only abort execution if a real error occured. */
221 if (errno != EINTR) {
222 perror("accept");
223 close(listening_socket);
224 return(-1);
225 /* no exit, just return with error */
226 } else {
227 continue; /* don't return - do the accept again */
228 }
229 }
230 }
231
232 ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
233 connected_socket
234 );
235
236 return connected_socket;
237 }
238
239 /* SK_read() */
240 /*++++++++++++++++++++++++++++++++++++++
241
242 This is just like the read() system call, except that it will make
243 sure that all your data goes through the socket.
244
245 int SK_read The number of bytes read.
246
247 int sockfd The socket file descriptor.
248
249 char *buf The buffer to be read from the socket.
250
251 size_t count The number of bytes in the buffer.
252
253 More:
254 +html+ <PRE>
255 Authors:
256 ottrey
257 +html+ </PRE>
258 ++++++++++++++++++++++++++++++++++++++*/
259 int SK_read(int sockfd, char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
260 size_t bytes_read = 0;
261 int this_read;
262
263 while (bytes_read < count) {
264 do
265 this_read = read(sockfd, buf, count - bytes_read);
266 while ( (this_read < 0) && (errno == EINTR) );
267 if (this_read < 0)
268 return this_read;
269 else if (this_read == 0)
270 return bytes_read;
271 bytes_read += this_read;
272 buf += this_read;
273 }
274
275 return count;
276
277 } /* SK_read() */
278
279
280 /* SK_write() */
281 /*++++++++++++++++++++++++++++++++++++++
282
283 This is just like the write() system call, accept that it will
284 make sure that all data is transmitted.
285
286 int sockfd The socket file descriptor.
287
288 char *buf The buffer to be written to the socket.
289
290 size_t count The number of bytes in the buffer.
291
292 More:
293 +html+ <PRE>
294 Authors:
295 ottrey
296
297 +html+ </PRE><DL COMPACT>
298 +html+ <DT>Online References:
299 +html+ <DD><UL>
300 +html+ </UL></DL>
301
302 ++++++++++++++++++++++++++++++++++++++*/
303 int SK_write(int sockfd, const char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
304 size_t bytes_sent = 0;
305 int this_write;
306
307
308 ER_dbg_va(FAC_SK, ASP_SK_WRIT,
309 "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
310 sockfd, buf, count);
311
312 while (bytes_sent < count) {
313 do
314 this_write = write(sockfd, buf, count - bytes_sent);
315 while ( (this_write < 0) && (errno == EINTR) );
316 if (this_write <= 0)
317 return this_write;
318 bytes_sent += this_write;
319 buf += this_write;
320 }
321 return count;
322 } /* SK_write() */
323
324
325 /* SK_gets() */
326 /*++++++++++++++++++++++++++++++++++++++
327
328 This function reads from a socket, until it recieves a linefeed
329 character. It fills the buffer "str" up to the maximum size "count".
330
331 int SK_gets The total_count of bytes read.
332
333 int sockfd The socket file descriptor.
334
335 char *str The buffer to be written from the socket.
336
337 size_t count The number of bytes in the buffer.
338
339 More:
340 +html+ <PRE>
341 Authors:
342 ottrey
343
344 Side Effects:
345 This function will return -1 if the socket is closed during the read operation.
346
347 Note that if a single line exceeds the length of count, the extra data
348 will be read and discarded! You have been warned.
349
350 To Do:
351 Capture the control-c properly!
352
353 +html+ </PRE>
354
355 ++++++++++++++++++++++++++++++++++++++*/
356 int SK_gets(int sockfd, char *str, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
357 int bytes_read;
358 int total_count = 0;
359 char *current_position;
360 char last_read = 0;
361
362 int control_c = 0;
363
364 current_position = str;
365 while (last_read != 10) {
366 bytes_read = read(sockfd, &last_read, 1);
367 if (bytes_read <= 0) {
368 /* The other side may have closed unexpectedly */
369 return SK_DISCONNECT;
370 /* Is this effective on other platforms than linux? */
371 }
372 if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
373 *current_position = last_read;
374 current_position++;
375 total_count++;
376 }
377
378 if (last_read == -1) {
379 bytes_read = read(sockfd, &last_read, 1);
380 if (last_read == -12) {
381 ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
382 control_c = 1;
383 ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
384 return SK_INTERRUPT;
385 }
386 }
387 }
388 if (count > 0) {
389 *current_position = 0;
390 }
391
392 return total_count;
393
394 } /* SK_gets() */
395
396
397 /* SK_puts() */
398 /*++++++++++++++++++++++++++++++++++++++
399
400 This function writes a character string out to a socket.
401
402 int SK_puts The total_count of bytes written,
403 or errors (represented as negative numbers)
404
405 int sockfd The socket file descriptor.
406
407 char *str The buffer to be written from the socket.
408
409 More:
410 +html+ <PRE>
411 Authors:
412 ottrey
413
414 Side Effects:
415 This function will return -1 if the socket is closed during the write operation.
416
417 Note that if a single line exceeds the length of count, the extra data
418 will be read and discarded! You have been warned.
419
420 +html+ </PRE>
421
422 ++++++++++++++++++++++++++++++++++++++*/
423 int SK_puts(int sockfd, const char *str) {
/* [<][>][^][v][top][bottom][index][help] */
424
425 return SK_write(sockfd, str, strlen(str));
426
427 } /* SK_puts() */
428
429 /* SK_putc() */
430 /*++++++++++++++++++++++++++++++++++++++
431
432 int SK_putc This function writes a single character out to a socket.
433
434 int sockfd socket
435 char ch character
436
437 return number of chars written
438
439 ++++++++++++++++++++++++++++++++++++++*/
440 int SK_putc(int sockfd, char ch) {
/* [<][>][^][v][top][bottom][index][help] */
441 return SK_write(sockfd, &ch, 1);
442 }/* SK_putc() */
443
444 /*++++++++++++++++++++++++++++++++++++++
445
446 This function reads a single character from a socket.
447
448 returns EOF when no character can be read.
449
450 ++++++++++++++++++++++++++++++++++++++*/
451 int SK_getc(int sockfd) {
/* [<][>][^][v][top][bottom][index][help] */
452 char ch;
453
454 if( read(sockfd, &ch, 1) <= 0 ) {
455 return EOF;
456 }
457 else {
458 return ch;
459 }
460 }/* SK_getc() */
461
462 /* SK_getpeername() */
463 /*++++++++++++++++++++++++++++++++++++++
464
465 This function will tell you who is at the other end of a connected stream socket.
466 XXX It's not working.
467 XXX ? MB it is...
468
469 int sockfd The socket file descriptor.
470
471 More:
472 +html+ <PRE>
473 Authors:
474 ottrey
475 +html+ </PRE>
476
477 ++++++++++++++++++++++++++++++++++++++*/
478 char *SK_getpeername(int sockfd)
/* [<][>][^][v][top][bottom][index][help] */
479 {
480 char *hostaddress=NULL;
481 struct sockaddr_in addr_in;
482 int namelen=sizeof(addr_in);
483
484 if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) {
485
486 dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK);
487
488 strcpy(hostaddress, inet_ntoa(addr_in.sin_addr)); /* XXX MT-UNSAFE */
489 }
490
491 return hostaddress;
492
493 } /* SK_getpeername() */
494
495 /* SK_getpeerip */
496 int SK_getpeerip(int sockfd, ip_addr_t *ip) {
/* [<][>][^][v][top][bottom][index][help] */
497 struct sockaddr_in addr_in;
498 int namelen=sizeof(addr_in);
499 int ret=-1;
500
501 memset(& addr_in, 0, sizeof(struct sockaddr_in));
502
503 if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
504 ret=0;
505 IP_addr_s2b(ip, &addr_in, namelen);
506 }
507
508 return ret;
509 }
510
511 /*-------------------------------------------------------------------
512 * CD varieties of the functions: broken connections get registered
513 * in the connection structure within the query environment
514 * as side effects.
515 * -----------------------------------------------------------------*/
516
517 /* SK_cd_puts() */
518 /*++++++++++++++++++++++++++++++++++++++
519
520 This function writes a character string out to a socket.
521
522 int SK_qe_puts The total_count of bytes written,
523 or errors (represented as negative numbers)
524
525 sk_conn_st *condat connection data
526
527 char *str The buffer to be written from the socket.
528
529 More:
530 if the connection structure has bad status for this connection
531 from previous calls, no write will be attempted.
532
533 +html+ <PRE>
534 Authors:
535 marek
536
537 Side Effects:
538 broken connections get registered
539 in the connection structure within the query environment
540
541 +html+ </PRE>
542
543 ++++++++++++++++++++++++++++++++++++++*/
544 int SK_cd_puts(sk_conn_st *condat, const char *str) {
/* [<][>][^][v][top][bottom][index][help] */
545 int res=SK_puts(condat->sock, str);
546
547 if( res < 0 ){
548 switch( - res ) {
549 /* dont know what to do and how to log */
550 case SK_DISCONNECT:
551 case SK_INTERRUPT:
552 /*("Thread received a control-c\n");*/
553 case SK_TIMEOUT:
554 /*("Reading timed out\n");*/
555 break;
556 default:
557 /* unexpected error code. bail out */
558 die;
559 }
560 }
561 } /* SK_cd_puts() */
562
563 /* SK_cd_gets() */
564 /*++++++++++++++++++++++++++++++++++++++
565
566 Wrapper around SK_gets.
567
568 int SK_cd_gets The total_count of bytes read,
569 or errors (represented as negative numbers)
570
571 sk_conn_st *condat connection data
572
573 char *str The buffer to be written from the socket.
574
575 More:
576 if the connection structure has bad status for this connection
577 from previous calls, no write will be attempted.
578
579 +html+ <PRE>
580 Authors:
581 marek
582
583 Side Effects:
584 broken connections get registered
585 in the connection structure within the query environment
586
587 +html+ </PRE>
588
589 ++++++++++++++++++++++++++++++++++++++*/
590 int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
591 int res=SK_gets(condat->sock, str, count);
592
593 if( res < 0 ){
594 switch( - res ) {
595 /* dont know what to do and how to log */
596 case SK_DISCONNECT:
597 case SK_INTERRUPT:
598 /*("Thread received a control-c\n");*/
599 case SK_TIMEOUT:
600 /*("Reading timed out\n");*/
601 break;
602 default:
603 /* unexpected error code. bail out */
604 die;
605 }
606 }
607 } /* SK_cd_gets() */
608
609
610 int SK_cd_close(sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
611 SK_close(condat->sock);
612 } /* SK_cd_close() */
613
614
615 int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
/* [<][>][^][v][top][bottom][index][help] */
616 {
617 #define SKBUFLEN 2047
618 va_list ap;
619 char buffer[SKBUFLEN+1];
620 int len;
621 char *newbuf = NULL;
622 char *finalbuf = buffer; /* points to where the text REALLY is */
623
624 /* vsnprintf returns the number of character it WOULD write if it could.
625 So we assume the buffer to be of adequate size for most cases,
626 and if it isn't, then we allocate to newbuf and call v*printf again
627 */
628 va_start(ap, txt);
629 len = vsnprintf(buffer, SKBUFLEN, txt, ap);
630 va_end(ap);
631
632 if( len > SKBUFLEN ) {
633 dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1)));
634
635 va_start(ap, txt);
636 vsnprintf(newbuf, len, txt, ap);
637 va_end(ap);
638
639 finalbuf = newbuf;
640 }
641 /* terminate */
642 finalbuf[len] = 0;
643
644 /* reuse len */
645 len = SK_cd_puts(condat, finalbuf);
646
647 if(newbuf != NULL) {
648 wr_free(newbuf);
649 }
650
651 return len;
652 }