Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

283 lines (247 sloc) 7.611 kb
#include "ten/net/ssl.hh"
#include "ten/ioproc.hh"
#include <openssl/err.h>
#include <arpa/inet.h>
namespace ten {
static int netfd_write(BIO *b, const char *buf, int num);
static int netfd_read(BIO *b, char *buf, int size);
static int netfd_puts(BIO *b, const char *str);
static long netfd_ctrl(BIO *b, int cmd, long num, void *ptr);
static int netfd_new(BIO *b);
static int netfd_free(BIO *b);
struct netfd_state_s {
/* fields for BIO_TYPE_CONNECT */
char *param_hostname;
char *param_port;
u_int8_t ip[4];
u_int16_t port;
/* field for BIO_TYPE_ACCEPT */
char *param_addr;
BIO *bio_chain;
};
typedef struct netfd_state_s netfd_state_t;
static BIO_METHOD methods_st = {
BIO_TYPE_SOCKET | BIO_TYPE_CONNECT | BIO_TYPE_ACCEPT,
"state threads netfd",
netfd_write,
netfd_read,
netfd_puts,
NULL, /* gets() */
netfd_ctrl,
netfd_new,
netfd_free,
NULL,
};
BIO_METHOD *BIO_s_netfd(void) {
return (&methods_st);
}
BIO *BIO_new_netfd(int fd, int close_flag) {
BIO *ret = BIO_new(BIO_s_netfd());
if (ret == NULL) return NULL;
BIO_set_fd(ret, fd, close_flag);
return ret;
}
static int netfd_new(BIO *b) {
b->init = 0;
b->num = 0;
b->ptr = calloc(1, sizeof(netfd_state_t));
b->flags = 0;
return 1;
}
static void _free_netfd(BIO *b) {
if (b == NULL) return;
netfd_state_t *s = (netfd_state_t *)b->ptr;
if (s == NULL) return;
if (b->num) {
if (b->shutdown) {
close(b->num);
}
}
if (s->param_hostname != NULL)
OPENSSL_free(s->param_hostname);
if (s->param_port != NULL)
OPENSSL_free(s->param_port);
if (s->param_addr != NULL)
OPENSSL_free(s->param_addr);
}
static int netfd_free(BIO *b) {
if (b == NULL) return 0;
if (b->ptr) {
_free_netfd(b);
free(b->ptr);
}
b->ptr = NULL;
return 1;
}
static int netfd_write(BIO *b, const char *buf, int num) {
//netfd_state_t *s = (netfd_state_t *)b->ptr;
return netsend(b->num, buf, num, 0, 0);
}
static int netfd_read(BIO *b, char *buf, int size) {
//netfd_state_t *s = (netfd_state_t *)b->ptr;
return netrecv(b->num, buf, size, 0, 0);
}
static int netfd_puts(BIO *b, const char *str) {
//netfd_state_t *s = (netfd_state_t *)b->ptr;
size_t n = strlen(str);
return netsend(b->num, str, n, 0, 0);
}
static int netfd_connect(BIO *b) {
netfd_state_t *s = (netfd_state_t *)b->ptr;
if (s->port == 0) {
if (BIO_get_port(s->param_port, &s->port) <= 0) {
return -1;
}
}
if (netdial(b->num, s->param_hostname, s->port) == 0) {
// success!
return 1;
}
return 0;
}
static long netfd_ctrl(BIO *b, int cmd, long num, void *ptr) {
netfd_state_t *s = (netfd_state_t *)b->ptr;
long ret = 1;
int *ip;
const char **pptr;
switch (cmd) {
case BIO_C_SET_FD:
_free_netfd(b);
b->num = *((int *)ptr);
b->shutdown = (int)num;
b->init = 1;
break;
case BIO_C_GET_FD:
if (b->init) {
ip = (int *)ptr;
if (ip) *ip=b->num;
ret = b->num;
} else {
ret = -1;
}
break;
case BIO_CTRL_GET_CLOSE:
ret = b->shutdown;
break;
case BIO_CTRL_SET_CLOSE:
b->shutdown = (int)num;
break;
case BIO_CTRL_DUP:
case BIO_CTRL_FLUSH:
ret = 1;
break;
case BIO_CTRL_RESET:
/* TODO: might need to support this for connection resets */
break;
case BIO_C_GET_CONNECT:
if (ptr != NULL) {
pptr=(const char **)ptr;
if (num == 0) {
*pptr = s->param_hostname;
} else if (num == 1) {
*pptr = s->param_port;
} else if (num == 2) {
*pptr = (char *)&(s->ip[0]);
} else if (num == 3) {
*((int *)ptr) = s->port;
}
if ((!b->init) || (ptr == NULL))
*pptr = "not initialized";
ret = 1;
}
break;
case BIO_C_SET_CONNECT:
if (ptr != NULL)
{
b->init=1;
if (num == 0) {
if (s->param_hostname != NULL)
OPENSSL_free(s->param_hostname);
s->param_hostname=BUF_strdup((char *)ptr);
} else if (num == 1) {
if (s->param_port != NULL)
OPENSSL_free(s->param_port);
s->param_port = BUF_strdup((char *)ptr);
} else if (num == 2) {
char buf[16];
unsigned char *p = (unsigned char *)ptr;
BIO_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
p[0],p[1],p[2],p[3]);
if (s->param_hostname != NULL)
OPENSSL_free(s->param_hostname);
s->param_hostname=BUF_strdup(buf);
memcpy(&(s->ip[0]), ptr, 4);
} else if (num == 3) {
//char buf[DECIMAL_SIZE(int)+1];
char buf[32];
BIO_snprintf(buf, sizeof(buf), "%d", (uint16_t)(intptr_t)ptr);
if (s->param_port != NULL)
OPENSSL_free(s->param_port);
s->param_port=BUF_strdup(buf);
s->port=(intptr_t)ptr;
}
}
break;
case BIO_C_SET_ACCEPT:
if (ptr != NULL) {
if (num == 0) {
b->init = 1;
if (s->param_addr != NULL)
OPENSSL_free(s->param_addr);
s->param_addr = BUF_strdup((char *)ptr);
} else if (num == 1) {
// no blocking io with state-threads
/*data->accept_nbio = (ptr != NULL);*/
} else if (num == 2) {
if (s->bio_chain != NULL)
BIO_free(s->bio_chain);
s->bio_chain = (BIO *)ptr;
}
}
break;
case BIO_C_DO_STATE_MACHINE:
ret = netfd_connect(b);
break;
default:
ret = 0;
break;
}
return ret;
}
sslerror::sslerror() {
err = ERR_get_error();
ERR_error_string(err, errstr);
}
sslsock::sslsock(int fd) throw (errno_error)
: sockbase(fd), ctx(0), bio(0)
{
}
sslsock::sslsock(int domain, int type, int protocol) throw (errno_error)
: sockbase(domain, type | SOCK_NONBLOCK, protocol), ctx(0), bio(0)
{
}
sslsock::~sslsock() {
BIO_free_all(bio);
SSL_CTX_free(ctx);
}
void sslsock::initssl(SSL_CTX *ctx_, bool client) {
ctx = ctx_;
BIO *ssl_bio = BIO_new_ssl(ctx, client);
BIO *net_bio = BIO_new_netfd(s.fd, 0);
bio = BIO_push(ssl_bio, net_bio);
}
void sslsock::initssl(const SSL_METHOD *method, bool client) {
initssl(SSL_CTX_new((SSL_METHOD *)method), client);
}
int sslsock::dial(const char *addr, uint16_t port, unsigned timeout_ms) {
int status = netdial(s.fd, addr, port);
if (status != 0) return status;
handshake();
return 0;
}
void sslsock::handshake() {
if (BIO_do_handshake(bio) <= 0) {
throw sslerror();
}
}
} // end namespace ten
Jump to Line
Something went wrong with that request. Please try again.