[core] bugfix: Fixed rare failed condition on handshake/negotiation stage;

v0.4.xx
Alexander Vdolainen 7 years ago
parent 5531b84123
commit 3d2b51f1fa

@ -84,6 +84,108 @@ int __resolvehost(const char *hostname, char *buf, int buf_len,
} }
#endif #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) static int __conn_read(sxlink_t *co, void *buf, size_t buf_len)
{ {
int rfd = SSL_get_fd(co->ssl), r; 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 */ /* ok, now we need to init ssl stuff */
/* check up - do we need to initialize SSL context? */ /* 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; if(r != SXE_SUCCESS) goto __fail;
/* now we will create an SSL connection */ /* 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 */ /* set the context to verify ssl connection */
SSL_set_ex_data(link->ssl, ex_ssldata_index, (void *)link); SSL_set_ex_data(link->ssl, ex_ssldata_index, (void *)link);
SSL_set_accept_state(link->ssl); 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 */ /* set connection to the batch mode */
link->flags |= SXMP_BATCHMODE; 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_fd(link->ssl, sck); /* attach connected socket */
SSL_set_connect_state(link->ssl); SSL_set_connect_state(link->ssl);
if(SSL_connect(link->ssl) == -1) { if(__conn_negotiate(link, SSLX_CONNECT) <= 0) {
r = SXE_EPERM; r = SXE_EPERM;
/* shutdown connection */ /* shutdown connection */
goto __fail; goto __fail;
@ -1359,6 +1462,9 @@ sxlink_t *sxlink_connect_at(sxhub_t *hub, const char *host,
return NULL; return NULL;
} }
#undef SSLX_ACCEPT
#undef SSLX_CONNECT
int sxlink_close(sxlink_t *co) int sxlink_close(sxlink_t *co)
{ {
sxmplv2_head_t mhead; sxmplv2_head_t mhead;

Loading…
Cancel
Save