modules/sk/cd_socket.c

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

DEFINITIONS

This source file includes following functions.
  1. SK_cd_make
  2. SK_cd_free
  3. SK_cd_puts
  4. sk_fill_rd_buf
  5. main
  6. SK_cd_gets
  7. SK_cd_close
  8. SK_cd_printf

   1 /***************************************
   2   $Revision: 1.8 $
   3 
   4   Socket module - cd_socket.c - basic read/write socket routines defined
   5                                 in terms of connection data structures
   6                                 with timeouts and storing information about
   7                                 broken connections.
   8 
   9   Status: NOT REVUED, TESTED
  10 
  11   Design and implementation by Marek Bukowy.
  12 
  13   ******************/ /******************
  14   Copyright (c) 1999,2000,2001,2002                     RIPE NCC
  15  
  16   All Rights Reserved
  17   
  18   Permission to use, copy, modify, and distribute this software and its
  19   documentation for any purpose and without fee is hereby granted,
  20   provided that the above copyright notice appear in all copies and that
  21   both that copyright notice and this permission notice appear in
  22   supporting documentation, and that the name of the author not be
  23   used in advertising or publicity pertaining to distribution of the
  24   software without specific, written prior permission.
  25   
  26   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  27   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  28   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  29   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  30   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  31   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  32   ***************************************/
  33 
  34 #include "rip.h"
  35 
  36 /*+
  37  * -------------------------------------------------------------------
  38  * CD (connection data structure) varieties of the functions: 
  39  *   broken connections get registered in the connection structure
  40  *   as side effects.
  41  * by marek
  42  * -----------------------------------------------------------------
  43 +*/
  44 
  45 /* SK_cd_make */
  46 /*++++++++++++++++++++++++++++++++++++++
  47   
  48   Construct a connection data given the socket or file descriptor.
  49   Also performs the getpeername check and stores the IP in an allocated
  50   string.
  51 
  52   sk_conn_st *condat    pointer to where the data is to be stored.
  53 
  54   int  sock             The socket or file descriptor.
  55 
  56   unsigned timeout      Read timeout (used in SK_cd_gets) in seconds.
  57                         Value of 0 disables the timeout.
  58   ++++++++++++++++++++++++++++++++++++++*/
  59 void SK_cd_make(sk_conn_st *condat, int  sock, unsigned timeout)
     /* [<][>][^][v][top][bottom][index][help] */
  60 {
  61   memset(condat, 0, sizeof(sk_conn_st));
  62 
  63   condat->sock = sock;
  64 
  65   condat->ip = SK_getpeername(sock); 
  66   dieif(condat->ip == NULL);
  67 
  68   SK_getpeerip(sock, &(condat->rIP));
  69   condat->eIP =  condat->rIP;
  70 
  71   condat->rd_timeout.tv_sec = timeout;
  72 
  73   condat->rd_buf_len = 0;
  74 }
  75 
  76 
  77 /*++++++++++++++++++++++++++++++++++++++
  78   Destroys the data allocated and anchored by the connection data structure.
  79 
  80   sk_conn_st *condat   Pointer to the connection data structure.
  81 
  82   ++++++++++++++++++++++++++++++++++++++*/
  83 void SK_cd_free(sk_conn_st *condat)
     /* [<][>][^][v][top][bottom][index][help] */
  84 {
  85   UT_free(condat->ip);
  86 }
  87 
  88 /* SK_cd_puts() */
  89 /*++++++++++++++++++++++++++++++++++++++
  90 
  91    This function writes a character string out to a socket, unless 
  92    the connection is broken. 
  93 
  94    int SK_cd_puts         Returns the total_count of bytes written, 
  95                           or inverted error codes (negative numbers):
  96                           (- SK_DISCONNECT) on broken connection,
  97                           (- SK_INTERRUPT)  on control-c received,
  98                           (- SK_TIMEOUT)    on timeout.
  99 
 100    sk_conn_st *condat     Pointer to the connection data structure.
 101 
 102    char   *str            The buffer to be written to the socket.
 103 
 104   More:
 105        if the connection structure has bad status for this connection
 106        from previous calls, no write will be attempted.
 107 
 108   +html+ <PRE>
 109 
 110   Side Effects:
 111        broken connections get registered in the connection structure 
 112         
 113   +html+ </PRE>
 114 
 115   ++++++++++++++++++++++++++++++++++++++*/
 116 int SK_cd_puts(sk_conn_st *condat, const char *str) 
     /* [<][>][^][v][top][bottom][index][help] */
 117 {
 118   int res;
 119   struct timeval *ptm;
 120   
 121   /* if we're not connected, return our status */
 122   if (condat->rtc != 0)  {
 123     return (-condat->rtc);
 124   }
 125 
 126   /* bad design to use 0 to mean "infinity", but we'll keep it because
 127      that's the current implementation - shane */
 128   ptm = &condat->rd_timeout;
 129   if ((ptm->tv_sec == 0) && (ptm->tv_usec == 0)) { /* if timeout 0, 
 130                                                       do blocking I/O */
 131     ptm = NULL;
 132   }
 133 
 134   /* use SK_puts() to do the actual work */
 135   res = SK_puts(condat->sock, str, ptm);
 136 
 137   /* if timed out (or some other error), then set the rtc variable */
 138   if (res < 0) {
 139     condat->rtc |= SK_DISCONNECT;
 140     res = -SK_DISCONNECT;
 141   }
 142 
 143   /* return documented value */
 144   return res;
 145 } /* SK_cd_puts() */
 146 
 147 /* fill the input buffer as much as possible */
 148 static int
 149 sk_fill_rd_buf (sk_conn_st *condat)
     /* [<][>][^][v][top][bottom][index][help] */
 150 {
 151     fd_set rset;
 152     struct timeval *ptm;
 153     int select_ret;
 154     int rd_buf_free;
 155     int read_ret;
 156     
 157     ptm = &(condat->rd_timeout);
 158     /* if timeout is 0, do blocking I/O - bogus, but that's how it is */
 159     if ((ptm->tv_sec == 0) && (ptm->tv_usec == 0)) {
 160         ptm = NULL;
 161     }
 162     FD_ZERO(&rset);
 163     FD_SET(condat->sock, &rset);
 164 
 165     /* wait for input to become available */
 166     select_ret = select(condat->sock + 1, &rset, NULL, NULL, ptm);
 167     if (select_ret < 0) {
 168         /* unfortunate, but bad things happen to good sockets - SK */
 169         ER_perror(FAC_SK, SK_SELECT, "(%d) %s", errno, strerror(errno));
 170         return -1;
 171     }
 172     if (select_ret == 0) {      
 173         condat->rtc |= SK_TIMEOUT;
 174         return -1;
 175     }
 176 
 177     /* calculate maximum amount to read */
 178     rd_buf_free = sizeof(condat->rd_buf) - (condat->rd_buf_len);
 179 
 180     /* read up to that much, if available */
 181     read_ret = read(condat->sock, 
 182                     condat->rd_buf + condat->rd_buf_len, 
 183                     rd_buf_free);
 184     if (read_ret <= 0) {
 185         condat->rtc |= SK_DISCONNECT;
 186         return -1;
 187     }
 188     condat->rd_buf_len += read_ret;
 189 
 190     /* return the fact that we got data */
 191     return read_ret;
 192 }
 193 
 194 #undef TEST_SK_FILL_RD_BUF
 195 
 196 /* test sk_fill_rd_buf() function - full path coverage */
 197 #ifdef TEST_SK_FILL_RD_BUF
 198 #include <unistd.h>
 199 #include <stdio.h>
 200 #include <errno.h>
 201 #include <string.h>
 202 
 203 int 
 204 main ()
     /* [<][>][^][v][top][bottom][index][help] */
 205 {
 206     sk_conn_st conn;
 207     int pfd[2];
 208     int tmp_fd;
 209     int bogus_fd;
 210     int i;
 211     int buf[INPUT_BUF_LEN+INPUT_BUF_LEN+100];
 212     int fill_buf_ret;
 213 
 214     /* test with bogus file descriptor and 0 timeout value */
 215     tmp_fd = open("/dev/null", O_RDONLY);
 216     if (tmp_fd == -1) {
 217         fprintf(stderr, "Error %d creating bogus file descriptor; %s\n", 
 218                 errno, strerror(errno));
 219         exit(1);
 220     }
 221     bogus_fd = tmp_fd;
 222     close(tmp_fd);
 223     SK_cd_make(&conn, bogus_fd, 0);
 224     if (sk_fill_rd_buf(&conn) != -1) {
 225         fprintf(stderr, "Filling buffer with bogus file descriptor worked\n");
 226         exit(1);
 227     }
 228 
 229     /* create a pipe for further testing */
 230     if (pipe(pfd) != 0) {
 231         fprintf(stderr, "Error %d creating pipe; %s\n", errno, strerror(errno));
 232         exit(1);
 233     }
 234     /* real file descriptor and non-0 timeout value */
 235     SK_cd_make(&conn, pfd[0], 1);
 236 
 237     /* test timeout */
 238     if (sk_fill_rd_buf(&conn) != -1) {
 239         fprintf(stderr, "Buffer filling failed to timeout properly\n");
 240         exit(1);
 241     }
 242     if (conn.rtc != SK_TIMEOUT) {
 243         fprintf(stderr, "Timeout didn't set flag properly\n");
 244         exit(1);
 245     }
 246 
 247     /* test EOF input */
 248     close(pfd[1]);
 249     conn.rtc = 0;
 250     if (sk_fill_rd_buf(&conn) != -1) {
 251         fprintf(stderr, "Buffer filling failed to timeout properly\n");
 252         exit(1);
 253     }
 254     if (conn.rtc != SK_DISCONNECT) {
 255         fprintf(stderr, "Disconnect didn't set flag properly\n");
 256         exit(1);
 257     }
 258 
 259     /* test empty buffer reading various values */
 260     {
 261         int lengths[] = 
 262             { 1, 100, INPUT_BUF_LEN-1, INPUT_BUF_LEN, 
 263               INPUT_BUF_LEN+1, INPUT_BUF_LEN+100 };
 264         for (i=0; i<sizeof(lengths)/sizeof(lengths[0]); i++) {
 265             close(pfd[0]);
 266             close(pfd[1]);
 267             if (pipe(pfd) != 0) {
 268                 fprintf(stderr, "Error %d creating pipe; %s\n", 
 269                         errno, strerror(errno));
 270                 exit(1);
 271             }
 272             SK_cd_make(&conn, pfd[0], 0);
 273             memset(buf, i+1, lengths[i]);
 274             if (write(pfd[1], buf, lengths[i]) != lengths[i]) {
 275                 fprintf(stderr, "Error %d writing to pipe; %s\n",
 276                         errno, strerror(errno));
 277                 exit(1);
 278             }
 279             fill_buf_ret = sk_fill_rd_buf(&conn);
 280             if (fill_buf_ret == -1) {
 281                 fprintf(stderr, "Error filling buffer\n");
 282                 exit(1);
 283             }
 284             if (lengths[i] < INPUT_BUF_LEN) {
 285                 if (fill_buf_ret != lengths[i]) {
 286                     fprintf(stderr, "Error filling buffer\n");
 287                     exit(1);
 288                 }
 289                 if (memcmp(buf, conn.rd_buf, lengths[i]) != 0) {
 290                     fprintf(stderr, "Error with buffer contents\n");
 291                     exit(1);
 292                 }
 293             } else {
 294                 if (fill_buf_ret != INPUT_BUF_LEN) {
 295                     fprintf(stderr, "Error filling buffer\n");
 296                     exit(1);
 297                 }
 298                 if (memcmp(buf, conn.rd_buf, INPUT_BUF_LEN) != 0) {
 299                     fprintf(stderr, "Error with buffer contents\n");
 300                     exit(1);
 301                 }
 302             }
 303         }
 304     }
 305 
 306     return 0;
 307 }
 308 #endif 
 309 
 310 /* SK_cd_gets() */
 311 /*++++++++++++++++++++++++++++++++++++++
 312 
 313   Read from a socket, until a linefeed character is received or the buffer
 314   fills up to the maximum size "count". If the connection data has non-zero
 315   timeout value for reading, it is used here between calls to read 
 316   the next 1 character.
 317 
 318    int SK_cd_gets      Returns the total_count of bytes read, 
 319                        or inverted error codes (negative numbers):
 320                        (- SK_DISCONNECT) on broken connection,
 321                        (- SK_TIMEOUT)    on timeout.
 322 
 323    sk_conn_st *condat  connection data
 324 
 325    char   *str         The buffer to store the data received from
 326                        the socket.
 327 
 328    size_t count        size of the buffer.
 329 
 330   More:
 331        if the connection structure has bad status for this connection
 332        from previous calls, no read will be attempted.
 333 
 334   +html+ <PRE>
 335   Author:
 336         marek
 337         
 338   Side Effects:
 339        broken connections get registered in the connection structure.
 340        
 341   +html+ </PRE>
 342 
 343   ++++++++++++++++++++++++++++++++++++++*/
 344 int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) 
     /* [<][>][^][v][top][bottom][index][help] */
 345 {
 346     char *eol;
 347     int line_len;
 348     int amt_to_copy;
 349 
 350     /* leave space for terminating '\0' */
 351     count--;
 352 
 353     /* we must always return a NUL-terminated string */
 354     str[0] = '\0';
 355 
 356     /* track current line length */
 357     line_len = 0;
 358 
 359     /* get input if none available */
 360     if (condat->rd_buf_len <= 0) {
 361         if (sk_fill_rd_buf(condat) == -1) {
 362             return line_len;
 363         }
 364     }
 365 
 366     for (;;) {
 367         /* we should always have something in the buffer here */
 368         dieif(condat->rd_buf_len <= 0);
 369 
 370         /* check for end of line */
 371         eol = memchr(condat->rd_buf, '\n', condat->rd_buf_len);
 372 
 373         /* figure out how much of the buffer to copy */
 374         if (eol == NULL) {
 375             /* no newline -> copy all available, if room */
 376             amt_to_copy = (count - line_len);
 377             if (amt_to_copy > condat->rd_buf_len) {
 378                 amt_to_copy = condat->rd_buf_len;
 379             }
 380         } else {
 381             /* newline -> copy line if room */
 382             amt_to_copy = eol - condat->rd_buf + 1;
 383             if (amt_to_copy > (count - line_len)) {
 384                 amt_to_copy = count - line_len;
 385             }
 386         }
 387 
 388         /* copy data to string */
 389         memcpy(str + line_len, condat->rd_buf, amt_to_copy);
 390         line_len += amt_to_copy;
 391         str[line_len] = '\0';
 392 
 393         /* remove data from input buffer */
 394         memmove(condat->rd_buf, 
 395                 condat->rd_buf + amt_to_copy, 
 396                 condat->rd_buf_len - amt_to_copy);
 397         condat->rd_buf_len -= amt_to_copy;
 398 
 399         /* if we got a newline or our buffer is full, exit */
 400         if ((eol != NULL) || (line_len >= count)) {
 401             return line_len;
 402         }
 403 
 404         /* otherwise get more input */
 405         if (sk_fill_rd_buf(condat) == -1) {
 406             return line_len;
 407         }
 408     }
 409 
 410 } /* SK_cd_gets() */
 411 
 412 
 413 /*++++++++++++++++++++++++++++++++++++++
 414   Wrapper around the close(2) system call, 
 415 
 416   int SK_cd_close         returns the error codes of close(2).
 417 
 418   sk_conn_st *condat      Pointer to the connection data structure.
 419 
 420     +html+ <PRE>
 421   Author:
 422         marek
 423     +html+ </PRE>
 424   ++++++++++++++++++++++++++++++++++++++*/
 425 int SK_cd_close(sk_conn_st *condat) {
     /* [<][>][^][v][top][bottom][index][help] */
 426   return SK_close(condat->sock);
 427 } /* SK_cd_close() */
 428 
 429 
 430 /* SK_cd_printf() */
 431 /*++++++++++++++++++++++++++++++++++++++
 432 
 433   Printf-like function to print to socket/file specified by connection
 434   data structure. First writes the text to a temporary buffer, then
 435   uses SK_cd_puts to print it. Maintains a 2K static buffer, and allocates
 436   more memory if this is not enough.
 437 
 438   int SK_cd_printf       Returns the SK_cd_puts error code/return value.
 439 
 440   sk_conn_st *condat     Pointer to the connection data structure.
 441 
 442   char *txt              Format text to be written
 443 
 444   ...                    more arguments (like printf)
 445 
 446   
 447     +html+ <PRE>
 448   Author:
 449         marek
 450     +html+ </PRE>
 451   ++++++++++++++++++++++++++++++++++++++*/
 452 int SK_cd_printf(sk_conn_st *condat, char *txt, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 453 {
 454 #define SKBUFLEN 2047
 455   va_list   ap;
 456   char      buffer[SKBUFLEN+1];
 457   unsigned  len;
 458   char      *newbuf = NULL;
 459   char      *finalbuf = buffer; /* points to where the text REALLY is */
 460  
 461   /* vsnprintf returns the number of character it WOULD write if it could.
 462      So we assume the buffer to be of adequate size for most cases,
 463      and if it isn't, then we allocate to newbuf and call v*printf again 
 464   */
 465   va_start(ap, txt);
 466   len = vsnprintf(buffer, SKBUFLEN, txt, ap);
 467   va_end(ap);
 468   
 469   if( len > SKBUFLEN ) {
 470     newbuf = (char *)UT_malloc(len+1);
 471     
 472     va_start(ap, txt);
 473     vsnprintf(newbuf, len+1, txt, ap);
 474     va_end(ap);   
 475     
 476     finalbuf = newbuf;
 477   }  
 478   /* terminate */
 479   finalbuf[len] = 0;
 480 
 481   /* reuse len */
 482   len = SK_cd_puts(condat, finalbuf);
 483 
 484   if(newbuf != NULL) {
 485     UT_free(newbuf);
 486   }
 487 
 488   return len;
 489 } /* SK_cd_printf() */
 490 

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