Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 371435) +++ channels/chan_sip.c (working copy) @@ -2515,12 +2515,145 @@ return timeout; } +static int sip_tls_read(struct sip_request *req, struct ast_tcptls_session_instance *tcptls_session, int authenticated, time_t start, struct sip_threadinfo *me) +{ + int res, cl, after_poll = 1, need_poll = 1; + struct sip_request reqcpy = { 0, }; + char buf[1024] = ""; + int timeout = -1; + + /* Read in headers one line at a time */ + while (ast_str_strlen(req->data) < 4 || strncmp(REQ_OFFSET_TO_STR(req, data->used - 4), "\r\n\r\n", 4)) { + if (!tcptls_session->client && !authenticated) { + if ((timeout = sip_check_authtimeout(start)) < 0) { + return -1; + } + + if (timeout == 0) { + ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP"); + return -1; + } + } else { + timeout = -1; + } + + /* special polling behavior is required for TLS + * sockets because of the buffering done in the + * TLS layer */ + if (!tcptls_session->ssl || need_poll) { + need_poll = 0; + after_poll = 1; + res = ast_wait_for_input(tcptls_session->fd, timeout); + if (res < 0) { + ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res); + return -1; + } else if (res == 0) { + /* timeout */ + ast_debug(2, "SIP TCP server timed out\n"); + return -1; + } + } + + ast_mutex_lock(&tcptls_session->lock); + if (!fgets(buf, sizeof(buf), tcptls_session->f)) { + ast_mutex_unlock(&tcptls_session->lock); + if (after_poll) { + return -1; + } else { + need_poll = 1; + continue; + } + } + ast_mutex_unlock(&tcptls_session->lock); + after_poll = 0; + if (me->stop) { + return -1; + } + ast_str_append(&req->data, 0, "%s", buf); + } + copy_request(&reqcpy, req); + parse_request(&reqcpy); + /* In order to know how much to read, we need the content-length header */ + if (sscanf(sip_get_header(&reqcpy, "Content-Length"), "%30d", &cl)) { + while (cl > 0) { + size_t bytes_read; + if (!tcptls_session->client && !authenticated) { + if ((timeout = sip_check_authtimeout(start)) < 0) { + return -1; + } + + if (timeout == 0) { + ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP"); + return -1; + } + } else { + timeout = -1; + } + + if (!tcptls_session->ssl || need_poll) { + need_poll = 0; + after_poll = 1; + res = ast_wait_for_input(tcptls_session->fd, timeout); + if (res < 0) { + ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res); + return -1; + } else if (res == 0) { + /* timeout */ + ast_debug(2, "SIP TCP server timed out\n"); + return -1; + } + } + + ast_mutex_lock(&tcptls_session->lock); + if (!(bytes_read = fread(buf, 1, MIN(sizeof(buf) - 1, cl), tcptls_session->f))) { + ast_mutex_unlock(&tcptls_session->lock); + if (after_poll) { + return -1; + } else { + need_poll = 1; + continue; + } + } + buf[bytes_read] = '\0'; + ast_mutex_unlock(&tcptls_session->lock); + after_poll = 0; + if (me->stop) { + return -1; + } + cl -= strlen(buf); + ast_str_append(&req->data, 0, "%s", buf); + } + } + /*! \todo XXX If there's no Content-Length or if the content-length and what + we receive is not the same - we should generate an error */ + return 0; +} + +static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_instance *tcptls_session) +{ + char readbuf[65565]; + int res; + + ast_wait_for_input(tcptls_session->fd, -1); + + res = recv(tcptls_session->fd, readbuf, (sizeof(readbuf)), 0); + if (res < 0) { + ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res); + return -1; + } else if (res == 0) { + ast_debug(2, "SIP TCP server timed out\n"); + return -1; + } + ast_str_append(&req->data, 0, "%s", readbuf); + return 0; +} + /*! \brief SIP TCP thread management function This function reads from the socket, parses the packet into a request */ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_session) { - int res, cl, timeout = -1, authenticated = 0, flags, after_poll = 0, need_poll = 1; + int res, timeout = -1, authenticated = 0, flags; time_t start; struct sip_request req = { 0, } , reqcpy = { 0, }; struct sip_threadinfo *me = NULL; @@ -2584,7 +2717,7 @@ /* set up pollfd to watch for reads on both the socket and the alert_pipe */ fds[0].fd = tcptls_session->fd; fds[1].fd = me->alert_pipe[0]; - fds[0].events = fds[1].events = POLLIN | POLLPRI; + fds[0].events = fds[1].events = POLLIN; if (!(req.data = ast_str_create(SIP_MIN_PACKET))) { goto cleanup; @@ -2633,8 +2766,6 @@ /* handle the socket event, check for both reads from the socket fd, * and writes from alert_pipe fd */ if (fds[0].revents) { /* there is data on the socket to be read */ - after_poll = 1; - fds[0].revents = 0; /* clear request structure */ @@ -2659,111 +2790,14 @@ } req.socket.fd = tcptls_session->fd; - /* Read in headers one line at a time */ - while (ast_str_strlen(req.data) < 4 || strncmp(REQ_OFFSET_TO_STR(&req, data->used - 4), "\r\n\r\n", 4)) { - if (!tcptls_session->client && !authenticated ) { - if ((timeout = sip_check_authtimeout(start)) < 0) { - goto cleanup; - } - - if (timeout == 0) { - ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP"); - goto cleanup; - } - } else { - timeout = -1; + if (tcptls_session->ssl) { + if (sip_tls_read(&req, tcptls_session, authenticated, start, me) < 0) { + goto cleanup; } - - /* special polling behavior is required for TLS - * sockets because of the buffering done in the - * TLS layer */ - if (!tcptls_session->ssl || need_poll) { - need_poll = 0; - after_poll = 1; - res = ast_wait_for_input(tcptls_session->fd, timeout); - if (res < 0) { - ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res); - goto cleanup; - } else if (res == 0) { - /* timeout */ - ast_debug(2, "SIP TCP server timed out\n"); - goto cleanup; - } - } - - ast_mutex_lock(&tcptls_session->lock); - if (!fgets(buf, sizeof(buf), tcptls_session->f)) { - ast_mutex_unlock(&tcptls_session->lock); - if (after_poll) { - goto cleanup; - } else { - need_poll = 1; - continue; - } - } - ast_mutex_unlock(&tcptls_session->lock); - after_poll = 0; - if (me->stop) { - goto cleanup; - } - ast_str_append(&req.data, 0, "%s", buf); + } else if (sip_tcp_read(&req, tcptls_session) < 0) { + goto cleanup; } - copy_request(&reqcpy, &req); - parse_request(&reqcpy); - /* In order to know how much to read, we need the content-length header */ - if (sscanf(sip_get_header(&reqcpy, "Content-Length"), "%30d", &cl)) { - while (cl > 0) { - size_t bytes_read; - if (!tcptls_session->client && !authenticated ) { - if ((timeout = sip_check_authtimeout(start)) < 0) { - goto cleanup; - } - if (timeout == 0) { - ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP"); - goto cleanup; - } - } else { - timeout = -1; - } - - if (!tcptls_session->ssl || need_poll) { - need_poll = 0; - after_poll = 1; - res = ast_wait_for_input(tcptls_session->fd, timeout); - if (res < 0) { - ast_debug(2, "SIP TCP server :: ast_wait_for_input returned %d\n", res); - goto cleanup; - } else if (res == 0) { - /* timeout */ - ast_debug(2, "SIP TCP server timed out\n"); - goto cleanup; - } - } - - ast_mutex_lock(&tcptls_session->lock); - if (!(bytes_read = fread(buf, 1, MIN(sizeof(buf) - 1, cl), tcptls_session->f))) { - ast_mutex_unlock(&tcptls_session->lock); - if (after_poll) { - goto cleanup; - } else { - need_poll = 1; - continue; - } - } - buf[bytes_read] = '\0'; - ast_mutex_unlock(&tcptls_session->lock); - after_poll = 0; - if (me->stop) { - goto cleanup; - } - cl -= strlen(buf); - ast_str_append(&req.data, 0, "%s", buf); - } - } - /*! \todo XXX If there's no Content-Length or if the content-length and what - we receive is not the same - we should generate an error */ - req.socket.tcptls_session = tcptls_session; handle_request_do(&req, &tcptls_session->remote_address); }