/ src / libnml / buffer / sendn.c
sendn.c
  1  /********************************************************************
  2  * Description: sendn.c
  3  *   Provides a C file for the sendn function from the book Advanced
  4  *   Programming in the UNIX Environment by Richard Stevens.
  5  *   The sendn function calls the send function repeatedly until n bytes
  6  *   have been written to the file descriptor.
  7  *
  8  *   Derived from a work by Fred Proctor & Will Shackleford
  9  *
 10  * Author:
 11  * License: LGPL Version 2
 12  * System: Linux
 13  *    
 14  * Copyright (c) 2004 All rights reserved.
 15  *
 16  * Last change: 
 17  ********************************************************************/
 18  
 19  #include <string.h>		/* strerror */
 20  #include <stdlib.h>		/* memset() */
 21  #include <errno.h>		/* errno */
 22  #include <math.h>		/* fabs() */
 23  #include <sys/socket.h>		/* send(), recv(), socket(), accept(),
 24  				   bind(), listen() */
 25  #include <sys/time.h>		/* struct timeval */
 26  #include "sendn.h"		/* sendn() */
 27  #include "rcs_print.hh"		/* rcs_print_error() */
 28  #include "_timer.h"		/* etime(), esleep() */
 29  
 30  int sendn_timedout = 0;
 31  int print_sendn_timeout_errors = 1;
 32  
 33  /* Write "n" bytes to a descriptor. */
 34  int sendn(int fd, const void *vptr, int n, int _flags, double _timeout)
 35  {
 36      int nleft;
 37      long nwritten;
 38      int select_ret;
 39      double start_time;
 40      char *ptr;
 41      struct timeval timeout_tv;
 42      fd_set send_fd_set;
 43  
 44      timeout_tv.tv_sec = (long) _timeout;
 45      timeout_tv.tv_usec = (long) (_timeout * 1000000.0);
 46      if (timeout_tv.tv_usec >= 1000000) {
 47  	timeout_tv.tv_usec = timeout_tv.tv_usec % 1000000;
 48      }
 49      FD_ZERO(&send_fd_set);
 50      FD_SET(fd, &send_fd_set);
 51  
 52      ptr = (char *) vptr;	/* can't do pointer arithmetic on void* */
 53      nleft = n;
 54      start_time = etime();
 55      while (nleft > 0) {
 56  	if (fabs(_timeout) > 1E-6) {
 57  	    if (_timeout > 0) {
 58                  double timeleft;
 59  		timeleft = start_time + _timeout - etime();
 60  		if (timeleft <= 0.0) {
 61  		    if (print_sendn_timeout_errors) {
 62  			rcs_print_error
 63  			    ("sendn(fd=%d, vptr=%p, int n=%d, int flags=%d, double _timeout=%f) timed out.\n",
 64  			    fd, vptr, n, _flags, _timeout);
 65  		    }
 66  		    sendn_timedout = 1;
 67  		    return -1;
 68  		}
 69  		timeout_tv.tv_sec = (long) timeleft;
 70  		timeout_tv.tv_usec = (long) (timeleft * 1000000.0);
 71  		if (timeout_tv.tv_usec >= 1000000) {
 72  		    timeout_tv.tv_usec = timeout_tv.tv_usec % 1000000;
 73  		}
 74  		select_ret =
 75  		    select(fd + 1, (fd_set *) NULL, &send_fd_set,
 76  		    (fd_set *) NULL, &timeout_tv);
 77  	    } else {
 78  		select_ret =
 79  		    select(fd + 1, (fd_set *) NULL, &send_fd_set,
 80  		    (fd_set *) NULL, NULL);
 81  	    }
 82  	    switch (select_ret) {
 83  	    case -1:
 84  		rcs_print_error("Error in select: %d -> %s\n", errno,
 85  		    strerror(errno));
 86  		rcs_print_error
 87  		    ("sendn(fd=%d, vptr=%p, int n=%d, int _flags=%d, double _timeout=%f) failed.\n",
 88  		    fd, vptr, n, _flags, _timeout);
 89  		return -1;
 90  
 91  	    case 0:
 92  		rcs_print_error
 93  		    ("sendn(fd=%d, vptr=%p, int n=%d, int _flags=%d, double _timeout=%f) timed out.\n",
 94  		    fd, vptr, n, _flags, _timeout);
 95  		return -1;
 96  
 97  	    default:
 98  		break;
 99  	    }
100  	}
101  	if ((nwritten = send(fd, ptr, nleft, _flags)) == -1) {
102  	    rcs_print_error("Send error: %d = %s\n", errno, strerror(errno));
103  	    return (-1);	/* error */
104  	}
105  	nleft -= nwritten;
106  	ptr += nwritten;
107  	if (nleft > 0 && _timeout > 0.0) {
108              double duration;
109              duration = etime() - start_time;
110              if (duration > _timeout) {
111                  rcs_print_error("sendn: timed out after %f seconds.\n", duration);
112  		return (-1);
113  	    }
114  	    esleep(0.001);
115  	}
116      }
117      rcs_print_debug(PRINT_SOCKET_WRITE_SIZE, "wrote %d bytes to %d\n", n, fd);
118      return (n);
119  }