1 | /*************************************** 2 | $Revision: 1.14 $ 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 | while(connected_socket < 0) { 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 | die; 214 | } 215 | } 216 | } 217 | } 218 | else { /* success */ 219 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d", 220 | connected_socket 221 | ); 222 | 223 | return connected_socket; 224 | } 225 | } /* while */ 226 | } 227 | 228 | 229 | /*++++++++++++++++++++++++++++++++++++++ 230 | 231 | er_ret_t SK_connect wrapper around connect(), doing non-blocking 232 | connection with timeout 233 | 234 | int *sock pointer to the storage for socket descriptor 235 | 236 | char *hostname host to connect to 237 | 238 | int port port to connect to 239 | 240 | int timeout in seconds 241 | 242 | Author: marek 243 | 244 | ++++++++++++++++++++++++++++++++++++++*/ 245 | er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout) 246 | { 247 | struct sockaddr_in sin; 248 | struct hostent *hp; 249 | int s; 250 | int flags; 251 | struct timeval ptm; 252 | fd_set rset, wset; 253 | int gs, sel, er, erlen=sizeof(er); 254 | int error; 255 | struct hostent result; 256 | char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */ 257 | 258 | /* look up the host name */ 259 | #ifdef __linux__ 260 | er = (gethostbyname_r(hostname, &result, aliasbuf, 261 | sizeof(aliasbuf), &hp, &error) < 0 ); 262 | #else /* default is Solaris implementation */ 263 | hp = gethostbyname_r(hostname, &result, aliasbuf, 264 | sizeof(aliasbuf), &error); 265 | er = ( hp == NULL ); 266 | #endif 267 | 268 | if( er ) { 269 | return SK_BADHOST; 270 | } 271 | 272 | /* create a socket */ 273 | s = socket(AF_INET, SOCK_STREAM, 0); 274 | if (s < 0) { 275 | return SK_SOCKET; 276 | } 277 | 278 | /* bind to it */ 279 | bzero((caddr_t)&sin, sizeof (sin)); 280 | sin.sin_family = hp->h_addrtype; 281 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 282 | close(s); 283 | return SK_BIND; 284 | } 285 | bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 286 | sin.sin_port=htons(port); 287 | 288 | /* connect in non-blocking mode */ 289 | flags = fcntl(s, F_GETFL, 0); 290 | fcntl(s, F_SETFL, flags | O_NONBLOCK ); 291 | 292 | if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0 293 | && errno != EINPROGRESS ) { 294 | close(s); 295 | return SK_CONNECT; 296 | } 297 | 298 | /* now wait for success */ 299 | FD_ZERO( &rset ); 300 | FD_SET( s, &rset ); 301 | wset = rset; 302 | ptm.tv_usec = 0; 303 | ptm.tv_sec = timeout; 304 | 305 | if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) { 306 | /* timeout */ 307 | close(s); 308 | return SK_TIMEOUT; 309 | } 310 | dieif( sel < 0 ); /* we don't expect problems with select */ 311 | 312 | gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen); 313 | 314 | if( gs < 0 || er ) { /* Stevens code, p.411 is exceptionally crappy */ 315 | close(s); 316 | return SK_CONNECT; 317 | } /* if error */ 318 | 319 | fcntl(s, F_SETFL, flags); 320 | *sock = s; 321 | 322 | return SK_OK; 323 | } 324 | 325 | 326 | /* SK_read() */ 327 | /*++++++++++++++++++++++++++++++++++++++ 328 | 329 | This is just like the read() system call, except that it will make 330 | sure that all your data goes through the socket. 331 | 332 | int SK_read Returns the number of bytes read. 333 | 334 | int sockfd The socket file descriptor. 335 | 336 | char *buf The buffer to be read from the socket. 337 | 338 | size_t count The number of bytes in the buffer. 339 | 340 | Author: 341 | ottrey 342 | 343 | ++++++++++++++++++++++++++++++++++++++*/ 344 | int SK_read(int sockfd, char *buf, size_t count) { 345 | size_t bytes_read = 0; 346 | int this_read; 347 | 348 | while (bytes_read < count) { 349 | do 350 | this_read = read(sockfd, buf, count - bytes_read); 351 | while ( (this_read < 0) && (errno == EINTR) ); 352 | if (this_read < 0) 353 | return this_read; 354 | else if (this_read == 0) 355 | return bytes_read; 356 | bytes_read += this_read; 357 | buf += this_read; 358 | } 359 | 360 | return count; 361 | 362 | } /* SK_read() */ 363 | 364 | 365 | /* SK_write() */ 366 | /*++++++++++++++++++++++++++++++++++++++ 367 | 368 | This is just like the write() system call, except that it will 369 | make sure that all data is transmitted. 370 | 371 | int SK_write Returns the number of bytes written. 372 | 373 | int sockfd The socket file descriptor. 374 | 375 | char *buf The buffer to be written to the socket. 376 | 377 | size_t count The number of bytes in the buffer. 378 | 379 | Author: 380 | ottrey 381 | 382 | ++++++++++++++++++++++++++++++++++++++*/ 383 | int SK_write(int sockfd, const char *buf, size_t count) { 384 | size_t bytes_sent = 0; 385 | int this_write; 386 | 387 | 388 | ER_dbg_va(FAC_SK, ASP_SK_WRIT, 389 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]", 390 | sockfd, buf, count); 391 | 392 | while (bytes_sent < count) { 393 | do 394 | this_write = write(sockfd, buf, count - bytes_sent); 395 | while ( (this_write < 0) && (errno == EINTR) ); 396 | if (this_write <= 0) 397 | return this_write; 398 | bytes_sent += this_write; 399 | buf += this_write; 400 | } 401 | return count; 402 | } /* SK_write() */ 403 | 404 | 405 | /* SK_gets() */ 406 | /*++++++++++++++++++++++++++++++++++++++ 407 | 408 | This function reads from a socket, until it recieves a linefeed 409 | character. It fills the buffer "str" up to the maximum size "count". 410 | 411 | int SK_gets Returns the total_count of bytes read. 412 | 413 | int sockfd The socket file descriptor. 414 | 415 | char *str The buffer to be written from the socket. 416 | 417 | size_t count The number of bytes in the buffer. 418 | 419 | 420 | Authors: 421 | ottrey, 422 | marek (modified for meaningful error codes). 423 | 424 | Side Effects: 425 | This function will return -1 if the socket is closed during the read operation. 426 | 427 | Note that if a single line exceeds the length of count, the extra data 428 | will be read and discarded! You have been warned. 429 | 430 | ++++++++++++++++++++++++++++++++++++++*/ 431 | int SK_gets(int sockfd, char *str, size_t count) { 432 | int bytes_read; 433 | int total_count = 0; 434 | char *current_position; 435 | char last_read = 0; 436 | 437 | int control_c = 0; 438 | 439 | current_position = str; 440 | while (last_read != 10) { 441 | 442 | bytes_read = read(sockfd, &last_read, 1); 443 | if (bytes_read <= 0) { 444 | /* The other side may have closed unexpectedly */ 445 | return SK_DISCONNECT; 446 | /* Is this effective on other platforms than linux? */ 447 | } 448 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) { 449 | *current_position = last_read; 450 | current_position++; 451 | total_count++; 452 | } 453 | 454 | if (last_read == -1) { 455 | bytes_read = read(sockfd, &last_read, 1); 456 | if (last_read == -12) { 457 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c"); 458 | control_c = 1; 459 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT"); 460 | return SK_INTERRUPT; 461 | } 462 | } 463 | } 464 | if (count > 0) { 465 | *current_position = 0; 466 | } 467 | 468 | return total_count; 469 | 470 | } /* SK_gets() */ 471 | 472 | 473 | /* SK_puts() */ 474 | /*++++++++++++++++++++++++++++++++++++++ 475 | 476 | This function writes a character string out to a socket. 477 | 478 | int SK_puts The total_count of bytes written, 479 | or errors (represented as negative numbers) 480 | 481 | int sockfd The socket file descriptor. 482 | 483 | char *str The buffer to be written from the socket. 484 | 485 | More: 486 | +html+ <PRE> 487 | Authors: 488 | ottrey 489 | 490 | Side Effects: 491 | This function will return -1 if the socket is closed during the write operation. 492 | +html+ </PRE> 493 | 494 | ++++++++++++++++++++++++++++++++++++++*/ 495 | int SK_puts(int sockfd, const char *str) { 496 | 497 | return SK_write(sockfd, str, strlen(str)); 498 | 499 | } /* SK_puts() */ 500 | 501 | /* SK_putc() */ 502 | /*++++++++++++++++++++++++++++++++++++++ 503 | 504 | This function writes a single character out to a socket. 505 | 506 | int SK_putc Returns the number of characters written. 507 | 508 | int sockfd socket 509 | 510 | char ch character 511 | 512 | ++++++++++++++++++++++++++++++++++++++*/ 513 | int SK_putc(int sockfd, char ch) { 514 | return SK_write(sockfd, &ch, 1); 515 | }/* SK_putc() */ 516 | 517 | /*++++++++++++++++++++++++++++++++++++++ 518 | 519 | This function reads a single character from a socket. 520 | 521 | returns EOF when no character can be read. 522 | 523 | ++++++++++++++++++++++++++++++++++++++*/ 524 | int SK_getc(int sockfd) { 525 | char ch; 526 | 527 | if( read(sockfd, &ch, 1) <= 0 ) { 528 | return EOF; 529 | } 530 | else { 531 | return ch; 532 | } 533 | }/* SK_getc() */ 534 | 535 | /* SK_getpeername() */ 536 | /*++++++++++++++++++++++++++++++++++++++ 537 | 538 | This function will tell you who is at the other end of a connected stream socket. 539 | 540 | char *SK_getpeername Returns allocated string with the IP in it, 541 | or "--" if the descriptor is not a socket, 542 | or NULL on error. 543 | 544 | int sockfd The socket or file descriptor. 545 | 546 | +html+ <PRE> 547 | Authors: 548 | ottrey, 549 | marek (modified error handling, made MT-Safe). 550 | +html+ </PRE> 551 | 552 | ++++++++++++++++++++++++++++++++++++++*/ 553 | char *SK_getpeername(int sockfd) 554 | { 555 | char *hostaddress=NULL; 556 | struct sockaddr_in addr_in; 557 | int namelen=sizeof(addr_in); 558 | 559 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) { 560 | 561 | dieif( wr_malloc((void **)&hostaddress, INET_ADDRSTRLEN) != UT_OK); 562 | inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN); 563 | } 564 | else { 565 | int er = errno; 566 | 567 | if( er == ENOTSOCK ) { 568 | hostaddress = wr_string("--"); 569 | } 570 | else { 571 | return NULL; 572 | } 573 | } 574 | 575 | return hostaddress; 576 | 577 | } /* SK_getpeername() */ 578 | 579 | 580 | /* SK_getpeerip */ 581 | /*++++++++++++++++++++++++++++++++++++++ 582 | 583 | This function will check the ip of the connected peer and store it in the 584 | ip_addr_t structure defined in the IP module. 585 | 586 | int SK_getpeerip returns 0 on success, -1 on failure. 587 | 588 | int sockfd The socket descriptor (file will result in -1) 589 | 590 | ip_addr_t *ip Pointer to where the address should be stored. 591 | 592 | +html+ <PRE> 593 | Author: 594 | marek 595 | +html+ </PRE> 596 | ++++++++++++++++++++++++++++++++++++++*/ 597 | 598 | int SK_getpeerip(int sockfd, ip_addr_t *ip) { 599 | struct sockaddr_in addr_in; 600 | int namelen=sizeof(addr_in); 601 | int ret=-1; 602 | 603 | memset(& addr_in, 0, sizeof(struct sockaddr_in)); 604 | 605 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) { 606 | ret=0; 607 | IP_addr_s2b(ip, &addr_in, namelen); 608 | } 609 | 610 | return ret; 611 | } 612 |