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