modules/sk/sk_socket.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. SK_atoport
  2. SK_close
  3. SK_getsock
  4. SK_accept_connection
  5. SK_connect
  6. SK_read
  7. SK_write
  8. SK_gets
  9. SK_puts
  10. SK_putc
  11. SK_getc
  12. SK_getpeername
  13. SK_getpeerip

   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) {
     /* [<][>][^][v][top][bottom][index][help] */
  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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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 

/* [<][>][^][v][top][bottom][index][help] */