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 |