home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / coven / glpv-1.1.tgz / glpv-1.1.tar / glpv / sockio.c < prev    next >
C/C++ Source or Header  |  2002-10-29  |  13KB  |  554 lines

  1. /*
  2.  * (C) 2001 Clemson University and The University of Chicago
  3.  *
  4.  * See COPYING in top-level directory.
  5.  */
  6.  
  7.  
  8. /* UNIX INCLUDE FILES */
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <string.h>    /* bzero and bcopy prototypes */
  13. #include <sys/types.h>
  14. #include <sys/socket.h>
  15. #include <sys/time.h>
  16. #include <fcntl.h>
  17. #include <netinet/in.h>
  18. #include <netinet/tcp.h>
  19. #include <netdb.h>
  20. #include <sys/poll.h>
  21. #include <sys/uio.h>
  22.  
  23. #include "sockio.h"
  24.  
  25.  
  26. /* FUNCTIONS */
  27. int new_sock() {
  28.     static int p_num = -1; /* set to tcp protocol # on first call */
  29.     struct protoent *pep;
  30.  
  31.    if (p_num == -1) {
  32.         if ((pep = getprotobyname("tcp")) == NULL) {
  33.             perror("Kernel does not support tcp");
  34.             return(-1);
  35.         }
  36.         p_num = pep->p_proto;
  37.     }
  38.     return(socket(AF_INET, SOCK_STREAM, p_num));
  39. }
  40.  
  41. int bind_sock(int sockd, int service)
  42. {
  43.     struct sockaddr_in saddr;
  44.  
  45.     bzero((char *)&saddr,sizeof(saddr));
  46.     saddr.sin_family = AF_INET;
  47.     saddr.sin_port = htons((u_short)service);
  48.     saddr.sin_addr.s_addr = INADDR_ANY;
  49. bind_sock_restart:
  50.     if (bind(sockd,(struct sockaddr *)&saddr,sizeof(saddr)) < 0) {
  51.         if (errno == EINTR) goto bind_sock_restart;
  52.         return(-1);
  53.     }
  54.     return(sockd);
  55. }
  56.  
  57. int connect_sock(int sockd, char *name, int service)
  58. {
  59.     struct sockaddr saddr;
  60.  
  61.     if (init_sock(&saddr, name, service) != 0) return(-1);
  62. connect_sock_restart:
  63.     if (connect(sockd,(struct sockaddr *)&saddr,sizeof(saddr)) < 0) {
  64.         if (errno == EINTR) goto connect_sock_restart;
  65.         return(-1);
  66.     }
  67.     return(sockd);
  68. }
  69.  
  70. int init_sock(struct sockaddr *saddrp, char *name, int service)
  71. {
  72.     struct hostent *hep;
  73.  
  74.     bzero((char *)saddrp,sizeof(struct sockaddr_in));
  75.     if (name == NULL) {
  76.         if ((hep = gethostbyname("localhost")) == NULL) {
  77.             return(-1);
  78.         }
  79.     }
  80.     else if ((hep = gethostbyname(name)) == NULL) {
  81.         return(-1);
  82.     }
  83.     ((struct sockaddr_in *) saddrp)->sin_family = AF_INET;
  84.     ((struct sockaddr_in *)saddrp)->sin_port = htons((u_short)service);
  85.     bcopy(hep->h_addr, (char *)&(((struct sockaddr_in *)saddrp)->sin_addr),
  86.         hep->h_length);
  87.     return(0);
  88. }
  89.  
  90. /* blocking receive */
  91. /* Returns -1 if it cannot get all len bytes
  92.  * and the # of bytes received otherwise
  93.  */
  94. int brecv(int s, void *buf, int len)
  95. {
  96.     int oldfl, ret, comp = len;
  97.     oldfl = fcntl(s, F_GETFL, 0);
  98.     if (oldfl & O_NONBLOCK) fcntl(s, F_SETFL, oldfl & (~O_NONBLOCK));
  99.  
  100.     while (comp) {
  101. brecv_restart:
  102.         if ((ret = recv(s, (char *) buf, comp, 0)) < 0) {
  103.             if (errno == EINTR) goto brecv_restart;
  104.             return(-1);
  105.         }
  106.         if (!ret) {
  107.             /* Note: this indicates a closed socket.  However, I don't
  108.              * like this behavior, so we're going to return -1 w/an EPIPE
  109.              * instead.
  110.              */
  111.             errno = EPIPE;
  112.             return(-1);
  113.         }
  114.         comp -= ret;
  115.         buf += ret;
  116.     }
  117.     return(len - comp);
  118. }
  119.  
  120. /* nonblocking receive */
  121. int nbrecv(int s, void *buf, int len)
  122. {
  123.     int oldfl, ret, comp = len;
  124.  
  125.     oldfl = fcntl(s, F_GETFL, 0);
  126.     if (!(oldfl & O_NONBLOCK)) fcntl(s, F_SETFL, oldfl | O_NONBLOCK);
  127.  
  128.     while (comp) {
  129. nbrecv_restart:
  130.         ret = recv(s, buf, comp, 0);
  131.         if (!ret) /* socket closed */ {
  132.             errno = EPIPE;
  133.             return(-1);
  134.         }
  135.         if (ret == -1 && errno == EWOULDBLOCK) {
  136.             return(len - comp); /* return amount completed */
  137.         }
  138.         if (ret == -1 && errno == EINTR) {
  139.             goto nbrecv_restart;
  140.         }
  141.         else if (ret == -1) {
  142.             return(-1);
  143.         }
  144.         comp -= ret;
  145.         buf += ret;
  146.     }
  147.     return(len - comp);
  148. }
  149.  
  150. /* nbpeek()
  151.  *
  152.  * performs a nonblocking check to see if the amount of data requested
  153.  * is actually available in a socket.  Does not actually read the data
  154.  * out.
  155.  *
  156.  * returns number of bytes available on succes, -1 on failure.
  157.  */
  158. int nbpeek(int s, int len)
  159. {
  160.     int oldfl, ret, comp = len;
  161.     char buffer[len];
  162.     void* buf = buffer;
  163.  
  164.     oldfl = fcntl(s, F_GETFL, 0);
  165.     if (!(oldfl & O_NONBLOCK)) fcntl(s, F_SETFL, oldfl | O_NONBLOCK);
  166.  
  167.     while (comp) {
  168. nbrecv_restart:
  169.         ret = recv(s, buf, comp, MSG_PEEK);
  170.         if (!ret) /* socket closed */ {
  171.             errno = EPIPE;
  172.             return(-1);
  173.         }
  174.         if (ret == -1 && errno == EWOULDBLOCK) {
  175.             return(len - comp); /* return amount completed */
  176.         }
  177.         if (ret == -1 && errno == EINTR) {
  178.             goto nbrecv_restart;
  179.         }
  180.         else if (ret == -1) {
  181.             return(-1);
  182.         }
  183.         comp -= ret;
  184.         buf += ret;
  185.     }
  186.     return(len - comp);
  187. }
  188.  
  189.  
  190. /* blocking send */
  191. int bsend(int s, void *buf, int len)
  192. {
  193.     int oldfl, ret, comp = len;
  194.     oldfl = fcntl(s, F_GETFL, 0);
  195.     if (oldfl & O_NONBLOCK) fcntl(s, F_SETFL, oldfl & (~O_NONBLOCK));
  196.  
  197.     while (comp) {
  198. bsend_restart:
  199.         if ((ret = send(s, (char *) buf, comp, 0)) < 0) {
  200.             if (errno == EINTR) goto bsend_restart;
  201.             return(-1);
  202.         }
  203.         comp -= ret;
  204.         buf += ret;
  205.     }
  206.     return(len - comp);
  207. }
  208.  
  209. /* blocking vector send */
  210. int bsendv(int s, const struct iovec *vec, int cnt)
  211. {
  212.     int tot, comp, ret, oldfl;
  213. #ifdef BSENDV_NO_WRITEV
  214.     struct iovec *cur = (struct iovec *)vec;
  215.     char *buf;
  216. #else
  217. #endif
  218.  
  219.     oldfl = fcntl(s, F_GETFL, 0);
  220.     if (oldfl & O_NONBLOCK) fcntl(s, F_SETFL, oldfl & (~O_NONBLOCK));
  221.  
  222. #ifdef BSENDV_NO_WRITEV
  223.     for (tot=0; cnt--; cur++) {
  224.         buf = (char *) cur->iov_base;
  225.         comp = cur->iov_len;
  226.         while (comp) {
  227. bsendv_restart:
  228.             if ((ret = send(s, buf, comp, 0)) < 0) {
  229.                 if (errno == EINTR) goto bsendv_restart;
  230.                 return(-1);
  231.             }
  232.             comp -= ret;
  233.             buf += ret;
  234.         }
  235.         tot += cur->iov_len;
  236.     }
  237.     return(tot);
  238. #else
  239.  
  240.     for(comp=0,tot=0; comp < cnt; comp++) tot += vec[comp].iov_len;
  241.  
  242.     if ((ret = writev(s, vec, cnt)) < 0) {
  243. bsendv_restart:
  244.         if (errno == EINTR) goto bsendv_restart;
  245.         return(-1);
  246.     }
  247.     return(ret);
  248. #endif
  249. }
  250.  
  251. /* nonblocking send */
  252. /* should always return 0 when nothing gets done! */
  253. int nbsend(int s, void *buf, int len)
  254. {
  255.     int oldfl, ret, comp = len;
  256.     oldfl = fcntl(s, F_GETFL, 0);
  257.     if (!(oldfl & O_NONBLOCK)) fcntl(s, F_SETFL, oldfl | O_NONBLOCK);
  258.  
  259.     while (comp) {
  260. nbsend_restart:
  261.         ret = send(s, (char *) buf, comp, 0);
  262.         if (ret == 0 || (ret == -1 && errno == EWOULDBLOCK))
  263.             return(len - comp); /* return amount completed */
  264.         if (ret == -1 && errno == EINTR) {
  265.             goto nbsend_restart;
  266.         }
  267.         else if (ret == -1) return(-1);
  268.         comp -= ret;
  269.         buf += ret;
  270.     }
  271.     return(len - comp);
  272. }
  273.  
  274. #ifdef __USE_SENDFILE__
  275. /* NBSENDFILE() - nonblocking (on the socket) send from file
  276.  *
  277.  * Here we are going to take advantage of the sendfile() call provided
  278.  * in the linux 2.2 kernel to send from an open file directly (ie. w/out
  279.  * explicitly reading into user space memory or memory mapping).
  280.  *
  281.  * We are going to set the non-block flag on the socket, but leave the
  282.  * file as is.
  283.  *
  284.  * Boy, that type on the offset for sockfile() sure is lame, isn't it?
  285.  * That's going to cause us some headaches when we want to do 64-bit
  286.  * I/O...
  287.  *
  288.  * Returns -1 on error, amount of data written to socket on success.
  289.  */
  290. int nbsendfile(int s, int f, int off, int len)
  291. {
  292.     int oldfl, ret, comp = len, myoff;
  293.  
  294.     oldfl = fcntl(s, F_GETFL, 0);
  295.     if (!(oldfl & O_NONBLOCK)) fcntl(s, F_SETFL, oldfl | O_NONBLOCK);
  296.  
  297.     while (comp) {
  298. nbsendfile_restart:
  299.         myoff = off;
  300.         ret = sendfile(s, f, &myoff, comp);
  301.         if (ret == 0 || (ret == -1 && errno == EWOULDBLOCK))
  302.             return(len - comp); /* return amount completed */
  303.         if (ret == -1 && errno == EINTR) {
  304.             goto nbsendfile_restart;
  305.         }
  306.         else if (ret == -1) return(-1);
  307.         comp -= ret;
  308.         off += ret;
  309.     }
  310.     return(len - comp);
  311. }
  312. #endif
  313.  
  314. /* routines to get and set socket options */
  315. int get_sockopt(int s, int optname)
  316. {
  317.     int val, len = sizeof(val);
  318.     if (getsockopt(s, SOL_SOCKET, optname, &val, &len) == -1)
  319.         return(-1);
  320.     else return(val);
  321. }
  322.  
  323. int set_tcpopt(int s, int optname, int val)
  324. {
  325.     if (setsockopt(s, SOL_TCP, optname, &val, sizeof(val)) == -1)
  326.         return(-1);
  327.     else return(val);
  328. }
  329.  
  330. int set_sockopt(int s, int optname, int val)
  331. {
  332.     if (setsockopt(s, SOL_SOCKET, optname, &val, sizeof(val)) == -1)
  333.         return(-1);
  334.     else return(val);
  335. }
  336.  
  337. int get_socktime(int s, int optname)
  338. {
  339.     struct timeval val;
  340.     int len = sizeof(val);
  341.     if (getsockopt(s, SOL_SOCKET, optname, &val, &len) == -1)
  342.         return(-1);
  343.     else return(val.tv_sec * 1000000 + val.tv_usec);
  344. }
  345.  
  346. int set_socktime(int s, int optname, int size)
  347. {
  348.     struct timeval val;
  349.     val.tv_sec = size / 1000000;
  350.     val.tv_usec = size % 1000000;
  351.     if (setsockopt(s, SOL_SOCKET, optname, &val, sizeof(val)) == -1)
  352.         return(-1);
  353.     else return(size);
  354. }
  355.  
  356. /* SOCKIO_DUMP_SOCKADDR() - dump info in a sockaddr structure
  357.  *
  358.  * Might or might not work for any given platform!
  359.  */
  360. int sockio_dump_sockaddr(struct sockaddr_in *ptr, FILE *fp)
  361. {
  362.     int i;
  363.     unsigned long int tmp;
  364.     struct hostent *hp;
  365.     char abuf[]="xxx.xxx.xxx.xxx\0";
  366.  
  367.     fprintf(fp, "sin_family = %d\n", ptr->sin_family);
  368.     fprintf(fp, "sin_port = %d (%d)\n", ptr->sin_port, ntohs(ptr->sin_port));
  369.     /* print in_addr info */
  370.     tmp = ptr->sin_addr.s_addr;
  371.     sprintf(&abuf[0], "%d.%d.%d.%d",(int)(tmp & 0xff),(int)((tmp >> 8) & 0xff),
  372.         (int)((tmp >> 16) & 0xff), (int)((tmp >> 24) & 0xff));
  373.     hp = gethostbyaddr((char *)&ptr->sin_addr.s_addr, sizeof(ptr->sin_addr),
  374.         ptr->sin_family);
  375.     fprintf(fp, "sin_addr = %lx (%s = %s)\n", (unsigned long)(ptr->sin_addr.s_addr), abuf, 
  376.         hp->h_name);
  377.     for (i = 0; i < sizeof(struct sockaddr) - sizeof(short int) -
  378.         sizeof(unsigned short int) - sizeof(struct in_addr); i++)
  379.     {
  380.         fprintf(fp, "%x", ptr->sin_zero[i]);
  381.     }
  382.     fprintf(fp, "\n");
  383.     return(0);
  384. } /* end of SOCKIO_DUMP_SOCKADDR() */
  385.  
  386.  
  387. /* connect_timeout()
  388.  *
  389.  * Attempts to do nonblocking connect() until a timeout occurs.  Useful for
  390.  * recovering from deadlocks...
  391.  *
  392.  * I apologize for all the goto's, but I hate to every syscall in a while()
  393.  * just for the EINTR case!  
  394.  */
  395. int connect_timeout(int s, struct sockaddr *saddrp, int len, int time_secs)
  396. {
  397.     struct pollfd pfds;
  398.     int ret, oldfl, err, val, val_len;
  399.  
  400.     /* set our socket to nonblocking */
  401.     oldfl = fcntl(s, F_GETFL, 0);
  402.     if (!(oldfl & O_NONBLOCK)) fcntl(s, F_SETFL, oldfl | O_NONBLOCK);
  403.  
  404. connect_timeout_connect_restart:
  405.     ret = connect(s, saddrp, len);
  406.     if (ret < 0) {
  407.         if (errno == EINTR) goto connect_timeout_connect_restart;
  408.         if (errno != EINPROGRESS) goto connect_timeout_err;
  409.  
  410.         pfds.fd = s;
  411.         pfds.events = POLLOUT;
  412. connect_timeout_poll_restart:
  413.         ret = poll(&pfds, 1, time_secs * 1000);
  414.         if (ret < 0) {
  415.             if (errno == EINTR) goto connect_timeout_poll_restart;
  416.             else goto connect_timeout_err;
  417.         }
  418.         if (ret == 0) {
  419.             /* timed out */
  420.             err = errno;
  421.             close(s); /* don't want it to keep trying */
  422.             errno = err;
  423.             goto connect_timeout_err;
  424.         }
  425.     }
  426.  
  427.     /* _apparent_ success -- check if connect really completed */
  428.     val_len = sizeof(val);
  429.     ret = getsockopt(s, SOL_SOCKET, SO_ERROR, &val, &len);
  430.     if (val != 0) {
  431.         errno = val;
  432.         goto connect_timeout_err;
  433.     }
  434.  
  435.     /* success -- make socket blocking again and return */
  436.     fcntl(s, F_SETFL, oldfl & (~O_NONBLOCK));
  437.     return 0;
  438.  
  439. connect_timeout_err:
  440.     /* save errno, set flags on socket back to what they were, return -1 */
  441.     err = errno;
  442.     fcntl(s, F_SETFL, oldfl);
  443.     errno = err;
  444.     return -1;
  445. }
  446.  
  447.  
  448. /* brecv_timeout()
  449.  *
  450.  * Attempts to do nonblocking recv's until a timeout occurs.  Useful for
  451.  * recovering from deadlocks in situations where you want to give up if a
  452.  * message does not finish arriving within a certain time frame.
  453.  *
  454.  * Same args as brecv, but with an additional timeout argument that is an
  455.  * integer number of seconds.   
  456.  * 
  457.  * returns number of bytes received, even if it did not recv all that was
  458.  * asked.  If any error other than timeout occurs, it returns -1 and sets
  459.  * errno accordingly.  */
  460. int brecv_timeout(int s, void *buf, int len, int timeout)
  461. {
  462.  
  463.     int recv_size = len;    /* amt we hope for each iteration */
  464.     int recv_total = 0;     /* total amt recv'd thus far */
  465.     void* recv_ptr = buf;   /* where to put the data */
  466.     int initial_tries = 4;  /* number of initial attempts to make */
  467.     int i = 0;
  468.     int ret = -1;
  469.     struct pollfd poll_conn;
  470.  
  471.     /* This determines the backoff times.  It will do a few attempts with the
  472.      * initial backoff first, then wait and do a final one after the
  473.      * remainder of the time is up.  Note that the initial backoff will be
  474.      * zero if a small overall timeout is specified by the caller.
  475.      */
  476.     int initial_backoff = timeout/initial_tries;
  477.     int final_backoff = timeout - (timeout/initial_tries);
  478.  
  479.     /* we don't accept -1 for infinite timeout.  That is the job of brecv. */
  480.     if(timeout < 0)
  481.     {
  482.         errno = EINVAL;
  483.         return(-1);
  484.     }
  485.  
  486.     /* initial attempts */
  487.     do
  488.     {
  489.         /* nbrecv() handles EINTR on its own */
  490.         if((ret = nbrecv(s, recv_ptr, recv_size)) < 0)
  491.         {
  492.             /* bail out at any error */
  493.             return(ret);
  494.         }
  495.  
  496.         /* update our progress */
  497.         recv_size -= ret;
  498.         recv_total += ret;
  499.         recv_ptr += ret;
  500.  
  501.         /* if we didn't finish, then poll for a while. */
  502.         if(recv_total < len)
  503.         {
  504.             poll_conn.fd = s;
  505.             poll_conn.events = POLLIN;
  506. brecv_timeout_poll1_restart:
  507.             ret = poll(&poll_conn, 1, (initial_backoff*1000));
  508.             if(ret < 0)
  509.             {
  510.                 if (errno == EINTR) goto brecv_timeout_poll1_restart;
  511.                 /* bail out on any "real" error */
  512.                 return(ret);
  513.             }
  514.         }
  515.         i++;
  516.     }
  517.     while((i < initial_tries) && (recv_total < len));
  518.     
  519.     /* see if we are done */
  520.     if(recv_total == len){
  521.         return(len);
  522.     }
  523.  
  524.     /* not done yet, give it one last chance: */
  525.     poll_conn.fd = s;
  526.     poll_conn.events = POLLIN;
  527. brecv_timeout_poll2_restart:
  528.     ret = poll(&poll_conn, 1, (final_backoff*1000));
  529.     if(ret < 0)
  530.     {
  531.         if (errno == EINTR) goto brecv_timeout_poll2_restart;
  532.         /* bail out on any "real" error */
  533.         return(ret);
  534.     }
  535.  
  536.     if((ret = nbrecv(s, recv_ptr, recv_size)) < 0)
  537.     {
  538.         return(ret);
  539.     }
  540.  
  541.     recv_size -= ret;
  542.     recv_total += ret;
  543.  
  544.     return(recv_total);
  545. }
  546.  
  547. /*
  548.  * Local variables:
  549.  *  c-indent-level: 3
  550.  *  c-basic-offset: 3
  551.  *  tab-width: 3
  552.  * End:
  553.  */
  554.