Simple tools for networking / objects in plain C Snapshot
|
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