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

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