1 /* hiinit.c - Hiquu I/O Engine Initialization 2 * Copyright (c) 2006,2012 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved. 3 * This is confidential unpublished proprietary source code of the author. 4 * NO WARRANTY, not even implied warranties. Contains trade secrets. 5 * Distribution prohibited unless authorized in writing. See file COPYING. 6 * Special grant: hiios.c may be used with zxid open source project under 7 * same licensing terms as zxid itself. 8 * $Id$ 9 * 10 * 15.4.2006, created over Easter holiday --Sampo 11 * 16.8.2012, modified license grant to allow use with ZXID.org --Sampo 12 * 6.9.2012, added support for TLS and SSL --Sampo 13 * 17.9.2012, factored init code to its own file --Sampo 14 */ 15 16 #include "platform.h" 17 18 #include <pthread.h> 19 #include <memory.h> 20 #include <stdlib.h> 21 //#include <unistd.h> 22 #include <fcntl.h> 23 #include <sys/types.h> 24 #include <sys/socket.h> 25 #include <errno.h> 26 #include <string.h> 27 28 #include <zx/zxid.h> 29 #include "akbox.h" 30 #include "hiproto.h" 31 #include "hiios.h" 32 #include "errmac.h" 33 34 extern zxid_conf* zxbus_cf; 35 extern int errmac_debug; 36 #ifdef MUTEX_DEBUG 37 extern pthread_mutexattr_t MUTEXATTR_DECL; 38 #endif 39 40 /* Called by: thread_loop, zxbusd_main */ 41 void hi_hit_init(struct hi_thr* hit) 42 { 43 memset(hit, 0, sizeof(struct hi_thr)); 44 hit->self = pthread_self(); 45 } 46 47 #ifdef USE_OPENSSL 48 //int zxbus_cert_verify_cb(X509_STORE_CTX* st_ctx, void* arg) { zxid_conf* cf = arg; return 0; } 49 /* Called by: */ 50 static int zxbus_verify_cb(int preverify_ok, X509_STORE_CTX* st_ctx) 51 { 52 //X509* err_cert = X509_STORE_CTX_get_current_cert(st_ctx); 53 int err; 54 55 if (preverify_ok) 56 return 1; /* Always Good! */ 57 err = X509_STORE_CTX_get_error(st_ctx); 58 D("verify err %d %s", err, X509_verify_cert_error_string(err)); 59 if (ONE_OF_4(err, 60 X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, 61 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, 62 X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, 63 X509_V_ERR_CERT_UNTRUSTED)) 64 return 1; /* ignore errors relating cert not being trusted */ 65 ERR("verify fail %d %s", err, X509_verify_cert_error_string(err)); 66 return 0; 67 } 68 69 /* Called by: */ 70 static void zxbus_info_cb(const SSL *ssl, int where, int ret) 71 { 72 const char *str; 73 74 if ((where & ~SSL_ST_MASK) & SSL_ST_CONNECT) str="SSL_connect"; 75 else if ((where & ~SSL_ST_MASK) & SSL_ST_ACCEPT) str="SSL_accept"; 76 else str="undefined"; 77 78 if (where & SSL_CB_LOOP) { 79 D("ssl_%p %s:%s", ssl, str, SSL_state_string_long(ssl)); 80 } else if (where & SSL_CB_ALERT) { 81 str=(where & SSL_CB_READ)?"read":"write"; 82 D("ssl_%p SSL3 alert %s:%s:%s", ssl, str, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); 83 } else if (where & SSL_CB_EXIT) { 84 if (ret == 0) 85 D("ssl_%p %s:failed in %s", ssl, str, SSL_state_string_long(ssl)); 86 else if (ret < 0) 87 D("ssl_%p %s:error in %s", ssl, str, SSL_state_string_long(ssl)); 88 } 89 } 90 #endif 91 92 /*() Allocate io structure (connection) pool and global PDU 93 * pool, from which per thread pools will be plensihed - see 94 * hi_pdu_alloc() - and initialize syncronization primitives. */ 95 96 /* Called by: zxbusd_main */ 97 struct hiios* hi_new_shuffler(struct hi_thr* hit, int nfd, int npdu, int nch, int nthr) 98 { 99 int i; 100 struct hiios* shf; 101 102 ZMALLOC(shf); 103 hit->shf = shf; 104 shf->nthr = nthr; 105 106 /* Allocate global pool of PDUs (as a blob) */ 107 108 ZMALLOCN(shf->pdu_buf_blob, sizeof(struct hi_pdu)*npdu); 109 shf->max_pdus = npdu; 110 for (i = npdu - 1; i; --i) { /* Link the PDUs to a list. */ 111 shf->pdu_buf_blob[i-1].qel.n = (struct hi_qel*)(shf->pdu_buf_blob + i); 112 pthread_mutex_init(&shf->pdu_buf_blob[i].qel.mut.ptmut, MUTEXATTR); 113 } 114 pthread_mutex_init(&shf->pdu_buf_blob[0].qel.mut.ptmut, MUTEXATTR); 115 shf->free_pdus = shf->pdu_buf_blob; /* Make PDUs available as free. */ 116 pthread_mutex_init(&shf->pdu_mut.ptmut, MUTEXATTR); 117 118 /* Allocate ios array as a blob and prepare them for I/O (by allocating cur_pdu) */ 119 120 ZMALLOCN(shf->ios, sizeof(struct hi_io) * nfd); 121 shf->max_ios = nfd; 122 for (i = 0; i < nfd; ++i) { 123 pthread_mutex_init(&shf->ios[i].qel.mut.ptmut, MUTEXATTR); 124 if (!(shf->ios[i].cur_pdu = hi_pdu_alloc(hit, "new_shuffler"))) { 125 ERR("Out of PDUs when preparing cur_pdu for each I/O object. Use -npdu to specify a value at least twice the value of -nfd. Current values: npdu=%d, nfd=%d", npdu, nfd); 126 exit(1); 127 } 128 shf->ios[i].cur_pdu->fe = &shf->ios[i]; 129 } 130 131 pthread_cond_init(&shf->todo_cond, 0); 132 pthread_mutex_init(&shf->todo_mut.ptmut, MUTEXATTR); 133 134 shf->poll_tok.kind = HI_POLLT; /* Permanently labeled as poll_tok (there is only 1) */ 135 shf->poll_tok.proto = HIPROTO_POLL_ON; /* Mark poll token as available */ 136 137 shf->max_evs = MIN(nfd, 1024); 138 #ifdef LINUX 139 shf->ep = epoll_create(nfd); 140 if (shf->ep == -1) { perror("epoll"); exit(1); } 141 ZMALLOCN(shf->evs, sizeof(struct epoll_event) * shf->max_evs); 142 #endif 143 #ifdef SUNOS 144 shf->ep = open("/dev/poll", O_RDWR); 145 if (shf->ep == -1) { perror("open(/dev/poll)"); exit(1); } 146 ZMALLOCN(shf->evs, sizeof(struct pollfd) * shf->max_evs); 147 #endif 148 #if defined(MACOSX) || defined(FREEBSD) 149 shf->ep = kqueue(); 150 if (shf->ep == -1) { perror("kqueue()"); exit(1); } 151 ZMALLOCN(shf->evs, sizeof(struct kevent) * shf->max_evs); 152 #endif 153 154 pthread_mutex_init(&shf->ent_mut.ptmut, MUTEXATTR); 155 156 shf->max_chs = nch; 157 ZMALLOCN(shf->chs, sizeof(struct hi_ch) * shf->max_chs); 158 159 #ifdef USE_OPENSSL 160 SSL_load_error_strings(); 161 SSL_library_init(); 162 #if 0 163 shf->ssl_ctx = SSL_CTX_new(SSLv23_method()); 164 #else 165 shf->ssl_ctx = SSL_CTX_new(TLSv1_method()); 166 #endif 167 if (!shf->ssl_ctx) { 168 ERR("SSL context initialization problem %d", 0); 169 zx_report_openssl_err("new_shuffler-ssl_ctx"); 170 return 0; 171 } 172 INFO("OpenSSL header-version(%lx) lib-version(%lx)(%s) %s %s %s %s", OPENSSL_VERSION_NUMBER, SSLeay(), SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS), SSLeay_version(SSLEAY_BUILT_ON), SSLeay_version(SSLEAY_PLATFORM), SSLeay_version(SSLEAY_DIR)); 173 if (errmac_debug>1) 174 SSL_CTX_set_info_callback(shf->ssl_ctx, zxbus_info_cb); 175 176 /*SSL_CTX_set_mode(shf->ssl_ctx, SSL_MODE_AUTO_RETRY); R/W only return w/complete. We use nonblocking I/O. */ 177 178 /* Verification strategy: do not attempt verification at SSL layer. Instead 179 * check the result afterwards against metadata based cert. However, 180 * we need to specify SSL_VERIFY_PEER to cause server to ask for ClientTLS. 181 * Normally this would cause the verification to happen, but we supply 182 * a callback that effectively causes verification to pass in any case, 183 * so that we postpone it to the moment when we see CONNECT. */ 184 SSL_CTX_set_verify(shf->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, zxbus_verify_cb); 185 //SSL_CTX_set_cert_verify_callback(shf->ssl_ctx, zxbus_cert_verify_cb, cf); 186 187 /*SSL_CTX_load_verify_locations() SSL_CTX_set_client_CA_list(3) SSL_CTX_set_cert_store(3) */ 188 if (!zxbus_cf->enc_cert) 189 zxbus_cf->enc_cert = zxid_read_cert(zxbus_cf, "enc-nopw-cert.pem"); 190 if (!zxbus_cf->enc_pkey) 191 zxbus_cf->enc_pkey = zxid_read_private_key(zxbus_cf, "enc-nopw-cert.pem"); 192 if (!SSL_CTX_use_certificate(shf->ssl_ctx, zxbus_cf->enc_cert)) { 193 ERR("SSL certificate problem %d", 0); 194 zx_report_openssl_err("new_shuffler-cert"); 195 return 0; 196 } 197 if (!SSL_CTX_use_PrivateKey(shf->ssl_ctx, zxbus_cf->enc_pkey)) { 198 ERR("SSL private key problem %d", 0); 199 zx_report_openssl_err("new_shuffler-privkey"); 200 return 0; 201 } 202 if (!SSL_CTX_check_private_key(shf->ssl_ctx)) { 203 ERR("SSL certificate-private key consistency problem %d", 0); 204 zx_report_openssl_err("new_shuffler-chk-privkey"); 205 return 0; 206 } 207 #endif 208 return shf; 209 } 210 211 /* EOF -- hiinit.c */ 212