socket.c

Go to the documentation of this file.
00001 #include "common.h"
00002 
00003 #ifdef _WINDOWS
00004 #include <Winsock2.h>
00005 #endif
00006 
00007 #include "log.h"
00008 #include "util.h"
00009 
00010 #include "hashtable.h"
00011 #include "vector.h"
00012 #include "thread.h"
00013 
00014 #include "socket.h"
00015 
00016 #include <stdio.h>
00017 #include <string.h>
00018 #include <stdlib.h>
00019 #include <signal.h>
00020 #include <fcntl.h>
00021 #include <errno.h>
00022 
00023 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00024 #include <unistd.h>
00025 #include <sys/time.h>
00026 #include <sys/socket.h>
00027 #include <netinet/in.h>
00028 #include <arpa/inet.h>
00029 #endif
00030 
00041 #ifdef CP_USE_SSL
00042 #include <openssl/ssl.h>
00043 #include <openssl/err.h>
00044 
00045 #ifdef _WINDOWS
00046 #include <wincrypt.h>
00047 #endif /* _WINDOWS */
00048 
00049 static cp_hashtable *ssl_ctx_table = NULL;
00050 
00051 volatile int ssl_initialized = 0;
00052 
00053 void cp_socket_ssl_init()
00054 {
00055     if (ssl_initialized) return;
00056     ssl_initialized = 1;
00057     
00058     SSL_library_init();
00059     SSL_load_error_strings();
00060     OpenSSL_add_all_algorithms();
00061 
00062     ssl_ctx_table = cp_hashtable_create(1, cp_hash_string, cp_hash_compare_string);
00063 }
00064 
00065 void cp_socket_ssl_shutdown()
00066 {
00067     if (ssl_initialized)
00068     {
00069         ssl_initialized = 0;
00070         if (ssl_ctx_table)
00071             cp_hashtable_destroy_custom(ssl_ctx_table, free, 
00072                                     (cp_destructor_fn) SSL_CTX_free);
00073         ssl_ctx_table = NULL;
00074 
00075         EVP_cleanup();
00076         ERR_free_strings();
00077     }
00078 }
00079     
00080 SSL_CTX *get_ssl_ctx(char *certificate_file, char *key_file)
00081 {
00082     int len;
00083     char *ck;
00084     SSL_CTX *ctx;
00085     if (ssl_ctx_table == NULL) cp_socket_ssl_init();
00086 
00087     len = strlen(certificate_file) + strlen(key_file) + 2;
00088     ck = malloc(len * sizeof(char));
00089 #ifdef CP_HAS_SNPRINTF
00090     snprintf(ck, len, "%s*%s", certificate_file, key_file);
00091 #else
00092     sprintf(ck, "%s*%s", certificate_file, key_file);
00093 #endif /* CP_HAS_SNPRINTF */
00094 
00095     ctx = cp_hashtable_get(ssl_ctx_table, ck);
00096     if (ctx == NULL)
00097     {
00098         int rc = 0;
00099         const SSL_METHOD *method = SSLv23_server_method();
00100         ctx = SSL_CTX_new(method);
00101         if (ctx == NULL)
00102         {
00103             rc = ERR_get_error();
00104             cp_error(CP_SSL_CTX_INITIALIZATION_ERROR, 
00105                      "can\'t create SSL context: %s", 
00106                      ERR_reason_error_string(rc));
00107             goto CTX_ERROR;
00108         }
00109         
00110         if (SSL_CTX_use_certificate_file(ctx, certificate_file, 
00111                                          SSL_FILETYPE_PEM) != 1)
00112         {
00113             rc = ERR_get_error();
00114             cp_error(CP_SSL_CTX_INITIALIZATION_ERROR, 
00115                      "certificate file: %s", ERR_reason_error_string(rc));      
00116             goto CTX_ERROR;
00117         }
00118 
00119         if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) != 1)
00120         {
00121             rc = ERR_get_error();
00122             cp_error(CP_SSL_CTX_INITIALIZATION_ERROR, 
00123                      "private key file: %s\n", ERR_reason_error_string(rc));    
00124             goto CTX_ERROR;
00125         }
00126     
00127         if (!(SSL_CTX_check_private_key(ctx)))
00128         {
00129             rc = ERR_get_error();
00130             cp_error(CP_SSL_CTX_INITIALIZATION_ERROR, 
00131                      "checking private key: %s", ERR_reason_error_string(rc));
00132             goto CTX_ERROR;
00133         }
00134 
00135         cp_hashtable_put(ssl_ctx_table, ck, ctx);
00136     }
00137         
00138     return ctx;
00139 
00140 CTX_ERROR:
00141     if (ctx)
00142         SSL_CTX_free(ctx);
00143 
00144     return NULL;
00145 }
00146     
00147 SSL_CTX *get_client_ssl_ctx(char *CA_file, char *CA_path)
00148 {
00149     SSL_CTX *ctx;
00150     cp_string *ckwrap = cp_string_create_empty(80);
00151     char *ck;
00152 
00153     if (ssl_ctx_table == NULL) cp_socket_ssl_init();
00154     
00155     if (CA_file) cp_string_cstrcat(ckwrap, CA_file);
00156     cp_string_cstrcat(ckwrap, "*");
00157     if (CA_path) cp_string_cstrcat(ckwrap, CA_path);
00158     ck = cp_string_tocstr(ckwrap);
00159     free(ckwrap);
00160     
00161     ctx = cp_hashtable_get(ssl_ctx_table, ck);
00162     if (ctx == NULL)
00163     {
00164         int rc;
00165         const SSL_METHOD *method = SSLv23_client_method();
00166         ctx = SSL_CTX_new(method);
00167 
00168         rc = SSL_CTX_load_verify_locations(ctx, CA_file, CA_path); 
00169         if (rc == 0) /* error */
00170         {
00171             rc = ERR_get_error();
00172             cp_error(CP_SSL_CTX_INITIALIZATION_ERROR, 
00173                      "loading CA certificate: %s", ERR_reason_error_string(rc));
00174             SSL_CTX_free(ctx);
00175             return NULL;
00176         }
00177 
00178         cp_hashtable_put(ssl_ctx_table, ck, ctx);
00179     }
00180     else 
00181         free(ck);
00182 
00183     return ctx;
00184 }
00185 
00186 #endif
00187 
00188 static volatile int socket_reg_id = 0;
00189 static cp_hashlist *socket_registry;
00190 static cp_vector *shutdown_hook = NULL;
00191 static volatile int initialized = 0;
00192 static volatile int shutting = 0;
00193 
00194 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00195 void cp_socket_signal_handler(int sig);
00196 #endif
00197 
00198 void cp_socket_init()
00199 {
00200 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00201     struct sigaction act;
00202 #endif
00203 
00204 #ifdef _WINDOWS
00205     WSADATA wsaData;
00206     WORD version;
00207     int error;
00208 #endif
00209 
00210     if (initialized) return;
00211     initialized = 1;
00212 
00213 #ifdef _WINDOWS
00214     version = MAKEWORD( 2, 0 );
00215     error = WSAStartup( version, &wsaData );
00216 
00217     /* check for error */   
00218     if ( error != 0 )
00219     {
00220         /* error occured */
00221         initialized = 0;
00222         return;
00223     }
00224 
00225     /* check for correct version */
00226     if ( LOBYTE( wsaData.wVersion ) != 2 ||
00227          HIBYTE( wsaData.wVersion ) != 0 )
00228     {   
00229         /* incorrect WinSock version */
00230         initialized = 0;
00231         WSACleanup();
00232         return;
00233     }
00234 #endif
00235 
00236     socket_registry = 
00237         cp_hashlist_create_by_mode(1, COLLECTION_MODE_DEEP, 
00238                                    cp_hash_int, cp_hash_compare_int);
00239 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00240     act.sa_handler = cp_socket_signal_handler;
00241     sigemptyset(&act.sa_mask);
00242     act.sa_flags = 0;
00243     sigaction(SIGPIPE, &act, NULL);
00244 #endif
00245 }
00246 
00247 void cp_socket_stop(cp_socket *sock)
00248 {
00249 #ifdef __TRACE__
00250     DEBUGMSG("stopping socket %lX", sock);
00251 #endif
00252     sock->closing = 1;
00253     
00254     shutdown(sock->fd, SHUT_RD);
00255 }
00256 
00257 void cp_tcp_add_shutdown_callback(void (*cb)(void *), void *prm)
00258 {
00259     cp_wrap *wrap;
00260 
00261     if (shutdown_hook == NULL)
00262         shutdown_hook = cp_vector_create(1);
00263 
00264     wrap = cp_wrap_new(prm, cb);
00265 
00266     cp_vector_add_element(shutdown_hook, wrap);
00267 }
00268 
00269 volatile int stopping_all = 0;
00270 
00271 void cp_socket_stop_all()
00272 {
00273     if (stopping_all) return;
00274     stopping_all = 1;
00275 
00276     if (socket_registry)
00277     {
00278         cp_socket *sock;
00279         cp_hashlist_iterator i;
00280         cp_hashlist_iterator_init(&i, socket_registry, COLLECTION_LOCK_READ);
00281         while ((sock = cp_hashlist_iterator_next_value(&i)))
00282             cp_socket_stop(sock);
00283         cp_hashlist_iterator_release(&i);
00284     }
00285 }
00286 
00287 void cp_socket_shutdown()
00288 {
00289     if (shutting) return;
00290 
00291     shutting = 1;
00292 
00293 #ifdef __TRACE__
00294     DEBUGMSG("shutting down socket layer");
00295 #endif
00296 
00297     if (shutdown_hook)
00298     {
00299         cp_vector_destroy_custom(shutdown_hook, 
00300                                  (cp_destructor_fn) cp_wrap_delete);
00301         shutdown_hook = NULL;
00302     }
00303 
00304     cp_socket_stop_all();
00305     if (socket_registry)
00306     {
00307         cp_hashlist_destroy(socket_registry);
00308         socket_registry = NULL;
00309     }
00310 
00311 #ifdef CP_USE_SSL
00312     cp_socket_ssl_shutdown();
00313 #endif /* CP_USE_SSL */
00314 
00315 #ifdef _WINDOWS
00316     WSACleanup();
00317 #endif
00318 }
00319 
00320 #if defined(unix) || defined(__unix__) || defined(__MACH__)
00321 void cp_socket_signal_handler(int sig)
00322 {
00323     switch (sig)
00324     {
00325         case SIGPIPE: 
00326 #ifdef __TRACE__
00327             DEBUGMSG("SIGPIPE - ignoring\n");
00328 #endif
00329             break;
00330     }
00331 }
00332 #endif /* unix */
00333 
00334 #if defined(unix) || defined(__unix__) || defined(__MACH__) 
00335 int setnonblocking(int sock)
00336 {
00337     int opts;
00338 
00339     /*
00340      * fcntl may set: 
00341      *
00342      * EACCES, EAGAIN: Operation is prohibited by locks held by other 
00343      *          processes. Or, operation is prohibited because the file has 
00344      *          been memory-mapped by another process. 
00345      * EBADF:   fd is not an open file descriptor, or the command was F_SETLK 
00346      *          or F_SETLKW and the file descriptor open mode doesn't match 
00347      *          with the type of lock requested.
00348      * EDEADLK: It was detected that the specified F_SETLKW command would 
00349      *          cause a deadlock.
00350      * EFAULT:  lock is outside your accessible address space.
00351      * EINTR:   For F_SETLKW, the command was interrupted by a signal. For 
00352      *          F_GETLK and F_SETLK, the command was interrupted by a signal 
00353      *          before the lock was checked or acquired. Most likely when 
00354      *          locking a remote file (e.g. locking over NFS), but can 
00355      *          sometimes happen locally.
00356      * EINVAL:  For F_DUPFD, arg is negative or is greater than the maximum 
00357      *          allowable value. For F_SETSIG, arg is not an allowable signal 
00358      *          number.
00359      * EMFILE:  For F_DUPFD, the process already has the maximum number of 
00360      *          file descriptors open. 
00361      * ENOLCK:  Too many segment locks open, lock table is full, or a remote 
00362      *          locking protocol failed (e.g. locking over NFS).
00363      * EPERM:   Attempted to clear the O_APPEND flag on a file that has the 
00364      *          append-only attribute set.
00365      */
00366     opts = fcntl(sock, F_GETFL);
00367     if (opts < 0) 
00368     {
00369         perror("fcntl(F_GETFL)");
00370         return -1;
00371     }
00372 
00373     opts |= O_NONBLOCK;
00374 
00375     if (fcntl(sock, F_SETFL, opts) < 0) 
00376     {
00377         perror("fcntl(F_SETFL)");
00378         return -1;
00379     }
00380 
00381     return opts;
00382 }
00383 #else /* unix */
00384 int setnonblocking(int sock)
00385 {
00386     DWORD ul=1;
00387     return ioctlsocket(sock, FIONBIO, &ul);
00388 }
00389 #endif /* unix */
00390 
00391 cp_connection_descriptor *cp_connection_descriptor_create(cp_socket *sock, 
00392                                                     struct sockaddr_in *addr, 
00393                                                     int fd)
00394 {
00395     cp_connection_descriptor *conn_desc = 
00396         (cp_connection_descriptor *) calloc(1, sizeof(cp_connection_descriptor));
00397 
00398     if (conn_desc == NULL)
00399     {
00400         cp_error(CP_MEMORY_ALLOCATION_FAILURE, 
00401                  "can\'t allocate cp_connection_descriptor (%d bytes)", 
00402                  sizeof(cp_connection_descriptor));
00403         return NULL;
00404     }
00405 
00406     conn_desc->sock = sock;
00407     conn_desc->addr = addr;
00408     conn_desc->fd = fd;
00409 
00410     return conn_desc;
00411 }
00412 
00413 #ifdef CP_USE_SSL
00414 cp_connection_descriptor *cp_connection_descriptor_create_ssl(cp_socket *sock, 
00415                                                     struct sockaddr_in *addr, 
00416                                                     int fd, 
00417                                                     SSL *ssl)
00418 {
00419     cp_connection_descriptor *conn_desc = 
00420         cp_connection_descriptor_create(sock, addr, fd);
00421 
00422     if (conn_desc) conn_desc->ssl = ssl;
00423 
00424     return conn_desc;
00425 }
00426 #endif
00427 
00428 void cp_connection_descriptor_destroy(cp_connection_descriptor *conn_desc)
00429 {
00430     if (conn_desc)
00431     {
00432 #ifdef CP_USE_SSL
00433         if (conn_desc->ssl) 
00434             cp_socket_ssl_connection_close(conn_desc->sock, conn_desc->ssl);
00435         else
00436 #endif
00437         cp_socket_connection_close(conn_desc->sock, conn_desc->fd);
00438         free(conn_desc);
00439     }
00440 }
00441 
00442 
00443 cp_socket *cp_socket_create(int port, cp_socket_strategy strategy, void *fn)
00444 {
00445     cp_socket *sock;
00446 
00447     cp_socket_init();
00448 
00449     sock = calloc(1, sizeof(cp_socket));
00450     if (sock == NULL) 
00451     {
00452         cp_error(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate cp_socket (%d bytes)", sizeof(cp_socket));
00453         return NULL;
00454     }
00455 
00456     sock->port = port;
00457     sock->backlog = CPSOCKET_DEFAULT_BACKLOG;
00458     sock->delay.tv_sec = CPSOCKET_DEFAULT_DELAY_SEC;
00459     sock->delay.tv_usec = CPSOCKET_DEFAULT_DELAY_USEC;
00460     sock->strategy = strategy;
00461     sock->fds = 
00462         cp_hashlist_create_by_option(COLLECTION_MODE_DEEP, 10, cp_hash_int, 
00463                 cp_hash_compare_int, NULL, free, NULL, free);
00464     if (sock->fds == NULL)
00465     {
00466         cp_error(CP_MEMORY_ALLOCATION_FAILURE, 
00467                  "can\'t allocate cp_socket fd list");
00468         free(sock);
00469         return NULL;
00470     }
00471 
00472     switch (strategy)
00473     {
00474         case CPSOCKET_STRATEGY_CALLBACK: 
00475             sock->action.callback = (cp_socket_callback) fn; 
00476 //            sock->bufs = cp_hashlist_create(10, cp_hash_int, cp_hash_compare_int);
00477             break;
00478 
00479         case CPSOCKET_STRATEGY_THREADPOOL:
00480             sock->poolsize_min = CPSOCKET_THREADPOOL_DEFAULT_SIZE_MIN;
00481             sock->poolsize_max = CPSOCKET_THREADPOOL_DEFAULT_SIZE_MAX;
00482             sock->action.thread_fn = (cp_socket_thread_function) fn; 
00483             break;
00484     }
00485 
00486     sock->id = socket_reg_id++;
00487     cp_hashlist_append(socket_registry, &sock->id, sock);
00488 
00489     return sock;
00490 }
00491 
00492 #ifdef CP_USE_SSL
00493 cp_socket *cp_socket_create_ssl(int port, 
00494                                 cp_socket_strategy strategy, 
00495                                 void *fn,
00496                                 char *certificate_file,
00497                                 char *key_file,
00498                                 int verification_mode)
00499 {
00500     cp_socket *socket = cp_socket_create(port, strategy, fn);
00501     if (socket)
00502     {
00503         socket->ctx = get_ssl_ctx(certificate_file, key_file);
00504         if (socket->ctx == NULL)
00505         {
00506             cp_socket_delete(socket);
00507             return NULL;
00508         }
00509             
00510         socket->use_ssl = 1;
00511         SSL_CTX_set_verify(socket->ctx, verification_mode, NULL);
00512     }
00513     return socket;
00514 }
00515 #endif
00516 
00517 void cp_socket_set_backlog(cp_socket *socket, int backlog)
00518 {
00519     socket->backlog = backlog;
00520 }
00521 
00522 void cp_socket_set_delay(cp_socket *socket, struct timeval delay)
00523 {
00524     socket->delay = delay;
00525 }
00526 
00527 void cp_socket_set_delay_sec(cp_socket *socket, long sec)
00528 {
00529     socket->delay.tv_sec = sec;
00530 }
00531 
00532 void cp_socket_set_delay_usec(cp_socket *socket, long usec)
00533 {
00534     socket->delay.tv_usec = usec;
00535 }
00536 
00537 void cp_socket_set_poolsize_min(cp_socket *socket, int min)
00538 {
00539     socket->poolsize_min = min;
00540 }
00541 
00542 void cp_socket_set_poolsize_max(cp_socket *socket, int max)
00543 {
00544     socket->poolsize_max = max;
00545 }
00546 
00547 void cp_socket_set_owner(cp_socket *socket, void *owner)
00548 {
00549     socket->owner = owner;
00550 }
00551 
00552 void *cp_socket_add_shutdown_callback(cp_socket *sock, 
00553                                       void (*cb)(void *),
00554                                       void *prm)
00555 {
00556     cp_wrap *wrap = cp_wrap_new(prm, (cp_destructor_fn) cb);
00557 
00558     if (sock->shutdown_callback == NULL)
00559         sock->shutdown_callback = cp_vector_create(1);
00560 
00561     return cp_vector_add_element(sock->shutdown_callback, wrap);
00562 }
00563 
00564 void cp_socket_delete(cp_socket *sock)
00565 {
00566     if (sock)
00567     {
00568         sock->closing = 1;
00569         switch(sock->strategy)
00570         {
00571             case CPSOCKET_STRATEGY_THREADPOOL:
00572                 cp_thread_pool_stop(sock->tpool);
00573                 cp_thread_pool_destroy(sock->tpool);
00574                 break;
00575 
00576             case CPSOCKET_STRATEGY_CALLBACK:
00577                 {
00578                     cp_hashlist_iterator *itr;
00579                     cp_hashlist_entry *entry;
00580                     int *pfd;
00581 
00582                     itr = cp_hashlist_create_iterator(sock->fds, COLLECTION_LOCK_NONE);
00583 
00584                     while ((entry = cp_hashlist_iterator_next(itr)))
00585                     {
00586                         pfd = (int *) cp_hashlist_entry_get_key(entry);
00587                         cp_socket_connection_close(sock, *pfd);
00588                     }
00589 
00590                     cp_hashlist_iterator_destroy(itr);
00591                 }
00592                 break;
00593         }
00594 
00595 // #ifdef CP_USE_SSL
00596 //      if (sock->use_ssl)
00597 //          SSL_CTX_free(sock->ctx);
00598 // #endif
00599 
00600         if (sock->shutdown_callback)
00601             cp_vector_destroy_custom(sock->shutdown_callback, 
00602                                      (cp_destructor_fn) cp_wrap_delete);
00603 
00604         if (socket_registry)
00605             cp_hashlist_remove(socket_registry, &sock->id);
00606         cp_hashlist_destroy_custom(sock->fds, free, free);
00607         free(sock);
00608     }
00609 }
00610 
00616 int cp_socket_listen(cp_socket *sock)
00617 {
00618     struct sockaddr_in insock;
00619     char *errmsg;
00620     int yes = 1;
00621     int fd;
00622     int rc = -1;
00623 
00624     if (sock->strategy == CPSOCKET_STRATEGY_THREADPOOL)
00625     {
00626         sock->tpool = cp_thread_pool_create(sock->poolsize_min, 
00627                                          sock->poolsize_max);
00628 
00629         if (sock->tpool == NULL)
00630         {
00631             errmsg = "can\'t create cp_thread pool";
00632             goto LISTEN_ERROR;
00633         }
00634     }
00635 
00636     if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
00637     {
00638         /* socket may set:
00639          * EPROTONOSUPPORT: The protocol type or the specified protocol is not 
00640          *                  supported within this domain. 
00641          * EAFNOSUPPORT: The implementation does not support the specified 
00642          *               address family. 
00643          * ENFILE: Not enough kernel memory to allocate a new socket structure. 
00644          * EMFILE: Process file table overflow. 
00645          * EACCES: Permission to create a socket of the specified type and/or 
00646          *         protocol is denied. 
00647          * ENOMEM: Insufficient memory is available. The socket cannot be 
00648          *         created until sufficient resources are freed. 
00649          * EINVAL: Unknown protocol, or protocol family not available.  
00650          */
00651         rc = errno;
00652         errmsg = "socket";
00653         goto LISTEN_ERROR;
00654     }
00655 
00656 //  setnonblocking(fd);
00657 #ifdef TRACE    
00658     DEBUGMSG("got socket: fd %d\n", fd);
00659 #endif
00660     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
00661                     (char *) &yes, sizeof(int)) < 0)
00662     {
00663         errmsg = "setsockopt";
00664         goto LISTEN_ERROR;
00665     }
00666 
00667     sock->fd = fd;
00668 
00669     memset(&insock, 0, sizeof(struct sockaddr_in));
00670     insock.sin_port = htons((unsigned short) sock->port);
00671     insock.sin_family = AF_INET;
00672 
00673     if (bind(sock->fd, (struct sockaddr *) &insock, 
00674              sizeof(struct sockaddr_in)) < 0)
00675     {
00676         /* bind may set:
00677          * EBADF: sockfd is not a valid descriptor 
00678          * EINVAL: The socket is already bound to an address or the addrlen is 
00679          *         wrong
00680          * EACCES: The address is protected, and the user is not the 
00681          *         super-user or search permission is denied on a component of 
00682          *         the path prefix.  
00683          * ENOTSOCK: Argument is a descriptor for a file, not a socket.         
00684          * EROFS: The socket inode would reside on a read-only file system. 
00685          * EFAULT: my_addr points outside the user's accessible address space. 
00686          * ENAMETOOLONG: my_addr is too long. 
00687          * ENOENT: The file does not exist.  
00688          * ENOMEM: Insufficient kernel memory was available. 
00689          * ENOTDIR: A component of the path prefix is not a directory. 
00690          * ELOOP: Too many symbolic links were encountered in resolving my_addr 
00691          */
00692         rc = errno;
00693         errmsg = "cp_socket_listen: bind";
00694         goto LISTEN_ERROR;
00695     }
00696 
00697     if (listen(sock->fd, sock->backlog) < 0)
00698     {
00699         /* listen may set:
00700          * EADDRINUSE: Another socket is already listening on the same port. 
00701          * EBADF: The argument s is not a valid descriptor. 
00702          * ENOTSOCK: The argument s is not a socket. 
00703          * EOPNOTSUPP: The socket is not of a type that supports the listen 
00704          *             operation. 
00705          */
00706         rc = errno;
00707         errmsg = "listen";
00708         goto LISTEN_ERROR;
00709     }
00710     gettimeofday(&sock->created, NULL);
00711     sock->connections_served = 0;
00712 #ifdef DEBUG
00713     DEBUGMSG("listening on port %d (fd %d)\n", sock->port, sock->fd); //~~ debug
00714 #endif
00715 
00716     return 0;
00717 
00718 LISTEN_ERROR:
00719     cp_perror(CP_IO_ERROR, rc, "cp_socket_listen: failed on %s", errmsg); 
00720     return rc;
00721 }
00722 
00723 
00724 int cp_socket_select_callback_impl(cp_socket *sock)
00725 {
00726     fd_set fds;
00727     unsigned int *pfd;
00728     cp_hashlist_iterator *itr;
00729     cp_hashlist_entry *entry;
00730     int rc = -1;
00731 #ifdef CP_USE_SSL
00732     cp_hashtable *ssl_entry = NULL;
00733     
00734     if (sock->use_ssl)
00735         ssl_entry = cp_hashtable_create(10, cp_hash_int, cp_hash_compare_int);
00736 #endif
00737 
00738     itr = cp_hashlist_create_iterator(sock->fds, COLLECTION_LOCK_NONE);
00739 
00740     while (!sock->closing)
00741     {
00742         FD_ZERO(&fds);
00743         
00744         sock->fdn = sock->fd;
00745 
00746         FD_SET(sock->fd, &fds);
00747         
00748         cp_hashlist_iterator_head(itr);
00749         while ((entry = cp_hashlist_iterator_next(itr)))
00750         {
00751             pfd = (unsigned int *) cp_hashlist_entry_get_key(entry);
00752             FD_SET(*pfd, &fds);
00753             if (sock->fdn < *pfd) sock->fdn = *pfd;
00754         }
00755 
00756         if ((rc = select(sock->fdn + 1, &fds, NULL, NULL, &sock->delay)) < 0)
00757         {
00758             cp_perror(CP_IO_ERROR, errno, 
00759                 "cp_socket_select_callback_impl: select failed");
00760 
00761             sock->closing = 1;
00762             break;
00763         }
00764 
00765         if (rc == 0) continue;
00766 
00767         if (FD_ISSET(sock->fd, &fds)) /* handle new connections */
00768         {
00769             int newconn;
00770             unsigned int l;
00771             struct sockaddr_in *insock = calloc(1, sizeof(struct sockaddr_in));
00772 
00773             newconn = accept(sock->fd, (struct sockaddr *) insock, &l);
00774             if (newconn < 0)
00775             {
00776                 cp_perror(CP_IO_ERROR, errno, 
00777                     "cp_socket_select_callback_impl: accept failed");
00778                 free(insock);
00779                 if (newconn == EBADF || 
00780 #ifdef ENOTSOCK
00781                     newconn == ENOTSOCK || 
00782 #endif 
00783 #ifdef EOPNOTSUPP
00784                     newconn == EOPNOTSUPP || 
00785 #endif
00786                     newconn == EINVAL || 
00787                     newconn == EFAULT || newconn == EPERM)
00788                     break; 
00789                 /* else if (newconn == EAGAIN || newconn == EINTR || 
00790                  *          newconn == ECONNABORTED || newconn == EMFILE || 
00791                  *          newconn == ENFILE || newconn == ENOMEM ||
00792                  *          newconn == EPROTO) 
00793                  */
00794                 continue;
00795             }
00796 
00797 #ifdef CP_USE_SSL
00798             if (sock->use_ssl)
00799             {
00800                 SSL *ssl = SSL_new(sock->ctx);
00801                 SSL_set_fd(ssl, newconn);
00802                 rc = SSL_accept(ssl);
00803                 if (rc <= 0)
00804                 {
00805                     int err = SSL_get_error(ssl, rc);
00806                     cp_error(CP_SSL_HANDSHAKE_FAILED, "cp_socket_select_callback_impl: %s", ERR_reason_error_string(err));
00807                     SSL_free(ssl);
00808                     free(insock);
00809                     continue;
00810                 }
00811                 cp_hashtable_put(ssl_entry, &newconn, ssl);
00812             }
00813 #endif
00814 
00815             cp_hashlist_append(sock->fds, &newconn, insock);
00816         }
00817 
00818         cp_hashlist_iterator_head(itr);
00819         while ((entry = cp_hashlist_iterator_next(itr)))
00820         {
00821             pfd = (unsigned int *) cp_hashlist_entry_get_key(entry);
00822             if (FD_ISSET(*pfd, &fds))
00823             {
00824 #ifdef CP_USE_SSL
00825                 if (sock->use_ssl)
00826                 {
00827                     SSL *ssl = cp_hashtable_get(ssl_entry, pfd);
00828                     (*sock->action.ssl_callback)(sock, ssl);
00829                 }
00830                 else
00831 #endif
00832                 (*sock->action.callback)(sock, *pfd);
00833             }
00834         }
00835     }
00836 
00837     cp_hashlist_iterator_destroy(itr);
00838 
00839 #ifdef CP_USE_SSL
00840     if (sock->use_ssl)
00841         cp_hashtable_destroy_custom(ssl_entry, NULL, 
00842                                     (cp_destructor_fn)SSL_free);
00843 #endif
00844 
00845     return 0;
00846 }
00847 
00848 int cp_socket_select_threadpool_impl(cp_socket *sock)
00849 {
00850     fd_set fds;
00851     int rc;
00852     struct timeval delay;
00853 
00854     while (!sock->closing)
00855     {
00856         FD_ZERO(&fds);
00857         
00858         sock->fdn = sock->fd;
00859 
00860         FD_SET(sock->fd, &fds);
00861 
00862         delay = sock->delay;
00863 
00864         rc = select(sock->fdn + 1, &fds, NULL, NULL, &delay);
00865         if (rc < 0)
00866         {
00867             /* select may set:
00868              * EBADF: An invalid file descriptor was given in one of the sets. 
00869              * EINTR: A non blocked signal was caught. 
00870              * EINVAL: n is negative or the value contained within timeout is 
00871              *         invalid. 
00872              * ENOMEM: select was unable to allocate memory for internal tables
00873              */
00874             rc = errno;
00875             /* ignore interrupts unless shutting down*/
00876             if (rc == EINTR || rc == EAGAIN) 
00877             {
00878                 if (stopping_all) //~~
00879                 {
00880                     sock->closing = 1;
00881                     break;
00882                 }
00883                 else
00884                     continue;
00885             }
00886 
00887             cp_perror(CP_IO_ERROR, rc, 
00888                 "cp_socket_select_threadpool_impl: select failed");
00889             sock->closing = 1;
00890             break;
00891         }
00892             
00893         if (rc == 0) continue;
00894 
00895         if (FD_ISSET(sock->fd, &fds)) /* handle new connections */
00896         {
00897             int *newconn = malloc(sizeof(int));
00898             cp_connection_descriptor *conn_desc;
00899             unsigned int l;
00900             struct sockaddr_in *insock = calloc(1, sizeof(struct sockaddr_in));
00901             l = sizeof(struct sockaddr_in);
00902 
00903             *newconn = accept(sock->fd, (struct sockaddr *) insock, &l);
00904             if (*newconn < 0)
00905             {
00906                 /* accept might set:
00907                  * EAGAIN: The socket is marked non-blocking and no connections
00908                  *         are present to be accepted.
00909                  * EBADF: The descriptor is invalid.         
00910                  * ENOTSOCK: The descriptor references a file, not a socket. 
00911                  * EOPNOTSUPP: The referenced socket is not of type SOCK_STREAM
00912                  * EINTR: The system call was interrupted by a signal that was 
00913                  *        caught before a valid connection arrived. 
00914                  * ECONNABORTED: A connection has been aborted. 
00915                  * EINVAL: Socket is not listening for connections. 
00916                  * EMFILE: The per-process limit of open file descriptors has 
00917                  *         been reached. 
00918                  * ENFILE: The system maximum for file descriptors has been 
00919                  *         reached. 
00920                  * EFAULT: The addr parameter is not in a writable part of the 
00921                  *         user address space. 
00922                  * ENOMEM: Not enough free memory. This often means that the 
00923                  *         memory allocation is limited by the socket buffer 
00924                  *         limits, not by the system memory. 
00925                  * EPROTO: Protocol error. 
00926                  * EPERM: Firewall rules forbid connection.  
00927                  */
00928                 rc = errno;
00929                 if (!(sock->closing 
00930 #ifdef ECONNABORTED
00931                     && rc == ECONNABORTED
00932 #endif
00933                     ))
00934                     cp_perror(CP_IO_ERROR, rc, 
00935                         "cp_socket_select_threadpool_impl: accept failed");
00936                 free(insock);
00937                 free(newconn);
00938                 if (rc == EBADF || 
00939 #ifdef ENOTSOCK
00940                     rc == ENOTSOCK || 
00941 #endif
00942 #ifdef EOPNOTSUPP
00943                     rc == EOPNOTSUPP || 
00944 #endif
00945                     rc == EINVAL || rc == EFAULT || rc == EPERM)
00946                     break; 
00947                 /* else if (rc == EAGAIN || rc == EINTR || rc == ECONNABORTED 
00948                  *          || rc == EMFILE || rc == ENFILE || rc == ENOMEM ||
00949                  *          rc == EPROTO) 
00950                  */
00951                 continue;
00952             }
00953 
00954             sock->connections_served++;
00955 #ifdef __TRACE__
00956             DEBUGMSG("adding connection on fd %d (%lX)", *newconn, (long) insock);
00957             DEBUGMSG("connection from %s", inet_ntoa(insock->sin_addr));
00958 #endif
00959         
00960 #ifdef CP_USE_SSL
00961             if (sock->use_ssl)
00962             {
00963                 SSL *ssl = SSL_new(sock->ctx);
00964                 SSL_set_fd(ssl, *newconn);
00965                 rc = SSL_accept(ssl);
00966                 if (rc <= 0)
00967                 {
00968                     int err = SSL_get_error(ssl, rc);
00969                     cp_error(CP_SSL_HANDSHAKE_FAILED, "cp_socket_select_callback_impl: %s", ERR_reason_error_string(err));
00970                     SSL_free(ssl);
00971                     free(insock);
00972                     continue;
00973                 }
00974 
00975                 conn_desc = cp_connection_descriptor_create_ssl(sock, insock, 
00976                                                                 *newconn, ssl);
00977             }
00978             else
00979 #endif
00980             conn_desc = cp_connection_descriptor_create(sock, insock, *newconn);
00981             gettimeofday(&conn_desc->created, NULL);
00982             cp_hashlist_append(sock->fds, newconn, insock);
00983 #ifdef __TRACE__
00984             cp_info("added: %lX (table: %lX)", (long) cp_hashlist_get(sock->fds, newconn), (long) sock->fds);
00985 #endif
00986             cp_thread_pool_get(sock->tpool, sock->action.thread_fn, conn_desc);
00987         
00988 #ifdef __TRACE__
00989             cp_info("dispatched; addr: %lX (table: %lX)", (long) cp_hashlist_get(sock->fds, newconn), (long) sock->fds);
00990 #endif
00991         }
00992     }
00993 
00994     return 0;
00995 }
00996 
00997 int cp_socket_select(cp_socket *sock)
00998 {
00999     int rc = 0;
01000 
01001     switch (sock->strategy)
01002     {
01003         case CPSOCKET_STRATEGY_CALLBACK:
01004             rc = cp_socket_select_callback_impl(sock);
01005             break;
01006 
01007         case CPSOCKET_STRATEGY_THREADPOOL:
01008             rc = cp_socket_select_threadpool_impl(sock);
01009             break;
01010     }
01011 
01012     return rc;
01013 }
01014 
01015 #ifdef CP_USE_SSL
01016 int cp_socket_ssl_connection_close(cp_socket *sock, SSL *ssl)
01017 {
01018     int rc = 0;
01019     int fd;
01020     struct sockaddr_in *insock;
01021 
01022     fd = SSL_get_fd(ssl);
01023     setnonblocking(fd);
01024     insock = (struct sockaddr_in *) cp_hashlist_get(sock->fds, &fd);
01025     if (insock)
01026     {
01027         rc = SSL_shutdown(ssl);
01028         if (rc == 0)
01029             rc = SSL_shutdown(ssl); 
01030         
01031         if (shutdown(fd, SHUT_WR) < 0)
01032         {
01033             /* shutdown might set:
01034              * EBADF:    s is not a valid descriptor. 
01035              * ENOTSOCK: s is a file, not a socket. 
01036              * ENOTCONN: The specified socket is not connected. 
01037              */
01038             cp_perror(CP_IO_ERROR, errno, 
01039                       "shutdown error on connection from %s", 
01040                        inet_ntoa(insock->sin_addr));
01041         }
01042 
01043         SSL_free(ssl);
01044         if (close(fd) < 0)
01045         {
01046             /* close might set:
01047              * EBADF: fd isn't a valid open file descriptor. 
01048              * EINTR: The close() call was interrupted by a signal. 
01049              * EIO:   An I/O error occurred. 
01050              */
01051              struct sockaddr_in *insock;
01052              rc = errno;
01053              insock = (struct sockaddr_in *) cp_hashlist_get(sock->fds, &fd);
01054              cp_perror(CP_IO_ERROR, rc, "error closing connection to %s", 
01055                        inet_ntoa(insock->sin_addr));
01056         }
01057         
01058         cp_hashlist_remove_deep(sock->fds, &fd);
01059     }
01060 
01061     return rc;
01062 }
01063 #endif
01064 
01065 int cp_socket_connection_close(cp_socket *sock, int fd)
01066 {
01067     struct sockaddr_in *insock;
01068     int rc = 0;
01069 
01070 #ifdef __TRACE__
01071     DEBUGMSG("closing fd %d (table: %lX)", fd, (long) sock->fds);
01072 #endif
01073     insock = (struct sockaddr_in *) cp_hashlist_get(sock->fds, &fd);
01074     if (insock) 
01075     {
01076 #ifdef __TRACE__
01077     DEBUGMSG("closing connection to %s", inet_ntoa(insock->sin_addr));
01078 #endif
01079         if (shutdown(fd, SHUT_RDWR) < 0)
01080             cp_perror(CP_IO_ERROR, errno, "shutdown error on connection to %s", 
01081                       inet_ntoa(insock->sin_addr));
01082 
01083         if ((rc = close(fd)) < 0)
01084             cp_perror(CP_IO_ERROR, rc, "error closing connection to %s", 
01085                       inet_ntoa(insock->sin_addr));
01086         
01087         cp_hashlist_remove_deep(sock->fds, &fd);
01088     }
01089     
01090     return rc;
01091 }
01092 
01093 int cp_connection_descrpitor_read(cp_connection_descriptor *desc, 
01094                                   char *buf, int len)
01095 {
01096     int rc;
01097 
01098 #ifdef CP_USE_SSL
01099     if (desc->sock->use_ssl)
01100     {
01101         rc = SSL_read(desc->ssl, buf, len);
01102         if (rc <= 0)
01103         {
01104             int err = SSL_get_error(desc->ssl, rc);
01105             const char *reason = ERR_reason_error_string(err);
01106             cp_error(CP_IO_ERROR, "write failed: %s", reason ? reason : ssl_err_inf(err));
01107         }
01108     }
01109     else
01110 #endif /* CP_USE_SSL */
01111     rc = read(desc->fd, buf, len);
01112 
01113     if (rc > 0) desc->bytes_read += rc;
01114 
01115     return rc;
01116 }
01117 
01118 int cp_connection_descriptor_write(cp_connection_descriptor *desc, 
01119                                    char *buf, int len)
01120 {
01121     int rc;
01122 #ifdef CP_USE_SSL
01123     if (desc->sock->use_ssl)
01124     {
01125         rc = SSL_write(desc->ssl, buf, len);
01126         if (rc <= 0)
01127         {
01128             int err = SSL_get_error(desc->ssl, rc);
01129             const char *reason = ERR_reason_error_string(err);
01130             cp_error(CP_IO_ERROR, "write failed: %s", reason ? reason : ssl_err_inf(err));
01131         }
01132     }
01133     else
01134 #endif
01135     rc = send(desc->fd, buf, len, 0);
01136 
01137     if (rc > 0) desc->bytes_sent += rc;
01138 
01139     return rc;
01140 }
01141 

Generated on Mon Dec 5 23:00:22 2011 for cprops by  doxygen 1.4.7