Do not use a FILE handle when doing SIP TCP reads.

This is used to solve an issue where a poll on a file
descriptor does not necessarily correspond to the readiness
of a FILE handle to be read.

This change makes it so that for TCP connections, we do a
recv() on the file descriptor instead.

Because TCP does not guarantee that an entire message or even
just one single message will arrive during a read, a loop has
been introduced to ensure that we only attempt to handle a
single message at a time. The tcptls_session_instance structure
has also had an overflow buffer added to it so that if more
than one TCP message arrives in one go, there is a place to
throw the excess.

Huge thanks goes out to Walter Doekes for doing extensive review
on this change and finding edge cases where code could fail.

(closes issue ASTERISK-20212)
reported by Phil Ciccone

Review: https://reviewboard.asterisk.org/r/2123
........

Merged revisions 374905 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 374906 from http://svn.asterisk.org/svn/asterisk/branches/10
........

Merged revisions 374914 from http://svn.asterisk.org/svn/asterisk/branches/11


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@374924 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Michelson
2012-10-12 16:31:01 +00:00
parent 399428224d
commit c7b23cbb0a
3 changed files with 867 additions and 118 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -155,6 +155,12 @@ struct ast_tcptls_session_instance {
int client;
struct ast_sockaddr remote_address;
struct ast_tcptls_session_args *parent;
/* Sometimes, when an entity reads TCP data, multiple
* logical messages might be read at the same time. In such
* a circumstance, there needs to be a place to stash the
* extra data.
*/
struct ast_str *overflow_buf;
};
#if defined(HAVE_FUNOPEN)

View File

@@ -142,6 +142,12 @@ HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_sessio
return write(tcptls_session->fd, buf, count);
}
static void session_instance_destructor(void *obj)
{
struct ast_tcptls_session_instance *i = obj;
ast_free(i->overflow_buf);
}
/*! \brief
* creates a FILE * from the fd passed by the accept thread.
* This operation is potentially expensive (certificate verification),
@@ -290,7 +296,7 @@ void *ast_tcptls_server_root(void *data)
}
continue;
}
tcptls_session = ao2_alloc(sizeof(*tcptls_session), NULL);
tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
if (!tcptls_session) {
ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
if (close(fd)) {
@@ -299,6 +305,7 @@ void *ast_tcptls_server_root(void *data)
continue;
}
tcptls_session->overflow_buf = ast_str_create(128);
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
tcptls_session->fd = fd;
@@ -498,10 +505,11 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s
}
}
if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), NULL))) {
if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) {
goto error;
}
tcptls_session->overflow_buf = ast_str_create(128);
tcptls_session->client = 1;
tcptls_session->fd = desc->accept_fd;
tcptls_session->parent = desc;