## modules/sk/socket.c

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

## FUNCTIONS

This source file includes following functions.

1. SK_atoport
2. func_atexit
3. func_sighup
4. func_sigint
5. SK_close
6. SK_getsock
7. SK_accept_connection
8. SK_read
9. SK_write
10. SK_gets
11. SK_puts
12. SK_putc
13. SK_getc
14. SK_getpeername
15. SK_getpeerip
16. SK_cd_puts
17. SK_cd_gets
18. SK_cd_close
19. SK_cd_printf

       1 /***************************************
       2   $Revision: 1.16 $
       3
       4   Example code: A socket module.
       5
       6   Status: NOT REVUED, NOT TESTED
       7
       8   +html+ <DL COMPACT>
       9   +html+ <DT>Online References:
      10   +html+ <DD><UL>
      11   +html+   <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>.
      12   +html+ </UL>
      13   +html+ </DL>
      14   +html+ <PRE>
      15   +html+ </PRE>
      16
      17   ******************/ /******************
      18   Modification History:
      19         ottrey (08/03/1999) Created from sockhelp.c.
      20         ottrey (08/03/1998) Heavily butchered.
      21         joao   (22/06/1999) Modified socket creation and accepts.
      22   ******************/ /******************
      23  REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE
      24   ***************************************/
      25 #include <arpa/inet.h>
      26 #include "socket.h"
      27 #include "constants.h"
      28 #include "stubs.h"
      29
      30 #include "iproutines.h"
      31 #include "memwrap.h"
      32
      33 extern int h_errno;
      34
      35
      36 /*+ String sizes +*/
      37 #define STR_S   63
      38 #define STR_M   255
      39 #define STR_L   1023
      40 #define STR_XL  4095
      41 #define STR_XXL 16383
      42
      43 /* SK_atoport() */
      44 /*++++++++++++++++++++++++++++++++++++++
      45    Take a service name, and a service type, and return a port number.  If the
      46    service name is not found, it tries it as a decimal number.  The number
      47    returned is byte ordered for the network.
      48
      49   char *service   Service name (or port number).
      50
      51   char *proto     Protocol (eg "tcp").
      52
      53   More:
      54   +html+ <PRE>
      55   Authors:
      56         ottrey
      57
      58   +html+ </PRE><DL COMPACT>
      59   +html+ <DT>Online References:
      60   +html+ <DD><UL>
      61   +html+ </UL></DL>
      62
      63   ++++++++++++++++++++++++++++++++++++++*/
      64 int SK_atoport(const char *service, const char *proto) {
         /* [<][>][^][v][top][bottom][index][help] */
      65   int port;
      66   long int lport;
      67   struct servent *serv;
      68   char *errpos;
      69   struct servent result;
      70   char buffer[STR_XXL];
      71
      72   /* First try to read it from /etc/services */
      73
      74   /*  serv = getservbyname(service, proto); */
      75   serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
      76   if (serv != NULL)
      77     port = serv->s_port;
      78   else { /* Not in services, maybe a number? */
      79     lport = strtol(service,&errpos,0);
      80     if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
      81       return -1; /* Invalid port address */
      82     port = htons(lport);
      83   }
      84   return port;
      85 } /* SK_atoport() */
      86
      87
      88 /* SK_close_listening_socket() */
      89 /*++++++++++++++++++++++++++++++++++++++
      90   XXX Note: Not sure how long this function will last.  Shouldn't _really_ need it.
      91
      92   More:
      93   +html+ <PRE>
      94   Authors:
      95         ottrey
      96
      97   +html+ </PRE><DL COMPACT>
      98   +html+ <DT>Online References:
      99   +html+ <DD><UL>
     100   +html+ </UL></DL>
     101
     102   ++++++++++++++++++++++++++++++++++++++*/
     103 /*void SK_close_listening_socket() {
     104   close(listening_socket);
     105 } */ /* SK_close_listening_socket */
     106
     107 static void func_atexit(void) {
         /* [<][>][^][v][top][bottom][index][help] */
     108   ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_atexit() called");
     109 }
     110
     111 static void func_sighup(int n) {
         /* [<][>][^][v][top][bottom][index][help] */
     112   ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sighup(%d) called", n);
     113 }
     114
     115 static void func_sigint(int n) {
         /* [<][>][^][v][top][bottom][index][help] */
     116   ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigint(%d) called", n);
     117 }
     118
     119
     120 void SK_close(int socket) {
         /* [<][>][^][v][top][bottom][index][help] */
     121   ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
     122
     123   close(socket);
     124 }
     125
     126 /* SK_getsock() */
     127 /*++++++++++++++++++++++++++++++++++++++
     128
     129    This function creates a socket and binds to it
     130
     131    int      SK_getsock       The new socket
     132
     133    int      socket_type      SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
     134
     135    u_short  port             The port to listen on.  Remember that ports < 1024 are
     136                              reserved for the root user.  Must be passed in network byte
     137                              order (see "man htons").
     138
     139    uint32_t bind_address     Address to bind to, in network order.
     140   More:
     141   +html+ <PRE>
     142   Authors:
     143         ottrey
     144         joao
     145
     146   +html+ </PRE><DL COMPACT>
     147   +html+ <DT>Online References:
     148   +html+ <DD><UL>
     149   +html+ </UL></DL>
     150
     151   ++++++++++++++++++++++++++++++++++++++*/
     152 int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
         /* [<][>][^][v][top][bottom][index][help] */
     153   struct sockaddr_in address;
     154   int listening_socket;
     155   int reuse_addr = 1;
     156
     157   /* Setup internet address information.
     158      This is used with the bind() call */
     159   memset((char *) &address, 0, sizeof(address));
     160   address.sin_family = AF_INET;
     161   address.sin_port = port;
     162   address.sin_addr.s_addr = bind_address;
     163
     164   /* Map all of the signals and exit routine */
     165   atexit(func_atexit);
     166   /* signal.h has a full list of signal names */
     167
     168   listening_socket = socket(AF_INET, socket_type, 0);
     169   if (listening_socket < 0) {
     170     perror("socket");
     171     exit(EXIT_FAILURE);
     172   }
     173
     174   setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
     175
     176   if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
     177     perror("bind");
     178     close(listening_socket);
     179     exit(EXIT_FAILURE);
     180   }
     181
     182
     183   if (socket_type == SOCK_STREAM) {
     184     listen(listening_socket, 5); /* Queue up to five connections before
     185                                   having them automatically rejected. */
     186   }
     187
     188   return listening_socket;
     189 } /* SK_getsock() */
     190
     191 /*++++++++++++++++++++++++++++++++++++++
     192
     193    Wait for an incoming connection on the specified socket
     194
     195    int  SK_accept_connection The socket for communicating to the client
     196
     197    int  listening_socket     The socket that the server is bound to
     198
     199   More:
     200   +html+ <PRE>
     201   Authors:
     202         joao
     203   +html+ </PRE>
     204   ++++++++++++++++++++++++++++++++++++++*/
     205 int SK_accept_connection(int listening_socket) {
         /* [<][>][^][v][top][bottom][index][help] */
     206   int connected_socket = -1;
     207
     208   while(connected_socket < 0) {
     209
     210     ER_dbg_va(FAC_SK, ASP_SK_GEN,
     211               "Going to accept connections on socket : %d",listening_socket);
     212
     213 /* XXX joao - ? - why is this here?
     214 fflush(NULL);
     215 */
     216
     217     connected_socket = accept(listening_socket, NULL, NULL);
     218     if (connected_socket < 0) {
     219       /* Either a real error occured, or blocking was interrupted for
     220          some reason.  Only abort execution if a real error occured. */
     221       if (errno != EINTR) {
     222         perror("accept");
     223         close(listening_socket);
     224         return(-1);
     225      /* no exit, just return with error */
     226       } else {
     227         continue;    /* don't return - do the accept again */
     228       }
     229     }
     230   }
     231
     232   ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
     233             connected_socket
     234             );
     235
     236   return connected_socket;
     237 }
     238
     239 /* SK_read() */
     240 /*++++++++++++++++++++++++++++++++++++++
     241
     242    This is just like the read() system call, except that it will make
     243    sure that all your data goes through the socket.
     244
     245    int    SK_read  The number of bytes read.
     246
     247    int    sockfd    The socket file descriptor.
     248
     249    char   *buf      The buffer to be read from the socket.
     250
     251    size_t count     The number of bytes in the buffer.
     252
     253   More:
     254   +html+ <PRE>
     255   Authors:
     256         ottrey
     257   +html+ </PRE>
     258   ++++++++++++++++++++++++++++++++++++++*/
     259 int SK_read(int sockfd, char *buf, size_t count) {
         /* [<][>][^][v][top][bottom][index][help] */
     260   size_t bytes_read = 0;
     261   int this_read;
     262
     263   while (bytes_read < count) {
     264     do
     265       this_read = read(sockfd, buf, count - bytes_read);
     266     while ( (this_read < 0) && (errno == EINTR) );
     267     if (this_read < 0)
     268       return this_read;
     269     else if (this_read == 0)
     270       return bytes_read;
     271     bytes_read += this_read;
     272     buf += this_read;
     273   }
     274
     275   return count;
     276
     277 } /* SK_read() */
     278
     279
     280 /* SK_write() */
     281 /*++++++++++++++++++++++++++++++++++++++
     282
     283    This is just like the write() system call, accept that it will
     284    make sure that all data is transmitted.
     285
     286    int    sockfd  The socket file descriptor.
     287
     288    char   *buf    The buffer to be written to the socket.
     289
     290    size_t count   The number of bytes in the buffer.
     291
     292   More:
     293   +html+ <PRE>
     294   Authors:
     295         ottrey
     296
     297   +html+ </PRE><DL COMPACT>
     298   +html+ <DT>Online References:
     299   +html+ <DD><UL>
     300   +html+ </UL></DL>
     301
     302   ++++++++++++++++++++++++++++++++++++++*/
     303 int SK_write(int sockfd, const char *buf, size_t count) {
         /* [<][>][^][v][top][bottom][index][help] */
     304   size_t  bytes_sent = 0;
     305   int     this_write;
     306
     307
     308   ER_dbg_va(FAC_SK, ASP_SK_WRIT,
     309             "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
     310             sockfd, buf, count);
     311
     312   while (bytes_sent < count) {
     313     do
     314       this_write = write(sockfd, buf, count - bytes_sent);
     315     while ( (this_write < 0) && (errno == EINTR) );
     316     if (this_write <= 0)
     317       return this_write;
     318     bytes_sent += this_write;
     319     buf += this_write;
     320   }
     321   return count;
     322 } /* SK_write() */
     323
     324
     325 /* SK_gets() */
     326 /*++++++++++++++++++++++++++++++++++++++
     327
     328    This function reads from a socket, until it recieves a linefeed
     329    character.  It fills the buffer "str" up to the maximum size "count".
     330
     331    int SK_gets  The total_count of bytes read.
     332
     333    int    sockfd    The socket file descriptor.
     334
     335    char   *str      The buffer to be written from the socket.
     336
     337    size_t count     The number of bytes in the buffer.
     338
     339   More:
     340   +html+ <PRE>
     341   Authors:
     342         ottrey
     343
     344   Side Effects:
     345         This function will return -1 if the socket is closed during the read operation.
     346
     347         Note that if a single line exceeds the length of count, the extra data
     348         will be read and discarded!  You have been warned.
     349
     350   To Do:
     351         Capture the control-c properly!
     352
     353   +html+ </PRE>
     354
     355   ++++++++++++++++++++++++++++++++++++++*/
     356 int SK_gets(int sockfd, char *str, size_t count) {
         /* [<][>][^][v][top][bottom][index][help] */
     357   int bytes_read;
     358   int total_count = 0;
     359   char *current_position;
     360   char last_read = 0;
     361
     362   int control_c = 0;
     363
     364   current_position = str;
     365   while (last_read != 10) {
     366     bytes_read = read(sockfd, &last_read, 1);
     367     if (bytes_read <= 0) {
     368       /* The other side may have closed unexpectedly */
     369       return SK_DISCONNECT;
     370       /* Is this effective on other platforms than linux? */
     371     }
     372     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
     373       *current_position = last_read;
     374       current_position++;
     375       total_count++;
     376     }
     377
     378     if (last_read == -1) {
     379       bytes_read = read(sockfd, &last_read, 1);
     380       if (last_read == -12) {
     381         ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
     382         control_c = 1;
     383         ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
     384         return SK_INTERRUPT;
     385       }
     386     }
     387   }
     388   if (count > 0) {
     389     *current_position = 0;
     390   }
     391
     392   return total_count;
     393
     394 } /* SK_gets() */
     395
     396
     397 /* SK_puts() */
     398 /*++++++++++++++++++++++++++++++++++++++
     399
     400    This function writes a character string out to a socket.
     401
     402    int SK_puts  The total_count of bytes written,
     403                 or errors (represented as negative numbers)
     404
     405    int    sockfd    The socket file descriptor.
     406
     407    char   *str      The buffer to be written from the socket.
     408
     409   More:
     410   +html+ <PRE>
     411   Authors:
     412         ottrey
     413
     414   Side Effects:
     415         This function will return -1 if the socket is closed during the write operation.
     416
     417         Note that if a single line exceeds the length of count, the extra data
     418         will be read and discarded!  You have been warned.
     419
     420   +html+ </PRE>
     421
     422   ++++++++++++++++++++++++++++++++++++++*/
     423 int SK_puts(int sockfd, const char *str) {
         /* [<][>][^][v][top][bottom][index][help] */
     424
     425   return SK_write(sockfd, str, strlen(str));
     426
     427 } /* SK_puts() */
     428
     429 /* SK_putc() */
     430 /*++++++++++++++++++++++++++++++++++++++
     431
     432    int SK_putc This function writes a single character out to a socket.
     433
     434    int sockfd        socket
     435    char ch           character
     436
     437    return number of chars written
     438
     439   ++++++++++++++++++++++++++++++++++++++*/
     440 int SK_putc(int sockfd, char ch) {
         /* [<][>][^][v][top][bottom][index][help] */
     441   return SK_write(sockfd, &ch, 1);
     442 }/* SK_putc() */
     443
     444 /*++++++++++++++++++++++++++++++++++++++
     445
     446    This function reads a single character from a socket.
     447
     448    returns EOF when no character can be read.
     449
     450   ++++++++++++++++++++++++++++++++++++++*/
     451 int SK_getc(int sockfd) {
         /* [<][>][^][v][top][bottom][index][help] */
     452   char ch;
     453
     454   if( read(sockfd, &ch, 1) <= 0 ) {
     455     return EOF;
     456   }
     457   else {
     458     return ch;
     459   }
     460 }/* SK_getc() */
     461
     462 /* SK_getpeername() */
     463 /*++++++++++++++++++++++++++++++++++++++
     464
     465    This function will tell you who is at the other end of a connected stream socket.
     466    XXX It's not working.
     467    XXX ? MB it is...
     468
     469    int    sockfd    The socket file descriptor.
     470
     471   More:
     472   +html+ <PRE>
     473   Authors:
     474         ottrey
     475   +html+ </PRE>
     476
     477   ++++++++++++++++++++++++++++++++++++++*/
     478 char *SK_getpeername(int sockfd)
         /* [<][>][^][v][top][bottom][index][help] */
     479 {
     480   char *hostaddress=NULL;
     481   struct sockaddr_in addr_in;
     482   int namelen=sizeof(addr_in);
     483
     484   if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) {
     485
     486     dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK);
     487
     488     strcpy(hostaddress, inet_ntoa(addr_in.sin_addr));  /* XXX MT-UNSAFE */
     489   }
     490
     491   return hostaddress;
     492
     493 } /* SK_getpeername() */
     494
     495 /* SK_getpeerip */
     496 int SK_getpeerip(int sockfd, ip_addr_t *ip) {
         /* [<][>][^][v][top][bottom][index][help] */
     497   struct sockaddr_in addr_in;
     498   int namelen=sizeof(addr_in);
     499   int ret=-1;
     500
     501   memset(& addr_in, 0, sizeof(struct sockaddr_in));
     502
     503   if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
     504     ret=0;
     505     IP_addr_s2b(ip, &addr_in, namelen);
     506   }
     507
     508   return ret;
     509 }
     510
     511 /*-------------------------------------------------------------------
     512  *   CD varieties of the functions: broken connections get registered
     513  *   in the connection structure within the query environment
     514  *   as side effects.
     515  * -----------------------------------------------------------------*/
     516
     517 /* SK_cd_puts() */
     518 /*++++++++++++++++++++++++++++++++++++++
     519
     520    This function writes a character string out to a socket.
     521
     522    int SK_qe_puts  The total_count of bytes written,
     523                 or errors (represented as negative numbers)
     524
     525    sk_conn_st *condat connection data
     526
     527    char   *str       The buffer to be written from the socket.
     528
     529   More:
     530        if the connection structure has bad status for this connection
     531        from previous calls, no write will be attempted.
     532
     533   +html+ <PRE>
     534   Authors:
     535         marek
     536
     537   Side Effects:
     538        broken connections get registered
     539        in the connection structure within the query environment
     540
     541   +html+ </PRE>
     542
     543   ++++++++++++++++++++++++++++++++++++++*/
     544 int SK_cd_puts(sk_conn_st *condat, const char *str) {
         /* [<][>][^][v][top][bottom][index][help] */
     545   int res=SK_puts(condat->sock, str);
     546
     547   if( res < 0 ){
     548     switch( - res ) {
     549       /* dont know what to do and how to log */
     550     case SK_DISCONNECT:
     551     case SK_INTERRUPT:
     552       /*("Thread received a control-c\n");*/
     553     case SK_TIMEOUT:
     554       /*("Reading timed out\n");*/
     555       break;
     556     default:
     557       /* unexpected error code. bail out */
     558       die;
     559     }
     560   }
     561 } /* SK_cd_puts() */
     562
     563 /* SK_cd_gets() */
     564 /*++++++++++++++++++++++++++++++++++++++
     565
     566    Wrapper around SK_gets.
     567
     568    int SK_cd_gets  The total_count of bytes read,
     569                    or errors (represented as negative numbers)
     570
     571    sk_conn_st *condat connection data
     572
     573    char   *str       The buffer to be written from the socket.
     574
     575   More:
     576        if the connection structure has bad status for this connection
     577        from previous calls, no write will be attempted.
     578
     579   +html+ <PRE>
     580   Authors:
     581         marek
     582
     583   Side Effects:
     584        broken connections get registered
     585        in the connection structure within the query environment
     586
     587   +html+ </PRE>
     588
     589   ++++++++++++++++++++++++++++++++++++++*/
     590 int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) {
         /* [<][>][^][v][top][bottom][index][help] */
     591   int res=SK_gets(condat->sock, str, count);
     592
     593   if( res < 0 ){
     594     switch( - res ) {
     595       /* dont know what to do and how to log */
     596     case SK_DISCONNECT:
     597     case SK_INTERRUPT:
     598       /*("Thread received a control-c\n");*/
     599     case SK_TIMEOUT:
     600       /*("Reading timed out\n");*/
     601       break;
     602     default:
     603       /* unexpected error code. bail out */
     604       die;
     605     }
     606   }
     607 } /* SK_cd_gets() */
     608
     609
     610 int SK_cd_close(sk_conn_st *condat) {
         /* [<][>][^][v][top][bottom][index][help] */
     611   SK_close(condat->sock);
     612 } /* SK_cd_close() */
     613
     614
     615 int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
         /* [<][>][^][v][top][bottom][index][help] */
     616 {
     617 #define SKBUFLEN 2047
     618   va_list   ap;
     619   char      buffer[SKBUFLEN+1];
     620   int       len;
     621   char      *newbuf = NULL;
     622   char      *finalbuf = buffer; /* points to where the text REALLY is */
     623
     624   /* vsnprintf returns the number of character it WOULD write if it could.
     625      So we assume the buffer to be of adequate size for most cases,
     626      and if it isn't, then we allocate to newbuf and call v*printf again
     627   */
     628   va_start(ap, txt);
     629   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
     630   va_end(ap);
     631
     632   if( len > SKBUFLEN ) {
     633     dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1)));
     634
     635     va_start(ap, txt);
     636     vsnprintf(newbuf, len, txt, ap);
     637     va_end(ap);
     638
     639     finalbuf = newbuf;
     640   }
     641   /* terminate */
     642   finalbuf[len] = 0;
     643
     644   /* reuse len */
     645   len = SK_cd_puts(condat, finalbuf);
     646
     647   if(newbuf != NULL) {
     648     wr_free(newbuf);
     649   }
     650
     651   return len;
     652 }

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