#include "astmanproxy.h" /* This routine based on get_input from Asterisk manager.c */ /* Good generic line-based input routine for \r\n\r\n terminated input */ /* Used by standard.c and other input handlers */ int get_input(struct mansession *s, char *output) { /* output must have at least sizeof(s->inbuf) space */ int res; int x; struct pollfd fds[1]; char iabuf[INET_ADDRSTRLEN]; if (debug > 3) debugmsg("in get_input"); /* Look for \r\n from the front, our preferred end of line */ for (x=0;xinlen;x++) { int xtra = 0; if (s->inbuf[x] == '\n') { if (x && s->inbuf[x-1] == '\r') { xtra = 1; } /* Copy output data not including \r\n */ memcpy(output, s->inbuf, x - xtra); /* Add trailing \0 */ output[x-xtra] = '\0'; /* Move remaining data back to the front */ memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x); s->inlen -= (x + 1); return 1; } } if (s->inlen >= sizeof(s->inbuf) - 1) { if (debug) debugmsg("Warning: Got long line with no end from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf); s->inlen = 0; } if (debug > 3) debugmsg("attempting poll operation"); /* get actual fd, even if a negative SSL fd */ fds[0].fd = get_real_fd(s->fd); fds[0].events = POLLIN; res = poll(fds, 1, -1); if (debug > 3) debugmsg("returned from poll op"); if (res < 0 && debug) { debugmsg("Select returned error"); } else if (res > 0) { debugmsg("attempting socket read in get_input..."); pthread_mutex_lock(&s->lock); /* read from socket; SSL or otherwise */ res = m_recv(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen, 0); pthread_mutex_unlock(&s->lock); if (res < 1) return -1; } /* We have some input, but it's not ready for processing */ s->inlen += res; s->inbuf[s->inlen] = '\0'; return 0; } char *astman_get_header(struct message *m, char *var) { char cmp[80]; int x; snprintf(cmp, sizeof(cmp), "%s: ", var); for (x=0;xhdrcount;x++) if (!strncasecmp(cmp, m->headers[x], strlen(cmp))) return m->headers[x] + strlen(cmp); return ""; } int AddHeader(struct message *m, const char *fmt, ...) { va_list ap; int res; if (m->hdrcount < MAX_HEADERS - 1) { va_start(ap, fmt); vsprintf(m->headers[m->hdrcount], fmt, ap); va_end(ap); m->hdrcount++; res = 0; } else res = 1; return res; } /* Recursive thread safe replacement of inet_ntoa */ const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia) { return inet_ntop(AF_INET, &ia, buf, bufsiz); } int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec) { int flags, n, error; socklen_t len; fd_set rset, wset; struct timeval tval; flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); error = 0; if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0) if (errno != EINPROGRESS) return(-1); /* Do whatever we want while the connect is taking place. */ if (n == 0) goto done; /* connect completed immediately */ 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 (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); } done: fcntl(sockfd, F_SETFL, flags); /* restore file status flags */ if (error) { /* close(sockfd); */ /* we want to retry... */ errno = error; return(-1); } return(0); } /*! If you are calling ast_carefulwrite, it is assumed that you are calling it on a file descriptor that _DOES_ have NONBLOCK set. This way, there is only one system call made to do a write, unless we actually have a need to wait. This way, we get better performance. */ int ast_carefulwrite(int fd, char *s, int len, int timeoutms) { /* Try to write string, but wait no more than ms milliseconds before timing out */ int res=0; struct pollfd fds[1]; while(len) { res = m_send(fd, s, len); if ((res < 0) && (errno != EAGAIN)) { return -1; } if (res < 0) res = 0; len -= res; s += res; res = 0; if (len) { fds[0].fd = get_real_fd(fd); fds[0].events = POLLOUT; /* Wait until writable again */ res = poll(fds, 1, timeoutms); if (res < 1) return -1; } } return res; }