Non-blocking (resumable) TLS: both peers drive netw_ssl_handshake_once / netw_ssl_server_handshake_once + the *_once movers from their own poll() loop, never the thread engine.
Non-blocking (resumable) TLS: both peers drive netw_ssl_handshake_once / netw_ssl_server_handshake_once + the *_once movers from their own poll() loop, never the thread engine.
#ifndef __windows__
#include <poll.h>
#endif
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#define MSG "nonblock-client->server"
#define REPLY "nonblock-server->client"
#define MSG_LEN 24
static const char garbage[] = "not a certificate";
BIO* b = BIO_new_mem_buf(garbage, (int)(sizeof(garbage) - 1));
if (b) {
X509* x = PEM_read_bio_X509(b, NULL, NULL, NULL);
if (x) X509_free(x);
BIO_free(b);
}
}
int opt = 0;
while ((opt = getopt(argc, argv, "hvV:")) != EOF) {
switch (opt) {
case 'V':
if (!strncmp("LOG_NULL", optarg, 8))
else if (!strncmp("LOG_NOTICE", optarg, 10))
else if (!strncmp("LOG_INFO", optarg, 8))
else if (!strncmp("LOG_ERR", optarg, 7))
else if (!strncmp("LOG_DEBUG", optarg, 9))
else {
fprintf(stderr, "Unknown log level %s\n", optarg);
exit(1);
}
break;
case 'v':
fprintf(stderr, "ex_network_ssl_nonblock\n");
exit(1);
case 'h':
default:
fprintf(stderr, "usage: %s [-V LOG_LEVEL]\n", argv[0]);
break;
}
}
}
#if N_OSSL_HAVE_PROTO_VERSION_SETTERS
SSL_CTX* ctx = SSL_CTX_new(TLS_server_method());
if (!ctx)
return NULL;
#else
SSL_CTX* ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!ctx)
return NULL;
#endif
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
BIO* cb = BIO_new_mem_buf(cert_pem->
data, (
int)cert_pem->
written);
BIO* kb = BIO_new_mem_buf(key_pem->
data, (
int)key_pem->
written);
X509* x = cb ? PEM_read_bio_X509(cb, NULL, NULL, NULL) : NULL;
EVP_PKEY* pk = kb ? PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL) : NULL;
int ok = x && pk && SSL_CTX_use_certificate(ctx, x) == 1 &&
SSL_CTX_use_PrivateKey(ctx, pk) == 1;
if (x)
X509_free(x);
if (pk)
EVP_PKEY_free(pk);
if (cb)
BIO_free(cb);
if (kb)
BIO_free(kb);
if (!ok) {
SSL_CTX_free(ctx);
return NULL;
}
return ctx;
}
#ifdef __windows__
fd_set rset, wset, eset;
struct timeval tv;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
if (want_write) {
FD_SET(fd, &wset);
FD_SET(fd, &eset);
} else {
FD_SET(fd, &rset);
}
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
return select((int)fd + 1, want_write ? NULL : &rset,
want_write ? &wset : NULL, want_write ? &eset : NULL, &tv);
#else
struct pollfd p;
p.fd = fd;
p.events = (short)(want_write ? POLLOUT : POLLIN);
p.revents = 0;
return poll(&p, 1, timeout_ms);
#endif
}
int guard;
for (guard = 0; guard < 10000; guard++) {
if (r == TRUE)
return TRUE;
return FALSE;
continue;
}
return FALSE;
continue;
}
return FALSE;
}
return FALSE;
}
int guard;
for (guard = 0; guard < 10000; guard++) {
if (r == TRUE)
return TRUE;
return FALSE;
continue;
}
return FALSE;
}
return FALSE;
}
int guard;
for (guard = 0; guard < 100000 &&
done < n; guard++) {
if (r > 0) {
continue;
}
return FALSE;
continue;
}
return FALSE;
continue;
}
return FALSE;
}
return done == n ? TRUE : FALSE;
}
int guard;
for (guard = 0; guard < 10000 && !c; guard++) {
break;
}
if (!c)
return NULL;
}
}
return NULL;
}
int p;
for (p = 18500; p < 18600; p++) {
char ps[16];
snprintf(ps, sizeof(ps), "%d", p);
snprintf(port_out, port_out_len, "%s", ps);
return l;
}
if (l)
}
return NULL;
}
int main(
int argc,
char** argv) {
SSL_CTX* sctx = NULL;
pthread_t th;
return 1;
}
if (!sctx) {
return 1;
}
if (!listen) {
SSL_CTX_free(sctx);
return 1;
}
} else {
}
} else {
n_log(
LOG_ERR,
"stale error queue: idle recv returned %zd, not WANT_READ", idle);
}
} else {
}
}
}
pthread_join(th, NULL);
}
SSL_CTX_free(sctx);
return 1;
}
return 0;
}
void process_args(int argc, char **argv)
NETWORK * netw
Network for server mode, accepting incomming.
static void * server_fn(void *p)
static NETWORK * bind_free(char *port_out, size_t port_out_len)
#define MSG_LEN
fixed exchange message length (both messages are 17 chars + NUL)
volatile sig_atomic_t done
#define MSG
client->server probe (both messages share this fixed length)
SSL_CTX * ctx
shared server ctx (owned by main)
static SSL_CTX * make_server_ctx(const N_STR *cert_pem, const N_STR *key_pem)
static int io_full(NETWORK *netw, char *buf, uint32_t n, int is_send)
static int poll_fd(SOCKET fd, int want_write, int timeout_ms)
static int drive_handshake(NETWORK *netw, int is_server, SSL_CTX *sctx)
NETWORK * listen
the listening socket
#define REPLY
server->client probe
static int drive_connect(NETWORK *netw)
int ok
set to 1 once the server completed the exchange
static void leave_stale_openssl_error(void)
leave a genuine error on this thread's OpenSSL queue (portable: a failed PEM parse,...
volatile char key[227]
TRUE while the key is held.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
#define LOG_NOTICE
normal but significant condition
#define LOG_NULL
no log output
#define LOG_INFO
informational
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
A box including a string and his lenght.
int n_x509_generate_ca(const char *cn, int days, N_STR **ca_cert_pem, N_STR **ca_key_pem)
Generate a self-signed certificate authority (CA) keypair and cert.
N_SOCKET link
networking socket
SOCKET sock
a normal socket
ssize_t send_ssl_data_once(void *netw, char *buf, uint32_t n)
single-attempt TLS send for non-blocking sockets (reactor use).
#define NETW_IO_WANT_READ
single-attempt I/O (send_data_once / recv_data_once): the operation cannot progress until the socket ...
ssize_t recv_ssl_data_once(void *netw, char *buf, uint32_t n)
single-attempt TLS recv for non-blocking sockets (reactor use).
int netw_ssl_set_verify(NETWORK *netw, int enable)
enable or disable SSL peer certificate verification
NETWORK * netw_accept_nonblock_from(NETWORK *from, int blocking)
make a normal blocking 'accept' .
int netw_ssl_server_handshake_once(NETWORK *netw, SSL_CTX *ctx)
non-blocking, resumable TLS server handshake against a shared ctx
int netw_connect_nonblock(NETWORK **netw, char *host, char *port, int ip_version)
begin a non-blocking TCP connect without waiting for it to complete
int netw_ssl_handshake_once(NETWORK *netw, const char *sni_hostname)
non-blocking, resumable TLS client handshake
int netw_init_openssl(void)
Do not directly use, internal api.
#define NETW_TLS_MAX_VERSION
highest TLS version the linked TLS library can negotiate, as a TLS*_VERSION constant.
int netw_make_listening(NETWORK **netw, char *addr, char *port, int nbpending, int ip_version)
Make a NETWORK be a Listening network.
int netw_unload_openssl(void)
Do not directly use, internal api.
#define NETWORK_IPALL
Flag for auto detection by OS of ip version to use.
int SOCKET
default socket declaration
int netw_connect_check(NETWORK *netw)
advance a non-blocking connect started by netw_connect_nonblock()
#define NETW_IO_WANT_WRITE
single-attempt I/O: the operation cannot progress until the socket is WRITABLE.
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
int netw_ssl_start_client(NETWORK *netw)
Set up a client SSL_CTX on an already-connected NETWORK.
int netw_ssl_set_versions(NETWORK *netw, int min_version, int max_version)
set the minimum (and optionally maximum) TLS protocol version on a connection's SSL context
Common headers and low-level functions & define.
N_STR and string function declaration.
X.509 helpers: self-signed CA generation and per-host leaf minting.