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