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