diff --git a/channels/chan_sip.c b/channels/chan_sip.c index d1461abf84..76b184bb8e 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -2646,156 +2646,6 @@ static int sip_check_authtimeout(time_t start) return timeout; } -/*! - * \brief Read a SIP request or response from a TLS connection - * - * Because TLS operations are hidden from view via a FILE handle, the - * logic for reading data is a bit complex, and we have to make periodic - * checks to be sure we aren't taking too long to perform the necessary - * action. - * - * \todo XXX This should be altered in the future not to use a FILE pointer - * - * \param req The request structure to fill in - * \param tcptls_session The TLS connection on which the data is being received - * \param authenticated A flag indicating whether authentication has occurred yet. - * This is only relevant in a server role. - * \param start The time at which we started attempting to read data. Used in - * determining if there has been a timeout. - * \param me Thread info. Used as a means of determining if the session needs to be stoppped. - * \retval -1 Failed to read data - * \retval 0 Succeeded in reading data - */ -static int sip_tls_read(struct sip_request *req, struct sip_request *reqcpy, struct ast_tcptls_session_instance *tcptls_session, - int authenticated, time_t start, struct sip_threadinfo *me) -{ - int res, content_length, after_poll = 1, need_poll = 1; - size_t datalen = ast_str_strlen(req->data); - char buf[1024] = ""; - int timeout = -1; - - /* Read in headers one line at a time */ - while (datalen < 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) { - ast_debug(2, "SIP TLS server failed to determine authentication timeout\n"); - return -1; - } - - if (timeout == 0) { - ast_debug(2, "SIP TLS server timed out\n"); - return -1; - } - } else { - timeout = -1; - } - - /* special polling behavior is required for TLS - * sockets because of the buffering done in the - * TLS layer */ - if (need_poll) { - need_poll = 0; - after_poll = 1; - res = ast_wait_for_input(tcptls_session->fd, timeout); - if (res < 0) { - ast_debug(2, "SIP TLS server :: ast_wait_for_input returned %d\n", res); - return -1; - } else if (res == 0) { - /* timeout */ - ast_debug(2, "SIP TLS server timed out\n"); - return -1; - } - } - - ao2_lock(tcptls_session); - if (!fgets(buf, sizeof(buf), tcptls_session->f)) { - ao2_unlock(tcptls_session); - if (after_poll) { - return -1; - } else { - need_poll = 1; - continue; - } - } - ao2_unlock(tcptls_session); - after_poll = 0; - if (me->stop) { - return -1; - } - ast_str_append(&req->data, 0, "%s", buf); - - datalen = ast_str_strlen(req->data); - if (datalen > SIP_MAX_PACKET_SIZE) { - ast_log(LOG_WARNING, "Rejecting TLS packet from '%s' because way too large: %zu\n", - ast_sockaddr_stringify(&tcptls_session->remote_address), datalen); - return -1; - } - } - 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", &content_length)) { - while (content_length > 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 TLS server timed out\n"); - return -1; - } - } else { - timeout = -1; - } - - if (need_poll) { - need_poll = 0; - after_poll = 1; - res = ast_wait_for_input(tcptls_session->fd, timeout); - if (res < 0) { - ast_debug(2, "SIP TLS server :: ast_wait_for_input returned %d\n", res); - return -1; - } else if (res == 0) { - /* timeout */ - ast_debug(2, "SIP TLS server timed out\n"); - return -1; - } - } - - ao2_lock(tcptls_session); - if (!(bytes_read = fread(buf, 1, MIN(sizeof(buf) - 1, content_length), tcptls_session->f))) { - ao2_unlock(tcptls_session); - if (after_poll) { - return -1; - } else { - need_poll = 1; - continue; - } - } - buf[bytes_read] = '\0'; - ao2_unlock(tcptls_session); - after_poll = 0; - if (me->stop) { - return -1; - } - content_length -= strlen(buf); - ast_str_append(&req->data, 0, "%s", buf); - - datalen = ast_str_strlen(req->data); - if (datalen > SIP_MAX_PACKET_SIZE) { - ast_log(LOG_WARNING, "Rejecting TLS packet from '%s' because way too large: %zu\n", - ast_sockaddr_stringify(&tcptls_session->remote_address), datalen); - return -1; - } - } - } - /*! \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; -} - /*! * \brief Indication of a TCP message's integrity */ @@ -2949,14 +2799,14 @@ static enum message_integrity check_message_integrity(struct ast_str **request, } /*! - * \brief Read SIP request or response from a TCP connection + * \brief Read SIP request or response from a TCP/TLS connection * * \param req The request structure to be filled in - * \param tcptls_session The TCP connection from which to read + * \param tcptls_session The TCP/TLS connection from which to read * \retval -1 Failed to read data * \retval 0 Successfully read data */ -static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_instance *tcptls_session, +static int sip_tcptls_read(struct sip_request *req, struct ast_tcptls_session_instance *tcptls_session, int authenticated, time_t start) { enum message_integrity message_integrity = MESSAGE_FRAGMENT; @@ -2974,7 +2824,7 @@ static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_insta } if (timeout == 0) { - ast_debug(2, "SIP TCP server timed out\n"); + ast_debug(2, "SIP TCP/TLS server timed out\n"); return -1; } } else { @@ -2982,19 +2832,22 @@ static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_insta } 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); + ast_debug(2, "SIP TCP/TLS server :: ast_wait_for_input returned %d\n", res); return -1; } else if (res == 0) { - ast_debug(2, "SIP TCP server timed out\n"); + ast_debug(2, "SIP TCP/TLS server timed out\n"); return -1; } - res = recv(tcptls_session->fd, readbuf, sizeof(readbuf) - 1, 0); + res = ast_tcptls_server_read(tcptls_session, readbuf, sizeof(readbuf) - 1); if (res < 0) { - ast_debug(2, "SIP TCP server error when receiving data\n"); + if (errno == EAGAIN || errno == EINTR) { + continue; + } + ast_debug(2, "SIP TCP/TLS server error when receiving data\n"); return -1; } else if (res == 0) { - ast_debug(2, "SIP TCP server has shut down\n"); + ast_debug(2, "SIP TCP/TLS server has shut down\n"); return -1; } readbuf[res] = '\0'; @@ -3003,10 +2856,10 @@ static int sip_tcp_read(struct sip_request *req, struct ast_tcptls_session_insta ast_str_append(&req->data, 0, "%s", ast_str_buffer(tcptls_session->overflow_buf)); ast_str_reset(tcptls_session->overflow_buf); } - + datalen = ast_str_strlen(req->data); if (datalen > SIP_MAX_PACKET_SIZE) { - ast_log(LOG_WARNING, "Rejecting TCP packet from '%s' because way too large: %zu\n", + ast_log(LOG_WARNING, "Rejecting TCP/TLS packet from '%s' because way too large: %zu\n", ast_sockaddr_stringify(&tcptls_session->remote_address), datalen); return -1; } @@ -3172,12 +3025,8 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s req.socket.port = htons(ourport_tcp); } req.socket.fd = tcptls_session->fd; - if (tcptls_session->ssl) { - res = sip_tls_read(&req, &reqcpy, tcptls_session, authenticated, start, me); - } else { - res = sip_tcp_read(&req, tcptls_session, authenticated, start); - } + res = sip_tcptls_read(&req, tcptls_session, authenticated, start); if (res < 0) { goto cleanup; }