1 | /*************************************** 2 | $Revision: 1.15 $ 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 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 "sk.h" 38 | #include "constants.h" 39 | #include "stubs.h" 40 | 41 | #include "memwrap.h" 42 | 43 | /*+ String sizes +*/ 44 | #define STR_S 63 45 | #define STR_XXL 16383 46 | 47 | /* SK_atoport() */ 48 | /*++++++++++++++++++++++++++++++++++++++ 49 | Take a service name, and a service type, and return a port number. If the 50 | service name is not found, it tries it as a decimal number. The number 51 | returned is byte ordered for the network. 52 | 53 | char *service Service name (or port number). 54 | 55 | char *proto Protocol (eg "tcp"). 56 | 57 | Author: 58 | ottrey. 59 | 60 | ++++++++++++++++++++++++++++++++++++++*/ 61 | int SK_atoport(const char *service, const char *proto) { 62 | unsigned port; 63 | long int lport; 64 | struct servent *serv; 65 | char *errpos; 66 | struct servent result; 67 | char buffer[STR_XXL]; 68 | 69 | /* First try to read it from /etc/services */ 70 | 71 | #ifdef __linux__ 72 | if(getservbyname_r(service, proto, &result, buffer, sizeof(buffer), &serv) < 0) serv = NULL; 73 | #else 74 | serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer)); 75 | #endif 76 | 77 | if (serv != NULL) 78 | port = serv->s_port; 79 | else { /* Not in services, maybe a number? */ 80 | lport = strtol(service,&errpos,0); 81 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) ) 82 | return -1; /* Invalid port address */ 83 | port = htons(lport); 84 | } 85 | return port; 86 | } /* SK_atoport() */ 87 | 88 | 89 | /* SK_close() */ 90 | /*++++++++++++++++++++++++++++++++++++++ 91 | 92 | int SK_close wrapper around closing the socket. Returns the value 93 | returned by close(2) 94 | 95 | int socket socket to be closed 96 | 97 | Author: 98 | ottrey 99 | ++++++++++++++++++++++++++++++++++++++*/ 100 | int SK_close(int socket) { 101 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket); 102 | 103 | return close(socket); 104 | } 105 | 106 | /* SK_getsock() */ 107 | /*++++++++++++++++++++++++++++++++++++++ 108 | 109 | int SK_getsock This function creates a socket and binds to it. 110 | Returns the number of the created 111 | descriptor/listening socket. 112 | 113 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets) 114 | 115 | unsigned port The port to listen on. Ports < 1024 are 116 | reserved for the root user. Host byte order. 117 | 118 | int backlog Size of the backlog queue to be set on that 119 | socket. 120 | 121 | uint32_t bind_address Address to bind to, in network order. 122 | 123 | Authors: 124 | ottrey, 125 | joao, 126 | marek (added htons conversion for port). 127 | 128 | ++++++++++++++++++++++++++++++++++++++*/ 129 | int SK_getsock(int socket_type, unsigned h_port, int backlog, 130 | uint32_t bind_address) { 131 | struct sockaddr_in address; 132 | int listening_socket; 133 | int reuse_addr = 1; 134 | u_short port = htons(h_port); 135 | 136 | /* Setup internet address information. 137 | This is used with the bind() call */ 138 | memset((char *) &address, 0, sizeof(address)); 139 | address.sin_family = AF_INET; 140 | address.sin_port = port; 141 | address.sin_addr.s_addr = bind_address; 142 | 143 | /* Map all of the signals and exit routine */ 144 | 145 | listening_socket = socket(AF_INET, socket_type, 0); 146 | if (listening_socket < 0) { 147 | perror("socket"); 148 | exit(EXIT_FAILURE); 149 | } 150 | 151 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr)); 152 | 153 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) { 154 | perror("bind"); 155 | close(listening_socket); 156 | exit(EXIT_FAILURE); 157 | } 158 | 159 | 160 | if (socket_type == SOCK_STREAM) { 161 | listen(listening_socket, backlog); /* Queue up to five connections before 162 | having them automatically rejected. */ 163 | } 164 | 165 | return listening_socket; 166 | } /* SK_getsock() */ 167 | 168 | /*++++++++++++++++++++++++++++++++++++++ 169 | 170 | Wait for an incoming connection on the specified socket 171 | 172 | int SK_accept_connection The socket for communicating to the client 173 | 174 | int listening_socket The socket that the server is bound to 175 | 176 | Authors: 177 | joao, 178 | marek. 179 | ++++++++++++++++++++++++++++++++++++++*/ 180 | int SK_accept_connection(int listening_socket) { 181 | int connected_socket = -1; 182 | int num_errors = 0; 183 | 184 | #define MAX_ACCEPT_ERRORS 3 185 | 186 | for (;;) { 187 | 188 | ER_dbg_va(FAC_SK, ASP_SK_GEN, 189 | "Going to accept connections on socket : %d",listening_socket); 190 | 191 | connected_socket = accept(listening_socket, NULL, NULL); 192 | if (connected_socket < 0) { 193 | /* Either a real error occured, or blocking was interrupted for 194 | some reason. Only abort execution if a real error occured. */ 195 | switch(errno) { 196 | case EINTR: /* Interrupted system call */ 197 | case ECONNABORTED: /* Software caused connection abort */ 198 | /* no warning */ 199 | continue; /* don't return - do the accept again */ 200 | default: 201 | /* special case: shutdown of the server - just return */ 202 | if( CO_get_do_server() == 0 ) { 203 | return -1; 204 | } 205 | else { /* real error */ 206 | if( ++num_errors < MAX_ACCEPT_ERRORS ) { 207 | /* warn */ 208 | ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno)); 209 | } 210 | else { 211 | /* crash */ 212 | ER_perror(FAC_SK, SK_ACERF, 213 | "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS); 214 | die; 215 | } 216 | } 217 | } 218 | } 219 | else { /* success */ 220 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d", 221 | connected_socket 222 | ); 223 | 224 | return connected_socket; 225 | } 226 | 227 | } 228 | } 229 | 230 | 231 | /*++++++++++++++++++++++++++++++++++++++ 232 | 233 | er_ret_t SK_connect wrapper around connect(), doing non-blocking 234 | connection with timeout 235 | 236 | int *sock pointer to the storage for socket descriptor 237 | 238 | char *hostname host to connect to 239 | 240 | int port port to connect to 241 | 242 | int timeout in seconds 243 | 244 | Author: marek 245 | 246 | ++++++++++++++++++++++++++++++++++++++*/ 247 | er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout) 248 | { 249 | struct sockaddr_in sin; 250 | struct hostent *hp; 251 | int s; 252 | int flags; 253 | struct timeval ptm; 254 | fd_set rset, wset; 255 | int gs, sel, er, erlen=sizeof(er); 256 | int error; 257 | struct hostent result; 258 | char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */ 259 | 260 | /* look up the host name */ 261 | #ifdef __linux__ 262 | er = (gethostbyname_r(hostname, &result, aliasbuf, 263 | sizeof(aliasbuf), &hp, &error) < 0 ); 264 | #else /* default is Solaris implementation */ 265 | hp = gethostbyname_r(hostname, &result, aliasbuf, 266 | sizeof(aliasbuf), &error); 267 | er = ( hp == NULL ); 268 | #endif 269 | 270 | if( er ) { 271 | return SK_BADHOST; 272 | } 273 | 274 | /* create a socket */ 275 | s = socket(AF_INET, SOCK_STREAM, 0); 276 | if (s < 0) { 277 | return SK_SOCKET; 278 | } 279 | 280 | /* bind to it */ 281 | bzero((caddr_t)&sin, sizeof (sin)); 282 | sin.sin_family = hp->h_addrtype; 283 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 284 | close(s); 285 | return SK_BIND; 286 | } 287 | bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 288 | sin.sin_port=htons(port); 289 | 290 | /* connect in non-blocking mode */ 291 | flags = fcntl(s, F_GETFL, 0); 292 | fcntl(s, F_SETFL, flags | O_NONBLOCK ); 293 | 294 | if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0 295 | && errno != EINPROGRESS ) { 296 | close(s); 297 | return SK_CONNECT; 298 | } 299 | 300 | /* now wait for success */ 301 | FD_ZERO( &rset ); 302 | FD_SET( s, &rset ); 303 | wset = rset; 304 | ptm.tv_usec = 0; 305 | ptm.tv_sec = timeout; 306 | 307 | if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) { 308 | /* timeout */ 309 | close(s); 310 | return SK_TIMEOUT; 311 | } 312 | dieif( sel < 0 ); /* we don't expect problems with select */ 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 | /* SK_read() */ 329 | /*++++++++++++++++++++++++++++++++++++++ 330 | 331 | This is just like the read() system call, except that it will make 332 | sure that all your data goes through the socket. 333 | 334 | int SK_read Returns the number of bytes read. 335 | 336 | int sockfd The socket file descriptor. 337 | 338 | char *buf The buffer to be read from the socket. 339 | 340 | size_t count The number of bytes in the buffer. 341 | 342 | Author: 343 | ottrey 344 | 345 | ++++++++++++++++++++++++++++++++++++++*/ 346 | int SK_read(int sockfd, char *buf, size_t count) { 347 | size_t bytes_read = 0; 348 | int this_read; 349 | 350 | while (bytes_read < count) { 351 | do 352 | this_read = read(sockfd, buf, count - bytes_read); 353 | while ( (this_read < 0) && (errno == EINTR) ); 354 | if (this_read < 0) 355 | return this_read; 356 | else if (this_read == 0) 357 | return bytes_read; 358 | bytes_read += this_read; 359 | buf += this_read; 360 | } 361 | 362 | return count; 363 | 364 | } /* SK_read() */ 365 | 366 | 367 | /* SK_write() */ 368 | /*++++++++++++++++++++++++++++++++++++++ 369 | 370 | This is just like the write() system call, except that it will 371 | make sure that all data is transmitted. 372 | 373 | int SK_write Returns the number of bytes written. 374 | 375 | int sockfd The socket file descriptor. 376 | 377 | char *buf The buffer to be written to the socket. 378 | 379 | size_t count The number of bytes in the buffer. 380 | 381 | Author: 382 | ottrey 383 | 384 | ++++++++++++++++++++++++++++++++++++++*/ 385 | int SK_write(int sockfd, const char *buf, size_t count) { 386 | size_t bytes_sent = 0; 387 | int this_write; 388 | 389 | 390 | ER_dbg_va(FAC_SK, ASP_SK_WRIT, 391 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]", 392 | sockfd, buf, count); 393 | 394 | while (bytes_sent < count) { 395 | do 396 | this_write = write(sockfd, buf, count - bytes_sent); 397 | while ( (this_write < 0) && (errno == EINTR) ); 398 | if (this_write <= 0) 399 | return this_write; 400 | bytes_sent += this_write; 401 | buf += this_write; 402 | } 403 | return count; 404 | } /* SK_write() */ 405 | 406 | 407 | /* SK_gets() */ 408 | /*++++++++++++++++++++++++++++++++++++++ 409 | 410 | This function reads from a socket, until it recieves a linefeed 411 | character. It fills the buffer "str" up to the maximum size "count". 412 | 413 | int SK_gets Returns the total_count of bytes read. 414 | 415 | int sockfd The socket file descriptor. 416 | 417 | char *str The buffer to be written from the socket. 418 | 419 | size_t count The number of bytes in the buffer. 420 | 421 | 422 | Authors: 423 | ottrey, 424 | marek (modified for meaningful error codes). 425 | 426 | Side Effects: 427 | This function will return -1 if the socket is closed during the read operation. 428 | 429 | Note that if a single line exceeds the length of count, the extra data 430 | will be read and discarded! You have been warned. 431 | 432 | ++++++++++++++++++++++++++++++++++++++*/ 433 | int SK_gets(int sockfd, char *str, size_t count) { 434 | int bytes_read; 435 | int total_count = 0; 436 | char *current_position; 437 | char last_read = 0; 438 | 439 | int control_c = 0; 440 | 441 | current_position = str; 442 | while (last_read != 10) { 443 | 444 | bytes_read = read(sockfd, &last_read, 1); 445 | if (bytes_read <= 0) { 446 | /* The other side may have closed unexpectedly */ 447 | return SK_DISCONNECT; 448 | /* Is this effective on other platforms than linux? */ 449 | } 450 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) { 451 | *current_position = last_read; 452 | current_position++; 453 | total_count++; 454 | } 455 | 456 | if (last_read == -1) { 457 | bytes_read = read(sockfd, &last_read, 1); 458 | if (last_read == -12) { 459 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c"); 460 | control_c = 1; 461 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT"); 462 | return SK_INTERRUPT; 463 | } 464 | } 465 | } 466 | if (count > 0) { 467 | *current_position = 0; 468 | } 469 | 470 | return total_count; 471 | 472 | } /* SK_gets() */ 473 | 474 | 475 | /* SK_puts() */ 476 | /*++++++++++++++++++++++++++++++++++++++ 477 | 478 | This function writes a character string out to a socket. 479 | 480 | int SK_puts The total_count of bytes written, 481 | or errors (represented as negative numbers) 482 | 483 | int sockfd The socket file descriptor. 484 | 485 | char *str The buffer to be written from the socket. 486 | 487 | More: 488 | +html+ <PRE> 489 | Authors: 490 | ottrey 491 | 492 | Side Effects: 493 | This function will return -1 if the socket is closed during the write operation. 494 | +html+ </PRE> 495 | 496 | ++++++++++++++++++++++++++++++++++++++*/ 497 | int SK_puts(int sockfd, const char *str) { 498 | 499 | return SK_write(sockfd, str, strlen(str)); 500 | 501 | } /* SK_puts() */ 502 | 503 | /* SK_putc() */ 504 | /*++++++++++++++++++++++++++++++++++++++ 505 | 506 | This function writes a single character out to a socket. 507 | 508 | int SK_putc Returns the number of characters written. 509 | 510 | int sockfd socket 511 | 512 | char ch character 513 | 514 | ++++++++++++++++++++++++++++++++++++++*/ 515 | int SK_putc(int sockfd, char ch) { 516 | return SK_write(sockfd, &ch, 1); 517 | }/* SK_putc() */ 518 | 519 | /*++++++++++++++++++++++++++++++++++++++ 520 | 521 | This function reads a single character from a socket. 522 | 523 | returns EOF when no character can be read. 524 | 525 | ++++++++++++++++++++++++++++++++++++++*/ 526 | int SK_getc(int sockfd) { 527 | char ch; 528 | 529 | if( read(sockfd, &ch, 1) <= 0 ) { 530 | return EOF; 531 | } 532 | else { 533 | return ch; 534 | } 535 | }/* SK_getc() */ 536 | 537 | /* SK_getpeername() */ 538 | /*++++++++++++++++++++++++++++++++++++++ 539 | 540 | This function will tell you who is at the other end of a connected stream socket. 541 | 542 | char *SK_getpeername Returns allocated string with the IP in it, 543 | or "--" if the descriptor is not a socket, 544 | or NULL on error. 545 | 546 | int sockfd The socket or file descriptor. 547 | 548 | +html+ <PRE> 549 | Authors: 550 | ottrey, 551 | marek (modified error handling, made MT-Safe). 552 | +html+ </PRE> 553 | 554 | ++++++++++++++++++++++++++++++++++++++*/ 555 | char *SK_getpeername(int sockfd) 556 | { 557 | char *hostaddress=NULL; 558 | struct sockaddr_in addr_in; 559 | int namelen=sizeof(addr_in); 560 | 561 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) { 562 | 563 | dieif( wr_malloc((void **)&hostaddress, INET_ADDRSTRLEN) != UT_OK); 564 | inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN); 565 | } 566 | else { 567 | int er = errno; 568 | 569 | if( er == ENOTSOCK ) { 570 | hostaddress = wr_string("--"); 571 | } 572 | else { 573 | return NULL; 574 | } 575 | } 576 | 577 | return hostaddress; 578 | 579 | } /* SK_getpeername() */ 580 | 581 | 582 | /* SK_getpeerip */ 583 | /*++++++++++++++++++++++++++++++++++++++ 584 | 585 | This function will check the ip of the connected peer and store it in the 586 | ip_addr_t structure defined in the IP module. 587 | 588 | int SK_getpeerip returns 0 on success, -1 on failure. 589 | 590 | int sockfd The socket descriptor (file will result in -1) 591 | 592 | ip_addr_t *ip Pointer to where the address should be stored. 593 | 594 | +html+ <PRE> 595 | Author: 596 | marek 597 | +html+ </PRE> 598 | ++++++++++++++++++++++++++++++++++++++*/ 599 | 600 | int SK_getpeerip(int sockfd, ip_addr_t *ip) { 601 | struct sockaddr_in addr_in; 602 | int namelen=sizeof(addr_in); 603 | int ret=-1; 604 | 605 | memset(& addr_in, 0, sizeof(struct sockaddr_in)); 606 | 607 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) { 608 | ret=0; 609 | IP_addr_s2b(ip, &addr_in, namelen); 610 | } 611 | 612 | return ret; 613 | } 614 |