1 | /***************************************
2 | $Revision: 1.20 $
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 | perror("bind");
147 | close(listening_socket);
148 | exit(EXIT_FAILURE);
149 | }
150 |
151 |
152 | if (socket_type == SOCK_STREAM) {
153 | listen(listening_socket, backlog); /* Queue up to five connections before
154 | having them automatically rejected. */
155 | }
156 |
157 | return listening_socket;
158 | } /* SK_getsock() */
159 |
160 | /*++++++++++++++++++++++++++++++++++++++
161 |
162 | Wait for an incoming connection on the specified socket
163 |
164 | int SK_accept_connection The socket for communicating to the client
165 |
166 | int listening_socket The socket that the server is bound to
167 |
168 | Authors:
169 | joao,
170 | marek.
171 | ++++++++++++++++++++++++++++++++++++++*/
172 | int SK_accept_connection(int listening_socket) {
173 | int connected_socket = -1;
174 | int num_errors = 0;
175 |
176 | #define MAX_ACCEPT_ERRORS 3
177 |
178 | for (;;) {
179 |
180 | ER_dbg_va(FAC_SK, ASP_SK_GEN,
181 | "Going to accept connections on socket : %d",listening_socket);
182 |
183 | connected_socket = accept(listening_socket, NULL, NULL);
184 | if (connected_socket < 0) {
185 | /* Either a real error occured, or blocking was interrupted for
186 | some reason. Only abort execution if a real error occured. */
187 | switch(errno) {
188 | case EINTR: /* Interrupted system call */
189 | case ECONNABORTED: /* Software caused connection abort */
190 | /* no warning */
191 | continue; /* don't return - do the accept again */
192 | default:
193 | /* special case: shutdown of the server - just return */
194 | if( CO_get_do_server() == 0 ) {
195 | return -1;
196 | }
197 | else { /* real error */
198 | if( ++num_errors < MAX_ACCEPT_ERRORS ) {
199 | /* warn */
200 | ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno));
201 | }
202 | else {
203 | /* crash */
204 | ER_perror(FAC_SK, SK_ACERF,
205 | "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS);
206 | die;
207 | }
208 | }
209 | }
210 | }
211 | else { /* success */
212 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
213 | connected_socket
214 | );
215 |
216 | return connected_socket;
217 | }
218 |
219 | }
220 | }
221 |
222 |
223 | /*++++++++++++++++++++++++++++++++++++++
224 |
225 | er_ret_t SK_connect wrapper around connect(), doing non-blocking
226 | connection with timeout
227 |
228 | int *sock pointer to the storage for socket descriptor
229 |
230 | char *hostname host to connect to
231 |
232 | int port port to connect to
233 |
234 | int timeout in seconds
235 |
236 | Author: marek
237 |
238 | ++++++++++++++++++++++++++++++++++++++*/
239 | er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout)
240 | {
241 | struct sockaddr_in sin;
242 | struct hostent *hp;
243 | int s;
244 | int flags;
245 | struct timeval ptm;
246 | fd_set rset, wset;
247 | int gs, sel, er, erlen=sizeof(er);
248 | int error;
249 | struct hostent result;
250 | char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
251 |
252 | /* look up the host name */
253 | #ifdef __linux__
254 | er = (gethostbyname_r(hostname, &result, aliasbuf,
255 | sizeof(aliasbuf), &hp, &error) < 0 );
256 | #else /* default is Solaris implementation */
257 | hp = gethostbyname_r(hostname, &result, aliasbuf,
258 | sizeof(aliasbuf), &error);
259 | er = ( hp == NULL );
260 | #endif
261 |
262 | if( er ) {
263 | return SK_BADHOST;
264 | }
265 |
266 | /* create a socket */
267 | s = socket(AF_INET, SOCK_STREAM, 0);
268 | if (s < 0) {
269 | return SK_SOCKET;
270 | }
271 |
272 | /* bind to it */
273 | bzero((caddr_t)&sin, sizeof (sin));
274 | sin.sin_family = hp->h_addrtype;
275 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
276 | close(s);
277 | return SK_BIND;
278 | }
279 | bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
280 | sin.sin_port=htons(port);
281 |
282 | /* connect in non-blocking mode */
283 | flags = fcntl(s, F_GETFL, 0);
284 | fcntl(s, F_SETFL, flags | O_NONBLOCK );
285 |
286 | if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
287 | && errno != EINPROGRESS ) {
288 | close(s);
289 | return SK_CONNECT;
290 | }
291 |
292 | /* now wait for success */
293 | FD_ZERO( &rset );
294 | FD_SET( s, &rset );
295 | wset = rset;
296 | ptm.tv_usec = 0;
297 | ptm.tv_sec = timeout;
298 |
299 | if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) {
300 | /* timeout */
301 | close(s);
302 | return SK_TIMEOUT;
303 | }
304 | if (sel < 0) {
305 | close(s);
306 | return SK_CONNECT;
307 | }
308 |
309 | gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
310 |
311 | if( gs < 0 || er ) { /* Stevens code, p.411 is exceptionally crappy */
312 | close(s);
313 | return SK_CONNECT;
314 | } /* if error */
315 |
316 | fcntl(s, F_SETFL, flags);
317 | *sock = s;
318 |
319 | return SK_OK;
320 | }
321 |
322 |
323 | /* SK_read() */
324 | /*++++++++++++++++++++++++++++++++++++++
325 |
326 | This is just like the read() system call, except that it will make
327 | sure that all your data goes through the socket.
328 |
329 | int SK_read Returns the number of bytes read.
330 |
331 | int sockfd The socket file descriptor.
332 |
333 | char *buf The buffer to be read from the socket.
334 |
335 | size_t count The number of bytes in the buffer.
336 |
337 | Author:
338 | ottrey
339 |
340 | ++++++++++++++++++++++++++++++++++++++*/
341 | int SK_read(int sockfd, char *buf, size_t count) {
342 | size_t bytes_read = 0;
343 | int this_read;
344 |
345 | while (bytes_read < count) {
346 | do
347 | this_read = read(sockfd, buf, count - bytes_read);
348 | while ( (this_read < 0) && (errno == EINTR) );
349 | if (this_read < 0)
350 | return this_read;
351 | else if (this_read == 0)
352 | return bytes_read;
353 | bytes_read += this_read;
354 | buf += this_read;
355 | }
356 |
357 | return count;
358 |
359 | } /* SK_read() */
360 |
361 |
362 | /* SK_write() */
363 | /*++++++++++++++++++++++++++++++++++++++
364 |
365 | int SK_write Returns:
366 | -1 on error
367 | 0 on timeout
368 | 1 on success (all bytes written)
369 |
370 | int sockfd The socket file descriptor.
371 |
372 | const char *buf The buffer to be written to the socket.
373 |
374 | int count The number of bytes in the buffer.
375 |
376 | const struct timeval *timeout Maximum time to wait between each
377 | write() call, or NULL for "forever".
378 |
379 | int *count_sent Set to the number of bytes sucessfully
380 | written. This value is always valid,
381 | although it will be less than the
382 | total number of bytes to send if
383 | the function returns -1 or 0. NULL
384 | may be sent if the caller does not
385 | care about the number of bytes sent on
386 | failure.
387 |
388 | ++++++++++++++++++++++++++++++++++++++*/
389 |
390 | int
391 | SK_write(int sockfd,
392 | const char *buf,
393 | int count,
394 | const struct timeval *timeout,
395 | int *count_sent)
396 | {
397 | int local_count_sent; /* only used if caller passes NULL */
398 | fd_set fds;
399 | int select_ret;
400 | struct timeval tv;
401 | int write_ret;
402 |
403 | /* copious logging never hurt anybody (well, except people with slow
404 | computers or small hard disks) */
405 | ER_dbg_va(FAC_SK, ASP_SK_WRIT,
406 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
407 | sockfd, buf, count);
408 |
409 | /* allow caller to pass NULL if it doesn't care about the count sent */
410 | if (count_sent == NULL) {
411 | count_sent = &local_count_sent;
412 | }
413 |
414 | /* loop around until we send all of our data, or we get a timeout or
415 | disconnect */
416 | *count_sent = 0;
417 | while (*count_sent < count) {
418 |
419 | /* first, call select() and see if we can write without blocking */
420 | FD_ZERO(&fds);
421 | FD_SET(sockfd, &fds);
422 | if (timeout == NULL) {
423 | select_ret = select(sockfd+1, NULL, &fds, NULL, NULL);
424 | } else {
425 | /* make a copy of timeout, because it's value is undefined
426 | on return from select() */
427 | tv = *timeout;
428 | select_ret = select(sockfd+1, NULL, &fds, NULL, &tv);
429 | }
430 | /* check for error */
431 | if (select_ret < 0) {
432 | /* log the error and return "timeout" */
433 | ER_perror(FAC_SK, SK_SELECT, "(%d) %s", errno, strerror(errno));
434 | return -1;
435 | }
436 | /* check for timeout */
437 | if ((select_ret == 0) || !FD_ISSET(sockfd, &fds)) {
438 | return -1;
439 | }
440 |
441 |
442 | /* at this point we can safely write */
443 | write_ret = write(sockfd, buf, count - *count_sent);
444 |
445 | /* if write failed, assume other side disconnected */
446 | if (write_ret <= 0) {
447 | return 0;
448 | }
449 |
450 | /* update our current status */
451 | *count_sent += write_ret;
452 | buf += write_ret;
453 |
454 | }
455 |
456 | /* all bytes sent, return success */
457 | return 1;
458 | } /* SK_write() */
459 |
460 |
461 | /* SK_gets() */
462 | /*++++++++++++++++++++++++++++++++++++++
463 |
464 | This function reads from a socket, until it recieves a linefeed
465 | character. It fills the buffer "str" up to the maximum size "count".
466 |
467 | int SK_gets Returns the total_count of bytes read.
468 |
469 | int sockfd The socket file descriptor.
470 |
471 | char *str The buffer to be written from the socket.
472 |
473 | size_t count The number of bytes in the buffer.
474 |
475 |
476 | Authors:
477 | ottrey,
478 | marek (modified for meaningful error codes).
479 |
480 | Side Effects:
481 | This function will return -1 if the socket is closed during the read operation.
482 |
483 | Note that if a single line exceeds the length of count, the extra data
484 | will be read and discarded! You have been warned.
485 |
486 | ++++++++++++++++++++++++++++++++++++++*/
487 | int SK_gets(int sockfd, char *str, size_t count) {
488 | int bytes_read;
489 | int total_count = 0;
490 | char *current_position;
491 | char last_read = 0;
492 |
493 | int control_c = 0;
494 |
495 | current_position = str;
496 | while (last_read != 10) {
497 |
498 | bytes_read = read(sockfd, &last_read, 1);
499 | if (bytes_read <= 0) {
500 | /* The other side may have closed unexpectedly */
501 | return SK_DISCONNECT;
502 | /* Is this effective on other platforms than linux? */
503 | }
504 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
505 | *current_position = last_read;
506 | current_position++;
507 | total_count++;
508 | }
509 |
510 | if (last_read == -1) {
511 | bytes_read = read(sockfd, &last_read, 1);
512 | if (last_read == -12) {
513 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
514 | control_c = 1;
515 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
516 | return SK_INTERRUPT;
517 | }
518 | }
519 | }
520 | if (count > 0) {
521 | *current_position = 0;
522 | }
523 |
524 | return total_count;
525 |
526 | } /* SK_gets() */
527 |
528 |
529 | /* SK_puts() */
530 | /*++++++++++++++++++++++++++++++++++++++
531 |
532 | This function writes a character string out to a socket.
533 |
534 | int SK_puts The total_count of bytes written,
535 | or -1 on hangup, error, or timeout
536 |
537 | int sockfd The socket file descriptor.
538 |
539 | char *str The buffer to be written from the socket.
540 |
541 | const struct timeval *timeout Maximum time to wait between each
542 | write() call, or NULL for "forever".
543 |
544 | ++++++++++++++++++++++++++++++++++++++*/
545 | int
546 | SK_puts(int sockfd, const char *str, const struct timeval *timeout)
547 | {
548 | int count_sent;
549 | if (SK_write(sockfd, str, strlen(str), timeout, &count_sent) <= 0) {
550 | return -1;
551 | } else {
552 | return count_sent;
553 | }
554 | } /* SK_puts() */
555 |
556 | /* SK_putc() */
557 | /*++++++++++++++++++++++++++++++++++++++
558 |
559 | This function writes a single character out to a socket.
560 |
561 | int SK_putc Returns the number of characters written.
562 |
563 | int sockfd socket
564 |
565 | char ch character
566 |
567 | const struct timeval *timeout Maximum time to wait between each
568 | write() call, or NULL for "forever".
569 |
570 | ++++++++++++++++++++++++++++++++++++++*/
571 | int
572 | SK_putc(int sockfd, char ch, const struct timeval *timeout)
573 | {
574 | int count_sent;
575 | SK_write(sockfd, &ch, 1, timeout, &count_sent);
576 | return count_sent;
577 | }/* SK_putc() */
578 |
579 | /*++++++++++++++++++++++++++++++++++++++
580 |
581 | This function reads a single character from a socket.
582 |
583 | returns EOF when no character can be read.
584 |
585 | ++++++++++++++++++++++++++++++++++++++*/
586 | int SK_getc(int sockfd) {
587 | char ch;
588 |
589 | if( read(sockfd, &ch, 1) <= 0 ) {
590 | return EOF;
591 | }
592 | else {
593 | return ch;
594 | }
595 | }/* SK_getc() */
596 |
597 | /* SK_getpeername() */
598 | /*++++++++++++++++++++++++++++++++++++++
599 |
600 | This function will tell you who is at the other end of a connected stream socket.
601 |
602 | char *SK_getpeername Returns allocated string with the IP in it,
603 | or "--" if the descriptor is not a socket,
604 | or NULL on error.
605 |
606 | int sockfd The socket or file descriptor.
607 |
608 | +html+ <PRE>
609 | Authors:
610 | ottrey,
611 | marek (modified error handling, made MT-Safe).
612 | +html+ </PRE>
613 |
614 | ++++++++++++++++++++++++++++++++++++++*/
615 | char *SK_getpeername(int sockfd)
616 | {
617 | char *hostaddress=NULL;
618 | struct sockaddr_in addr_in;
619 | int namelen=sizeof(addr_in);
620 |
621 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
622 |
623 | hostaddress = (char *)UT_malloc(INET_ADDRSTRLEN);
624 | inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN);
625 | }
626 | else {
627 | int er = errno;
628 |
629 | if( er == ENOTSOCK ) {
630 | hostaddress = wr_string("--");
631 | }
632 | else {
633 | /* XXX: hack to avoid crash in the case where peer disconnects */
634 | /* To fix this, the socket interface needs to deal with a structure
635 | containing not only the file descriptor, but also the address of
636 | the host and the peer. Other goodies, like the current time,
637 | time of last operation, and last errno could also be included
638 | for good measure. */
639 | hostaddress = UT_strdup("127.0.0.1");
640 | }
641 | }
642 |
643 | return hostaddress;
644 |
645 | } /* SK_getpeername() */
646 |
647 |
648 | /* SK_getpeerip */
649 | /*++++++++++++++++++++++++++++++++++++++
650 |
651 | This function will check the ip of the connected peer and store it in the
652 | ip_addr_t structure defined in the IP module.
653 |
654 | int SK_getpeerip returns 0 on success, -1 on failure.
655 |
656 | int sockfd The socket descriptor (file will result in -1)
657 |
658 | ip_addr_t *ip Pointer to where the address should be stored.
659 |
660 | +html+ <PRE>
661 | Author:
662 | marek
663 | +html+ </PRE>
664 | ++++++++++++++++++++++++++++++++++++++*/
665 |
666 | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
667 | struct sockaddr_in addr_in;
668 | int namelen=sizeof(addr_in);
669 | int ret=-1;
670 |
671 | memset(& addr_in, 0, sizeof(struct sockaddr_in));
672 |
673 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
674 | ret=0;
675 | IP_addr_s2b(ip, &addr_in, namelen);
676 | } else {
677 | /* XXX: hack to avoid crash in the case where peer disconnects */
678 | /* To fix this, the socket interface needs to deal with a structure
679 | containing not only the file descriptor, but also the address of
680 | the host and the peer. Other goodies, like the current time,
681 | time of last operation, and last errno could also be included
682 | for good measure. */
683 | ret = 0;
684 | addr_in.sin_family = AF_INET;
685 | addr_in.sin_addr.s_addr = INADDR_LOOPBACK;
686 | addr_in.sin_port = 0;
687 | IP_addr_s2b(ip, &addr_in, namelen);
688 | }
689 |
690 | return ret;
691 | }
692 |