Simple tools for networking / objects in plain C Snapshot
sock.c
Go to the documentation of this file.
00001 
00002 #include <netinet/in.h>
00003 #include <netinet/tcp.h>
00004 #include <arpa/inet.h>
00005 #include <sys/select.h>
00006 #include <sys/ioctl.h>
00007 #include <sys/time.h>
00008 #include <sys/types.h>
00009 #include <sys/socket.h>
00010 #include <unistd.h>
00011 
00012 #include <stdio.h>
00013 #include <stdint.h>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <errno.h>
00017 
00018 #include "sock.h"
00019 #include "ioutils.h"
00020 
00021 int SOCK_attach( SOCKCTX *ctx , int fd, int verbose, int flags)
00022 {
00023   ctx->verbose = verbose;
00024   ctx->connected = 0;
00025 
00026   ctx->addr = 0;
00027   ctx->addr_size = 0;
00028 
00029   disable_sigpipe();
00030  
00031   ctx->fd = fd;
00032  
00033  if ( fd_set_blocking( ctx->fd, 0 ) ) {
00034      if (ctx->verbose) {
00035        fprintf(stderr, "Failed to make socket non blocking errno %d\n", errno);
00036      }
00037   }
00038 
00039   if ((flags & SOCKCTX_FLAGS_NAGLE_ON) == 0) {  
00040     if ( fd_set_nagling( ctx->fd, 1 ) ) {
00041        if (ctx->verbose) {
00042          fprintf(stderr,"Failed to set nodelay option (set nodelay option). errno %d\n",errno);
00043        }    
00044     }
00045   }
00046 
00047   ctx->close_on_peer_close = 1; 
00048   if (flags & SOCKTCX_FLAGS_DONT_CLOSE_ON_PEER_CLOSE) {
00049     if ( fd_set_linger_option( ctx->fd, 1, LINGER_OPTION_VALUE) ) {
00050       if (ctx->verbose) {
00051        fprintf(stderr,"Failed to set linger option. %d\n", errno );
00052       }
00053     }
00054     ctx->close_on_peer_close = 0; 
00055   }
00056 
00057   return 0;
00058 }
00059 
00060 
00061 int SOCK_init( SOCKCTX *ctx , int verbose, int flags)
00062 {
00063   int fd;
00064  
00065   fd = socket( PF_INET, SOCK_STREAM, 0 );
00066   if (fd == -1) {
00067      if (verbose) {
00068        fprintf(stderr, "Failed to create socket %d\n", errno);
00069      }
00070      return -1;
00071   }
00072 
00073   return SOCK_attach( ctx , fd, verbose, flags);
00074 }
00075  
00076 
00077 int SOCK_send_buffer_sizes( SOCKCTX *ctx, int read_buffer_size, int write_buffer_size)
00078 {
00079   if (read_buffer_size > 0) {
00080     if (fd_set_buf_size( ctx->fd, Receive_buffer, read_buffer_size)) {
00081       fprintf(stderr,"Failed to set receive buffer size to %d\n",read_buffer_size);
00082       return -1;
00083     }
00084   }
00085   
00086   if (write_buffer_size > 0) {
00087     if (fd_set_buf_size( ctx->fd, Send_buffer, write_buffer_size)) {
00088       fprintf(stderr,"Failed to set send buffer size to %d\n",write_buffer_size);
00089       return -1;
00090     }
00091   }
00092   return 0;  
00093 
00094 }
00095 
00096 
00097 int SOCK_connect( SOCKCTX *ctx, void *addr, int addr_size, int connect_timeout)
00098 {
00099   int rt;
00100   fd_set wset,eset;
00101   struct timeval tv;
00102   int error = 0;
00103   int len;
00104     
00105   if (ctx->connected) {
00106     return 0;
00107   }
00108 
00109   if (addr != 0) {
00110      ctx->addr = malloc( addr_size );
00111      if (!ctx->addr) {
00112        goto err;
00113      }
00114      memcpy( ctx->addr, addr, addr_size );
00115      ctx->addr_size = addr_size;
00116   }
00117 
00118   if (!ctx->addr) {
00119     goto err;
00120   }
00121 
00122   do {
00123     rt = connect( ctx->fd, (struct sockaddr *) ctx->addr, ctx->addr_size );
00124   } while( rt == -1 && errno == EINTR);
00125 
00126   if (rt == -1) {
00127 
00128 
00129 #if 0
00130      if (errno != EINPROGRESS) {
00131         if (ctx->verbose) {
00132           fprintf(stderr,"Connect syscall failed. %d\n", errno );
00133         }
00134         goto err;
00135      }
00136 #endif
00137 
00138      FD_ZERO(&wset);
00139      FD_SET(ctx->fd,&wset);
00140      eset = wset;
00141 
00142      tv.tv_sec = connect_timeout;
00143      tv.tv_usec = 0;
00144 
00145      do {
00146        rt = select( ctx->fd + 1, 0, &wset, &eset, &tv ); 
00147      } while( rt == -1 && errno == EINTR);
00148      
00149      if (rt <= 0) {
00150         if (ctx->verbose) {
00151           fprintf(stderr,"Connect timed out. %d\n", errno );
00152         }
00153         goto err;
00154      }
00155 
00156      if (FD_ISSET( ctx->fd, &wset) ||  FD_ISSET( ctx->fd, &eset)) {
00157        len = sizeof(error);
00158        error = 0;
00159        if (getsockopt( ctx->fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *) &len ) || error) {
00160          if (ctx->verbose) {
00161            fprintf(stderr,"Connect socket error. %d errno %d\n", error, errno );
00162          }
00163          goto err;
00164        }
00165      }
00166 
00167      if (! FD_ISSET( ctx->fd, &wset)) {
00168          if (ctx->verbose) {
00169            fprintf(stderr,"Still not connected. errno %d\n", errno );
00170          }
00171          goto err;
00172      }
00173   }
00174 
00175 
00176   ctx->connected = 1;
00177   return 0;
00178 
00179 err:
00180   SOCK_close(ctx);
00181   return -1;
00182 }
00183 
00184 
00185 
00186 int SOCK_recv( SOCKCTX *ctx, void *msg, size_t length, int read_timeout )
00187 {
00188   int rt;
00189   fd_set rset;
00190   struct timeval tv;
00191      
00192 retry:
00193      do {
00194        rt = recv( ctx->fd, msg, length, 0 );
00195      } while( rt == -1 && errno == EINTR );
00196 
00197      if (rt == -1) {
00198           
00199         if (errno != EAGAIN) {
00200            if (ctx->verbose) {
00201              fprintf(stderr,"recv failed errno %d\n", errno );
00202            }
00203            goto err;
00204         }
00205 
00206         FD_ZERO(&rset);
00207         FD_SET(ctx->fd,&rset);
00208 
00209         tv.tv_sec = read_timeout;
00210         tv.tv_usec = 0;
00211 
00212         do {
00213           rt = select( ctx->fd + 1, &rset, 0, 0, &tv ); 
00214         } while( rt == -1 && errno == EINTR);
00215         
00216 
00217         if (rt == -1) {
00218           if (ctx->verbose) {
00219             fprintf(stderr, "select failed. %d\n", errno );
00220           }
00221         }
00222      
00223         if (rt == 0) {
00224            if (ctx->verbose) {
00225              fprintf(stderr,"read timed out\n" );
00226            }
00227            goto err;
00228         }
00229 
00230         if (rt == 1) {
00231            goto retry;
00232         }
00233 
00234      }
00235 
00236    if (rt == 0 && ctx->close_on_peer_close  ) {
00237       SOCK_close( ctx );
00238    }
00239    return rt;
00240 
00241 err:
00242    return -1;
00243 }        
00244 
00245 int SOCK_recv_all( SOCKCTX *ctx, void *msg, size_t length, int read_timeout )
00246 {
00247   size_t pos;
00248   int rt;
00249 
00250 
00251   for(pos = 0; pos < length; ) {
00252       rt = SOCK_recv( ctx, msg, length, read_timeout );
00253       if (rt <= 0) {
00254         return rt;
00255       }
00256       pos += rt;
00257   }
00258   return pos;
00259 }
00260 
00261 
00262 int SOCK_send( SOCKCTX *ctx, void *bmsg, size_t length, int write_timeout )
00263 {
00264   int rt;
00265   size_t pos;
00266   fd_set wset;
00267   struct timeval tv;
00268   char *msg = bmsg;
00269 
00270   for( pos = 0; pos < length; ) {
00271 
00272      do {
00273        rt = send( ctx->fd, msg + pos, length - pos, 0 );
00274      } while( rt == -1 && errno == EINTR );
00275 
00276      if (rt == -1) {
00277           
00278         if (errno != EAGAIN) {
00279            if (ctx->verbose) {
00280              fprintf(stderr,"send failed errno %d\n", errno );
00281            }
00282            goto err;
00283         }
00284 
00285         FD_ZERO(&wset);
00286         FD_SET(ctx->fd,&wset);
00287 
00288         tv.tv_sec = write_timeout;
00289         tv.tv_usec = 0;
00290 
00291         do {
00292           rt = select( ctx->fd + 1, 0, &wset, 0, &tv ); 
00293         } while( rt == -1 && errno == EINTR);
00294         
00295 
00296         if (rt == -1) {
00297           if (ctx->verbose) {
00298             fprintf(stderr, "select failed. %d\n", errno );
00299           }
00300         }
00301      
00302         if (rt == 0) {
00303            if (ctx->verbose) {
00304              fprintf(stderr,"send timed out\n" );
00305            }
00306            goto err;
00307         }
00308      }
00309      pos += rt;
00310    }
00311    return pos;
00312 
00313 err:
00314    return -1;
00315 }        
00316 
00317 int SOCK_close( SOCKCTX *ctx )
00318 {
00319   if (ctx->fd != -1) {
00320     if (close(ctx->fd)) {
00321       if (ctx->verbose) {
00322          fprintf(stderr,"Close failed errno %d\n", errno);
00323       }
00324     }
00325     ctx->fd = -1;
00326     ctx->connected = 0;
00327   }
00328   return 0;
00329 }
00330 
00331 int SOCK_close_with_reset( SOCKCTX *ctx )
00332 {
00333   if (ctx->fd != -1) {
00334     if (fd_close_by_RST( ctx->fd )) {
00335       if (ctx->verbose) {
00336         fprintf(stderr,"Failed to set linger option. %d\n", errno );
00337       }
00338     }
00339   }
00340   ctx->fd = -1;
00341   ctx->connected = 0;
00342   return 0;
00343 }
00344   
00345