Skip to content

Instantly share code, notes, and snippets.

@roxlu
Created April 5, 2014 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/f01f95eaa02e7276b4c4 to your computer and use it in GitHub Desktop.
Save roxlu/f01f95eaa02e7276b4c4 to your computer and use it in GitHub Desktop.
- krx_https_on_new_connection(), c: 0x7feffa00b000
----- HANDSHAKE START - before/accept initialization - UNKWN
----- ACCEPT LOOP - before/accept initialization - UNKWN
----- ACCEPT LOOP - SSLv3 read client hello A - 3RCH_A
----- ACCEPT LOOP - SSLv3 write server hello A - 3WSH_A
----- ACCEPT LOOP - SSLv3 write certificate A - 3WSC_A
----- ACCEPT LOOP - SSLv3 write certificate reques - 3WCR_A
----- ACCEPT LOOP - SSLv3 flush data - 3FLUSH
----- ACCEPT LOOP - SSLv3 read client certificate - 3RCC_A
----- CONNECT EXIT - SSLv3 read client certificate - 3RCC_A
----- ACCEPT LOOP - SSLv3 read client certificate - 3RCC_A
----- ACCEPT LOOP - SSLv3 read client key exchange - 3RCKEA
----- ACCEPT LOOP - SSLv3 read finished A - 3RFINA
----- ACCEPT LOOP - SSLv3 write change cipher spec - 3WCCSA
----- ACCEPT LOOP - SSLv3 write finished A - 3WFINA
----- ACCEPT LOOP - SSLv3 flush data - 3FLUSH
----- HANDSHAKE DONE - SSL negotiation finished succe - SSLOK
----- ACCEPT LOOP - SSL negotiation finished succe - SSLOK
----- CONNECT EXIT - SSL negotiation finished succe - SSLOK
Error: krx_https_http_on_body(), failed to parse incoming json.
Written: 61, len: 61
----- READ ALERT - SSL negotiation finished succe - SSLOK
----- WRITE ALERT - SSL negotiation finished succe - SSLOK
- krx_https_conn_read(), 0x7feffa00b000, status: end of file
- krx_https_close_connection(): 0x7feffa00b000
- krx_https_conn_on_closed(): 0x7feffa00b000
- krx_https_conn_shutdown(): 0x7feffa00b000
krx_https_on_new_connection(), c: 0x7feffa00b170
----- HANDSHAKE START - before/accept initialization - UNKWN
----- ACCEPT LOOP - before/accept initialization - UNKWN
----- ACCEPT LOOP - SSLv3 read client hello A - 3RCH_A
----- ACCEPT LOOP - SSLv3 write server hello A - 3WSH_A
----- ACCEPT LOOP - SSLv3 write certificate A - 3WSC_A
----- ACCEPT LOOP - SSLv3 write certificate reques - 3WCR_A
----- ACCEPT LOOP - SSLv3 flush data - 3FLUSH
----- ACCEPT LOOP - SSLv3 read client certificate - 3RCC_A
----- CONNECT EXIT - SSLv3 read client certificate - 3RCC_A
----- READ ALERT - SSLv3 read client certificate - 3RCC_A
----- WRITE ALERT - SSLv3 read client certificate - 3RCC_A
-- krx_ssl_info_callback: error occured.
- krx_https_conn_read(), 0x7feffa00b170, status: end of file
- krx_https_close_connection(): 0x7feffa00b170
- krx_https_on_new_connection(), c: 0x7feffa00b2e0
- krx_https_conn_on_closed(): 0x7feffa00b170
- krx_https_conn_shutdown(): 0x7feffa00b170
--
----- HANDSHAKE START - before/accept initialization - UNKWN
----- ACCEPT LOOP - before/accept initialization - UNKWN
----- ACCEPT LOOP - SSLv3 read client hello A - 3RCH_A
----- ACCEPT LOOP - SSLv3 write server hello A - 3WSH_A
----- ACCEPT LOOP - SSLv3 write certificate A - 3WSC_A
----- ACCEPT LOOP - SSLv3 write certificate reques - 3WCR_A
----- ACCEPT LOOP - SSLv3 flush data - 3FLUSH
----- ACCEPT LOOP - SSLv3 read client certificate - 3RCC_A
----- CONNECT EXIT - SSLv3 read client certificate - 3RCC_A
----- READ ALERT - SSLv3 read client certificate - 3RCC_A
----- WRITE ALERT - SSLv3 read client certificate - 3RCC_A
-- krx_ssl_info_callback: error occured.
- krx_https_conn_read(), 0x7feffa00b2e0, status: end of file
- krx_https_close_connection(): 0x7feffa00b2e0
- krx_https_conn_on_closed(): 0x7feffa00b2e0
- krx_https_conn_shutdown(): 0x7feffa00b2e0
#include "krx_https.h"
/* --------------------------------------------------------------------------- */
static int krx_https_on_message_begin(http_parser* p);
static int krx_https_on_url(http_parser* p, const char* at, size_t length);
static int krx_https_on_status(http_parser* p, const char* at, size_t length);
static int krx_https_on_header_field(http_parser* p, const char* at, size_t length);
static int krx_https_on_header_value(http_parser* p, const char* at, size_t length);
static int krx_https_on_headers_complete(http_parser* p);
static int krx_https_on_body(http_parser* p, const char* at, size_t length);
static int krx_https_on_message_complete(http_parser* p);
static uv_buf_t krx_https_alloc_buffer(uv_handle_t* handle, size_t nbytes);
static int krx_https_conn_send(krx_https_conn* c, uint8_t* buf, int len);
static void krx_https_conn_on_write(uv_write_t* req, int status);
static void krx_https_conn_read(uv_stream_t* stream, ssize_t nbytes, uv_buf_t buf);
static int krx_https_conn_init(krx_https* k, krx_https_conn* c);
static int krx_https_conn_shutdown(krx_https_conn* c); /* cleans up allocated memory, state, etc.. so it can be reused again */
static void krx_https_conn_on_closed(uv_handle_t* handle);
static void krx_https_on_new_connection(uv_stream_t* server, int status);
static void krx_https_ssl_info_callback(const SSL* ssl, int where, int ret);
static int krx_https_ssl_create(krx_https* k, krx_https_conn* c);
static int krx_https_ssl_verify_peer(int ok, X509_STORE_CTX* ctx);
static int krx_https_ssl_create_ctx(krx_https* k, const char* certfile, const char* kefile);
static int krx_https_ssl_check_output_buffer(krx_https_conn* c);
static int krx_https_ssl_check_input_buffer(krx_https_conn* c);
/* --------------------------------------------------------------------------- */
static int krx_https_on_message_begin(http_parser* p) {
return 0;
}
static int krx_https_on_url(http_parser* p, const char* at, size_t length) {
return 0;
}
static int krx_https_on_status(http_parser* p, const char* at, size_t length) {
return 0;
}
static int krx_https_on_header_field(http_parser* p, const char* at, size_t length) {
return 0;
}
static int krx_https_on_header_value(http_parser* p, const char* at, size_t length) {
return 0;
}
static int krx_https_on_headers_complete(http_parser* p) {
return 0;
}
static int krx_https_on_body(http_parser* p, const char* at, size_t length) {
krx_https_conn* c = (krx_https_conn*)p->data;
if(!c) {
printf("Error: no data pointer set on http parser.\n");
return -5;
}
if(c->k && c->k->on_body) {
c->k->on_body(c, (uint8_t*)at, length);
}
return 0;
}
static int krx_https_on_message_complete(http_parser* p) {
const char* resp = "HTTP/1.0 200 OK\r\n"
"Content-Length: 4\r\n"
"Connection:Close\r\n"
"\r\n"
"test";
krx_https_conn* c = (krx_https_conn*)p->data;
krx_https_send_data(c, (uint8_t*)resp, strlen(resp)+1);
return 0;
}
/* --------------------------------------------------------------------------- */
static uv_buf_t krx_https_alloc_buffer(uv_handle_t* handle, size_t nbytes) {
char* p = malloc(nbytes);
if(!p) {
printf("Error: krx_https_alloc_buffer(), cannot allocate %ld bytes.\n", nbytes);
exit(1);
}
return uv_buf_init(p, nbytes);
}
static void krx_https_conn_on_write(uv_write_t* req, int status) {
free(req);
}
static int krx_https_conn_send(krx_https_conn* c, uint8_t* buf, int len) {
uv_write_t* req = NULL;
int r = -1;
/* validate input */
if(!c) {
printf("Error: krx_https_conn_send, invalid pointer.\n");
free(buf);
buf = NULL;
return -1;
}
/* create a write request */
req = (uv_write_t*)malloc(sizeof(uv_write_t));
if(!req) {
printf("Error: krx_https_conn_send(), cannot alloc req.\n");
free(buf);
buf = NULL;
return -2;
}
req->data = c;
uv_buf_t write_buf = uv_buf_init((char*)buf, len);
r = uv_write(req, (uv_stream_t*)&c->client, &write_buf, 1, krx_https_conn_on_write);
if(r != 0) {
printf("Error: something went wrong with writing the data to connection.\n");
/* @todo(roxlu): free some things here?? */
free(write_buf.base);
buf = NULL;
return -3;
}
/* @todo(roxlu): shouldn't this be free'd in the on_write cb? */
free(write_buf.base);
buf = NULL;
return len;
}
static int krx_https_ssl_check_output_buffer(krx_https_conn* c) {
if(!c) {
printf("Error: krx_https_ssl_check_output_buffer(), invalid pointer.\n");
return -1;
}
if(!c->ssl) {
printf("Error: krx_https_ssl_check_output_buffer(), invalid SSL pointer.\n");
return -2;
}
/* check if there is data in the output bio. */
int pending = BIO_ctrl_pending(c->out_bio);
if(pending > 0) {
uint8_t* buffer = (uint8_t*)malloc(pending); /* is free'd after write, @todo(roxlu): make sure it is! */
if(!buffer) {
printf("Error: cannot allocate memory for SSL data.\n");
return -3;
}
int nread = BIO_read(c->out_bio, buffer, pending);
int nsend = krx_https_conn_send(c, buffer, nread);
if(nsend != nread) {
printf("Error: krx_https_ssl_check_output_buffer(), didn't sent the complete output buffer: %d <> %d\n", nread, nsend);
return -4;
}
}
return 0;
}
static int krx_https_ssl_check_input_buffer(krx_https_conn* c) {
int r = 0;
if(!c || !c->ssl) {
printf("Error: krx_https_ssl_check_input_buffer(), invalid pointers.\n");
return -1;
}
int pending = BIO_ctrl_pending(c->in_bio);
if(pending <= 0) {
return 0;
}
uint8_t* buf = malloc(pending);
if(!buf) {
printf("Error: krx_https_ssl_check_input_buffer(), cannot allocate temp buffer.\n");
return -2;
}
#if 0
int r = SSL_read(c->ssl, buf, pending);
if(r < 0) {
printf("Error: krx_https_ssl_check_input_buffer(), cannot SSL_read().\n");
free(buf);
buf = NULL;
return -3;
}
#else
int nread = 0;
while(pending > 0) {
int r = SSL_read(c->ssl, buf + nread, pending);
if(r <= 0) {
break;
}
nread += r;
pending -= r;
}
r = nread;
#endif
#if 0
for(int i = 0; i < r; ++i) {
printf("%c", buf[i]);
}
printf("\n------------------\n");
#endif
if(r <= 0) {
free(buf);
buf = NULL;
return -4;
}
int nparsed = http_parser_execute(&c->http, &c->http_cfg, (const char*)buf, r);
free(buf);
buf = NULL;
return pending;
}
static void krx_https_conn_read(uv_stream_t* stream, ssize_t nbytes, uv_buf_t buf) {
krx_https_conn* c = (krx_https_conn*)stream->data;
if(!c) {
printf("Error: krx_https_conn_read(), user pointer not set.\n");
exit(1);
}
/* disconnected or other error. */
if(nbytes < 0) {
free(buf.base);
printf("- krx_https_conn_read(), %p, status: %s\n", c, uv_strerror(nbytes));
krx_https_close_connection(c);
return;
}
/* digest incoming data */
int written = BIO_write(c->in_bio, buf.base, nbytes);
if(written > 0) {
if(!SSL_is_init_finished(c->ssl)) {
int r = SSL_do_handshake(c->ssl);
if(r < 0) {
char buf[200];
int err = SSL_get_error(c->ssl, r);
char* d = ERR_error_string(err,buf);
}
krx_https_ssl_check_output_buffer(c);
}
else {
krx_https_ssl_check_input_buffer(c);
}
}
free(buf.base);
buf.base = NULL;
}
static int krx_https_conn_init(krx_https* k, krx_https_conn* c) {
if(!c) {
printf("Error: krx_https_conn_init(), invalid connection pointer.\n");
return -1;
}
if(!k) {
printf("Error: krx_https_conn_init(), invalid krx_https pointer.\n");
return -2;
}
int r = 0;
r = uv_tcp_init(k->loop, &c->client);
if(r != 0) {
printf("Error: krx_https_conn_init(), uv_tcp_init() failed for client.\n");
return -3;
}
r = uv_accept((uv_stream_t*)&k->server, (uv_stream_t*)&c->client);
if(r != 0) {
printf("Error: krx_https_conn_innit(), uv_accept() failed.\n");
printf("@todo(roxlu): when closed we need to cleanup! add callback handler.\n");
uv_close((uv_handle_t*)&c->client, NULL);
return -4;
}
r = uv_read_start((uv_stream_t*)&c->client, krx_https_alloc_buffer, krx_https_conn_read);
if(r != 0) {
printf("Error: krx_https_conn_init(), uv_read_start() failed: %s\n", uv_strerror(r));
return -5;
}
if(c->ssl) {
printf("Error: krx_https_conn_init(), connection already has an ssl object (?!). @todo(roxlu): fix.\n");
}
c->is_free = 0;
c->k = k;
c->ssl = NULL;
c->in_bio = NULL;
c->out_bio = NULL;
c->client.data = c; /* @todo(roxlu): this could be done initialize only once ... */
/* init http parser */
c->http_cfg.on_message_begin = krx_https_on_message_begin;
c->http_cfg.on_url = krx_https_on_url;
c->http_cfg.on_status = krx_https_on_status;
c->http_cfg.on_header_field = krx_https_on_header_field;
c->http_cfg.on_header_value = krx_https_on_header_value;
c->http_cfg.on_headers_complete = krx_https_on_headers_complete;
c->http_cfg.on_body = krx_https_on_body;
c->http_cfg.on_message_complete = krx_https_on_message_complete;
http_parser_init(&c->http , HTTP_REQUEST);
c->http.data = c;
/* init ssl */
r = krx_https_ssl_create(k, c) < 0;
if(r < 0) {
return r;
}
return 0;
}
static int krx_https_conn_shutdown(krx_https_conn* c) {
printf("- krx_https_conn_shutdown(): %p\n", c);
if(!c) {
printf("Error: krx_https_conn_shutdown(), invalid arguments.\n");
return -1;
}
#if 0
if(c->in_bio) {
printf("IN_BIO.\n");
if(BIO_free(c->in_bio) != 1) {
printf("Error: krx_https_conn_shutdown(), cannot free in bio.\n");
}
c->in_bio = NULL;
}
if(c->out_bio) {
printf("OUT_BIO.\n");
if(BIO_free(c->out_bio) != 1) {
printf("Error: krx_https_conn_shutdown(), cannot free out bio.\n");
}
c->out_bio = NULL;
}
#endif
if(c->ssl) {
//SSL_clear(c->ssl);
SSL_free(c->ssl);
c->ssl = NULL;
}
if(!c->k) {
printf("Error: krx_https_conn_shutdown(), k member not set!.\n");
}
else {
c->k->num_connections--;
if(c->k->num_connections < 0) {
// shouldn't happen.
printf("Error: krx_https_conn_shutdown(), less then zero connections (?)...\n");
}
//printf("Verbose: disconnected, total connections: %d\n", c->k->num_connections);
}
//c->is_free = 1;
printf("--\n");
return 0;
}
static void krx_https_ssl_info_callback(const SSL* ssl, int where, int ret) {
/* TMP: no output */
if(ret == 0) {
printf("-- krx_ssl_info_callback: error occured.\n");
return;
}
SSL_WHERE_INFO(ssl, where, SSL_CB_READ_ALERT, "READ ALERT");
SSL_WHERE_INFO(ssl, where, SSL_CB_WRITE_ALERT, "WRITE ALERT");
SSL_WHERE_INFO(ssl, where, SSL_CB_ACCEPT_LOOP, "ACCEPT LOOP");
SSL_WHERE_INFO(ssl, where, SSL_CB_CONNECT_EXIT, "CONNECT EXIT");
SSL_WHERE_INFO(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
SSL_WHERE_INFO(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
}
static int krx_https_ssl_create(krx_https* k, krx_https_conn* c) {
if(!k || !c) {
printf("Error: krx_https_ssl_create(), invalid pointer(s): k: %p, c: %p\n", k, c);
return -1;
}
if(c->ssl) {
printf("Error: krx_https_ssl_create(), is seems the connection already has a ssl object.\n");
return -2;
}
if(!k->ctx) {
printf("Error: krx_https_ssl_create(), seems like the SSL_CTX is invalid.\n");
return -3;
}
/* create SSL* */
c->ssl = SSL_new(k->ctx);
if(!c->ssl) {
printf("Error: krx_https_ssl_create(), cannot create new SSL*.\n");
return -4;
}
/* info callback */
SSL_set_info_callback(c->ssl, krx_https_ssl_info_callback);
/* bios */
c->in_bio = BIO_new(BIO_s_mem());
if(c->in_bio == NULL) {
printf("Error: cannot allocate read bio.\n");
return -2;
}
BIO_set_mem_eof_return(c->in_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
c->out_bio = BIO_new(BIO_s_mem());
if(c->out_bio == NULL) {
printf("Error: cannot allocate write bio.\n");
return -3;
}
BIO_set_mem_eof_return(c->out_bio, -1); /* see: https://www.openssl.org/docs/crypto/BIO_s_mem.html */
SSL_set_bio(c->ssl, c->in_bio, c->out_bio);
SSL_set_accept_state(c->ssl);
//SSL_do_handshake(c->ssl);
return 0;
}
static void krx_https_on_new_connection(uv_stream_t* server, int status) {
if(status == -1) {
printf("Error: krx_https_on_new_connection(), received an invalid status: %d\n", status);
return;
}
krx_https* k = (krx_https*)server->data;
if(!k) {
printf("Error: krx_https_on_new_connection(), data member not set.\n");
exit(1);
}
if(k->num_connections >= k->allocated_connections) {
printf("Warning: @todo, krx_https_on_new_connect(), not enough space to handle a new connection: allocated: %d, curr: %d\n", k->allocated_connections, k->num_connections);
exit(1);
}
/* find free connection */
krx_https_conn* c = NULL;
for(int i = 0; i < k->allocated_connections; ++i) {
if(k->connections[i].is_free == 1) {
c = &k->connections[i];
break;
}
}
if(!c) {
printf("Error: cannot find a free connection.\n");
exit(1);
}
//krx_https_conn* c = &k->connections[k->num_connections];
if(krx_https_conn_init(k, c) < 0) {
printf("Error: cannot innitialize a new connection.\n");
exit(1);
}
k->num_connections++;
printf("- krx_https_on_new_connection(), c: %p\n", c);
};
static int krx_https_ssl_verify_peer(int ok, X509_STORE_CTX* ctx) {
return 1;
}
static int krx_https_ssl_create_ctx(krx_https* k, const char* certfile, const char* kefile) {
int r = 0;
if(!k) {
printf("Error: krx_https_ssl_create_ctx(), invalid pointer.\n");
return -1;
}
/* create a new context using DTLS */
k->ctx = SSL_CTX_new(TLSv1_1_server_method());
if(!k->ctx) {
printf("Error: cannot create SSL_CTX.\n");
ERR_print_errors_fp(stderr);
return -1;
}
/* set our supported ciphers */
r = SSL_CTX_set_cipher_list(k->ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
if(r != 1) {
printf("Error: cannot set the cipher list.\n");
ERR_print_errors_fp(stderr);
return -2;
}
/* the client doesn't have to send it's certificate */
SSL_CTX_set_verify(k->ctx, SSL_VERIFY_PEER, krx_https_ssl_verify_peer);
/* certificate file; contains also the public key */
r = SSL_CTX_use_certificate_file(k->ctx, certfile, SSL_FILETYPE_PEM);
if(r != 1) {
printf("Error: cannot load certificate file.\n");
ERR_print_errors_fp(stderr);
return -3;
}
/* load private key */
r = SSL_CTX_use_PrivateKey_file(k->ctx, kefile, SSL_FILETYPE_PEM);
if(r != 1) {
printf("Error: cannot load private key file.\n");
ERR_print_errors_fp(stderr);
return -4;
}
/* check if the private key is valid */
r = SSL_CTX_check_private_key(k->ctx);
if(r != 1) {
printf("Error: checking the private key failed. \n");
ERR_print_errors_fp(stderr);
return -5;
}
return 0;
}
/* --------------------------------------------------------------------------- */
int krx_https_init(krx_https* k, const char* certfile, const char* keyfile) {
int r = 0;
if(!k) {
printf("Error: krx_https_init(), invalid pointer.\n");
return -1;
}
if(k->state & KRX_HTTPS_STATE_INITIALIZED) {
printf("Error: rkx_signaling_init(), already initialized.\n");
return -2;
}
k->allocated_connections = 10;
k->connections = malloc(sizeof(krx_https_conn) * k->allocated_connections);
if(!k->connections) {
printf("Error: krx_https_init(), cannot initialize connection array.\n");
return -3;
}
/* make all connections "free" */
for(int i = 0; i < k->allocated_connections; ++i) {
k->connections[i].is_free = 1;
}
k->on_body = NULL;
k->loop = NULL;
k->num_connections = 0;
k->state = KRX_HTTPS_STATE_INITIALIZED;
/* initialize SSL */
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
/* create the SSL context */
r = krx_https_ssl_create_ctx(k, certfile, keyfile);
if(r < 0) {
return r;
}
return 0;
}
int krx_https_shutdown() {
printf("@todo(roxlu): cleanup https.\n");
/* shutdown SSL */
ERR_remove_state(0);
ENGINE_cleanup();
CONF_modules_unload(1);
ERR_free_strings();
EVP_cleanup();
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
CRYPTO_cleanup_all_ex_data();
return 0;
}
int krx_https_start(krx_https* k, const char* ip, int port) {
int r = 0;
if(!k) {
printf("Error: krx_https_start(), invalid pointer.\n");
return -1;
}
if( !(k->state & KRX_HTTPS_STATE_INITIALIZED) ) {
printf("Error: krx_https_start(), not initialized, call krx_https_init() first.\n");
return -2;
}
if(!k->loop) {
k->loop = uv_default_loop();
}
r = uv_tcp_init(k->loop, &k->server);
if(r != 0) {
printf("Error: krx_https_start(), cannot initialized tcp: %s.\n", uv_strerror(r));
return -3;
}
struct sockaddr_in saddr = uv_ip4_addr(ip, port);
r = uv_tcp_bind(&k->server, saddr);
if(r != 0) {
printf("Error: krx_https_start(), cannot bind the port: %s.\n", uv_strerror(r));
return -4;
}
r = uv_listen((uv_stream_t*)&k->server, 128, krx_https_on_new_connection);
if(r != 0) {
printf("Error: krx_https_start(), cannot start listening: %s.\n", uv_strerror(r));
return -5;
}
printf("Lets start!.\n");
k->state |= KRX_HTTPS_STATE_ACCEPTING;
k->server.data = k;
printf("k->server: %p, k: %p\n", &k->server, &k);
printf("k->num_connections: %d\n", k->num_connections);
printf("k->allocated_connections: %d\n", k->allocated_connections);
printf("k->allocated_connections: %p\n", &k->allocated_connections);
return 0;
}
void krx_https_update(krx_https* k) {
#if !defined(NDEBUG)
if(!k) {
printf("Error: krx_https_update(), invalid pointer.\n");
exit(1);
}
if( !(k->state & KRX_HTTPS_STATE_ACCEPTING) ) {
printf("Error: krx_https_update(), invalid state.\n");
exit(1);
}
if(!k->loop) {
printf("Error: krx_https_update(), no loop set.\n");
exit(1);
}
#endif
uv_run(k->loop, UV_RUN_NOWAIT);
}
static void krx_https_conn_on_closed(uv_handle_t* handle) {
krx_https_conn* c = (krx_https_conn*)handle->data;
printf("- krx_https_conn_on_closed(): %p\n", c);
krx_https_conn_shutdown(c);
}
int krx_https_close_connection(krx_https_conn* c) {
printf("- krx_https_close_connection(): %p\n", c);
if(!c) {
printf("Error: krx_https_close_connection(), invalid connection pointer.\n");
return -1;
}
uv_close((uv_handle_t*)&c->client, krx_https_conn_on_closed);
return 0;
}
int krx_https_send_data(krx_https_conn* c, uint8_t* buf, int len) {
if(!c || !buf || len <= 0 || !c->ssl) {
printf("Error: krx_https_send_data(), invalid arguments.\n");
return -1;
}
int result = 0;
int r = 0;
int written = 0;
while(written < len) {
r = SSL_write(c->ssl, buf, len);
if(r <= 0) {
printf("Error: krx_https_send_data(), failed SSL_write()ing.\n");
result = -2;
break;
}
written += r;
}
krx_https_ssl_check_output_buffer(c);
printf("Written: %d, len: %d\n", written, len);
return result;
}
/*
openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -out client-cert.pem
openssl req -x509 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-cert.pem
*/
#ifndef KRX_HTTP_SERVER_H
#define KRX_HTTP_SERVER_H
#include <uv.h>
#include <http_parser.h>
#include <openssl/err.h>
#include <openssl/dh.h>
#include <openssl/ssl.h>
#include <openssl/conf.h>
#include <openssl/engine.h>
/* SSL debug */
#define SSL_WHERE_INFO(ssl, w, flag, msg) { \
if(w & flag) { \
printf("----- "); \
printf("%20.20s", msg); \
printf(" - %30.30s ", SSL_state_string_long(ssl)); \
printf(" - %5.10s ", SSL_state_string(ssl)); \
printf("\n"); \
} \
}
#define KRX_HTTPS_STATE_NONE 0
#define KRX_HTTPS_STATE_INITIALIZED 1
#define KRX_HTTPS_STATE_ACCEPTING 2
typedef struct krx_https krx_https;
typedef struct krx_https_conn krx_https_conn;
typedef void(*krx_https_on_body_cb)(krx_https_conn* c, uint8_t* buf, int nbytes);
struct krx_https_conn {
uv_tcp_t client;
SSL* ssl;
BIO* in_bio;
BIO* out_bio;
http_parser_settings http_cfg;
http_parser http;
krx_https* k;
int is_free;
};
struct krx_https {
/* tcp / TLS */
uv_tcp_t server;
uv_loop_t* loop;
int state;
SSL_CTX* ctx;
/* managing connections */
krx_https_conn* connections;
int num_connections;
int allocated_connections;
/* callback */
krx_https_on_body_cb on_body;
void* user;
};
int krx_https_init(krx_https* k, const char* certfile, const char* keyfile);
int krx_https_shutdown(krx_https* k);
int krx_https_start(krx_https* k, const char* ip, int port);
void krx_https_update(krx_https* k);
int krx_https_close_connection(krx_https_conn* c); /* cleans up and closes the connection; it can be reused again after this */
int krx_https_send_data(krx_https_conn* c, uint8_t* buf, int len); /* send application data */
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment