1048 lines
20 KiB
C
1048 lines
20 KiB
C
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <netdb.h>
|
|
#include <openssl/err.h>
|
|
#include <openssl/ssl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/epoll.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
|
|
#include "dataq.h"
|
|
#include "netio.h"
|
|
#include "request.h"
|
|
#include "utils.h"
|
|
|
|
static int iomgr_update_poll(iomgr_t*, endpoint_t*, int);
|
|
static int endpoint_update_epoll(endpoint_t*);
|
|
|
|
static int io_fsm_init(io_fsm_t* fsm, endpoint_t* ep, io_fsm_op_t op)
|
|
{
|
|
if ((fsm == NULL) || (ep == NULL)
|
|
|| ((op != FSM_IO_READ) && (op != FSM_IO_WRITE))) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
fsm->ep = ep;
|
|
fsm->op = op;
|
|
fsm->state = FSM_STATE_INIT;
|
|
fsm->pkt = NULL;
|
|
fsm->iocount = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int io_fsm_start(io_fsm_t* fsm, io_packet_t* pkt)
|
|
{
|
|
endpoint_t* ep;
|
|
|
|
if ((fsm == NULL) || (pkt == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ep = (endpoint_t*)fsm->ep;
|
|
if ((ep == NULL) || (ep->ssl == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((fsm->state != FSM_STATE_INIT) && (fsm->state != FSM_STATE_DONE)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (fsm->op) {
|
|
case FSM_IO_READ:
|
|
fsm->state = FSM_STATE_READ_PKT_HEAD;
|
|
break;
|
|
case FSM_IO_WRITE:
|
|
fsm->state = FSM_STATE_WRITE_PKT_HEAD;
|
|
break;
|
|
}
|
|
|
|
fsm->pkt = pkt;
|
|
fsm->iocount = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int io_fsm_do(io_fsm_t* fsm, char* data, size_t len)
|
|
{
|
|
int rc = 0;
|
|
size_t count;
|
|
endpoint_t* ep = (endpoint_t*)fsm->ep;
|
|
|
|
count = len - fsm->iocount;
|
|
|
|
switch (fsm->op) {
|
|
case FSM_IO_READ:
|
|
rc = SSL_read(ep->ssl, data + fsm->iocount, count);
|
|
break;
|
|
case FSM_IO_WRITE:
|
|
rc = SSL_write(ep->ssl, data + fsm->iocount, count);
|
|
break;
|
|
}
|
|
|
|
if (rc <= 0) {
|
|
int err = 0;
|
|
int ecode = 0;
|
|
|
|
ecode = errno;
|
|
err = SSL_get_error(ep->ssl, rc);
|
|
switch (err) {
|
|
case SSL_ERROR_WANT_READ:
|
|
case SSL_ERROR_WANT_WRITE:
|
|
rc = 0;
|
|
break;
|
|
case SSL_ERROR_SYSCALL:
|
|
if ((rc < 0) && ((ecode == EAGAIN) || (ecode == EWOULDBLOCK))) {
|
|
rc = 0;
|
|
} else {
|
|
fsm->state = FSM_STATE_ERROR;
|
|
rc = -errno;
|
|
}
|
|
if (rc == 0) {
|
|
/* we meet EOF */
|
|
fsm->state = FSM_STATE_ERROR;
|
|
}
|
|
break;
|
|
default:
|
|
fsm->state = FSM_STATE_ERROR;
|
|
rc = -errno;
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
fsm->iocount += rc;
|
|
count -= rc;
|
|
if (count == 0) {
|
|
rc = fsm->iocount;
|
|
|
|
switch (fsm->state) {
|
|
case FSM_STATE_READ_PKT_HEAD:
|
|
fsm->state = FSM_STATE_READ_PKT;
|
|
fsm->iocount = 0;
|
|
if (alloc_packet(fsm->pkt) < 0) {
|
|
fsm->state = FSM_STATE_ERROR;
|
|
rc = -ENOMEM;
|
|
}
|
|
break;
|
|
case FSM_STATE_READ_PKT:
|
|
case FSM_STATE_WRITE_PKT:
|
|
fsm->state = FSM_STATE_DONE;
|
|
fsm->iocount = 0;
|
|
break;
|
|
case FSM_STATE_WRITE_PKT_HEAD:
|
|
fsm->state = FSM_STATE_WRITE_PKT;
|
|
fsm->iocount = 0;
|
|
break;
|
|
case FSM_STATE_DONE:
|
|
break;
|
|
case FSM_STATE_INIT:
|
|
case FSM_STATE_ERROR:
|
|
/* should never go here and make compiler happy */
|
|
rc = -EINVAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int io_fsm_perform(io_fsm_t* fsm)
|
|
{
|
|
char* data;
|
|
size_t len;
|
|
|
|
if ((fsm == NULL) || (fsm->state == FSM_STATE_INIT)
|
|
|| (fsm->state == FSM_STATE_DONE) || (fsm->state == FSM_STATE_ERROR)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (fsm->state) {
|
|
case FSM_STATE_READ_PKT_HEAD:
|
|
case FSM_STATE_WRITE_PKT_HEAD:
|
|
data = (char*)&(fsm->pkt->sz);
|
|
len = sizeof(fsm->pkt->sz);
|
|
break;
|
|
case FSM_STATE_READ_PKT:
|
|
case FSM_STATE_WRITE_PKT:
|
|
data = fsm->pkt->data;
|
|
len = fsm->pkt->sz;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return io_fsm_do(fsm, data, len);
|
|
}
|
|
|
|
static int set_fd_nonblocking(int fd)
|
|
{
|
|
int flags = 0;
|
|
int rc = 0;
|
|
|
|
flags = fcntl(fd, F_GETFL, 0);
|
|
if (flags < 0) {
|
|
return -errno;
|
|
}
|
|
|
|
rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
if (rc < 0) {
|
|
return -errno;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int socket_create(int domain, int type, int port, int backlog)
|
|
{
|
|
int sock;
|
|
int opt = 1;
|
|
|
|
if ((domain < 0) || (type < 0)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
sock = socket(domain, type, 0);
|
|
if (sock < 0) {
|
|
SET_ERROR(errno);
|
|
|
|
return -errno;
|
|
}
|
|
|
|
fcntl(sock, F_SETFD, (fcntl(sock, F_GETFD) | FD_CLOEXEC));
|
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
|
|
sizeof(opt))
|
|
< 0) {
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
if (port > 0) {
|
|
struct sockaddr_in sin;
|
|
|
|
memset((char*)&sin, 0, sizeof(sin));
|
|
sin.sin_family = domain;
|
|
sin.sin_port = htons(port);
|
|
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
|
|
int rc;
|
|
|
|
SET_ERROR(errno);
|
|
|
|
rc = -errno;
|
|
(void)close(sock);
|
|
|
|
return rc;
|
|
}
|
|
|
|
if (backlog > 0) {
|
|
if (listen(sock, backlog) < 0) {
|
|
int rc;
|
|
|
|
SET_ERROR(errno);
|
|
|
|
rc = -errno;
|
|
(void)close(sock);
|
|
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
|
|
return sock;
|
|
}
|
|
|
|
static int socket_connect(int sock, char* host, int port)
|
|
{
|
|
struct sockaddr_in server;
|
|
struct hostent* hp;
|
|
int rc;
|
|
|
|
server.sin_family = AF_INET;
|
|
hp = gethostbyname(host);
|
|
if (hp == NULL) {
|
|
SET_ERROR(errno);
|
|
|
|
rc = -errno;
|
|
|
|
return rc;
|
|
}
|
|
|
|
memcpy((char*)&server.sin_addr, (char*)hp->h_addr, (int)hp->h_length);
|
|
|
|
server.sin_port = htons(port);
|
|
|
|
rc = connect(sock, (struct sockaddr*)&server, sizeof(server));
|
|
if (rc < 0) {
|
|
SET_ERROR(errno);
|
|
|
|
return -errno;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int socket_accept(int sock)
|
|
{
|
|
socklen_t len;
|
|
int s;
|
|
struct sockaddr_in from;
|
|
|
|
len = sizeof(from);
|
|
s = accept(sock, (struct sockaddr*)&from, &len);
|
|
if (s < 0) {
|
|
SET_ERROR(errno);
|
|
|
|
return -errno;
|
|
}
|
|
|
|
fcntl(s, F_SETFD, (fcntl(s, F_GETFD) | FD_CLOEXEC));
|
|
|
|
return s;
|
|
}
|
|
|
|
int alloc_packet(io_packet_t* pkt)
|
|
{
|
|
if (pkt->sz <= 0) {
|
|
SET_ERROR(EINVAL);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
pkt->data = (char*)malloc(pkt->sz);
|
|
if (pkt->data == NULL) {
|
|
SET_ERROR(ENOMEM);
|
|
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void free_packet(io_packet_t* pkt)
|
|
{
|
|
if (pkt != NULL) {
|
|
FREEUP(pkt->data);
|
|
}
|
|
}
|
|
|
|
#define MAX_EPOLL_EVENTS (5)
|
|
|
|
static int handle_input(endpoint_t* ep)
|
|
{
|
|
int rc = 0;
|
|
|
|
if ((ep->fsm_in.state == FSM_STATE_INIT)
|
|
|| (ep->fsm_in.state == FSM_STATE_DONE)) {
|
|
io_packet_t* pkt;
|
|
|
|
pkt = ep->fsm_in.pkt;
|
|
if (pkt == NULL) {
|
|
pkt = (io_packet_t*)calloc(1, sizeof(*pkt));
|
|
if (pkt == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
} else {
|
|
free_packet(pkt);
|
|
ep->fsm_in.pkt = NULL;
|
|
}
|
|
|
|
io_fsm_start(&(ep->fsm_in), pkt);
|
|
}
|
|
|
|
rc = io_fsm_perform(&(ep->fsm_in));
|
|
if (rc < 0) {
|
|
return rc;
|
|
}
|
|
|
|
if (ep->fsm_in.state == FSM_STATE_DONE) {
|
|
INVOKE_MSG_HANDLER(ep);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_output(endpoint_t* ep)
|
|
{
|
|
int rc = 0;
|
|
|
|
if ((ep->fsm_out.state == FSM_STATE_INIT)
|
|
|| (ep->fsm_out.state == FSM_STATE_DONE)) {
|
|
data_item_t* it = NULL;
|
|
io_packet_t* pkt = NULL;
|
|
|
|
it = endpoint_deq(ep);
|
|
if (it == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
pkt = ITPTR_TO_PACKET(it);
|
|
rc = io_fsm_start(&(ep->fsm_out), pkt);
|
|
if (rc < 0) {
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
rc = io_fsm_perform(&(ep->fsm_out));
|
|
if (rc < 0) {
|
|
return rc;
|
|
}
|
|
|
|
if (ep->fsm_out.state == FSM_STATE_DONE) {
|
|
/* handle output done */
|
|
io_packet_t* pkt = ep->fsm_out.pkt;
|
|
|
|
if (pkt != NULL) {
|
|
free_packet(pkt);
|
|
FREEUP(pkt);
|
|
}
|
|
|
|
ep->fsm_out.pkt = NULL;
|
|
|
|
endpoint_update_epoll(ep);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_error(endpoint_t* ep)
|
|
{
|
|
iomgr_t* iomgr = (iomgr_t*)ep->owner;
|
|
|
|
if (iomgr != NULL) {
|
|
iomgr_unmonitor(iomgr, ep);
|
|
}
|
|
|
|
INVOKE_ERR_HANDLER(ep);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int handle_ssl_handshake(endpoint_t* ep)
|
|
{
|
|
int rc;
|
|
int err;
|
|
int ecode = 0;
|
|
|
|
rc = SSL_do_handshake(ep->ssl);
|
|
if (rc == 1) {
|
|
ep->ssl_handshake_done = 1;
|
|
return 1;
|
|
}
|
|
|
|
ecode = errno;
|
|
err = SSL_get_error(ep->ssl, rc);
|
|
switch (err) {
|
|
case SSL_ERROR_WANT_READ:
|
|
case SSL_ERROR_WANT_WRITE:
|
|
rc = 0;
|
|
break;
|
|
default:
|
|
errno = ecode;
|
|
perror("SSL_do_handshake");
|
|
rc = handle_error(ep);
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int io_handler(struct epoll_event* p)
|
|
{
|
|
endpoint_t* ep = (endpoint_t*)p->data.ptr;
|
|
int rc = 0;
|
|
|
|
if (ep == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!ep->ssl_handshake_done) {
|
|
return handle_ssl_handshake(ep);
|
|
}
|
|
|
|
if ((p->events & EPOLLIN) != 0) {
|
|
if (ep->msg_handler != NULL) {
|
|
rc = handle_input(ep);
|
|
} else if (ep->conn_handler != NULL) {
|
|
rc = ep->conn_handler(p);
|
|
}
|
|
}
|
|
|
|
if (rc >= 0) {
|
|
if ((p->events & EPOLLOUT) != 0) {
|
|
rc = handle_output(ep);
|
|
}
|
|
}
|
|
|
|
if (rc < 0) {
|
|
rc = handle_error(ep);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void* io_worker(void* args)
|
|
{
|
|
iomgr_t* iomgr = (iomgr_t*)args;
|
|
|
|
while (1) {
|
|
int nfds = -1;
|
|
int i;
|
|
struct epoll_event events[MAX_EPOLL_EVENTS];
|
|
|
|
nfds = epoll_wait(iomgr->epoll_fd, events, MAX_EPOLL_EVENTS, -1);
|
|
if (nfds == -1) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
|
|
perror("epoll");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < nfds; i++) {
|
|
io_handler(&events[i]);
|
|
}
|
|
|
|
pthread_testcancel();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int endpoint_calc_flags(endpoint_t* ep)
|
|
{
|
|
int flags = EPOLLIN;
|
|
|
|
if (!ep->ssl_handshake_done) {
|
|
flags = flags | EPOLLOUT;
|
|
} else if (ep->outq.head != NULL) {
|
|
flags = flags | EPOLLOUT;
|
|
} else {
|
|
io_fsm_t* fsm = &(ep->fsm_out);
|
|
|
|
switch (fsm->state) {
|
|
/* we are in the middle stages of output */
|
|
case FSM_STATE_WRITE_PKT_HEAD:
|
|
case FSM_STATE_WRITE_PKT:
|
|
flags = flags | EPOLLOUT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
static int endpoint_update_epoll(endpoint_t* ep)
|
|
{
|
|
int flags;
|
|
|
|
mylock_lock(&(ep->lock));
|
|
flags = endpoint_calc_flags(ep);
|
|
if (flags != ep->flags) {
|
|
if (ep->iomgr != NULL) {
|
|
int rc1;
|
|
|
|
mylock_lock(&(ep->iomgr->lock));
|
|
rc1 = iomgr_update_poll(ep->iomgr, ep, flags);
|
|
mylock_unlock(&(ep->iomgr->lock));
|
|
|
|
if (rc1 >= 0) {
|
|
ep->flags = flags;
|
|
} else {
|
|
WARN("rc1=%d < 0", rc1);
|
|
}
|
|
}
|
|
}
|
|
|
|
mylock_unlock(&(ep->lock));
|
|
return 0;
|
|
}
|
|
|
|
static void outq_item_killer(data_item_t* it)
|
|
{
|
|
if (it != NULL) {
|
|
io_packet_t* pkt = ITPTR_TO_PACKET(it);
|
|
|
|
free_packet(pkt);
|
|
FREEUP(pkt);
|
|
}
|
|
}
|
|
|
|
static int do_endpoint_init(endpoint_t* ep)
|
|
{
|
|
if (ep == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ep->flags = 0;
|
|
ep->fd = -1;
|
|
ep->owner = NULL;
|
|
ep->data = NULL;
|
|
ep->iomgr = NULL;
|
|
ep->ssl = NULL;
|
|
ep->busy = 0;
|
|
ep->ssl_handshake_done = 0;
|
|
ep->msg_handler = NULL;
|
|
ep->err_handler = NULL;
|
|
|
|
dataq_init(&(ep->outq), outq_item_killer);
|
|
mylock_init(&(ep->lock));
|
|
|
|
io_fsm_init(&(ep->fsm_in), ep, FSM_IO_READ);
|
|
io_fsm_init(&(ep->fsm_out), ep, FSM_IO_WRITE);
|
|
|
|
return 1;
|
|
}
|
|
endpoint_t* endpoint_get()
|
|
{
|
|
endpoint_t* ep;
|
|
|
|
ep = (endpoint_t*)calloc(1, sizeof(*ep));
|
|
if (ep == NULL) {
|
|
SET_ERROR(errno);
|
|
|
|
return ep;
|
|
}
|
|
|
|
do_endpoint_init(ep);
|
|
|
|
return ep;
|
|
}
|
|
|
|
int endpoint_init(endpoint_t* ep, int domain, int type, int port, int backlog)
|
|
{
|
|
int fd = -1;
|
|
|
|
if (ep == NULL) {
|
|
SET_ERROR(EINVAL);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
fd = socket_create(domain, type, port, backlog);
|
|
if (fd < 0) {
|
|
return -errno;
|
|
}
|
|
|
|
do_endpoint_init(ep);
|
|
ep->fd = fd;
|
|
/* no need to ssl handle shake in server endpoint just for init connection
|
|
*/
|
|
ep->ssl_handshake_done = 1;
|
|
|
|
return fd;
|
|
}
|
|
|
|
int endpoint_connect(endpoint_t* ep, char* host, int port)
|
|
{
|
|
int rc = -1;
|
|
iomgr_t* iomgr = (iomgr_t*)ep->iomgr;
|
|
|
|
rc = socket_connect(ep->fd, host, port);
|
|
if (rc < 0) {
|
|
return rc;
|
|
}
|
|
|
|
ep->ssl = SSL_new(iomgr->ssl_ctx);
|
|
|
|
SSL_set_fd(ep->ssl, ep->fd);
|
|
|
|
SSL_set_connect_state(ep->ssl);
|
|
|
|
set_fd_nonblocking(ep->fd);
|
|
|
|
ep->flags = 0;
|
|
ep->ssl_handshake_done = 0;
|
|
|
|
handle_ssl_handshake(ep);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int endpoint_accept(endpoint_t* ep, endpoint_t* ep2)
|
|
{
|
|
int sock = -1;
|
|
int rc = 0;
|
|
iomgr_t* iomgr = (iomgr_t*)ep->iomgr;
|
|
|
|
sock = socket_accept(ep->fd);
|
|
if (sock < 0) {
|
|
return sock;
|
|
}
|
|
|
|
ep2->ssl = SSL_new(iomgr->ssl_ctx);
|
|
|
|
rc = SSL_set_fd(ep2->ssl, sock);
|
|
if (rc <= 0) {
|
|
int err = SSL_get_error(ep2->ssl, rc);
|
|
|
|
ERROR("SSL_set_fd returns error: %d", err);
|
|
close(sock);
|
|
return -errno;
|
|
}
|
|
|
|
SSL_set_accept_state(ep2->ssl);
|
|
|
|
set_fd_nonblocking(sock);
|
|
|
|
ep2->fd = sock;
|
|
ep2->flags = 0;
|
|
|
|
return sock;
|
|
}
|
|
|
|
int endpoint_set_owner(endpoint_t* ep, void* owner)
|
|
{
|
|
if ((ep == NULL) || (owner == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
mylock_lock(&(ep->lock));
|
|
ep->owner = owner;
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int endpoint_set_peer(endpoint_t* ep, xce_peerinfo_t* peer)
|
|
{
|
|
mylock_lock(&(ep->lock));
|
|
ep->peer = peer;
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int endpoint_set_conn_handler(endpoint_t* ep, conn_handler_t h)
|
|
{
|
|
if (ep->fd < 0) {
|
|
SET_ERROR(EINVAL);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
mylock_lock(&(ep->lock));
|
|
ep->conn_handler = h;
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int endpoint_set_msg_handler(endpoint_t* ep, msg_handler_t h)
|
|
{
|
|
if ((ep == NULL) || (h == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
mylock_lock(&(ep->lock));
|
|
ep->msg_handler = h;
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int endpoint_set_err_handler(endpoint_t* ep, err_handler_t h)
|
|
{
|
|
if ((ep == NULL) || (h == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
mylock_lock(&(ep->lock));
|
|
ep->err_handler = h;
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return 1;
|
|
}
|
|
|
|
int endpoint_enq(endpoint_t* ep, data_item_t* it)
|
|
{
|
|
int rc = 0;
|
|
|
|
if ((ep == NULL) || (it == NULL)) {
|
|
SET_ERROR(EINVAL);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
mylock_lock(&(ep->lock));
|
|
rc = dataq_enq(&(ep->outq), it);
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
endpoint_update_epoll(ep);
|
|
|
|
return rc;
|
|
}
|
|
|
|
data_item_t* endpoint_deq(endpoint_t* ep)
|
|
{
|
|
data_item_t* it = NULL;
|
|
|
|
if (ep == NULL) {
|
|
SET_ERROR(EINVAL);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
mylock_lock(&(ep->lock));
|
|
it = dataq_deq(&(ep->outq), NULL);
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return it;
|
|
}
|
|
|
|
uint64_t endpoint_getseq(endpoint_t* ep)
|
|
{
|
|
uint64_t seq;
|
|
|
|
mylock_lock(&(ep->lock));
|
|
seq = ep->seq++;
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return seq;
|
|
}
|
|
|
|
void endpoint_block_tasks(endpoint_t* ep)
|
|
{
|
|
TRACE("%s[%ld] block tasks for endpoint %p", __func__, pthread_self(), ep);
|
|
mylock_lock(&(ep->lock));
|
|
ep->busy = 1;
|
|
mylock_unlock(&(ep->lock));
|
|
}
|
|
|
|
void endpoint_unblock_tasks(endpoint_t* ep)
|
|
{
|
|
TRACE("%s[%ld] unblock tasks for endpoint %p", __func__, pthread_self(),
|
|
ep);
|
|
mylock_lock(&(ep->lock));
|
|
ep->busy = 0;
|
|
mylock_unlock(&(ep->lock));
|
|
}
|
|
|
|
int endpoint_is_task_blocked(endpoint_t* ep)
|
|
{
|
|
int busy;
|
|
|
|
mylock_lock(&(ep->lock));
|
|
busy = ep->busy;
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
TRACE("%s[%ld] endpoint %p task %s", __func__, pthread_self(), ep,
|
|
(busy != 0) ? "blocked" : "not blocked");
|
|
|
|
return (busy != 0);
|
|
}
|
|
|
|
void endpoint_fini(endpoint_t* ep)
|
|
{
|
|
dataq_fini(&(ep->outq));
|
|
FREEUP(ep->data);
|
|
|
|
if (ep->fd >= 0) {
|
|
close(ep->fd);
|
|
}
|
|
|
|
if (ep->ssl != NULL) {
|
|
SSL_free(ep->ssl);
|
|
ep->ssl = NULL;
|
|
}
|
|
|
|
if (ep->fsm_in.pkt != NULL) {
|
|
free_packet(ep->fsm_in.pkt);
|
|
|
|
FREEUP(ep->fsm_in.pkt);
|
|
}
|
|
|
|
if (ep->fsm_out.pkt != NULL) {
|
|
free_packet(ep->fsm_out.pkt);
|
|
|
|
FREEUP(ep->fsm_out.pkt);
|
|
}
|
|
|
|
ep->flags = 0;
|
|
ep->msg_handler = NULL;
|
|
ep->err_handler = NULL;
|
|
ep->owner = NULL;
|
|
}
|
|
|
|
void initialize_openssl()
|
|
{
|
|
SSL_load_error_strings();
|
|
OpenSSL_add_ssl_algorithms();
|
|
}
|
|
|
|
void cleanup_openssl() { EVP_cleanup(); }
|
|
|
|
SSL_CTX* create_ssl_context(char* cert_file, char* key_file)
|
|
{
|
|
const SSL_METHOD* method;
|
|
SSL_CTX* ctx;
|
|
|
|
/* any of cert_file or key_file is NULL, just as client */
|
|
if ((cert_file == NULL) || (key_file == NULL)) {
|
|
method = TLS_client_method();
|
|
ctx = SSL_CTX_new(method);
|
|
return ctx;
|
|
}
|
|
|
|
method = TLS_server_method();
|
|
|
|
ctx = SSL_CTX_new(method);
|
|
if (ctx == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) {
|
|
SSL_CTX_free(ctx);
|
|
return NULL;
|
|
}
|
|
|
|
if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) {
|
|
SSL_CTX_free(ctx);
|
|
return NULL;
|
|
}
|
|
|
|
if (!SSL_CTX_check_private_key(ctx)) {
|
|
SSL_CTX_free(ctx);
|
|
return NULL;
|
|
}
|
|
|
|
return ctx;
|
|
}
|
|
|
|
int iomgr_init(iomgr_t* iomgr)
|
|
{
|
|
mylock_init(&(iomgr->lock));
|
|
iomgr->epoll_fd = epoll_create1(0);
|
|
if (iomgr->epoll_fd < 0) {
|
|
SET_ERROR(errno);
|
|
|
|
return -errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void iomgr_set_ssl_ctx(iomgr_t* iomgr, SSL_CTX* ssl_ctx)
|
|
{
|
|
if ((iomgr == NULL) || (ssl_ctx == NULL)) {
|
|
return;
|
|
}
|
|
|
|
iomgr->ssl_ctx = ssl_ctx;
|
|
}
|
|
|
|
static int iomgr_update_poll(iomgr_t* iomgr, endpoint_t* ep, int flags)
|
|
{
|
|
struct epoll_event ev;
|
|
|
|
ev.events = flags;
|
|
ev.data.ptr = ep;
|
|
|
|
return epoll_ctl(iomgr->epoll_fd, EPOLL_CTL_MOD, ep->fd, &ev);
|
|
}
|
|
|
|
int iomgr_monitor(endpoint_t* ep)
|
|
{
|
|
struct epoll_event ev;
|
|
int rc;
|
|
int flags;
|
|
iomgr_t* iomgr = (iomgr_t*)ep->iomgr;
|
|
|
|
if (iomgr->ssl_ctx == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
flags = EPOLLIN;
|
|
ev.events = flags;
|
|
ev.data.ptr = ep;
|
|
|
|
mylock_lock(&(ep->lock));
|
|
ep->iomgr = iomgr;
|
|
mylock_lock(&(iomgr->lock));
|
|
rc = epoll_ctl(iomgr->epoll_fd, EPOLL_CTL_ADD, ep->fd, &ev);
|
|
mylock_unlock(&(iomgr->lock));
|
|
|
|
if (rc >= 0) {
|
|
ep->flags = flags;
|
|
}
|
|
|
|
mylock_unlock(&(ep->lock));
|
|
|
|
return rc;
|
|
}
|
|
|
|
int iomgr_unmonitor(iomgr_t* iomgr, endpoint_t* ep)
|
|
{
|
|
int rc;
|
|
|
|
mylock_lock(&(iomgr->lock));
|
|
rc = epoll_ctl(iomgr->epoll_fd, EPOLL_CTL_DEL, ep->fd, NULL);
|
|
if (rc < 0) {
|
|
SET_ERROR(errno);
|
|
|
|
rc = -errno;
|
|
}
|
|
mylock_unlock(&(iomgr->lock));
|
|
|
|
return rc;
|
|
}
|
|
|
|
int iomgr_start(iomgr_t* iomgr)
|
|
{
|
|
int rc;
|
|
|
|
rc = pthread_create(&(iomgr->worker), NULL, &io_worker, iomgr);
|
|
return rc;
|
|
}
|
|
|
|
int iomgr_fini(iomgr_t* iomgr)
|
|
{
|
|
if (iomgr->ssl_ctx != NULL) {
|
|
SSL_CTX_free(iomgr->ssl_ctx);
|
|
iomgr->ssl_ctx = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int iomgr_stop(iomgr_t* iomgr)
|
|
{
|
|
int rc;
|
|
void* res;
|
|
|
|
if (iomgr->worker == 0) {
|
|
return 0;
|
|
}
|
|
|
|
rc = pthread_cancel(iomgr->worker);
|
|
if (rc != 0) {
|
|
SET_ERROR(errno);
|
|
|
|
return -errno;
|
|
}
|
|
|
|
rc = pthread_join(iomgr->worker, &res);
|
|
if (rc != 0) {
|
|
SET_ERROR(errno);
|
|
|
|
return -errno;
|
|
}
|
|
|
|
if (res == PTHREAD_CANCELED) {
|
|
iomgr->worker = 0;
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|