## 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] */