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