|
|
|
@ -64,6 +64,7 @@
|
|
|
|
|
# define USE_SSL
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
void stio_closeasyncsck (stio_t* stio, stio_sckhnd_t sck)
|
|
|
|
|
{
|
|
|
|
@ -359,8 +360,10 @@ static int dev_sck_kill (stio_dev_t* dev, int force)
|
|
|
|
|
|
|
|
|
|
if (IS_STATEFUL(rdev))
|
|
|
|
|
{
|
|
|
|
|
if (rdev->state & (STIO_DEV_SCK_ACCEPTED | STIO_DEV_SCK_CONNECTED | STIO_DEV_SCK_CONNECTING | STIO_DEV_SCK_LISTENING))
|
|
|
|
|
if (STIO_DEV_SCK_GET_PROGRESS(rdev))
|
|
|
|
|
{
|
|
|
|
|
/* for STIO_DEV_SCK_CONNECTING, STIO_DEV_SCK_CONNECTING_SSL, and STIO_DEV_ACCEPTING_SSL
|
|
|
|
|
* on_disconnect() is called without corresponding on_connect() */
|
|
|
|
|
if (rdev->on_disconnect) rdev->on_disconnect (rdev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -473,7 +476,6 @@ static int dev_sck_read_stateless (stio_dev_t* dev, void* buf, stio_iolen_t* len
|
|
|
|
|
static int dev_sck_write_stateful (stio_dev_t* dev, const void* data, stio_iolen_t* len, const stio_devaddr_t* dstaddr)
|
|
|
|
|
{
|
|
|
|
|
stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
if (rdev->ssl)
|
|
|
|
@ -561,6 +563,98 @@ static int dev_sck_write_stateless (stio_dev_t* dev, const void* data, stio_iole
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
static int connect_ssl (stio_dev_sck_t* dev)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (dev->ssl_ctx);
|
|
|
|
|
|
|
|
|
|
if (!dev->ssl)
|
|
|
|
|
{
|
|
|
|
|
SSL* ssl;
|
|
|
|
|
|
|
|
|
|
ssl = SSL_new (dev->ssl_ctx);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
{
|
|
|
|
|
dev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SSL_set_fd (ssl, dev->sck) == 0)
|
|
|
|
|
{
|
|
|
|
|
SSL_free (ssl);
|
|
|
|
|
dev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SSL_set_read_ahead (ssl, 0);
|
|
|
|
|
dev->ssl = ssl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = SSL_connect (dev->ssl);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
{
|
|
|
|
|
int err = SSL_get_error (dev->ssl, ret);
|
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
/* handshaking isn't complete */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1; /* connected */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int accept_ssl (stio_dev_sck_t* dev)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (dev->ssl_ctx);
|
|
|
|
|
|
|
|
|
|
if (!dev->ssl)
|
|
|
|
|
{
|
|
|
|
|
SSL* ssl;
|
|
|
|
|
|
|
|
|
|
ssl = SSL_new (dev->ssl_ctx);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
{
|
|
|
|
|
dev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SSL_set_fd (ssl, dev->sck) == 0)
|
|
|
|
|
{
|
|
|
|
|
dev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
SSL_set_read_ahead (ssl, 0);
|
|
|
|
|
|
|
|
|
|
dev->ssl = ssl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = SSL_accept ((SSL*)dev->ssl);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
{
|
|
|
|
|
int err = SSL_get_error (dev->ssl, ret);
|
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
/* handshaking isn't complete */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1; /* accepted */
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
|
|
|
|
{
|
|
|
|
|
stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev;
|
|
|
|
@ -654,8 +748,8 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
|
|
|
|
SSL_CTX_check_private_key (ssl_ctx) == 0 /*||
|
|
|
|
|
SSL_CTX_use_certificate_chain_file (ssl_ctx, bnd->chainfile) == 0*/)
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
SSL_CTX_free (ssl_ctx);
|
|
|
|
|
rdev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -699,7 +793,6 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
|
|
|
|
int x;
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
SSL_CTX* ssl_ctx = STIO_NULL;
|
|
|
|
|
SSL* ssl = STIO_NULL;
|
|
|
|
|
#endif
|
|
|
|
|
if (!IS_STATEFUL(rdev))
|
|
|
|
|
{
|
|
|
|
@ -715,25 +808,41 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
if (conn->options & STIO_DEV_SCK_CONNECT_SSL)
|
|
|
|
|
{
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
|
|
|
|
if (!ssl_ctx)
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*{
|
|
|
|
|
int flags = fcntl (rdev->sck, F_GETFL);
|
|
|
|
|
fcntl (rdev->sck, F_SETFL, flags & ~O_NONBLOCK);
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
/* the socket is already non-blocking */
|
|
|
|
|
x = connect (rdev->sck, sa, sl);
|
|
|
|
|
/*{
|
|
|
|
|
int flags = fcntl (rdev->sck, F_GETFL);
|
|
|
|
|
fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK);
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
if (x == -1)
|
|
|
|
|
{
|
|
|
|
|
if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN)
|
|
|
|
|
{
|
|
|
|
|
if (stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) >= 0)
|
|
|
|
|
if (stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT) <= -1)
|
|
|
|
|
{
|
|
|
|
|
/* watcher update failure. it's critical */
|
|
|
|
|
stio_stop (rdev->stio, STIO_STOPREQ_WATCHER_UPDATE_ERROR);
|
|
|
|
|
goto oops_connect;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
stio_tmrjob_t tmrjob;
|
|
|
|
|
|
|
|
|
@ -748,58 +857,72 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (rdev->tmrjob_index == STIO_TMRIDX_INVALID);
|
|
|
|
|
rdev->tmrjob_index = stio_instmrjob (rdev->stio, &tmrjob);
|
|
|
|
|
if (rdev->tmrjob_index == STIO_TMRIDX_INVALID)
|
|
|
|
|
{
|
|
|
|
|
stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN);
|
|
|
|
|
/* event manipulation failure can't be handled properly. so ignore it.
|
|
|
|
|
* anyway, it's already in a failure condition */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (rdev->tmrjob_index == STIO_TMRIDX_INVALID) goto oops_connect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdev->state |= STIO_DEV_SCK_CONNECTING;
|
|
|
|
|
rdev->remoteaddr = conn->remoteaddr;
|
|
|
|
|
rdev->on_connect = conn->on_connect;
|
|
|
|
|
rdev->on_disconnect = conn->on_disconnect;
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
rdev->ssl_ctx = ssl_ctx;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
ssl = SSL_new (ssl_ctx);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SSL_set_fd (ssl, rdev->sck);
|
|
|
|
|
|
|
|
|
|
if (SSL_connect(ssl) <= 0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdev->stio->errnum = stio_syserrtoerrnum(errno);
|
|
|
|
|
|
|
|
|
|
oops_connect:
|
|
|
|
|
if (stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_UPDATE, STIO_DEV_EVENT_IN) <= -1)
|
|
|
|
|
{
|
|
|
|
|
/* watcher update failure. it's critical */
|
|
|
|
|
stio_stop (rdev->stio, STIO_STOPREQ_WATCHER_UPDATE_ERROR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
if (ssl_ctx) SSL_CTX_free (ssl_ctx);
|
|
|
|
|
#endif
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* connected immediately */
|
|
|
|
|
|
|
|
|
|
rdev->remoteaddr = conn->remoteaddr;
|
|
|
|
|
rdev->on_connect = conn->on_connect;
|
|
|
|
|
rdev->on_disconnect = conn->on_disconnect;
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
rdev->ssl_ctx = ssl_ctx;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* connected immediately */
|
|
|
|
|
rdev->state |= STIO_DEV_SCK_CONNECTED;
|
|
|
|
|
rdev->remoteaddr = conn->remoteaddr;
|
|
|
|
|
rdev->on_connect = conn->on_connect;
|
|
|
|
|
rdev->on_disconnect = conn->on_disconnect;
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
rdev->ssl_ctx = ssl_ctx;
|
|
|
|
|
#endif
|
|
|
|
|
sl = STIO_SIZEOF(localaddr);
|
|
|
|
|
if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &sl) == 0) rdev->localaddr = localaddr;
|
|
|
|
|
|
|
|
|
|
sl = STIO_SIZEOF(localaddr);
|
|
|
|
|
if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &sl) == 0) rdev->localaddr = localaddr;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
if (ssl_ctx)
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
x = connect_ssl (rdev);
|
|
|
|
|
if (x <= -1) return -1;
|
|
|
|
|
if (x == 0)
|
|
|
|
|
{
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING_SSL);
|
|
|
|
|
/* TODO: schedule a ssl-connecting timeout job */
|
|
|
|
|
}
|
|
|
|
|
else goto connect_ok;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
connect_ok:
|
|
|
|
|
#endif
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTED);
|
|
|
|
|
if (rdev->on_connect (rdev) <= -1) return -1;
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case STIO_DEV_SCK_LISTEN:
|
|
|
|
@ -820,7 +943,7 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdev->state |= STIO_DEV_SCK_LISTENING;
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_LISTENING);
|
|
|
|
|
rdev->on_connect = lstn->on_connect;
|
|
|
|
|
rdev->on_disconnect = lstn->on_disconnect;
|
|
|
|
|
return 0;
|
|
|
|
@ -866,6 +989,210 @@ static stio_dev_mth_t dev_mth_clisck =
|
|
|
|
|
};
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
|
|
static int harvest_outgoing_connection (stio_dev_sck_t* rdev)
|
|
|
|
|
{
|
|
|
|
|
int errcode;
|
|
|
|
|
stio_scklen_t len;
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (!(rdev->state & STIO_DEV_SCK_CONNECTED));
|
|
|
|
|
|
|
|
|
|
len = STIO_SIZEOF(errcode);
|
|
|
|
|
if (getsockopt (rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1)
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = stio_syserrtoerrnum(errno);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (errcode == 0)
|
|
|
|
|
{
|
|
|
|
|
stio_sckaddr_t localaddr;
|
|
|
|
|
stio_scklen_t addrlen;
|
|
|
|
|
|
|
|
|
|
/* connected */
|
|
|
|
|
|
|
|
|
|
if (rdev->tmrjob_index != STIO_TMRIDX_INVALID)
|
|
|
|
|
{
|
|
|
|
|
stio_deltmrjob (rdev->stio, rdev->tmrjob_index);
|
|
|
|
|
STIO_ASSERT (rdev->tmrjob_index == STIO_TMRIDX_INVALID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addrlen = STIO_SIZEOF(localaddr);
|
|
|
|
|
if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &addrlen) == 0) rdev->localaddr = localaddr;
|
|
|
|
|
|
|
|
|
|
if (stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_RENEW, 0) <= -1)
|
|
|
|
|
{
|
|
|
|
|
/* watcher update failure. it's critical */
|
|
|
|
|
stio_stop (rdev->stio, STIO_STOPREQ_WATCHER_RENEW_ERROR);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
if (rdev->ssl_ctx)
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
STIO_ASSERT (!rdev->ssl); /* must not be SSL-connected yet */
|
|
|
|
|
|
|
|
|
|
x = connect_ssl (rdev);
|
|
|
|
|
if (x <= -1) return -1;
|
|
|
|
|
if (x == 0)
|
|
|
|
|
{
|
|
|
|
|
/* not SSL-connected */
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING_SSL);
|
|
|
|
|
/* TODO: schedule ssl_connect timeout job */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
goto ssl_connected;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ssl_connected:
|
|
|
|
|
#endif
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTED);
|
|
|
|
|
if (rdev->on_connect (rdev) <= -1) return -1;
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (errcode == EINPROGRESS || errcode == EWOULDBLOCK)
|
|
|
|
|
{
|
|
|
|
|
/* still in progress */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = stio_syserrtoerrnum(errcode);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int accept_incoming_connection (stio_dev_sck_t* rdev)
|
|
|
|
|
{
|
|
|
|
|
stio_sckhnd_t clisck;
|
|
|
|
|
stio_sckaddr_t remoteaddr;
|
|
|
|
|
stio_scklen_t addrlen;
|
|
|
|
|
stio_dev_sck_t* clidev;
|
|
|
|
|
|
|
|
|
|
/* this is a server(lisening) socket */
|
|
|
|
|
|
|
|
|
|
addrlen = STIO_SIZEOF(remoteaddr);
|
|
|
|
|
clisck = accept (rdev->sck, (struct sockaddr*)&remoteaddr, &addrlen);
|
|
|
|
|
if (clisck == STIO_SCKHND_INVALID)
|
|
|
|
|
{
|
|
|
|
|
if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
|
|
|
|
|
if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */
|
|
|
|
|
|
|
|
|
|
rdev->stio->errnum = stio_syserrtoerrnum(errno);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* use rdev->dev_size when instantiating a client sck device
|
|
|
|
|
* instead of STIO_SIZEOF(stio_dev_sck_t). therefore, the
|
|
|
|
|
* extension area as big as that of the master sck device
|
|
|
|
|
* is created in the client sck device */
|
|
|
|
|
clidev = (stio_dev_sck_t*)stio_makedev (rdev->stio, rdev->dev_size, &dev_mth_clisck, rdev->dev_evcb, &clisck);
|
|
|
|
|
if (!clidev)
|
|
|
|
|
{
|
|
|
|
|
close (clisck);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (clidev->sck == clisck);
|
|
|
|
|
|
|
|
|
|
clidev->dev_capa |= STIO_DEV_CAPA_IN | STIO_DEV_CAPA_OUT | STIO_DEV_CAPA_STREAM | STIO_DEV_CAPA_OUT_QUEUED;
|
|
|
|
|
clidev->remoteaddr = remoteaddr;
|
|
|
|
|
|
|
|
|
|
addrlen = STIO_SIZEOF(clidev->localaddr);
|
|
|
|
|
if (getsockname(clisck, (struct sockaddr*)&clidev->localaddr, &addrlen) == -1) clidev->localaddr = rdev->localaddr;
|
|
|
|
|
|
|
|
|
|
#if defined(SO_ORIGINAL_DST)
|
|
|
|
|
/* if REDIRECT is used, SO_ORIGINAL_DST returns the original
|
|
|
|
|
* destination address. When REDIRECT is not used, it returnes
|
|
|
|
|
* the address of the local socket. In this case, it should
|
|
|
|
|
* be same as the result of getsockname(). */
|
|
|
|
|
addrlen = STIO_SIZEOF(clidev->orgdstaddr);
|
|
|
|
|
if (getsockopt (clisck, SOL_IP, SO_ORIGINAL_DST, &clidev->orgdstaddr, &addrlen) == -1) clidev->orgdstaddr = rdev->localaddr;
|
|
|
|
|
#else
|
|
|
|
|
clidev->orgdstaddr = rdev->localaddr;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!stio_equalsckaddrs (rdev->stio, &clidev->orgdstaddr, &clidev->localaddr))
|
|
|
|
|
{
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_INTERCEPTED;
|
|
|
|
|
}
|
|
|
|
|
else if (stio_getsckaddrport (&clidev->localaddr) != stio_getsckaddrport(&rdev->localaddr))
|
|
|
|
|
{
|
|
|
|
|
/* When TPROXY is used, getsockname() and SO_ORIGNAL_DST return
|
|
|
|
|
* the same addresses. however, the port number may be different
|
|
|
|
|
* as a typical TPROXY rule is set to change the port number.
|
|
|
|
|
* However, this check is fragile if the server port number is
|
|
|
|
|
* set to 0.
|
|
|
|
|
*
|
|
|
|
|
* Take note that the above assumption gets wrong if the TPROXY
|
|
|
|
|
* rule doesn't change the port number. so it won't be able
|
|
|
|
|
* to handle such a TPROXYed packet without port transformation. */
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_INTERCEPTED;
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
|
|
|
|
else if ((clidev->initial_ifindex = resolve_ifindex (fd, clidev->localaddr)) <= -1)
|
|
|
|
|
{
|
|
|
|
|
/* the local_address is not one of a local address.
|
|
|
|
|
* it's probably proxied. */
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_INTERCEPTED;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* inherit some event handlers from the parent.
|
|
|
|
|
* you can still change them inside the on_connect handler */
|
|
|
|
|
clidev->on_connect = rdev->on_connect;
|
|
|
|
|
clidev->on_disconnect = rdev->on_disconnect;
|
|
|
|
|
clidev->on_write = rdev->on_write;
|
|
|
|
|
clidev->on_read = rdev->on_read;
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (clidev->tmrjob_index == STIO_TMRIDX_INVALID);
|
|
|
|
|
|
|
|
|
|
if (rdev->ssl_ctx)
|
|
|
|
|
{
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (clidev, STIO_DEV_SCK_ACCEPTING_SSL);
|
|
|
|
|
STIO_ASSERT (clidev->state & STIO_DEV_SCK_ACCEPTING_SSL);
|
|
|
|
|
/* actual SSL acceptance must be completed in the client device */
|
|
|
|
|
|
|
|
|
|
/* let the client device know the SSL context to use */
|
|
|
|
|
clidev->ssl_ctx = rdev->ssl_ctx;
|
|
|
|
|
|
|
|
|
|
if (stio_ispostime(&rdev->ssl_accept_tmout))
|
|
|
|
|
{
|
|
|
|
|
stio_tmrjob_t tmrjob;
|
|
|
|
|
|
|
|
|
|
STIO_MEMSET (&tmrjob, 0, STIO_SIZEOF(tmrjob));
|
|
|
|
|
tmrjob.ctx = clidev;
|
|
|
|
|
stio_gettime (&tmrjob.when);
|
|
|
|
|
stio_addtime (&tmrjob.when, &rdev->ssl_accept_tmout, &tmrjob.when);
|
|
|
|
|
|
|
|
|
|
tmrjob.handler = ssl_accept_timedout;
|
|
|
|
|
tmrjob.idxptr = &clidev->tmrjob_index;
|
|
|
|
|
|
|
|
|
|
clidev->tmrjob_index = stio_instmrjob (clidev->stio, &tmrjob);
|
|
|
|
|
if (clidev->tmrjob_index == STIO_TMRIDX_INVALID)
|
|
|
|
|
{
|
|
|
|
|
/* TODO: call a warning/error callback */
|
|
|
|
|
/* timer job scheduling failed. halt the device */
|
|
|
|
|
stio_dev_halt ((stio_dev_t*)clidev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (clidev, STIO_DEV_SCK_ACCEPTED);
|
|
|
|
|
if (clidev->on_connect(clidev) <= -1) stio_dev_sck_halt (clidev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dev_evcb_sck_ready_stateful (stio_dev_t* dev, int events)
|
|
|
|
|
{
|
|
|
|
|
stio_dev_sck_t* rdev = (stio_dev_sck_t*)dev;
|
|
|
|
@ -892,286 +1219,151 @@ static int dev_evcb_sck_ready_stateful (stio_dev_t* dev, int events)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this socket can connect */
|
|
|
|
|
if (rdev->state & STIO_DEV_SCK_CONNECTING)
|
|
|
|
|
switch (STIO_DEV_SCK_GET_PROGRESS(rdev))
|
|
|
|
|
{
|
|
|
|
|
if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
/* device hang-up */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_IN))
|
|
|
|
|
{
|
|
|
|
|
/* invalid event masks. generic device error */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & STIO_DEV_EVENT_OUT)
|
|
|
|
|
{
|
|
|
|
|
int errcode;
|
|
|
|
|
stio_scklen_t len;
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (!(rdev->state & STIO_DEV_SCK_CONNECTED));
|
|
|
|
|
|
|
|
|
|
len = STIO_SIZEOF(errcode);
|
|
|
|
|
if (getsockopt (rdev->sck, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1)
|
|
|
|
|
case STIO_DEV_SCK_CONNECTING:
|
|
|
|
|
if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = stio_syserrtoerrnum(errno);
|
|
|
|
|
/* device hang-up */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (errcode == 0)
|
|
|
|
|
else if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_IN))
|
|
|
|
|
{
|
|
|
|
|
stio_sckaddr_t localaddr;
|
|
|
|
|
stio_scklen_t addrlen;
|
|
|
|
|
/* invalid event masks. generic device error */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & STIO_DEV_EVENT_OUT)
|
|
|
|
|
{
|
|
|
|
|
/* when connected, the socket becomes writable */
|
|
|
|
|
return harvest_outgoing_connection (rdev);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0; /* success but don't invoke on_read() */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdev->state &= ~STIO_DEV_SCK_CONNECTING;
|
|
|
|
|
rdev->state |= STIO_DEV_SCK_CONNECTED;
|
|
|
|
|
case STIO_DEV_SCK_CONNECTING_SSL:
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
/* device hang-up */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & STIO_DEV_EVENT_PRI)
|
|
|
|
|
{
|
|
|
|
|
/* invalid event masks. generic device error */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & (STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT))
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
|
|
|
|
|
if (stio_dev_watch ((stio_dev_t*)rdev, STIO_DEV_WATCH_RENEW, 0) <= -1) return -1;
|
|
|
|
|
x = connect_ssl (rdev);
|
|
|
|
|
if (x <= -1) return -1;
|
|
|
|
|
if (x == 0) return 0; /* not SSL-Connected */
|
|
|
|
|
|
|
|
|
|
if (rdev->tmrjob_index != STIO_TMRIDX_INVALID)
|
|
|
|
|
{
|
|
|
|
|
stio_deltmrjob (rdev->stio, rdev->tmrjob_index);
|
|
|
|
|
STIO_ASSERT (rdev->tmrjob_index == STIO_TMRIDX_INVALID);
|
|
|
|
|
rdev->tmrjob_index = STIO_TMRIDX_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addrlen = STIO_SIZEOF(localaddr);
|
|
|
|
|
if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &addrlen) == 0) rdev->localaddr = localaddr;
|
|
|
|
|
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTED);
|
|
|
|
|
if (rdev->on_connect (rdev) <= -1) return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (errcode == EINPROGRESS || errcode == EWOULDBLOCK)
|
|
|
|
|
{
|
|
|
|
|
/* still in progress */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = stio_syserrtoerrnum(errcode);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0; /* success but don't invoke on_read() */
|
|
|
|
|
}
|
|
|
|
|
else if (rdev->state & STIO_DEV_SCK_LISTENING)
|
|
|
|
|
{
|
|
|
|
|
if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
/* device hang-up */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_OUT))
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & STIO_DEV_EVENT_IN)
|
|
|
|
|
{
|
|
|
|
|
stio_sckhnd_t clisck;
|
|
|
|
|
stio_sckaddr_t remoteaddr;
|
|
|
|
|
stio_scklen_t addrlen;
|
|
|
|
|
stio_dev_sck_t* clidev;
|
|
|
|
|
|
|
|
|
|
/* this is a server(lisening) socket */
|
|
|
|
|
|
|
|
|
|
addrlen = STIO_SIZEOF(remoteaddr);
|
|
|
|
|
clisck = accept (rdev->sck, (struct sockaddr*)&remoteaddr, &addrlen);
|
|
|
|
|
if (clisck == STIO_SCKHND_INVALID)
|
|
|
|
|
{
|
|
|
|
|
if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
|
|
|
|
|
if (errno == EINTR) return 0; /* if interrupted by a signal, treat it as if it's EINPROGRESS */
|
|
|
|
|
|
|
|
|
|
rdev->stio->errnum = stio_syserrtoerrnum(errno);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* use rdev->dev_size when instantiating a client sck device
|
|
|
|
|
* instead of STIO_SIZEOF(stio_dev_sck_t). therefore, the
|
|
|
|
|
* extension area as big as that of the master sck device
|
|
|
|
|
* is created in the client sck device */
|
|
|
|
|
clidev = (stio_dev_sck_t*)stio_makedev (rdev->stio, rdev->dev_size, &dev_mth_clisck, rdev->dev_evcb, &clisck);
|
|
|
|
|
if (!clidev)
|
|
|
|
|
{
|
|
|
|
|
close (clisck);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (clidev->sck == clisck);
|
|
|
|
|
|
|
|
|
|
clidev->dev_capa |= STIO_DEV_CAPA_IN | STIO_DEV_CAPA_OUT | STIO_DEV_CAPA_STREAM | STIO_DEV_CAPA_OUT_QUEUED;
|
|
|
|
|
if (rdev->ssl_ctx)
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_ACCEPTING_SSL;
|
|
|
|
|
else
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_ACCEPTED;
|
|
|
|
|
/*clidev->parent = sck;*/
|
|
|
|
|
clidev->remoteaddr = remoteaddr;
|
|
|
|
|
|
|
|
|
|
addrlen = STIO_SIZEOF(clidev->localaddr);
|
|
|
|
|
if (getsockname(clisck, (struct sockaddr*)&clidev->localaddr, &addrlen) == -1) clidev->localaddr = rdev->localaddr;
|
|
|
|
|
|
|
|
|
|
#if defined(SO_ORIGINAL_DST)
|
|
|
|
|
/* if REDIRECT is used, SO_ORIGINAL_DST returns the original
|
|
|
|
|
* destination address. When REDIRECT is not used, it returnes
|
|
|
|
|
* the address of the local socket. In this case, it should
|
|
|
|
|
* be same as the result of getsockname(). */
|
|
|
|
|
addrlen = STIO_SIZEOF(clidev->orgdstaddr);
|
|
|
|
|
if (getsockopt (clisck, SOL_IP, SO_ORIGINAL_DST, &clidev->orgdstaddr, &addrlen) == -1) clidev->orgdstaddr = rdev->localaddr;
|
|
|
|
|
#else
|
|
|
|
|
clidev->orgdstaddr = rdev->localaddr;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!stio_equalsckaddrs (rdev->stio, &clidev->orgdstaddr, &clidev->localaddr))
|
|
|
|
|
{
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_INTERCEPTED;
|
|
|
|
|
}
|
|
|
|
|
else if (stio_getsckaddrport (&clidev->localaddr) != stio_getsckaddrport(&rdev->localaddr))
|
|
|
|
|
{
|
|
|
|
|
/* When TPROXY is used, getsockname() and SO_ORIGNAL_DST return
|
|
|
|
|
* the same addresses. however, the port number may be different
|
|
|
|
|
* as a typical TPROXY rule is set to change the port number.
|
|
|
|
|
* However, this check is fragile if the server port number is
|
|
|
|
|
* set to 0.
|
|
|
|
|
*
|
|
|
|
|
* Take note that the above assumption gets wrong if the TPROXY
|
|
|
|
|
* rule doesn't change the port number. so it won't be able
|
|
|
|
|
* to handle such a TPROXYed packet without port transformation. */
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_INTERCEPTED;
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
|
|
|
|
else if ((clidev->initial_ifindex = resolve_ifindex (fd, clidev->localaddr)) <= -1)
|
|
|
|
|
{
|
|
|
|
|
/* the local_address is not one of a local address.
|
|
|
|
|
* it's probably proxied. */
|
|
|
|
|
clidev->state |= STIO_DEV_SCK_INTERCEPTED;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* inherit some event handlers from the parent.
|
|
|
|
|
* you can still change them inside the on_connect handler */
|
|
|
|
|
clidev->on_connect = rdev->on_connect;
|
|
|
|
|
clidev->on_disconnect = rdev->on_disconnect;
|
|
|
|
|
clidev->on_write = rdev->on_write;
|
|
|
|
|
clidev->on_read = rdev->on_read;
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (clidev->tmrjob_index == STIO_TMRIDX_INVALID);
|
|
|
|
|
|
|
|
|
|
if (clidev->state & STIO_DEV_SCK_ACCEPTED)
|
|
|
|
|
{
|
|
|
|
|
STIO_ASSERT (!(clidev->state & STIO_DEV_SCK_ACCEPTING_SSL));
|
|
|
|
|
if (clidev->on_connect(clidev) <= -1) stio_dev_sck_halt (clidev);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STIO_ASSERT (clidev->state & STIO_DEV_SCK_ACCEPTING_SSL);
|
|
|
|
|
/* actual SSL acceptance must be completed in the client device */
|
|
|
|
|
|
|
|
|
|
/* let the client device know the SSL context to use */
|
|
|
|
|
clidev->ssl_ctx = rdev->ssl_ctx;
|
|
|
|
|
|
|
|
|
|
if (stio_ispostime(&rdev->ssl_accept_tmout))
|
|
|
|
|
{
|
|
|
|
|
stio_tmrjob_t tmrjob;
|
|
|
|
|
|
|
|
|
|
STIO_MEMSET (&tmrjob, 0, STIO_SIZEOF(tmrjob));
|
|
|
|
|
tmrjob.ctx = clidev;
|
|
|
|
|
stio_gettime (&tmrjob.when);
|
|
|
|
|
stio_addtime (&tmrjob.when, &rdev->ssl_accept_tmout, &tmrjob.when);
|
|
|
|
|
|
|
|
|
|
tmrjob.handler = ssl_accept_timedout;
|
|
|
|
|
tmrjob.idxptr = &clidev->tmrjob_index;
|
|
|
|
|
|
|
|
|
|
clidev->tmrjob_index = stio_instmrjob (clidev->stio, &tmrjob);
|
|
|
|
|
if (clidev->tmrjob_index == STIO_TMRIDX_INVALID)
|
|
|
|
|
{
|
|
|
|
|
/* TODO: call a warning callback */
|
|
|
|
|
printf ("SSL ACCEPT TIMEOUT CAN't BE HONORED....\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0; /* success but don't invoke on_read() */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (rdev->state & STIO_DEV_SCK_ACCEPTING_SSL)
|
|
|
|
|
{
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
printf ("SSL IN ACCPEING>.. %p.......................\n", rdev);
|
|
|
|
|
/* client socket has been accepted. SSL accpetance is needed here */
|
|
|
|
|
if (!rdev->ssl)
|
|
|
|
|
{
|
|
|
|
|
SSL* ssl;
|
|
|
|
|
|
|
|
|
|
printf ("SSL CREATED.....................\n");
|
|
|
|
|
ssl = SSL_new (rdev->ssl_ctx);
|
|
|
|
|
if (!ssl)
|
|
|
|
|
{
|
|
|
|
|
printf ("SSL ERROR 1>..................... %s\n", ERR_reason_error_string(ERR_get_error()));
|
|
|
|
|
rdev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SSL_set_fd (ssl, rdev->sck) == 0)
|
|
|
|
|
{
|
|
|
|
|
printf ("SSL ERROR 2>..................... %s\n", ERR_reason_error_string(ERR_get_error()));
|
|
|
|
|
rdev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
SSL_set_read_ahead (ssl, 0);
|
|
|
|
|
|
|
|
|
|
rdev->ssl = ssl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = SSL_accept ((SSL*)rdev->ssl);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
{
|
|
|
|
|
int err = SSL_get_error (rdev->ssl, ret);
|
|
|
|
|
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
/* handshaking isn't complete */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf ("SSL ERROR 3>..................... %s\n", ERR_reason_error_string(err));
|
|
|
|
|
rdev->stio->errnum = STIO_ESYSERR;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0; /* success. no actual I/O yet */
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
rdev->stio->errnum = STIO_EINTERN;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
printf ("SSL ACCEPTED.....................\n");
|
|
|
|
|
if (rdev->tmrjob_index != STIO_TMRIDX_INVALID)
|
|
|
|
|
{
|
|
|
|
|
stio_deltmrjob (rdev->stio, rdev->tmrjob_index);
|
|
|
|
|
rdev->tmrjob_index = STIO_TMRIDX_INVALID;
|
|
|
|
|
}
|
|
|
|
|
case STIO_DEV_SCK_LISTENING:
|
|
|
|
|
|
|
|
|
|
rdev->state &= ~STIO_DEV_SCK_ACCEPTING_SSL;
|
|
|
|
|
rdev->state |= STIO_DEV_SCK_ACCEPTED;
|
|
|
|
|
if (rdev->on_connect(rdev) <= -1) stio_dev_sck_halt (rdev);
|
|
|
|
|
if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
/* device hang-up */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_OUT))
|
|
|
|
|
{
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & STIO_DEV_EVENT_IN)
|
|
|
|
|
{
|
|
|
|
|
return accept_incoming_connection (rdev);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0; /* success but don't invoke on_read() */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0; /* no reading or writing yet */
|
|
|
|
|
case STIO_DEV_SCK_ACCEPTING_SSL:
|
|
|
|
|
#if defined(USE_SSL)
|
|
|
|
|
if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
/* device hang-up */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & STIO_DEV_EVENT_PRI)
|
|
|
|
|
{
|
|
|
|
|
/* invalid event masks. generic device error */
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVERR;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else if (events & (STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT))
|
|
|
|
|
{
|
|
|
|
|
int x;
|
|
|
|
|
x = accept_ssl (rdev);
|
|
|
|
|
if (x <= -1) return -1;
|
|
|
|
|
if (x <= 0) return 0; /* not SSL-accepted yet */
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
rdev->stio->errnum = STIO_EINTERN;
|
|
|
|
|
return -1;
|
|
|
|
|
#endif
|
|
|
|
|
if (rdev->tmrjob_index != STIO_TMRIDX_INVALID)
|
|
|
|
|
{
|
|
|
|
|
stio_deltmrjob (rdev->stio, rdev->tmrjob_index);
|
|
|
|
|
rdev->tmrjob_index = STIO_TMRIDX_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_ACCEPTED);
|
|
|
|
|
if (rdev->on_connect(rdev) <= -1) stio_dev_sck_halt (rdev);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0; /* no reading or writing yet */
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
rdev->stio->errnum = STIO_EINTERN;
|
|
|
|
|
return -1;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT))
|
|
|
|
|
{
|
|
|
|
|
/* probably half-open? */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1; /* the device is ok. carry on reading or writing */
|
|
|
|
|
}
|
|
|
|
|
else if (events & STIO_DEV_EVENT_HUP)
|
|
|
|
|
{
|
|
|
|
|
if (events & (STIO_DEV_EVENT_PRI | STIO_DEV_EVENT_IN | STIO_DEV_EVENT_OUT))
|
|
|
|
|
{
|
|
|
|
|
/* probably half-open? */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rdev->stio->errnum = STIO_EDEVHUP;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1; /* the device is ok. carry on reading or writing */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dev_evcb_sck_ready_stateless (stio_dev_t* dev, int events)
|
|
|
|
|