From ca4ed8c2cbec7db4d9001e4f5725dcb3ea71399a Mon Sep 17 00:00:00 2001 From: David Troy Date: Thu, 6 Apr 2006 22:30:00 +0000 Subject: git-svn-id: http://svncommunity.digium.com/svn/astmanproxy/branches/1.20pre@89 f02b47b9-160a-0410-81a6-dc3441afb0ec --- TODO | 2 + perl/soapclient.pl | 17 ------ src/astmanproxy.c | 9 +-- src/soap.c | 157 ----------------------------------------------------- src/ssl.c | 73 +++++++++++++++++++++---- 5 files changed, 68 insertions(+), 190 deletions(-) delete mode 100755 perl/soapclient.pl delete mode 100644 src/soap.c diff --git a/TODO b/TODO index 8083f1c..d360db5 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,6 @@ fix non-blocking in ast_connect +fix reconnect to lost asterisk server (socket reuse) +check s->connect construct kill autodisconnect concept; this would be managed by inputcomplete/outputcomplete in drivers? finish SOAP handler diff --git a/perl/soapclient.pl b/perl/soapclient.pl deleted file mode 100755 index 76c766c..0000000 --- a/perl/soapclient.pl +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/perl -w -# -# This is for testing only; the thought is to add content handlers -# to http.c to deal with 1) REST (default), 2) XML/XMLRPC, -# 3) SOAP http data input -# -# Do not expect this to do anything right now - -use SOAP::Lite; - -print SOAP::Lite - -> uri('http://localhost:1234/astmanproxy') - -> proxy('http://localhost:1234/') - -> astman('Action: Ping') - -> result . "\n"; - -exit(0); diff --git a/src/astmanproxy.c b/src/astmanproxy.c index dbbb05c..a22f1b8 100644 --- a/src/astmanproxy.c +++ b/src/astmanproxy.c @@ -120,7 +120,7 @@ void leave(int sig) { void Version( void ) { - printf("astmanproxy: Version %s, (C) David C. Troy\n", PROXY_VERSION); + printf("astmanproxy: Version %s, (C) David C. Troy 2005-2006\n", PROXY_VERSION); return; } @@ -345,7 +345,8 @@ void *HandleAsterisk(struct mansession *s) if (!WriteClients(&m)) break; } else if (res < 0) { - if (debug) + /* TODO: do we need to do more than this here? or something different? */ + if ( debug ) debugmsg("asterisk@%s: Not connected", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); if ( ConnectAsterisk(s) ) break; @@ -385,8 +386,8 @@ int ConnectAsterisk(struct mansession *s) { for ( ;; ) { if ( ast_connect(s) == -1 ) { if (debug) - debugmsg("asterisk@%s: Connect failed, Retrying (%d) %s", - ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), r, strerror(errno) ); + debugmsg("asterisk@%s: Connect failed, Retrying (%d) %s [%d]", + ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), r, strerror(errno), errno ); if (pc.maxretries && (++r>pc.maxretries) ) { res = 1; break; diff --git a/src/soap.c b/src/soap.c deleted file mode 100644 index 8a8d245..0000000 --- a/src/soap.c +++ /dev/null @@ -1,157 +0,0 @@ -/* Asterisk Manager Proxy - Copyright (c) 2005 David C. Troy - - This program is free software, distributed under the terms of - the GNU General Public License. - - HTTP Input Handler -*/ - -#include "astmanproxy.h" - -int ParseHTTPInput(char *buf, struct message *m) { - char *n, *v; - - n = buf; - while ( (v = strstr(n, "=")) ) { - v += 1; - debugmsg("n: %s, v: %s", n, v); - strncat(m->headers[m->hdrcount], n, v-n-1); - strcat(m->headers[m->hdrcount], ": "); - - if ( (n = strstr(v, "&")) ) { - n += 1; - } else { - n = (v + strlen(v) + 1); - } - strncat(m->headers[m->hdrcount], v, n-v-1); - debugmsg("got hdr: %s", m->headers[m->hdrcount]); - m->hdrcount++; - } - - return (m->hdrcount > 0); -} - -int HTTPHeader(struct mansession *s, char *status) { - - - time_t t; - struct tm tm; - char date[80]; - char ctype[15], hdr[MAX_LEN]; - - time(&t); - localtime_r(&t, &tm); - strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); - - if ( !strcasecmp("xml", s->output->formatname) ) - sprintf(ctype, "text/xml"); - else - sprintf(ctype, "text/plain"); - - if (!strcmp("200 OK", status) ) - sprintf(hdr, - "HTTP/1.1 %s\r\n" - "Date: %s\r\n" - "Content-Type: %s\r\n" - "Connection: close\r\n" - "Server: %s/%s\r\n\r\n", status, - date, ctype, PROXY_BANNER, PROXY_VERSION); - else - sprintf(hdr, - "HTTP/1.1 %s\r\n" - "Date: %s\r\n" - "Status: %s\r\n" - "Server: %s/%s\r\n\r\n", status, date, status, PROXY_BANNER, PROXY_VERSION); - - pthread_mutex_lock(&s->lock); - s->inputcomplete = 1; - ast_carefulwrite(s->fd, hdr, strlen(hdr), s->writetimeout); - pthread_mutex_unlock(&s->lock); - debugmsg("http header: %s", hdr); - - return 0; -} - -int _read(struct mansession *s, struct message *m) { - - /* Note: No single line may be longer than MAX_LEN/s->inbuf, as per get_input */ - /* No HTTP Input may be longer than BUFSIZE */ - - char line[MAX_LEN], method[10], formdata[MAX_LEN], status[15]; - int res, clength = 0; - - memset(method, 0, sizeof method); - memset(formdata, 0, sizeof formdata); - memset(status, 0, sizeof status); - - /* for http, don't do get_input forever */ - for (;;) { - - if (s->inputcomplete && !s->outputcomplete) - continue; - else if (s->inputcomplete && s->outputcomplete) - return -1; - - memset(line, 0, sizeof line); - res = get_input(s, line); - debugmsg("res=%d, line: %s",res, line); - - if (res > 0) { - debugmsg("Got http: %s", line); - - if ( !clength && !strncasecmp(line, "Content-Length: ", 16) ) - clength = atoi(line+16); - - if (!*method) { - if ( !strncmp(line,"POST",4) ) { - strncpy(method, line, 4); - } else if ( !strncmp(line,"GET",3)) { - if ( strlen(line) > 14 ) { - /* GET / HTTP/1.1 ---- this is bad */ - /* GET /?Action=Ping&ActionID=Foo HTTP/1.1 */ - strncpy(method, line, 3); - memcpy(formdata, line+6, strstr(line, " HTTP")-line-6); - sprintf(status, "200 OK"); - } else - sprintf(status, "501 Not Implemented"); - } - } - } else if (res == 0) { - if (*method && !*formdata) { - if ( !strcasecmp(method, "POST") && clength && s->inlen==clength) { - pthread_mutex_lock(&s->lock); - strncpy(formdata, s->inbuf, clength); - s->inlen = 0; - pthread_mutex_unlock(&s->lock); - sprintf(status, "200 OK"); - } - } - } - - if (res < 0) - break; - - if (*status) { - HTTPHeader(s, status); - - /* now, let's transform and copy into a standard message block */ - if (!strcmp("200 OK", status) ) { - res = ParseHTTPInput(formdata, m); - return res; - } else { - pthread_mutex_lock(&s->lock); - s->outputcomplete = 1; - pthread_mutex_unlock(&s->lock); - return 0; - } - } - } - return -1; -} - -int _autodisconnect() { - return 1; -} - -/* We do not define a _write or _onconnect method */ diff --git a/src/ssl.c b/src/ssl.c index c77d57a..9f9ff0f 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -340,6 +340,7 @@ int ast_connect(struct mansession *a) { return -1; if (a->server->use_ssl) { + debugmsg("initiating ssl connection"); if ((s=sec_getslot())!=-1) { /* find a slot for the ssl handle */ sec_channel[s].fd = fd; /* remember the real fd */ @@ -360,6 +361,7 @@ int ast_connect(struct mansession *a) { } } + debugmsg("returning ast_connect with %d", fd); pthread_mutex_lock(&a->lock); a->fd = fd; pthread_mutex_unlock(&a->lock); @@ -369,22 +371,69 @@ int ast_connect(struct mansession *a) { int connect_nonb(struct mansession *a) { - int s, flags, one=1; + int flags, n, error; + socklen_t len; + fd_set rset, wset; + struct timeval tval; + int nsec = 1, sockfd; + + sockfd = get_real_fd(a->fd); + + flags = fcntl(sockfd, F_GETFL, 0); + fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + + error = 0; + if ( (n = connect(sockfd, (struct sockaddr *) &a->sin, sizeof(a->sin)) ) < 0 ) { + /* TODO: This seems like the nine pound hammer to me... */ + /* perhaps something a bit more elegant; errno seems to change too */ + if (errno == EISCONN || errno == 103 || errno==111) { + debugmsg("connect_nonb: error %d, closing old fd and grabbing a new one...", errno); + /* looks like our old socket died, let's round up a new one and try again */ + close_sock(a->fd); + pthread_mutex_lock(&a->lock); + a->fd = socket(AF_INET, SOCK_STREAM, 0); + pthread_mutex_unlock(&a->lock); + return(-1); + } + if (errno != EINPROGRESS) + return(-1); + } - s = get_real_fd(a->fd); + /* Do whatever we want while the connect is taking place. */ -/* flags = fcntl(s, F_GETFL, 0); - fcntl(s, F_SETFL, flags | O_NONBLOCK); */ + if (n == 0) + goto done; /* connect completed immediately */ - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one))==-1) { - (void)close(s); - return -1; + FD_ZERO(&rset); + FD_SET(sockfd, &rset); + wset = rset; + tval.tv_sec = nsec; + tval.tv_usec = 0; + + if ( (n = select(sockfd+1, &rset, &wset, NULL, + nsec ? &tval : NULL)) == 0) { + /*close(sockfd);*/ /* we want to retry */ + errno = ETIMEDOUT; + return(-1); } - if (connect(s, (struct sockaddr *) &a->sin, sizeof(a->sin)) < 0) { - if (errno != EINPROGRESS) - return -1; + if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { + len = sizeof(error); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) + return(-1); /* Solaris pending error */ + } else { + /*err_quit("select error: sockfd not set");*/ + logmsg("select error: sockfd not set"); + return(-1); } - return s; -} +done: + fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ + + if (error) { + /* close(sockfd); */ /* disable for now, we want to retry... */ + errno = error; + return(-1); + } + return(sockfd); +} -- cgit