1 | /***************************************
2 | $Revision: 1.22 $
3 |
4 | Socket module - routines facilitating calls to socket library.
5 |
6 | Status: NOT REVUED, TESTED
7 |
8 | Basic code adapted by Chris Ottrey from
9 | http://www.ibrado.com/sock-faq/sfaq.html#faq65 - sample source code.
10 | ******************/ /******************
11 | Modification History:
12 | ottrey (08/03/1999) Created from sockhelp.c.
13 | ottrey (08/03/1998) Heavily butchered.
14 | joao (22/06/1999) Modified socket creation and accepts.
15 | marek (December 2000) Added connection function w/timeout.
16 | ******************/ /******************
17 | Copyright (c) 1999,2000,2001,2002 RIPE NCC
18 |
19 | All Rights Reserved
20 |
21 | Permission to use, copy, modify, and distribute this software and its
22 | documentation for any purpose and without fee is hereby granted,
23 | provided that the above copyright notice appear in all copies and that
24 | both that copyright notice and this permission notice appear in
25 | supporting documentation, and that the name of the author not be
26 | used in advertising or publicity pertaining to distribution of the
27 | software without specific, written prior permission.
28 |
29 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
30 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
31 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
32 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
33 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
34 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 | ***************************************/
36 |
37 | #include "rip.h"
38 |
39 | /* SK_atoport() */
40 | /*++++++++++++++++++++++++++++++++++++++
41 | Take a service name, and a service type, and return a port number. If the
42 | service name is not found, it tries it as a decimal number. The number
43 | returned is byte ordered for the network.
44 |
45 | char *service Service name (or port number).
46 |
47 | char *proto Protocol (eg "tcp").
48 |
49 | Author:
50 | ottrey.
51 |
52 | ++++++++++++++++++++++++++++++++++++++*/
53 | int SK_atoport(const char *service, const char *proto) {
54 | unsigned port;
55 | long int lport;
56 | struct servent *serv;
57 | char *errpos;
58 | struct servent result;
59 | char buffer[STR_XXL];
60 |
61 | /* First try to read it from /etc/services */
62 |
63 | #ifdef __linux__
64 | if(getservbyname_r(service, proto, &result, buffer, sizeof(buffer), &serv) < 0) serv = NULL;
65 | #else
66 | serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
67 | #endif
68 |
69 | if (serv != NULL)
70 | port = serv->s_port;
71 | else { /* Not in services, maybe a number? */
72 | lport = strtol(service,&errpos,0);
73 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
74 | return -1; /* Invalid port address */
75 | port = htons(lport);
76 | }
77 | return port;
78 | } /* SK_atoport() */
79 |
80 |
81 | /* SK_close() */
82 | /*++++++++++++++++++++++++++++++++++++++
83 |
84 | int SK_close wrapper around closing the socket. Returns the value
85 | returned by close(2)
86 |
87 | int socket socket to be closed
88 |
89 | Author:
90 | ottrey
91 | ++++++++++++++++++++++++++++++++++++++*/
92 | int SK_close(int socket) {
93 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
94 |
95 | return close(socket);
96 | }
97 |
98 | /* SK_getsock() */
99 | /*++++++++++++++++++++++++++++++++++++++
100 |
101 | int SK_getsock This function creates a socket and binds to it.
102 | Returns the number of the created
103 | descriptor/listening socket.
104 |
105 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
106 |
107 | unsigned port The port to listen on. Ports < 1024 are
108 | reserved for the root user. Host byte order.
109 |
110 | int backlog Size of the backlog queue to be set on that
111 | socket.
112 |
113 | uint32_t bind_address Address to bind to, in network order.
114 |
115 | Authors:
116 | ottrey,
117 | joao,
118 | marek (added htons conversion for port).
119 |
120 | ++++++++++++++++++++++++++++++++++++++*/
121 | int SK_getsock(int socket_type, unsigned h_port, int backlog,
122 | uint32_t bind_address) {
123 | struct sockaddr_in address;
124 | int listening_socket;
125 | int reuse_addr = 1;
126 | u_short port = htons(h_port);
127 |
128 | /* Setup internet address information.
129 | This is used with the bind() call */
130 | memset((char *) &address, 0, sizeof(address));
131 | address.sin_family = AF_INET;
132 | address.sin_port = port;
133 | address.sin_addr.s_addr = bind_address;
134 |
135 | /* Map all of the signals and exit routine */
136 |
137 | listening_socket = socket(AF_INET, socket_type, 0);
138 | if (listening_socket < 0) {
139 | perror("socket");
140 | exit(EXIT_FAILURE);
141 | }
142 |
143 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
144 |
145 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
146 | fprintf(stderr,
147 | "error %d with bind() to %s:%d; %s\n",
148 | errno,
149 | inet_ntoa(address.sin_addr),
150 | h_port,
151 | strerror(errno));
152 | close(listening_socket);
153 | exit(EXIT_FAILURE);
154 | }
155 |
156 |
157 | if (socket_type == SOCK_STREAM) {
158 | listen(listening_socket, backlog); /* Queue up to five connections before
159 | having them automatically rejected. */
160 | }
161 |
162 | return listening_socket;
163 | } /* SK_getsock() */
164 |
165 | /*++++++++++++++++++++++++++++++++++++++
166 |
167 | Wait for an incoming connection on the specified socket
168 |
169 | int SK_accept_connection The socket for communicating to the client
170 |
171 | int listening_socket The socket that the server is bound to
172 |
173 | Authors:
174 | joao,
175 | marek.
176 | ++++++++++++++++++++++++++++++++++++++*/
177 | int SK_accept_connection(int listening_socket) {
178 | int connected_socket = -1;
179 | int num_errors = 0;
180 |
181 | #define MAX_ACCEPT_ERRORS 3
182 |
183 | for (;;) {
184 |
185 | ER_dbg_va(FAC_SK, ASP_SK_GEN,
186 | "Going to accept connections on socket : %d",listening_socket);
187 |
188 | connected_socket = accept(listening_socket, NULL, NULL);
189 | if (connected_socket < 0) {
190 | /* Either a real error occured, or blocking was interrupted for
191 | some reason. Only abort execution if a real error occured. */
192 | switch(errno) {
193 | case EINTR: /* Interrupted system call */
194 | case ECONNABORTED: /* Software caused connection abort */
195 | /* no warning */
196 | continue; /* don't return - do the accept again */
197 | default:
198 | /* special case: shutdown of the server - just return */
199 | if( CO_get_do_server() == 0 ) {
200 | return -1;
201 | }
202 | else { /* real error */
203 | if( ++num_errors < MAX_ACCEPT_ERRORS ) {
204 | /* warn */
205 | ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno));
206 | }
207 | else {
208 | /* crash */
209 | ER_perror(FAC_SK, SK_ACERF,
210 | "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS);
211 | die;
212 | }
213 | }
214 | }
215 | }
216 | else { /* success */
217 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
218 | connected_socket
219 | );
220 |
221 | return connected_socket;
222 | }
223 |
224 | }
225 | }
226 |
227 |
228 | /*++++++++++++++++++++++++++++++++++++++
229 |
230 | er_ret_t SK_connect wrapper around connect(), doing non-blocking
231 | connection with timeout
232 |
233 | int *sock pointer to the storage for socket descriptor
234 |
235 | char *hostname host to connect to
236 |
237 | int port port to connect to
238 |
239 | int timeout in seconds
240 |
241 | Author: marek
242 |
243 | ++++++++++++++++++++++++++++++++++++++*/
244 | er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout)
245 | {
246 | struct sockaddr_in sin;
247 | struct hostent *hp;
248 | int s;
249 | int flags;
250 | struct timeval ptm;
251 | fd_set rset, wset;
252 | int gs, sel, er, erlen=sizeof(er);
253 | int error;
254 | struct hostent result;
255 | char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
256 |
257 | /* look up the host name */
258 | #ifdef __linux__
259 | er = (gethostbyname_r(hostname, &result, aliasbuf,
260 | sizeof(aliasbuf), &hp, &error) < 0 );
261 | #else /* default is Solaris implementation */
262 | hp = gethostbyname_r(hostname, &result, aliasbuf,
263 | sizeof(aliasbuf), &error);
264 | er = ( hp == NULL );
265 | #endif
266 |
267 | if( er ) {
268 | return SK_BADHOST;
269 | }
270 |
271 | /* create a socket */
272 | s = socket(AF_INET, SOCK_STREAM, 0);
273 | if (s < 0) {
274 | return SK_SOCKET;
275 | }
276 |
277 | /* bind to it */
278 | bzero((caddr_t)&sin, sizeof (sin));
279 | sin.sin_family = hp->h_addrtype;
280 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
281 | close(s);
282 | return SK_BIND;
283 | }
284 | bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
285 | sin.sin_port=htons(port);
286 |
287 | /* connect in non-blocking mode */
288 | flags = fcntl(s, F_GETFL, 0);
289 | fcntl(s, F_SETFL, flags | O_NONBLOCK );
290 |
291 | if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
292 | && errno != EINPROGRESS ) {
293 | close(s);
294 | return SK_CONNECT;
295 | }
296 |
297 | /* now wait for success */
298 | FD_ZERO( &rset );
299 | FD_SET( s, &rset );
300 | wset = rset;
301 | ptm.tv_usec = 0;
302 | ptm.tv_sec = timeout;
303 |
304 | if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) {
305 | /* timeout */
306 | close(s);
307 | return SK_TIMEOUT;
308 | }
309 | if (sel < 0) {
310 | close(s);
311 | return SK_CONNECT;
312 | }
313 |
314 | gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
315 |
316 | if( gs < 0 || er ) { /* Stevens code, p.411 is exceptionally crappy */
317 | close(s);
318 | return SK_CONNECT;
319 | } /* if error */
320 |
321 | fcntl(s, F_SETFL, flags);
322 | *sock = s;
323 |
324 | return SK_OK;
325 | }
326 |
327 |
328 | /* XXX: deprecated SK_read(), SK_gets(), and SK_getc(), since these
329 | functions are unused, and do not work with the buffering added
330 | to SK_cd_gets()
331 | - Shane, 2002-05-13 */
332 |
333 | #if 0
334 | /* SK_read() */
335 | /*++++++++++++++++++++++++++++++++++++++
336 |
337 | This is just like the read() system call, except that it will make
338 | sure that all your data goes through the socket.
339 |
340 | int SK_read Returns the number of bytes read.
341 |
342 | int sockfd The socket file descriptor.
343 |
344 | char *buf The buffer to be read from the socket.
345 |
346 | size_t count The number of bytes in the buffer.
347 |
348 | Author:
349 | ottrey
350 |
351 | ++++++++++++++++++++++++++++++++++++++*/
352 | int SK_read(int sockfd, char *buf, size_t count) {
353 | size_t bytes_read = 0;
354 | int this_read;
355 |
356 | while (bytes_read < count) {
357 | do
358 | this_read = read(sockfd, buf, count - bytes_read);
359 | while ( (this_read < 0) && (errno == EINTR) );
360 | if (this_read < 0)
361 | return this_read;
362 | else if (this_read == 0)
363 | return bytes_read;
364 | bytes_read += this_read;
365 | buf += this_read;
366 | }
367 |
368 | return count;
369 |
370 | } /* SK_read() */
371 | #endif /* 0 */
372 |
373 |
374 | /* SK_write() */
375 | /*++++++++++++++++++++++++++++++++++++++
376 |
377 | int SK_write Returns:
378 | -1 on error
379 | 0 on timeout
380 | 1 on success (all bytes written)
381 |
382 | int sockfd The socket file descriptor.
383 |
384 | const char *buf The buffer to be written to the socket.
385 |
386 | int count The number of bytes in the buffer.
387 |
388 | const struct timeval *timeout Maximum time to wait between each
389 | write() call, or NULL for "forever".
390 |
391 | int *count_sent Set to the number of bytes sucessfully
392 | written. This value is always valid,
393 | although it will be less than the
394 | total number of bytes to send if
395 | the function returns -1 or 0. NULL
396 | may be sent if the caller does not
397 | care about the number of bytes sent on
398 | failure.
399 |
400 | ++++++++++++++++++++++++++++++++++++++*/
401 |
402 | int
403 | SK_write(int sockfd,
404 | const char *buf,
405 | int count,
406 | const struct timeval *timeout,
407 | int *count_sent)
408 | {
409 | int local_count_sent; /* only used if caller passes NULL */
410 | fd_set fds;
411 | int select_ret;
412 | struct timeval tv;
413 | int write_ret;
414 |
415 | /* copious logging never hurt anybody (well, except people with slow
416 | computers or small hard disks) */
417 | ER_dbg_va(FAC_SK, ASP_SK_WRIT,
418 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
419 | sockfd, buf, count);
420 |
421 | /* allow caller to pass NULL if it doesn't care about the count sent */
422 | if (count_sent == NULL) {
423 | count_sent = &local_count_sent;
424 | }
425 |
426 | /* loop around until we send all of our data, or we get a timeout or
427 | disconnect */
428 | *count_sent = 0;
429 | while (*count_sent < count) {
430 |
431 | /* first, call select() and see if we can write without blocking */
432 | FD_ZERO(&fds);
433 | FD_SET(sockfd, &fds);
434 | if (timeout == NULL) {
435 | select_ret = select(sockfd+1, NULL, &fds, NULL, NULL);
436 | } else {
437 | /* make a copy of timeout, because it's value is undefined
438 | on return from select() */
439 | tv = *timeout;
440 | select_ret = select(sockfd+1, NULL, &fds, NULL, &tv);
441 | }
442 | /* check for error */
443 | if (select_ret < 0) {
444 | /* log the error and return "timeout" */
445 | ER_perror(FAC_SK, SK_SELECT, "(%d) %s", errno, strerror(errno));
446 | return -1;
447 | }
448 | /* check for timeout */
449 | if ((select_ret == 0) || !FD_ISSET(sockfd, &fds)) {
450 | return -1;
451 | }
452 |
453 |
454 | /* at this point we can safely write */
455 | write_ret = write(sockfd, buf, count - *count_sent);
456 |
457 | /* if write failed, assume other side disconnected */
458 | if (write_ret <= 0) {
459 | return 0;
460 | }
461 |
462 | /* update our current status */
463 | *count_sent += write_ret;
464 | buf += write_ret;
465 |
466 | }
467 |
468 | /* all bytes sent, return success */
469 | return 1;
470 | } /* SK_write() */
471 |
472 |
473 | #if 0
474 | /* SK_gets() */
475 | /*++++++++++++++++++++++++++++++++++++++
476 |
477 | This function reads from a socket, until it recieves a linefeed
478 | character. It fills the buffer "str" up to the maximum size "count".
479 |
480 | int SK_gets Returns the total_count of bytes read.
481 |
482 | int sockfd The socket file descriptor.
483 |
484 | char *str The buffer to be written from the socket.
485 |
486 | size_t count The number of bytes in the buffer.
487 |
488 |
489 | Authors:
490 | ottrey,
491 | marek (modified for meaningful error codes).
492 |
493 | Side Effects:
494 | This function will return -1 if the socket is closed during the read operation.
495 |
496 | Note that if a single line exceeds the length of count, the extra data
497 | will be read and discarded! You have been warned.
498 |
499 | ++++++++++++++++++++++++++++++++++++++*/
500 | int SK_gets(int sockfd, char *str, size_t count) {
501 | int bytes_read;
502 | int total_count = 0;
503 | char *current_position;
504 | char last_read = 0;
505 |
506 | int control_c = 0;
507 |
508 | current_position = str;
509 | while (last_read != 10) {
510 |
511 | bytes_read = read(sockfd, &last_read, 1);
512 | if (bytes_read <= 0) {
513 | /* The other side may have closed unexpectedly */
514 | return SK_DISCONNECT;
515 | /* Is this effective on other platforms than linux? */
516 | }
517 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
518 | *current_position = last_read;
519 | current_position++;
520 | total_count++;
521 | }
522 |
523 | if (last_read == -1) {
524 | bytes_read = read(sockfd, &last_read, 1);
525 | if (last_read == -12) {
526 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
527 | control_c = 1;
528 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
529 | return SK_INTERRUPT;
530 | }
531 | }
532 | }
533 | if (count > 0) {
534 | *current_position = 0;
535 | }
536 |
537 | return total_count;
538 |
539 | } /* SK_gets() */
540 | #endif /* 0 */
541 |
542 |
543 | /* SK_puts() */
544 | /*++++++++++++++++++++++++++++++++++++++
545 |
546 | This function writes a character string out to a socket.
547 |
548 | int SK_puts The total_count of bytes written,
549 | or -1 on hangup, error, or timeout
550 |
551 | int sockfd The socket file descriptor.
552 |
553 | char *str The buffer to be written from the socket.
554 |
555 | const struct timeval *timeout Maximum time to wait between each
556 | write() call, or NULL for "forever".
557 |
558 | ++++++++++++++++++++++++++++++++++++++*/
559 | int
560 | SK_puts(int sockfd, const char *str, const struct timeval *timeout)
561 | {
562 | int count_sent;
563 | if (SK_write(sockfd, str, strlen(str), timeout, &count_sent) <= 0) {
564 | return -1;
565 | } else {
566 | return count_sent;
567 | }
568 | } /* SK_puts() */
569 |
570 | /* SK_putc() */
571 | /*++++++++++++++++++++++++++++++++++++++
572 |
573 | This function writes a single character out to a socket.
574 |
575 | int SK_putc Returns the number of characters written.
576 |
577 | int sockfd socket
578 |
579 | char ch character
580 |
581 | const struct timeval *timeout Maximum time to wait between each
582 | write() call, or NULL for "forever".
583 |
584 | ++++++++++++++++++++++++++++++++++++++*/
585 | int
586 | SK_putc(int sockfd, char ch, const struct timeval *timeout)
587 | {
588 | int count_sent;
589 | SK_write(sockfd, &ch, 1, timeout, &count_sent);
590 | return count_sent;
591 | }/* SK_putc() */
592 |
593 | #if 0
594 | /*++++++++++++++++++++++++++++++++++++++
595 |
596 | This function reads a single character from a socket.
597 |
598 | returns EOF when no character can be read.
599 |
600 | ++++++++++++++++++++++++++++++++++++++*/
601 | int SK_getc(int sockfd) {
602 | char ch;
603 |
604 | if( read(sockfd, &ch, 1) <= 0 ) {
605 | return EOF;
606 | }
607 | else {
608 | return ch;
609 | }
610 | }/* SK_getc() */
611 | #endif /* 0 */
612 |
613 | /* SK_getpeername() */
614 | /*++++++++++++++++++++++++++++++++++++++
615 |
616 | This function will tell you who is at the other end of a connected stream socket.
617 |
618 | char *SK_getpeername Returns allocated string with the IP in it,
619 | or "--" if the descriptor is not a socket,
620 | or NULL on error.
621 |
622 | int sockfd The socket or file descriptor.
623 |
624 | +html+ <PRE>
625 | Authors:
626 | ottrey,
627 | marek (modified error handling, made MT-Safe).
628 | +html+ </PRE>
629 |
630 | ++++++++++++++++++++++++++++++++++++++*/
631 | char *SK_getpeername(int sockfd)
632 | {
633 | char *hostaddress=NULL;
634 | struct sockaddr_in addr_in;
635 | int namelen=sizeof(addr_in);
636 |
637 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
638 |
639 | hostaddress = (char *)UT_malloc(INET_ADDRSTRLEN);
640 | inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN);
641 | }
642 | else {
643 | int er = errno;
644 |
645 | if( er == ENOTSOCK ) {
646 | hostaddress = wr_string("--");
647 | }
648 | else {
649 | /* XXX: hack to avoid crash in the case where peer disconnects */
650 | /* To fix this, the socket interface needs to deal with a structure
651 | containing not only the file descriptor, but also the address of
652 | the host and the peer. Other goodies, like the current time,
653 | time of last operation, and last errno could also be included
654 | for good measure. */
655 | hostaddress = UT_strdup("127.0.0.1");
656 | }
657 | }
658 |
659 | return hostaddress;
660 |
661 | } /* SK_getpeername() */
662 |
663 |
664 | /* SK_getpeerip */
665 | /*++++++++++++++++++++++++++++++++++++++
666 |
667 | This function will check the ip of the connected peer and store it in the
668 | ip_addr_t structure defined in the IP module.
669 |
670 | int SK_getpeerip returns 0 on success, -1 on failure.
671 |
672 | int sockfd The socket descriptor (file will result in -1)
673 |
674 | ip_addr_t *ip Pointer to where the address should be stored.
675 |
676 | +html+ <PRE>
677 | Author:
678 | marek
679 | +html+ </PRE>
680 | ++++++++++++++++++++++++++++++++++++++*/
681 |
682 | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
683 | struct sockaddr_in addr_in;
684 | int namelen=sizeof(addr_in);
685 | int ret=-1;
686 |
687 | memset(& addr_in, 0, sizeof(struct sockaddr_in));
688 |
689 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
690 | ret=0;
691 | IP_addr_s2b(ip, &addr_in, namelen);
692 | } else {
693 | /* XXX: hack to avoid crash in the case where peer disconnects */
694 | /* To fix this, the socket interface needs to deal with a structure
695 | containing not only the file descriptor, but also the address of
696 | the host and the peer. Other goodies, like the current time,
697 | time of last operation, and last errno could also be included
698 | for good measure. */
699 | ret = 0;
700 | addr_in.sin_family = AF_INET;
701 | addr_in.sin_addr.s_addr = INADDR_LOOPBACK;
702 | addr_in.sin_port = 0;
703 | IP_addr_s2b(ip, &addr_in, namelen);
704 | }
705 |
706 | return ret;
707 | }
708 |