|
|
|
@ -84,6 +84,108 @@ int __resolvehost(const char *hostname, char *buf, int buf_len,
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* connection helper, since for accept and connect are the same sets of ops
|
|
|
|
|
* using defines here ... ugly again, btw works.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define SSLX_ACCEPT 0
|
|
|
|
|
#define SSLX_CONNECT 1
|
|
|
|
|
|
|
|
|
|
static int __conn_negotiate(sxlink_t *co, int way)
|
|
|
|
|
{
|
|
|
|
|
int rfd = SSL_get_fd(co->ssl), r;
|
|
|
|
|
fd_set readset, writeset;
|
|
|
|
|
int read_blocked = 0, read_blocked_on_write = 0;
|
|
|
|
|
char em[3];
|
|
|
|
|
|
|
|
|
|
memset(em, 0, sizeof(char)*3);
|
|
|
|
|
switch(way) {
|
|
|
|
|
case SSLX_ACCEPT: strcpy(em, "AC"); break;
|
|
|
|
|
case SSLX_CONNECT: strcpy(em, "CO"); break;
|
|
|
|
|
default:
|
|
|
|
|
sxlink_log(co, SXERROR_LOG, "[sxmplv2] Negotiate way (accept?connect?) is invalid.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__retry:
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
__try_again:
|
|
|
|
|
ERR_clear_error();
|
|
|
|
|
if(way == SSLX_ACCEPT) r = SSL_accept(co->ssl);
|
|
|
|
|
else r = SSL_connect(co->ssl);
|
|
|
|
|
switch(SSL_get_error (co->ssl, r)) {
|
|
|
|
|
case SSL_ERROR_NONE:
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
case SSL_ERROR_WANT_READ:
|
|
|
|
|
/* get prepare to select */
|
|
|
|
|
read_blocked = 1;
|
|
|
|
|
break;
|
|
|
|
|
case SSL_ERROR_WANT_WRITE: /* here we blocked on write */
|
|
|
|
|
read_blocked_on_write = 1;
|
|
|
|
|
break;
|
|
|
|
|
case SSL_ERROR_SYSCALL:
|
|
|
|
|
if(errno == EAGAIN || errno == EINTR) goto __try_again;
|
|
|
|
|
else {
|
|
|
|
|
sxlink_log(co, SXERROR_LOG, "[sxmplv2] (%s)SSL syscall error.\n", em);
|
|
|
|
|
goto __close_conn;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SSL_ERROR_SSL:
|
|
|
|
|
sxlink_log(co, SXERROR_LOG, "[sxmplv2] (%s)SSL error occured:%s. Connection will be closed.\n",
|
|
|
|
|
em, ERR_error_string(ERR_get_error(), NULL));
|
|
|
|
|
goto __close_conn;
|
|
|
|
|
break;
|
|
|
|
|
case SSL_ERROR_ZERO_RETURN:
|
|
|
|
|
sxlink_log(co, SXERROR_LOG, "[sxmplv2] (%s)SSL connection is cleary closed.\n", em);
|
|
|
|
|
default:
|
|
|
|
|
__close_conn:
|
|
|
|
|
ERR_free_strings();
|
|
|
|
|
co->flags |= SXMP_CLOSED;
|
|
|
|
|
sxlink_log(co, SXERROR_LOG, "[sxmplv2] (%s)Unknown error on %s (errno = %d)\n",
|
|
|
|
|
em, co->uuid, errno);
|
|
|
|
|
ERR_remove_state(0);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
} while(SSL_pending(co->ssl) && !read_blocked);
|
|
|
|
|
|
|
|
|
|
__select_retry:
|
|
|
|
|
|
|
|
|
|
if(read_blocked) {
|
|
|
|
|
FD_ZERO(&readset);
|
|
|
|
|
FD_SET(rfd, &readset);
|
|
|
|
|
/* waits until something will be ready to read */
|
|
|
|
|
r = select(rfd + 1, &readset, NULL, NULL, NULL);
|
|
|
|
|
if(r < 0) {
|
|
|
|
|
if(errno == EINTR || errno == EAGAIN) goto __select_retry;
|
|
|
|
|
sxlink_log(co, SXERROR_LOG, "[sxmplv2] (%s)Select (%d) on %s\n", em, errno, co->uuid);
|
|
|
|
|
ERR_remove_state(0);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if(!r) {
|
|
|
|
|
sxlink_log(co, SXERROR_LOG, "[sxmplv2] (%s)Nothing to wait for\n", em);
|
|
|
|
|
ERR_remove_state(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
read_blocked = 0;
|
|
|
|
|
if(r && FD_ISSET(rfd, &readset)) goto __retry; /* try to read again */
|
|
|
|
|
}
|
|
|
|
|
if(read_blocked_on_write) { /* we was blocked on write */
|
|
|
|
|
FD_ZERO(&readset);
|
|
|
|
|
FD_ZERO(&writeset);
|
|
|
|
|
FD_SET(rfd, &readset);
|
|
|
|
|
FD_SET(rfd, &writeset);
|
|
|
|
|
|
|
|
|
|
r = select(rfd + 1, &readset, &writeset, NULL, NULL);
|
|
|
|
|
read_blocked_on_write = 0;
|
|
|
|
|
if(r && FD_ISSET(rfd, &writeset)) goto __retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __conn_read(sxlink_t *co, void *buf, size_t buf_len)
|
|
|
|
|
{
|
|
|
|
|
int rfd = SSL_get_fd(co->ssl), r;
|
|
|
|
@ -979,7 +1081,7 @@ sxlink_t *sxlink_master_accept(sxhub_t *hub, int sck, struct in_addr *addr)
|
|
|
|
|
|
|
|
|
|
/* ok, now we need to init ssl stuff */
|
|
|
|
|
/* check up - do we need to initialize SSL context? */
|
|
|
|
|
r = _sxhub_settls_ctx_s(hub);
|
|
|
|
|
r = _sxhub_settls_ctx_s(hub); /* TODO: mark on first failed attempt */
|
|
|
|
|
if(r != SXE_SUCCESS) goto __fail;
|
|
|
|
|
|
|
|
|
|
/* now we will create an SSL connection */
|
|
|
|
@ -990,7 +1092,8 @@ sxlink_t *sxlink_master_accept(sxhub_t *hub, int sck, struct in_addr *addr)
|
|
|
|
|
/* set the context to verify ssl connection */
|
|
|
|
|
SSL_set_ex_data(link->ssl, ex_ssldata_index, (void *)link);
|
|
|
|
|
SSL_set_accept_state(link->ssl);
|
|
|
|
|
if(SSL_accept(link->ssl) == -1) { r = SXE_EPERM; goto __fail; } /* leak here ? */
|
|
|
|
|
if(__conn_negotiate(link, SSLX_ACCEPT) <= 0)
|
|
|
|
|
{ r = SXE_EPERM; goto __fail; } /* leak here ? */
|
|
|
|
|
|
|
|
|
|
/* set connection to the batch mode */
|
|
|
|
|
link->flags |= SXMP_BATCHMODE;
|
|
|
|
@ -1214,7 +1317,7 @@ sxlink_t *sxlink_connect_at(sxhub_t *hub, const char *host,
|
|
|
|
|
}
|
|
|
|
|
SSL_set_fd(link->ssl, sck); /* attach connected socket */
|
|
|
|
|
SSL_set_connect_state(link->ssl);
|
|
|
|
|
if(SSL_connect(link->ssl) == -1) {
|
|
|
|
|
if(__conn_negotiate(link, SSLX_CONNECT) <= 0) {
|
|
|
|
|
r = SXE_EPERM;
|
|
|
|
|
/* shutdown connection */
|
|
|
|
|
goto __fail;
|
|
|
|
@ -1359,6 +1462,9 @@ sxlink_t *sxlink_connect_at(sxhub_t *hub, const char *host,
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef SSLX_ACCEPT
|
|
|
|
|
#undef SSLX_CONNECT
|
|
|
|
|
|
|
|
|
|
int sxlink_close(sxlink_t *co)
|
|
|
|
|
{
|
|
|
|
|
sxmplv2_head_t mhead;
|
|
|
|
|