Merged revisions 284597 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.8 ................ r284597 | tilghman | 2010-09-02 00:00:34 -0500 (Thu, 02 Sep 2010) | 29 lines Merged revisions 284593,284595 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.6.2 ................ r284593 | tilghman | 2010-09-01 17:59:50 -0500 (Wed, 01 Sep 2010) | 18 lines Merged revisions 284478 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r284478 | tilghman | 2010-09-01 13:49:11 -0500 (Wed, 01 Sep 2010) | 11 lines Ensure that all areas that previously used select(2) now use poll(2), with implementations that need poll(2) implemented with select(2) safe against 1024-bit overflows. This is a followup to the fix for the pthread timer in 1.6.2 and beyond, fixing a potential crash bug in all supported releases. (closes issue #17678) Reported by: russell Branch: https://origsvn.digium.com/svn/asterisk/team/tilghman/ast_select Review: https://reviewboard.asterisk.org/r/824/ ........ ................ r284595 | tilghman | 2010-09-01 22:57:43 -0500 (Wed, 01 Sep 2010) | 2 lines Failed to rerun bootstrap.sh after last commit ................ ................ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@284598 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
37f68a5475
commit
c32f63c825
|
@ -23,6 +23,7 @@
|
|||
#define _OOSOCKET_H_
|
||||
|
||||
#include "asterisk/poll-compat.h"
|
||||
#include "asterisk/compiler.h"
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
#include <winsock.h>
|
||||
|
@ -329,9 +330,9 @@ EXTERN int ooSocketSendTo(OOSOCKET socket, const ASN1OCTET* pdata,
|
|||
* returns.
|
||||
* @return Completion status of operation: 0 (ASN_OK) = success,
|
||||
* negative return value is error.
|
||||
*/
|
||||
*/
|
||||
EXTERN int ooSocketSelect(int nfds, fd_set *readfds, fd_set *writefds,
|
||||
fd_set *exceptfds, struct timeval * timeout);
|
||||
fd_set *exceptfds, struct timeval * timeout) __attribute_deprecated__;
|
||||
|
||||
EXTERN int ooSocketPoll(struct pollfd *pfds, int nfds, int timeout);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*****************************************************************************/
|
||||
#include "asterisk.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/poll-compat.h"
|
||||
|
||||
#include "ooports.h"
|
||||
#include "oochannels.h"
|
||||
|
@ -1980,22 +1981,12 @@ int ooStopMonitorCalls()
|
|||
|
||||
OOBOOL ooChannelsIsConnectionOK(OOH323CallData *call, OOSOCKET sock)
|
||||
{
|
||||
struct timeval to;
|
||||
fd_set readfds;
|
||||
int ret = 0, nfds=0;
|
||||
struct timeval to = { .tv_usec = 500 };
|
||||
struct pollfd pfds = { .fd = sock, .events = POLLIN };
|
||||
int ret = 0;
|
||||
|
||||
to.tv_sec = 0;
|
||||
to.tv_usec = 500;
|
||||
FD_ZERO(&readfds);
|
||||
ret = ast_poll2(&pfds, 1, &to);
|
||||
|
||||
FD_SET(sock, &readfds);
|
||||
if(nfds < (int)sock)
|
||||
nfds = (int)sock;
|
||||
|
||||
nfds++;
|
||||
|
||||
ret = ooSocketSelect(nfds, &readfds, NULL, NULL, &to);
|
||||
|
||||
if(ret == -1)
|
||||
{
|
||||
OOTRACEERR3("Error in select ...broken pipe check(%s, %s)\n",
|
||||
|
|
|
@ -7160,15 +7160,14 @@ static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame
|
|||
static struct ast_frame *misdn_read(struct ast_channel *ast)
|
||||
{
|
||||
struct chan_list *tmp;
|
||||
fd_set rrfs;
|
||||
struct timeval tv = { 0, 20000 };
|
||||
int len, t;
|
||||
struct pollfd pfd = { .fd = -1, .events = POLLIN };
|
||||
|
||||
if (!ast) {
|
||||
chan_misdn_log(1, 0, "misdn_read called without ast\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
|
||||
if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
|
||||
chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -7178,21 +7177,18 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
FD_ZERO(&rrfs);
|
||||
FD_SET(tmp->pipe[0], &rrfs);
|
||||
|
||||
t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv);
|
||||
if (!t) {
|
||||
chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
|
||||
len = 160;
|
||||
}
|
||||
pfd.fd = tmp->pipe[0];
|
||||
t = ast_poll(&pfd, 1, 20);
|
||||
|
||||
if (t < 0) {
|
||||
chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n", strerror(errno));
|
||||
chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (FD_ISSET(tmp->pipe[0], &rrfs)) {
|
||||
if (!t) {
|
||||
chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
|
||||
len = 160;
|
||||
} else if (pfd.revents & POLLIN) {
|
||||
len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));
|
||||
|
||||
if (len <= 0) {
|
||||
|
@ -10456,25 +10452,21 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
|
|||
ast_queue_frame(ch->ast, &frame);
|
||||
}
|
||||
} else {
|
||||
fd_set wrfs;
|
||||
struct timeval tv = { 0, 0 };
|
||||
struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
|
||||
int t;
|
||||
|
||||
FD_ZERO(&wrfs);
|
||||
FD_SET(ch->pipe[1], &wrfs);
|
||||
|
||||
t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
|
||||
if (!t) {
|
||||
chan_misdn_log(9, bc->port, "Select Timed out\n");
|
||||
break;
|
||||
}
|
||||
t = ast_poll(&pfd, 1, 0);
|
||||
|
||||
if (t < 0) {
|
||||
chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
|
||||
chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (!t) {
|
||||
chan_misdn_log(9, bc->port, "poll() timed out\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(ch->pipe[1], &wrfs)) {
|
||||
if (pfd.revents & POLLOUT) {
|
||||
chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
|
||||
if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
|
||||
chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
|
||||
|
|
|
@ -1017,12 +1017,12 @@ static void phone_check_exception(struct phone_pvt *i)
|
|||
|
||||
static void *do_monitor(void *data)
|
||||
{
|
||||
fd_set rfds, efds;
|
||||
int n, res;
|
||||
struct pollfd *fds = NULL;
|
||||
int nfds = 0, inuse_fds = 0, res;
|
||||
struct phone_pvt *i;
|
||||
int tonepos = 0;
|
||||
/* The tone we're playing this round */
|
||||
struct timeval wait = {0,0};
|
||||
struct timeval tv = { 0, 0 };
|
||||
int dotone;
|
||||
/* This thread monitors all the frame relay interfaces which are not yet in use
|
||||
(and thus do not have a separate thread) indefinitely */
|
||||
|
@ -1036,33 +1036,38 @@ static void *do_monitor(void *data)
|
|||
}
|
||||
/* Build the stuff we're going to select on, that is the socket of every
|
||||
phone_pvt that does not have an associated owner channel */
|
||||
n = -1;
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&efds);
|
||||
i = iflist;
|
||||
dotone = 0;
|
||||
while (i) {
|
||||
if (FD_ISSET(i->fd, &rfds))
|
||||
ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
|
||||
inuse_fds = 0;
|
||||
for (i = iflist; i; i = i->next) {
|
||||
if (!i->owner) {
|
||||
/* This needs to be watched, as it lacks an owner */
|
||||
FD_SET(i->fd, &rfds);
|
||||
FD_SET(i->fd, &efds);
|
||||
if (i->fd > n)
|
||||
n = i->fd;
|
||||
if (inuse_fds == nfds) {
|
||||
void *tmp = ast_realloc(fds, (nfds + 1) * sizeof(*fds));
|
||||
if (!tmp) {
|
||||
/* Avoid leaking */
|
||||
continue;
|
||||
}
|
||||
fds = tmp;
|
||||
nfds++;
|
||||
}
|
||||
fds[inuse_fds].fd = i->fd;
|
||||
fds[inuse_fds].events = POLLIN | POLLERR;
|
||||
fds[inuse_fds].revents = 0;
|
||||
inuse_fds++;
|
||||
|
||||
if (i->dialtone && i->mode != MODE_SIGMA) {
|
||||
/* Remember we're going to have to come back and play
|
||||
more dialtones */
|
||||
if (ast_tvzero(wait)) {
|
||||
if (ast_tvzero(tv)) {
|
||||
/* If we're due for a dialtone, play one */
|
||||
if (write(i->fd, DialTone + tonepos, 240) != 240)
|
||||
if (write(i->fd, DialTone + tonepos, 240) != 240) {
|
||||
ast_log(LOG_WARNING, "Dial tone write error\n");
|
||||
}
|
||||
}
|
||||
dotone++;
|
||||
}
|
||||
}
|
||||
|
||||
i = i->next;
|
||||
}
|
||||
/* Okay, now that we know what to do, release the interface lock */
|
||||
ast_mutex_unlock(&iflock);
|
||||
|
@ -1071,26 +1076,28 @@ static void *do_monitor(void *data)
|
|||
if (dotone && i && i->mode != MODE_SIGMA) {
|
||||
/* If we're ready to recycle the time, set it to 30 ms */
|
||||
tonepos += 240;
|
||||
if (tonepos >= sizeof(DialTone))
|
||||
tonepos = 0;
|
||||
if (ast_tvzero(wait)) {
|
||||
wait = ast_tv(30000, 0);
|
||||
if (tonepos >= sizeof(DialTone)) {
|
||||
tonepos = 0;
|
||||
}
|
||||
res = ast_select(n + 1, &rfds, NULL, &efds, &wait);
|
||||
if (ast_tvzero(tv)) {
|
||||
tv = ast_tv(0, 30000);
|
||||
}
|
||||
res = ast_poll2(fds, inuse_fds, &tv);
|
||||
} else {
|
||||
res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
|
||||
wait = ast_tv(0,0);
|
||||
res = ast_poll(fds, inuse_fds, -1);
|
||||
tv = ast_tv(0, 0);
|
||||
tonepos = 0;
|
||||
}
|
||||
/* Okay, select has finished. Let's see what happened. */
|
||||
if (res < 0) {
|
||||
ast_debug(1, "select return %d: %s\n", res, strerror(errno));
|
||||
ast_debug(1, "poll returned %d: %s\n", res, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
/* If there are no fd's changed, just continue, it's probably time
|
||||
to play some more dialtones */
|
||||
if (!res)
|
||||
if (!res) {
|
||||
continue;
|
||||
}
|
||||
/* Alright, lock the interface list again, and let's look and see what has
|
||||
happened */
|
||||
if (ast_mutex_lock(&iflock)) {
|
||||
|
@ -1098,15 +1105,27 @@ static void *do_monitor(void *data)
|
|||
continue;
|
||||
}
|
||||
|
||||
i = iflist;
|
||||
for(; i; i=i->next) {
|
||||
if (FD_ISSET(i->fd, &rfds)) {
|
||||
for (i = iflist; i; i = i->next) {
|
||||
int j;
|
||||
/* Find the record */
|
||||
for (j = 0; j < inuse_fds; j++) {
|
||||
if (fds[j].fd == i->fd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found? */
|
||||
if (j == inuse_fds) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fds[j].revents & POLLIN) {
|
||||
if (i->owner) {
|
||||
continue;
|
||||
}
|
||||
phone_mini_packet(i);
|
||||
}
|
||||
if (FD_ISSET(i->fd, &efds)) {
|
||||
if (fds[j].revents & POLLERR) {
|
||||
if (i->owner) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1116,7 +1135,6 @@ static void *do_monitor(void *data)
|
|||
ast_mutex_unlock(&iflock);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static int restart_monitor()
|
||||
|
|
|
@ -1119,8 +1119,7 @@ static void *hidthread(void *arg)
|
|||
struct usb_device *usb_dev;
|
||||
struct usb_dev_handle *usb_handle;
|
||||
struct chan_usbradio_pvt *o = (struct chan_usbradio_pvt *) arg;
|
||||
struct timeval to;
|
||||
fd_set rfds;
|
||||
struct pollfd pfd = { .events = POLLIN };
|
||||
|
||||
usb_dev = hid_device_init(o->devstr);
|
||||
if (usb_dev == NULL) {
|
||||
|
@ -1156,63 +1155,49 @@ static void *hidthread(void *arg)
|
|||
traceusb1(("hidthread: Starting normally on %s!!\n",o->name));
|
||||
lastrx = 0;
|
||||
// popen
|
||||
while(!o->stophid)
|
||||
{
|
||||
to.tv_sec = 0;
|
||||
to.tv_usec = 50000; // maw sph
|
||||
while (!o->stophid) {
|
||||
pfd.fd = o->pttkick;
|
||||
pfd.revents = 0;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(o->pttkick[0],&rfds);
|
||||
/* ast_select emulates linux behaviour in terms of timeout handling */
|
||||
res = ast_select(o->pttkick[0] + 1, &rfds, NULL, NULL, &to);
|
||||
res = ast_poll2(&pfd, 1, 50);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
|
||||
ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
if (FD_ISSET(o->pttkick[0],&rfds))
|
||||
{
|
||||
if (pfd.revents & POLLIN) { {
|
||||
char c;
|
||||
|
||||
if (read(o->pttkick[0],&c,1) < 0) {
|
||||
if (read(o->pttkick[0], &c, 1) < 0) {
|
||||
ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
if(o->wanteeprom)
|
||||
{
|
||||
if (o->wanteeprom) {
|
||||
ast_mutex_lock(&o->eepromlock);
|
||||
if (o->eepromctl == 1) /* to read */
|
||||
{
|
||||
if (o->eepromctl == 1) { /* to read */
|
||||
/* if CS okay */
|
||||
if (!get_eeprom(usb_handle,o->eeprom))
|
||||
{
|
||||
if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC)
|
||||
{
|
||||
ast_log(LOG_NOTICE,"UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n",o->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!get_eeprom(usb_handle, o->eeprom)) {
|
||||
if (o->eeprom[EEPROM_MAGIC_ADDR] != EEPROM_MAGIC) {
|
||||
ast_log(LOG_NOTICE, "UNSUCCESSFUL: EEPROM MAGIC NUMBER BAD on channel %s\n", o->name);
|
||||
} else {
|
||||
o->rxmixerset = o->eeprom[EEPROM_RXMIXERSET];
|
||||
o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
|
||||
o->txmixaset = o->eeprom[EEPROM_TXMIXASET];
|
||||
o->txmixbset = o->eeprom[EEPROM_TXMIXBSET];
|
||||
memcpy(&o->rxvoiceadj,&o->eeprom[EEPROM_RXVOICEADJ],sizeof(float));
|
||||
memcpy(&o->rxctcssadj,&o->eeprom[EEPROM_RXCTCSSADJ],sizeof(float));
|
||||
memcpy(&o->rxvoiceadj, &o->eeprom[EEPROM_RXVOICEADJ], sizeof(float));
|
||||
memcpy(&o->rxctcssadj, &o->eeprom[EEPROM_RXCTCSSADJ], sizeof(float));
|
||||
o->txctcssadj = o->eeprom[EEPROM_TXCTCSSADJ];
|
||||
o->rxsquelchadj = o->eeprom[EEPROM_RXSQUELCHADJ];
|
||||
ast_log(LOG_NOTICE,"EEPROM Loaded on channel %s\n",o->name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ast_log(LOG_NOTICE,"USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n",o->name);
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "USB Adapter has no EEPROM installed or Checksum BAD on channel %s\n", o->name);
|
||||
}
|
||||
hid_set_outputs(usb_handle,bufsave);
|
||||
}
|
||||
if (o->eepromctl == 2) /* to write */
|
||||
{
|
||||
}
|
||||
if (o->eepromctl == 2) { /* to write */
|
||||
put_eeprom(usb_handle,o->eeprom);
|
||||
hid_set_outputs(usb_handle,bufsave);
|
||||
ast_log(LOG_NOTICE,"USB Parameters written to EEPROM on %s\n",o->name);
|
||||
ast_log(LOG_NOTICE, "USB Parameters written to EEPROM on %s\n", o->name);
|
||||
}
|
||||
o->eepromctl = 0;
|
||||
ast_mutex_unlock(&o->eepromlock);
|
||||
|
@ -1220,38 +1205,43 @@ static void *hidthread(void *arg)
|
|||
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
|
||||
hid_get_inputs(usb_handle,buf);
|
||||
keyed = !(buf[o->hid_io_cor_loc] & o->hid_io_cor);
|
||||
if (keyed != o->rxhidsq)
|
||||
{
|
||||
if(o->debuglevel)printf("chan_usbradio() hidthread: update rxhidsq = %d\n",keyed);
|
||||
if (keyed != o->rxhidsq) {
|
||||
if (o->debuglevel) {
|
||||
printf("chan_usbradio() hidthread: update rxhidsq = %d\n", keyed);
|
||||
}
|
||||
o->rxhidsq=keyed;
|
||||
}
|
||||
|
||||
/* if change in tx state as controlled by xpmr */
|
||||
txtmp=o->pmrChan->txPttOut;
|
||||
|
||||
if (o->lasttx != txtmp)
|
||||
{
|
||||
o->pmrChan->txPttHid=o->lasttx = txtmp;
|
||||
if(o->debuglevel)printf("hidthread: tx set to %d\n",txtmp);
|
||||
buf[o->hid_gpio_loc] = 0;
|
||||
if (!o->invertptt)
|
||||
{
|
||||
if (txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
|
||||
txtmp = o->pmrChan->txPttOut;
|
||||
|
||||
if (o->lasttx != txtmp) {
|
||||
o->pmrChan->txPttHid = o->lasttx = txtmp;
|
||||
if (o->debuglevel) {
|
||||
ast_debug(0, "hidthread: tx set to %d\n", txtmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!txtmp) buf[o->hid_gpio_loc] = o->hid_io_ptt;
|
||||
buf[o->hid_gpio_loc] = 0;
|
||||
if (!o->invertptt) {
|
||||
if (txtmp) {
|
||||
buf[o->hid_gpio_loc] = o->hid_io_ptt;
|
||||
}
|
||||
} else {
|
||||
if (!txtmp) {
|
||||
buf[o->hid_gpio_loc] = o->hid_io_ptt;
|
||||
}
|
||||
}
|
||||
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
|
||||
memcpy(bufsave,buf,sizeof(buf));
|
||||
hid_set_outputs(usb_handle,buf);
|
||||
memcpy(bufsave, buf, sizeof(buf));
|
||||
hid_set_outputs(usb_handle, buf);
|
||||
}
|
||||
time(&o->lasthidtime);
|
||||
}
|
||||
buf[o->hid_gpio_loc] = 0;
|
||||
if (o->invertptt) buf[o->hid_gpio_loc] = o->hid_io_ptt;
|
||||
if (o->invertptt) {
|
||||
buf[o->hid_gpio_loc] = o->hid_io_ptt;
|
||||
}
|
||||
buf[o->hid_gpio_ctl_loc] = o->hid_gpio_ctl;
|
||||
hid_set_outputs(usb_handle,buf);
|
||||
hid_set_outputs(usb_handle, buf);
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
|
@ -1452,37 +1442,29 @@ static void *sound_thread(void *arg)
|
|||
*/
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
for (;;) {
|
||||
fd_set rfds, wfds;
|
||||
int maxfd, res;
|
||||
struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev } };
|
||||
int res;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(o->sndcmd[0], &rfds);
|
||||
maxfd = o->sndcmd[0]; /* pipe from the main process */
|
||||
if (o->cursound > -1 && o->sounddev < 0)
|
||||
if (o->cursound > -1 && o->sounddev < 0) {
|
||||
setformat(o, O_RDWR); /* need the channel, try to reopen */
|
||||
else if (o->cursound == -1 && o->owner == NULL)
|
||||
{
|
||||
} else if (o->cursound == -1 && o->owner == NULL) {
|
||||
setformat(o, O_CLOSE); /* can close */
|
||||
}
|
||||
if (o->sounddev > -1) {
|
||||
if (!o->owner) { /* no one owns the audio, so we must drain it */
|
||||
FD_SET(o->sounddev, &rfds);
|
||||
maxfd = MAX(o->sounddev, maxfd);
|
||||
pfd[1].events = POLLIN;
|
||||
}
|
||||
if (o->cursound > -1) {
|
||||
FD_SET(o->sounddev, &wfds);
|
||||
maxfd = MAX(o->sounddev, maxfd);
|
||||
pfd[1].events |= POLLOUT;
|
||||
}
|
||||
}
|
||||
/* ast_select emulates linux behaviour in terms of timeout handling */
|
||||
res = ast_select(maxfd + 1, &rfds, &wfds, NULL, NULL);
|
||||
res = ast_poll(pfd, o->sounddev > -1 ? 2 : 1, -1);
|
||||
if (res < 1) {
|
||||
ast_log(LOG_WARNING, "select failed: %s\n", strerror(errno));
|
||||
ast_log(LOG_WARNING, "poll failed: %s\n", strerror(errno));
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
if (FD_ISSET(o->sndcmd[0], &rfds)) {
|
||||
if (pfd[0].revents & POLLIN) {
|
||||
/* read which sound to play from the pipe */
|
||||
int i, what = -1;
|
||||
|
||||
|
@ -1495,14 +1477,17 @@ static void *sound_thread(void *arg)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (sounds[i].ind == -1)
|
||||
if (sounds[i].ind == -1) {
|
||||
ast_log(LOG_WARNING, "invalid sound index: %d\n", what);
|
||||
}
|
||||
}
|
||||
if (o->sounddev > -1) {
|
||||
if (FD_ISSET(o->sounddev, &rfds)) /* read and ignore errors */
|
||||
if (pfd[1].revents & POLLIN) { /* read and ignore errors */
|
||||
read(o->sounddev, ign, sizeof(ign));
|
||||
if (FD_ISSET(o->sounddev, &wfds))
|
||||
}
|
||||
if (pfd[1].revents & POLLOUT) {
|
||||
send_sound(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL; /* Never reached */
|
||||
|
|
|
@ -234,34 +234,34 @@ struct video_out_desc {
|
|||
* and contain all configurtion info.
|
||||
*/
|
||||
struct video_desc {
|
||||
char codec_name[64]; /* the codec we use */
|
||||
char codec_name[64]; /* the codec we use */
|
||||
|
||||
int stayopen; /* set if gui starts manually */
|
||||
pthread_t vthread; /* video thread */
|
||||
ast_mutex_t dec_lock; /* sync decoder and video thread */
|
||||
int shutdown; /* set to shutdown vthread */
|
||||
struct ast_channel *owner; /* owner channel */
|
||||
int stayopen; /* set if gui starts manually */
|
||||
pthread_t vthread; /* video thread */
|
||||
ast_mutex_t dec_lock; /* sync decoder and video thread */
|
||||
int shutdown; /* set to shutdown vthread */
|
||||
struct ast_channel *owner; /* owner channel */
|
||||
|
||||
|
||||
struct fbuf_t enc_in; /* encoder input buffer, allocated in video_out_init() */
|
||||
struct fbuf_t enc_in; /* encoder input buffer, allocated in video_out_init() */
|
||||
|
||||
char keypad_file[256]; /* image for the keypad */
|
||||
char keypad_font[256]; /* font for the keypad */
|
||||
char keypad_file[256]; /* image for the keypad */
|
||||
char keypad_font[256]; /* font for the keypad */
|
||||
|
||||
char sdl_videodriver[256];
|
||||
char sdl_videodriver[256];
|
||||
|
||||
struct fbuf_t rem_dpy; /* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */
|
||||
struct fbuf_t loc_dpy; /* display local source, no buffer (managed by SDL in bmp[1]) */
|
||||
struct fbuf_t rem_dpy; /* display remote video, no buffer (it is in win[WIN_REMOTE].bmp) */
|
||||
struct fbuf_t loc_dpy; /* display local source, no buffer (managed by SDL in bmp[1]) */
|
||||
|
||||
/* geometry of the thumbnails for all video sources. */
|
||||
struct fbuf_t src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */
|
||||
struct fbuf_t src_dpy[MAX_VIDEO_SOURCES]; /* no buffer allocated here */
|
||||
|
||||
int frame_freeze; /* flag to freeze the incoming frame */
|
||||
int frame_freeze; /* flag to freeze the incoming frame */
|
||||
|
||||
/* local information for grabbers, codecs, gui */
|
||||
struct gui_info *gui;
|
||||
struct video_dec_desc *in; /* remote video descriptor */
|
||||
struct video_out_desc out; /* local video descriptor */
|
||||
struct gui_info *gui;
|
||||
struct video_dec_desc *in; /* remote video descriptor */
|
||||
struct video_out_desc out; /* local video descriptor */
|
||||
};
|
||||
|
||||
static AVPicture *fill_pict(struct fbuf_t *b, AVPicture *p);
|
||||
|
@ -387,8 +387,9 @@ static struct fbuf_t *grabber_read(struct video_device *dev, int fps)
|
|||
*/
|
||||
static void grabber_move(struct video_device *dev, int dx, int dy)
|
||||
{
|
||||
if (dev->grabber && dev->grabber->move)
|
||||
dev->grabber->move(dev->grabber_data, dx, dy);
|
||||
if (dev->grabber && dev->grabber->move) {
|
||||
dev->grabber->move(dev->grabber_data, dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -508,33 +509,32 @@ static int video_out_init(struct video_desc *env)
|
|||
/* now setup the parameters for the encoder.
|
||||
* XXX should be codec-specific
|
||||
*/
|
||||
{
|
||||
AVCodecContext *enc_ctx = avcodec_alloc_context();
|
||||
v->enc_ctx = enc_ctx;
|
||||
enc_ctx->pix_fmt = enc_in->pix_fmt;
|
||||
enc_ctx->width = enc_in->w;
|
||||
enc_ctx->height = enc_in->h;
|
||||
/* XXX rtp_callback ?
|
||||
* rtp_mode so ffmpeg inserts as many start codes as possible.
|
||||
*/
|
||||
enc_ctx->rtp_mode = 1;
|
||||
enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
|
||||
enc_ctx->bit_rate = v->bitrate;
|
||||
enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
|
||||
enc_ctx->qmin = v->qmin; /* should be configured */
|
||||
enc_ctx->time_base = (AVRational){1, v->fps};
|
||||
enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
|
||||
{
|
||||
AVCodecContext *enc_ctx = avcodec_alloc_context();
|
||||
v->enc_ctx = enc_ctx;
|
||||
enc_ctx->pix_fmt = enc_in->pix_fmt;
|
||||
enc_ctx->width = enc_in->w;
|
||||
enc_ctx->height = enc_in->h;
|
||||
/* XXX rtp_callback ?
|
||||
* rtp_mode so ffmpeg inserts as many start codes as possible.
|
||||
*/
|
||||
enc_ctx->rtp_mode = 1;
|
||||
enc_ctx->rtp_payload_size = v->mtu / 2; // mtu/2
|
||||
enc_ctx->bit_rate = v->bitrate;
|
||||
enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate/2;
|
||||
enc_ctx->qmin = v->qmin; /* should be configured */
|
||||
enc_ctx->time_base = (AVRational){1, v->fps};
|
||||
enc_ctx->gop_size = v->fps*5; // emit I frame every 5 seconds
|
||||
|
||||
v->enc->enc_init(v->enc_ctx);
|
||||
|
||||
if (avcodec_open(enc_ctx, v->codec) < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n",
|
||||
codec);
|
||||
av_free(enc_ctx);
|
||||
v->enc_ctx = NULL;
|
||||
return video_out_uninit(env);
|
||||
v->enc->enc_init(v->enc_ctx);
|
||||
|
||||
if (avcodec_open(enc_ctx, v->codec) < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to initialize the encoder %d\n", codec);
|
||||
av_free(enc_ctx);
|
||||
v->enc_ctx = NULL;
|
||||
return video_out_uninit(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Allocate enough for the encoded bitstream. As we are compressing,
|
||||
* we hope that the output is never larger than the input size.
|
||||
|
@ -637,9 +637,9 @@ static void my_scale(struct fbuf_t *in, AVPicture *p_in,
|
|||
p_in = fill_pict(in, &my_p_in);
|
||||
if (p_out == NULL)
|
||||
p_out = fill_pict(out, &my_p_out);
|
||||
|
||||
/*if win_w is different from zero then we must change
|
||||
the size of the scaled buffer (the position is already
|
||||
|
||||
/*if win_w is different from zero then we must change
|
||||
the size of the scaled buffer (the position is already
|
||||
encoded into the out parameter)*/
|
||||
if (out->win_w) { /* picture in picture enabled */
|
||||
eff_w=out->win_w;
|
||||
|
@ -650,26 +650,26 @@ static void my_scale(struct fbuf_t *in, AVPicture *p_in,
|
|||
img_convert(p_out, out->pix_fmt,
|
||||
p_in, in->pix_fmt, in->w, in->h);
|
||||
#else /* XXX replacement */
|
||||
{
|
||||
struct SwsContext *convert_ctx;
|
||||
|
||||
convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
|
||||
eff_w, eff_h, out->pix_fmt,
|
||||
SWS_BICUBIC, NULL, NULL, NULL);
|
||||
if (convert_ctx == NULL) {
|
||||
ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
|
||||
return;
|
||||
}
|
||||
if (0)
|
||||
ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
|
||||
in->pix_fmt, in->w, in->h, out->pix_fmt, eff_w, eff_h);
|
||||
sws_scale(convert_ctx,
|
||||
p_in->data, p_in->linesize,
|
||||
in->w, in->h, /* src slice */
|
||||
p_out->data, p_out->linesize);
|
||||
{
|
||||
struct SwsContext *convert_ctx;
|
||||
|
||||
sws_freeContext(convert_ctx);
|
||||
}
|
||||
convert_ctx = sws_getContext(in->w, in->h, in->pix_fmt,
|
||||
eff_w, eff_h, out->pix_fmt,
|
||||
SWS_BICUBIC, NULL, NULL, NULL);
|
||||
if (convert_ctx == NULL) {
|
||||
ast_log(LOG_ERROR, "FFMPEG::convert_cmodel : swscale context initialization failed");
|
||||
return;
|
||||
}
|
||||
if (0)
|
||||
ast_log(LOG_WARNING, "in %d %dx%d out %d %dx%d\n",
|
||||
in->pix_fmt, in->w, in->h, out->pix_fmt, eff_w, eff_h);
|
||||
sws_scale(convert_ctx,
|
||||
p_in->data, p_in->linesize,
|
||||
in->w, in->h, /* src slice */
|
||||
p_out->data, p_out->linesize);
|
||||
|
||||
sws_freeContext(convert_ctx);
|
||||
}
|
||||
#endif /* XXX replacement */
|
||||
}
|
||||
|
||||
|
@ -873,18 +873,20 @@ static void *video_thread(void *arg)
|
|||
}
|
||||
}
|
||||
sdl_setup(env);
|
||||
if (!ast_strlen_zero(save_display))
|
||||
if (!ast_strlen_zero(save_display)) {
|
||||
setenv("DISPLAY", save_display, 1);
|
||||
}
|
||||
|
||||
ast_mutex_init(&env->dec_lock); /* used to sync decoder and renderer */
|
||||
|
||||
if (grabber_open(&env->out)) {
|
||||
ast_log(LOG_WARNING, "cannot open local video source\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (env->out.device_num)
|
||||
if (env->out.device_num) {
|
||||
env->out.devices[env->out.device_primary].status_index |= IS_PRIMARY | IS_SECONDARY;
|
||||
|
||||
}
|
||||
|
||||
/* even if no device is connected, we must call video_out_init,
|
||||
* as some of the data structures it initializes are
|
||||
* used in get_video_frames()
|
||||
|
@ -893,14 +895,14 @@ static void *video_thread(void *arg)
|
|||
|
||||
/* Writes intial status of the sources. */
|
||||
if (env->gui) {
|
||||
for (i = 0; i < env->out.device_num; i++) {
|
||||
print_message(env->gui->thumb_bd_array[i].board,
|
||||
src_msgs[env->out.devices[i].status_index]);
|
||||
}
|
||||
for (i = 0; i < env->out.device_num; i++) {
|
||||
print_message(env->gui->thumb_bd_array[i].board,
|
||||
src_msgs[env->out.devices[i].status_index]);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct timeval t = { 0, 50000 }; /* XXX 20 times/sec */
|
||||
struct timespec t = { 0, 50000000 }; /* XXX 20 times/sec */
|
||||
struct ast_frame *p, *f;
|
||||
struct ast_channel *chan;
|
||||
int fd;
|
||||
|
@ -908,13 +910,14 @@ static void *video_thread(void *arg)
|
|||
|
||||
/* determine if video format changed */
|
||||
if (count++ % 10 == 0) {
|
||||
if (env->out.sendvideo && env->out.devices)
|
||||
sprintf(buf, "%s %s %dx%d @@ %dfps %dkbps",
|
||||
if (env->out.sendvideo && env->out.devices) {
|
||||
snprintf(buf, sizeof(buf), "%s %s %dx%d @@ %dfps %dkbps",
|
||||
env->out.devices[env->out.device_primary].name, env->codec_name,
|
||||
env->enc_in.w, env->enc_in.h,
|
||||
env->out.fps, env->out.bitrate/1000);
|
||||
else
|
||||
sprintf(buf, "hold");
|
||||
env->out.fps, env->out.bitrate / 1000);
|
||||
} else {
|
||||
sprintf(buf, "hold");
|
||||
}
|
||||
caption = buf;
|
||||
}
|
||||
|
||||
|
@ -923,36 +926,36 @@ static void *video_thread(void *arg)
|
|||
* otherwise the drag will not work */
|
||||
if (env->gui)
|
||||
eventhandler(env, caption);
|
||||
|
||||
|
||||
/* sleep for a while */
|
||||
ast_select(0, NULL, NULL, NULL, &t);
|
||||
nanosleep(&t, NULL);
|
||||
|
||||
if (env->in) {
|
||||
struct video_dec_desc *v = env->in;
|
||||
|
||||
/*
|
||||
* While there is something to display, call the decoder and free
|
||||
* the buffer, possibly enabling the receiver to store new data.
|
||||
*/
|
||||
while (v->dec_in_dpy) {
|
||||
struct fbuf_t *tmp = v->dec_in_dpy; /* store current pointer */
|
||||
struct video_dec_desc *v = env->in;
|
||||
|
||||
/* decode the frame, but show it only if not frozen */
|
||||
if (v->d_callbacks->dec_run(v, tmp) && !env->frame_freeze)
|
||||
show_frame(env, WIN_REMOTE);
|
||||
tmp->used = 0; /* mark buffer as free */
|
||||
tmp->ebit = 0;
|
||||
ast_mutex_lock(&env->dec_lock);
|
||||
if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN]) /* advance to next, circular */
|
||||
v->dec_in_dpy = &v->dec_in[0];
|
||||
/*
|
||||
* While there is something to display, call the decoder and free
|
||||
* the buffer, possibly enabling the receiver to store new data.
|
||||
*/
|
||||
while (v->dec_in_dpy) {
|
||||
struct fbuf_t *tmp = v->dec_in_dpy; /* store current pointer */
|
||||
|
||||
if (v->dec_in_cur == NULL) /* receiver was idle, enable it... */
|
||||
v->dec_in_cur = tmp; /* using the slot just freed */
|
||||
else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
|
||||
v->dec_in_dpy = NULL; /* nothing more to display */
|
||||
ast_mutex_unlock(&env->dec_lock);
|
||||
/* decode the frame, but show it only if not frozen */
|
||||
if (v->d_callbacks->dec_run(v, tmp) && !env->frame_freeze)
|
||||
show_frame(env, WIN_REMOTE);
|
||||
tmp->used = 0; /* mark buffer as free */
|
||||
tmp->ebit = 0;
|
||||
ast_mutex_lock(&env->dec_lock);
|
||||
if (++v->dec_in_dpy == &v->dec_in[N_DEC_IN]) /* advance to next, circular */
|
||||
v->dec_in_dpy = &v->dec_in[0];
|
||||
|
||||
if (v->dec_in_cur == NULL) /* receiver was idle, enable it... */
|
||||
v->dec_in_cur = tmp; /* using the slot just freed */
|
||||
else if (v->dec_in_dpy == v->dec_in_cur) /* this was the last slot */
|
||||
v->dec_in_dpy = NULL; /* nothing more to display */
|
||||
ast_mutex_unlock(&env->dec_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (env->shutdown)
|
||||
break;
|
||||
|
@ -988,7 +991,7 @@ static void *video_thread(void *arg)
|
|||
for (p = f; p; p = AST_LIST_NEXT(p, frame_list)) {
|
||||
if (write(fd, &blah, l) != l)
|
||||
ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d: %s!\n",
|
||||
chan->name, f->frametype, f->subclass, strerror(errno));
|
||||
chan->name, f->frametype, f->subclass, strerror(errno));
|
||||
}
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
|
@ -1194,13 +1197,13 @@ int console_video_cli(struct video_desc *env, const char *var, int fd)
|
|||
if (env == NULL)
|
||||
return 1; /* unrecognised */
|
||||
|
||||
if (!strcasecmp(var, "videodevice")) {
|
||||
if (!strcasecmp(var, "videodevice")) {
|
||||
ast_cli(fd, "videodevice is [%s]\n", env->out.devices[env->out.device_primary].name);
|
||||
} else if (!strcasecmp(var, "videocodec")) {
|
||||
} else if (!strcasecmp(var, "videocodec")) {
|
||||
ast_cli(fd, "videocodec is [%s]\n", env->codec_name);
|
||||
} else if (!strcasecmp(var, "sendvideo")) {
|
||||
} else if (!strcasecmp(var, "sendvideo")) {
|
||||
ast_cli(fd, "sendvideo is [%s]\n", env->out.sendvideo ? "on" : "off");
|
||||
} else if (!strcasecmp(var, "video_size")) {
|
||||
} else if (!strcasecmp(var, "video_size")) {
|
||||
int in_w = 0, in_h = 0;
|
||||
if (env->in) {
|
||||
in_w = env->in->dec_out.w;
|
||||
|
@ -1212,22 +1215,22 @@ int console_video_cli(struct video_desc *env, const char *var, int fd)
|
|||
env->loc_dpy.w, env->loc_dpy.h,
|
||||
env->rem_dpy.w, env->rem_dpy.h,
|
||||
in_w, in_h);
|
||||
} else if (!strcasecmp(var, "bitrate")) {
|
||||
} else if (!strcasecmp(var, "bitrate")) {
|
||||
ast_cli(fd, "bitrate is [%d]\n", env->out.bitrate);
|
||||
} else if (!strcasecmp(var, "qmin")) {
|
||||
} else if (!strcasecmp(var, "qmin")) {
|
||||
ast_cli(fd, "qmin is [%d]\n", env->out.qmin);
|
||||
} else if (!strcasecmp(var, "fps")) {
|
||||
} else if (!strcasecmp(var, "fps")) {
|
||||
ast_cli(fd, "fps is [%d]\n", env->out.fps);
|
||||
} else if (!strcasecmp(var, "startgui")) {
|
||||
} else if (!strcasecmp(var, "startgui")) {
|
||||
env->stayopen = 1;
|
||||
console_video_start(env, NULL);
|
||||
} else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
|
||||
} else if (!strcasecmp(var, "stopgui") && env->stayopen != 0) {
|
||||
env->stayopen = 0;
|
||||
if (env->gui && env->owner)
|
||||
ast_cli_command(-1, "console hangup");
|
||||
else /* not in a call */
|
||||
console_video_uninit(env);
|
||||
} else {
|
||||
} else {
|
||||
return 1; /* unrecognised */
|
||||
}
|
||||
return 0; /* recognised */
|
||||
|
|
45
configure.ac
45
configure.ac
|
@ -60,6 +60,7 @@ case "${host_os}" in
|
|||
;;
|
||||
darwin*)
|
||||
AC_DEFINE([AST_POLL_COMPAT], 1, [Define to 1 if internal poll should be used.])
|
||||
AC_DEFINE([_DARWIN_UNLIMITED_SELECT], 1, [Define to 1 if running on Darwin.])
|
||||
;;
|
||||
*)
|
||||
AC_PREFIX_DEFAULT([/usr])
|
||||
|
@ -466,7 +467,7 @@ AC_FUNC_STRNLEN
|
|||
AC_FUNC_STRTOD
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap ntohll newlocale putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl])
|
||||
AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ffsll ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob htonll ioperm inet_ntoa isascii memchr memmove memset mkdir munmap ntohll newlocale ppoll putenv re_comp regcomp select setenv socket strcasecmp strcasestr strchr strcspn strdup strerror strlcat strlcpy strncasecmp strndup strnlen strrchr strsep strspn strstr strtod strtol strtold strtoq unsetenv utime vasprintf getpeereid sysctl swapctl])
|
||||
|
||||
# NOTE: we use AC_CHECK_LIB to get -lm into the arguments for later checks,
|
||||
# so that AC_CHECK_FUNCS can detect functions in that library.
|
||||
|
@ -741,6 +742,48 @@ AC_RUN_IFELSE(
|
|||
AC_MSG_RESULT(unknown)
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING(if we can increase the maximum select-able file descriptor)
|
||||
AC_RUN_IFELSE(
|
||||
AC_LANG_PROGRAM([
|
||||
#include <stdio.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
], [[
|
||||
struct rlimit rlim = { FD_SETSIZE * 2, FD_SETSIZE * 2 };
|
||||
int fd0, fd1;
|
||||
struct timeval tv = { 0, };
|
||||
struct ast_fdset { long fds_bits[[1024]]; } fds = { { 0, } };
|
||||
if (setrlimit(RLIMIT_NOFILE, &rlim)) { exit(1); }
|
||||
if ((fd0 = open("/dev/null", O_RDONLY)) < 0) { exit(1); }
|
||||
if (dup2(fd0, (fd1 = FD_SETSIZE + 1)) < 0) { exit(1); }
|
||||
FD_SET(fd0, (fd_set *) &fds);
|
||||
FD_SET(fd1, (fd_set *) &fds);
|
||||
if (select(FD_SETSIZE + 2, (fd_set *) &fds, NULL, NULL, &tv) < 0) { exit(1); }
|
||||
exit(0)]]),
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE([HAVE_VARIABLE_FDSET], 1, [Define to 1 if your system can support larger than default select bitmasks.]),
|
||||
AC_MSG_RESULT(no),
|
||||
AC_MSG_RESULT(cross-compile)
|
||||
)
|
||||
|
||||
if test "${ac_cv_have_variable_fdset}x" = "0x"; then
|
||||
AC_RUN_IFELSE(
|
||||
AC_LANG_PROGRAM([
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
], [if (getuid() != 0) { exit(1); }]),
|
||||
AC_DEFINE([CONFIGURE_RAN_AS_ROOT], 1, [Some configure tests will unexpectedly fail if configure is run by a non-root user. These may be able to be tested at runtime.]))
|
||||
fi
|
||||
|
||||
AST_GCC_ATTRIBUTE(pure)
|
||||
AST_GCC_ATTRIBUTE(malloc)
|
||||
AST_GCC_ATTRIBUTE(const)
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
/* Define to 1 if the `closedir' function returns void instead of `int'. */
|
||||
#undef CLOSEDIR_VOID
|
||||
|
||||
/* Some configure tests will unexpectedly fail if configure is run by a
|
||||
non-root user. These may be able to be tested at runtime. */
|
||||
#undef CONFIGURE_RAN_AS_ROOT
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
|
@ -381,9 +385,6 @@
|
|||
/* Define to 1 if your system defines the locale_t type in xlocale.h */
|
||||
#undef HAVE_LOCALE_T_IN_XLOCALE_H
|
||||
|
||||
/* Define to 1 if you have the `localtime_r' function. */
|
||||
#undef HAVE_LOCALTIME_R
|
||||
|
||||
/* Define to 1 if you have the `log' function. */
|
||||
#undef HAVE_LOG
|
||||
|
||||
|
@ -538,6 +539,9 @@
|
|||
/* Define to 1 if you have the `powl' function. */
|
||||
#undef HAVE_POWL
|
||||
|
||||
/* Define to 1 if you have the `ppoll' function. */
|
||||
#undef HAVE_PPOLL
|
||||
|
||||
/* Define to 1 if you have the ISDN PRI library. */
|
||||
#undef HAVE_PRI
|
||||
|
||||
|
@ -803,7 +807,7 @@
|
|||
/* Define to 1 if you have the `strtoq' function. */
|
||||
#undef HAVE_STRTOQ
|
||||
|
||||
/* Define to 1 if `st_blksize' is a member of `struct stat'. */
|
||||
/* Define to 1 if `st_blksize' is member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_BLKSIZE
|
||||
|
||||
/* Define to 1 if you have the mISDN Supplemental Services library. */
|
||||
|
@ -956,6 +960,10 @@
|
|||
/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
|
||||
#undef HAVE_UTIME_NULL
|
||||
|
||||
/* Define to 1 if your system can support larger than default select bitmasks.
|
||||
*/
|
||||
#undef HAVE_VARIABLE_FDSET
|
||||
|
||||
/* Define to 1 if you have the `vasprintf' function. */
|
||||
#undef HAVE_VASPRINTF
|
||||
|
||||
|
@ -1074,12 +1082,12 @@
|
|||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if the C compiler supports function prototypes. */
|
||||
#undef PROTOTYPES
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
#undef PTHREAD_CREATE_JOINABLE
|
||||
|
@ -1099,6 +1107,11 @@
|
|||
/* Define to the type of arg 5 for `select'. */
|
||||
#undef SELECT_TYPE_ARG5
|
||||
|
||||
/* Define to 1 if the `setvbuf' function takes the buffering type as its
|
||||
second argument and the buffer pointer as the third, as on System V before
|
||||
release 3. */
|
||||
#undef SETVBUF_REVERSED
|
||||
|
||||
/* The size of `char *', as computed by sizeof. */
|
||||
#undef SIZEOF_CHAR_P
|
||||
|
||||
|
@ -1128,30 +1141,23 @@
|
|||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
#undef TM_IN_SYS_TIME
|
||||
|
||||
/* Enable extensions on AIX 3, Interix. */
|
||||
/* Define to 1 if on AIX 3.
|
||||
System headers sometimes define this.
|
||||
We just want to avoid a redefinition error message. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
|
||||
/* Define to 1 if running on Darwin. */
|
||||
#undef _DARWIN_UNLIMITED_SELECT
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable threading extensions on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
|
||||
#undef _LARGEFILE_SOURCE
|
||||
|
@ -1169,6 +1175,20 @@
|
|||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
/* Enable extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
|
||||
/* Define like PROTOTYPES; this can be used by system headers. */
|
||||
#undef __PROTOTYPES
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
|
|
|
@ -2232,44 +2232,6 @@ static inline void timersub(struct timeval *tvend, struct timeval *tvstart, stru
|
|||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Waits for activity on a group of channels
|
||||
* \param nfds the maximum number of file descriptors in the sets
|
||||
* \param rfds file descriptors to check for read availability
|
||||
* \param wfds file descriptors to check for write availability
|
||||
* \param efds file descriptors to check for exceptions (OOB data)
|
||||
* \param tvp timeout while waiting for events
|
||||
* \details
|
||||
* This is the same as a standard select(), except it guarantees the
|
||||
* behaviour where the passed struct timeval is updated with how much
|
||||
* time was not slept while waiting for the specified events
|
||||
*/
|
||||
static inline int ast_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tvp)
|
||||
{
|
||||
#ifdef __linux__
|
||||
return select(nfds, rfds, wfds, efds, tvp);
|
||||
#else
|
||||
if (tvp) {
|
||||
struct timeval tv, tvstart, tvend, tvlen;
|
||||
int res;
|
||||
|
||||
tv = *tvp;
|
||||
gettimeofday(&tvstart, NULL);
|
||||
res = select(nfds, rfds, wfds, efds, tvp);
|
||||
gettimeofday(&tvend, NULL);
|
||||
timersub(&tvend, &tvstart, &tvlen);
|
||||
timersub(&tv, &tvlen, tvp);
|
||||
if (tvp->tv_sec < 0 || (tvp->tv_sec == 0 && tvp->tv_usec < 0)) {
|
||||
tvp->tv_sec = 0;
|
||||
tvp->tv_usec = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else
|
||||
return select(nfds, rfds, wfds, efds, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! \brief Retrieves the current T38 state of a channel */
|
||||
static inline enum ast_t38_state ast_channel_get_t38_state(struct ast_channel *chan)
|
||||
{
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
#ifndef __AST_POLL_COMPAT_H
|
||||
#define __AST_POLL_COMPAT_H
|
||||
|
||||
#include "asterisk/select.h"
|
||||
|
||||
#ifndef AST_POLL_COMPAT
|
||||
|
||||
#include <sys/poll.h>
|
||||
|
@ -114,4 +116,24 @@ int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout);
|
|||
|
||||
#endif /* AST_POLL_COMPAT */
|
||||
|
||||
/*!
|
||||
* \brief Same as poll(2), except the time is specified in microseconds and
|
||||
* the tv argument is modified to indicate the time remaining.
|
||||
*/
|
||||
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv);
|
||||
|
||||
/*!
|
||||
* \brief Shortcut for conversion of FD_ISSET to poll(2)-based
|
||||
*/
|
||||
static inline int ast_poll_fd_index(struct pollfd *haystack, int nfds, int needle)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
if (haystack[i].fd == needle) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* __AST_POLL_COMPAT_H */
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* Tilghman Lesher <tlesher AT digium DOT com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!\file
|
||||
* \brief Bitfield expansions for ast_select
|
||||
*/
|
||||
|
||||
#ifndef __AST_SELECT_H
|
||||
#define __AST_SELECT_H
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern unsigned int ast_FD_SETSIZE;
|
||||
|
||||
#if !defined(HAVE_VARIABLE_FDSET) && defined(CONFIGURE_RAN_AS_ROOT)
|
||||
#define ast_fdset fd_set
|
||||
#else
|
||||
typedef struct {
|
||||
long fds_bits[4096 / sizeof(long)]; /* 32768 bits */
|
||||
} ast_fdset;
|
||||
|
||||
#undef FD_ZERO
|
||||
#define FD_ZERO(a) \
|
||||
do { \
|
||||
long *bytes = (long *) a; \
|
||||
int i; \
|
||||
for (i = 0; i < sizeof(*(a)) / sizeof(long); i++) { \
|
||||
bytes[i] = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#undef FD_SET
|
||||
#define FD_SET(fd, fds) \
|
||||
do { \
|
||||
long *bytes = (long *) fds; \
|
||||
if (fd / sizeof(*bytes) + ((fd + 1) % sizeof(*bytes) ? 1 : 0) < sizeof(*(fds))) { \
|
||||
bytes[fd / (sizeof(*bytes))] |= 1L << (fd % sizeof(*bytes)); \
|
||||
} else { \
|
||||
ast_log(LOG_ERROR, "FD %d exceeds the maximum size of ast_fdset!\n", fd); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /* HAVE_VARIABLE_FDSET */
|
||||
|
||||
/*! \brief Waits for activity on a group of channels
|
||||
* \param nfds the maximum number of file descriptors in the sets
|
||||
* \param rfds file descriptors to check for read availability
|
||||
* \param wfds file descriptors to check for write availability
|
||||
* \param efds file descriptors to check for exceptions (OOB data)
|
||||
* \param tvp timeout while waiting for events
|
||||
* This is the same as a standard select(), except it guarantees the
|
||||
* behaviour where the passed struct timeval is updated with how much
|
||||
* time was not slept while waiting for the specified events
|
||||
*/
|
||||
static inline int ast_select(int nfds, ast_fdset *rfds, ast_fdset *wfds, ast_fdset *efds, struct timeval *tvp)
|
||||
{
|
||||
#ifdef __linux__
|
||||
ast_assert((unsigned int) nfds <= ast_FD_SETSIZE);
|
||||
return select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, tvp);
|
||||
#else
|
||||
int save_errno = 0;
|
||||
|
||||
ast_assert((unsigned int) nfds <= ast_FD_SETSIZE);
|
||||
if (tvp) {
|
||||
struct timeval tv, tvstart, tvend, tvlen;
|
||||
int res;
|
||||
|
||||
tv = *tvp;
|
||||
gettimeofday(&tvstart, NULL);
|
||||
res = select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, tvp);
|
||||
save_errno = errno;
|
||||
gettimeofday(&tvend, NULL);
|
||||
timersub(&tvend, &tvstart, &tvlen);
|
||||
timersub(&tv, &tvlen, tvp);
|
||||
if (tvp->tv_sec < 0 || (tvp->tv_sec == 0 && tvp->tv_usec < 0)) {
|
||||
tvp->tv_sec = 0;
|
||||
tvp->tv_usec = 0;
|
||||
}
|
||||
errno = save_errno;
|
||||
return res;
|
||||
}
|
||||
else
|
||||
return select(nfds, (fd_set *) rfds, (fd_set *) wfds, (fd_set *) efds, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AST_SELECT_H */
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2008, Digium, Inc.
|
||||
* Copyright (C) 1999 - 2010, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
|
@ -272,6 +272,8 @@ static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
|
|||
static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
|
||||
static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
|
||||
|
||||
extern unsigned int ast_FD_SETSIZE;
|
||||
|
||||
static char *_argv[256];
|
||||
static int shuttingdown;
|
||||
static int restartnow;
|
||||
|
@ -3167,7 +3169,8 @@ int main(int argc, char *argv[])
|
|||
char *buf;
|
||||
const char *runuser = NULL, *rungroup = NULL;
|
||||
char *remotesock = NULL;
|
||||
int moduleresult; /*!< Result from the module load subsystem */
|
||||
int moduleresult; /*!< Result from the module load subsystem */
|
||||
struct rlimit l;
|
||||
|
||||
/* Remember original args for restart */
|
||||
if (argc > ARRAY_LEN(_argv) - 1) {
|
||||
|
@ -3352,7 +3355,6 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
if (ast_opt_dump_core) {
|
||||
struct rlimit l;
|
||||
memset(&l, 0, sizeof(l));
|
||||
l.rlim_cur = RLIM_INFINITY;
|
||||
l.rlim_max = RLIM_INFINITY;
|
||||
|
@ -3361,6 +3363,44 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &l)) {
|
||||
ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
#if !defined(CONFIGURE_RAN_AS_ROOT)
|
||||
/* Check if select(2) will run with more file descriptors */
|
||||
do {
|
||||
int fd, fd2;
|
||||
ast_fdset readers;
|
||||
struct timeval tv = { 0, };
|
||||
|
||||
if (l.rlim_cur <= FD_SETSIZE) {
|
||||
/* The limit of select()able FDs is irrelevant, because we'll never
|
||||
* open one that high. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(fd = open("/dev/null", O_RDONLY))) {
|
||||
ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
|
||||
break; /* XXX Should we exit() here? XXX */
|
||||
}
|
||||
|
||||
fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
|
||||
if (dup2(fd, fd2)) {
|
||||
ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
FD_ZERO(&readers);
|
||||
FD_SET(fd2, &readers);
|
||||
if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
|
||||
ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
|
||||
}
|
||||
} while (0);
|
||||
#elif defined(HAVE_VARIABLE_FDSET)
|
||||
ast_FD_SETSIZE = l.rlim_cur;
|
||||
#endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
|
||||
|
||||
if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
|
||||
rungroup = ast_config_AST_RUN_GROUP;
|
||||
if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
|
||||
|
|
|
@ -438,7 +438,7 @@ static const struct ast_datastore_info dial_features_info = {
|
|||
static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
|
||||
static void parkinglot_unref(struct ast_parkinglot *parkinglot);
|
||||
static void parkinglot_destroy(void *obj);
|
||||
int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *fs, int *max);
|
||||
int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *fs);
|
||||
struct ast_parkinglot *find_parkinglot(const char *name);
|
||||
static struct ast_parkinglot *create_parkinglot(const char *name);
|
||||
static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
|
||||
|
@ -3603,9 +3603,10 @@ static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_
|
|||
}
|
||||
|
||||
/*! \brief Run management on parkinglots, called once per parkinglot */
|
||||
int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
|
||||
int manage_parkinglot(struct ast_parkinglot *curlot, struct pollfd **pfds, int *nfds, int *ms)
|
||||
{
|
||||
|
||||
struct pollfd *new_fds = NULL;
|
||||
int new_nfds = 0;
|
||||
struct parkeduser *pu;
|
||||
int res = 0;
|
||||
char parkingslot[AST_MAX_EXTENSION];
|
||||
|
@ -3628,12 +3629,12 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
|
|||
/* Get chan, exten from derived kludge */
|
||||
if (pu->peername[0]) {
|
||||
char *peername = ast_strdupa(pu->peername);
|
||||
char *cp = strrchr(peername, '-');
|
||||
char *dash = strrchr(peername, '-');
|
||||
char *peername_flat; /* using something like DAHDI/52 for an extension name is NOT a good idea */
|
||||
int i;
|
||||
|
||||
if (cp) {
|
||||
*cp = 0;
|
||||
if (dash) {
|
||||
*dash = '\0';
|
||||
}
|
||||
|
||||
peername_flat = ast_strdupa(peername);
|
||||
|
@ -3712,14 +3713,33 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
|
|||
} else { /* still within parking time, process descriptors */
|
||||
for (x = 0; x < AST_MAX_FDS; x++) {
|
||||
struct ast_frame *f;
|
||||
int y;
|
||||
|
||||
if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds)))
|
||||
if (chan->fds[x] == -1) {
|
||||
continue; /* nothing on this descriptor */
|
||||
}
|
||||
|
||||
for (y = 0; y < *nfds; y++) {
|
||||
if ((*pfds[y]).fd == chan->fds[x]) {
|
||||
/* Found poll record! */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (y == *nfds) {
|
||||
/* Not found */
|
||||
continue;
|
||||
|
||||
if (FD_ISSET(chan->fds[x], efds))
|
||||
}
|
||||
|
||||
if (!((*pfds[y]).revents & (POLLIN | POLLERR))) {
|
||||
/* Next x */
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*pfds[y]).revents & POLLERR) {
|
||||
ast_set_flag(chan, AST_FLAG_EXCEPTION);
|
||||
else
|
||||
} else {
|
||||
ast_clear_flag(chan, AST_FLAG_EXCEPTION);
|
||||
}
|
||||
chan->fdno = x;
|
||||
|
||||
/* See if they need servicing */
|
||||
|
@ -3760,22 +3780,32 @@ int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds,
|
|||
}
|
||||
} /* End for */
|
||||
if (x >= AST_MAX_FDS) {
|
||||
std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
|
||||
std: for (x = 0; x < AST_MAX_FDS; x++) { /* mark fds for next round */
|
||||
if (chan->fds[x] > -1) {
|
||||
FD_SET(chan->fds[x], nrfds);
|
||||
FD_SET(chan->fds[x], nefds);
|
||||
if (chan->fds[x] > *max)
|
||||
*max = chan->fds[x];
|
||||
void *tmp = ast_realloc(new_fds, (new_nfds + 1) * sizeof(*new_fds));
|
||||
if (!tmp) {
|
||||
continue;
|
||||
}
|
||||
new_fds = tmp;
|
||||
new_fds[new_nfds].fd = chan->fds[x];
|
||||
new_fds[new_nfds].events = POLLIN | POLLERR;
|
||||
new_fds[new_nfds].revents = 0;
|
||||
new_nfds++;
|
||||
}
|
||||
}
|
||||
/* Keep track of our shortest wait */
|
||||
if (tms < *ms || *ms < 0)
|
||||
if (tms < *ms || *ms < 0) {
|
||||
*ms = tms;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&curlot->parkings);
|
||||
|
||||
ast_free(*pfds);
|
||||
*pfds = new_fds;
|
||||
*nfds = new_nfds;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -3789,35 +3819,26 @@ std: for (x=0; x<AST_MAX_FDS; x++) { /* mark fds for next round */
|
|||
*/
|
||||
static void *do_parking_thread(void *ignore)
|
||||
{
|
||||
fd_set rfds, efds; /* results from previous select, to be preserved across loops. */
|
||||
fd_set nrfds, nefds; /* args for the next select */
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&efds);
|
||||
struct pollfd *pfds = NULL;
|
||||
int nfds = 0;
|
||||
|
||||
for (;;) {
|
||||
int res = 0;
|
||||
int ms = -1; /* select timeout, uninitialized */
|
||||
int max = -1; /* max fd, none there yet */
|
||||
struct ao2_iterator iter;
|
||||
struct ast_parkinglot *curlot;
|
||||
FD_ZERO(&nrfds);
|
||||
FD_ZERO(&nefds);
|
||||
int ms = -1; /* poll2 timeout, uninitialized */
|
||||
iter = ao2_iterator_init(parkinglots, 0);
|
||||
|
||||
while ((curlot = ao2_iterator_next(&iter))) {
|
||||
res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
|
||||
manage_parkinglot(curlot, &pfds, &nfds, &ms);
|
||||
ao2_ref(curlot, -1);
|
||||
}
|
||||
ao2_iterator_destroy(&iter);
|
||||
|
||||
rfds = nrfds;
|
||||
efds = nefds;
|
||||
{
|
||||
struct timeval wait = ast_samp2tv(ms, 1000);
|
||||
/* Wait for something to happen */
|
||||
ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
|
||||
}
|
||||
/* Wait for something to happen */
|
||||
ast_poll(pfds, nfds, ms);
|
||||
pthread_testcancel();
|
||||
}
|
||||
/* If this WERE reached, we'd need to free(pfds) */
|
||||
return NULL; /* Never reached */
|
||||
}
|
||||
|
||||
|
|
192
main/poll.c
192
main/poll.c
|
@ -10,9 +10,9 @@
|
|||
|
||||
struct pollfd
|
||||
{
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
}
|
||||
|
||||
int poll (struct pollfd *pArray, unsigned long n_fds, int timeout)
|
||||
|
@ -73,54 +73,44 @@
|
|||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <unistd.h> /* standard Unix definitions */
|
||||
#include <sys/types.h> /* system types */
|
||||
#include <sys/time.h> /* time definitions */
|
||||
#include <assert.h> /* assertion macros */
|
||||
#include <string.h> /* string functions */
|
||||
#include <unistd.h> /* standard Unix definitions */
|
||||
#include <sys/types.h> /* system types */
|
||||
#include <sys/time.h> /* time definitions */
|
||||
#include <assert.h> /* assertion macros */
|
||||
#include <string.h> /* string functions */
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk/utils.h" /* this package */
|
||||
#include "asterisk/poll-compat.h" /* this package */
|
||||
|
||||
#ifdef AST_POLL_COMPAT
|
||||
unsigned int ast_FD_SETSIZE = FD_SETSIZE;
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) a > b ? a : b
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Private Functions
|
||||
Private Functions
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
static int map_poll_spec
|
||||
#if __STDC__ > 0
|
||||
(struct pollfd *pArray,
|
||||
unsigned long n_fds,
|
||||
fd_set *pReadSet,
|
||||
fd_set *pWriteSet,
|
||||
fd_set *pExceptSet)
|
||||
#else
|
||||
(pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
|
||||
struct pollfd *pArray;
|
||||
unsigned long n_fds;
|
||||
fd_set *pReadSet;
|
||||
fd_set *pWriteSet;
|
||||
fd_set *pExceptSet;
|
||||
#endif
|
||||
#if defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL)
|
||||
static int map_poll_spec(struct pollfd *pArray, unsigned long n_fds,
|
||||
ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
|
||||
{
|
||||
register unsigned long i; /* loop control */
|
||||
register struct pollfd *pCur; /* current array element */
|
||||
register int max_fd = -1; /* return value */
|
||||
register unsigned long i; /* loop control */
|
||||
register struct pollfd *pCur; /* current array element */
|
||||
register int max_fd = -1; /* return value */
|
||||
|
||||
/*!\note
|
||||
/*
|
||||
* Map the poll() structures into the file descriptor sets required
|
||||
* by select().
|
||||
*/
|
||||
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
|
||||
/* Skip any bad FDs in the array. */
|
||||
|
||||
if (pCur->fd < 0)
|
||||
if (pCur->fd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pCur->events & POLLIN) {
|
||||
/* "Input Ready" notification desired. */
|
||||
|
@ -145,34 +135,28 @@ static int map_poll_spec
|
|||
|
||||
return max_fd;
|
||||
}
|
||||
|
||||
static struct timeval *map_timeout
|
||||
#if __STDC__ > 0
|
||||
(int poll_timeout, struct timeval *pSelTimeout)
|
||||
#else
|
||||
(poll_timeout, pSelTimeout)
|
||||
int poll_timeout;
|
||||
struct timeval *pSelTimeout;
|
||||
#endif
|
||||
|
||||
#ifdef AST_POLL_COMPAT
|
||||
static struct timeval *map_timeout(int poll_timeout, struct timeval *pSelTimeout)
|
||||
{
|
||||
struct timeval *pResult;
|
||||
|
||||
/*!\note
|
||||
* Map the poll() timeout value into a select() timeout. The possible
|
||||
* values of the poll() timeout value, and their meanings, are:
|
||||
*
|
||||
* VALUE MEANING
|
||||
*
|
||||
* -1 wait indefinitely (until signal occurs)
|
||||
* 0 return immediately, don't block
|
||||
* >0 wait specified number of milliseconds
|
||||
*
|
||||
* select() uses a "struct timeval", which specifies the timeout in
|
||||
* seconds and microseconds, so the milliseconds value has to be mapped
|
||||
* accordingly.
|
||||
*/
|
||||
/*
|
||||
Map the poll() timeout value into a select() timeout. The possible
|
||||
values of the poll() timeout value, and their meanings, are:
|
||||
|
||||
assert(pSelTimeout != (struct timeval *) NULL);
|
||||
VALUE MEANING
|
||||
|
||||
-1 wait indefinitely (until signal occurs)
|
||||
0 return immediately, don't block
|
||||
>0 wait specified number of milliseconds
|
||||
|
||||
select() uses a "struct timeval", which specifies the timeout in
|
||||
seconds and microseconds, so the milliseconds value has to be mapped
|
||||
accordingly.
|
||||
*/
|
||||
|
||||
assert(pSelTimeout != NULL);
|
||||
|
||||
switch (poll_timeout) {
|
||||
case -1:
|
||||
|
@ -203,25 +187,13 @@ static struct timeval *map_timeout
|
|||
|
||||
return pResult;
|
||||
}
|
||||
#endif /* AST_POLL_COMPAT */
|
||||
|
||||
static void map_select_results
|
||||
#if __STDC__ > 0
|
||||
(struct pollfd *pArray,
|
||||
unsigned long n_fds,
|
||||
fd_set *pReadSet,
|
||||
fd_set *pWriteSet,
|
||||
fd_set *pExceptSet)
|
||||
#else
|
||||
(pArray, n_fds, pReadSet, pWriteSet, pExceptSet)
|
||||
struct pollfd *pArray;
|
||||
unsigned long n_fds;
|
||||
fd_set *pReadSet;
|
||||
fd_set *pWriteSet;
|
||||
fd_set *pExceptSet;
|
||||
#endif
|
||||
static void map_select_results(struct pollfd *pArray, unsigned long n_fds,
|
||||
ast_fdset *pReadSet, ast_fdset *pWriteSet, ast_fdset *pExceptSet)
|
||||
{
|
||||
register unsigned long i; /* loop control */
|
||||
register struct pollfd *pCur; /* current array element */
|
||||
register unsigned long i; /* loop control */
|
||||
register struct pollfd *pCur; /* current array element */
|
||||
|
||||
for (i = 0, pCur = pArray; i < n_fds; i++, pCur++) {
|
||||
/* Skip any bad FDs in the array. */
|
||||
|
@ -231,59 +203,101 @@ static void map_select_results
|
|||
}
|
||||
|
||||
/* Exception events take priority over input events. */
|
||||
|
||||
pCur->revents = 0;
|
||||
if (FD_ISSET (pCur->fd, pExceptSet)) {
|
||||
if (FD_ISSET(pCur->fd, (fd_set *) pExceptSet)) {
|
||||
pCur->revents |= POLLPRI;
|
||||
} else if (FD_ISSET (pCur->fd, pReadSet)) {
|
||||
} else if (FD_ISSET(pCur->fd, (fd_set *) pReadSet)) {
|
||||
pCur->revents |= POLLIN;
|
||||
}
|
||||
|
||||
if (FD_ISSET (pCur->fd, pWriteSet)) {
|
||||
if (FD_ISSET(pCur->fd, (fd_set *) pWriteSet)) {
|
||||
pCur->revents |= POLLOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif /* defined(AST_POLL_COMPAT) || !defined(HAVE_PPOLL) */
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Public Functions
|
||||
Public Functions
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef AST_POLL_COMPAT
|
||||
int ast_internal_poll(struct pollfd *pArray, unsigned long n_fds, int timeout)
|
||||
{
|
||||
fd_set read_descs; /* input file descs */
|
||||
fd_set write_descs; /* output file descs */
|
||||
fd_set except_descs; /* exception descs */
|
||||
ast_fdset read_descs; /* input file descs */
|
||||
ast_fdset write_descs; /* output file descs */
|
||||
ast_fdset except_descs; /* exception descs */
|
||||
struct timeval stime; /* select() timeout value */
|
||||
int ready_descriptors; /* function result */
|
||||
int max_fd = 0; /* maximum fd value */
|
||||
int ready_descriptors; /* function result */
|
||||
int max_fd = 0; /* maximum fd value */
|
||||
struct timeval *pTimeout; /* actually passed */
|
||||
int save_errno;
|
||||
|
||||
FD_ZERO (&read_descs);
|
||||
FD_ZERO (&write_descs);
|
||||
FD_ZERO (&except_descs);
|
||||
FD_ZERO(&read_descs);
|
||||
FD_ZERO(&write_descs);
|
||||
FD_ZERO(&except_descs);
|
||||
|
||||
/* Map the poll() file descriptor list in the select() data structures. */
|
||||
|
||||
if (pArray) {
|
||||
max_fd = map_poll_spec (pArray, n_fds,
|
||||
max_fd = map_poll_spec (pArray, n_fds,
|
||||
&read_descs, &write_descs, &except_descs);
|
||||
}
|
||||
|
||||
/* Map the poll() timeout value in the select() timeout structure. */
|
||||
pTimeout = map_timeout(timeout, &stime);
|
||||
|
||||
pTimeout = map_timeout (timeout, &stime);
|
||||
|
||||
/* Make the select() call. */
|
||||
ready_descriptors = select(max_fd + 1, &read_descs, &write_descs,
|
||||
|
||||
ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs,
|
||||
&except_descs, pTimeout);
|
||||
save_errno = errno;
|
||||
|
||||
if (ready_descriptors >= 0) {
|
||||
map_select_results (pArray, n_fds,
|
||||
&read_descs, &write_descs, &except_descs);
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
return ready_descriptors;
|
||||
}
|
||||
#endif /* AST_POLL_COMPAT */
|
||||
|
||||
int ast_poll2(struct pollfd *pArray, unsigned long n_fds, struct timeval *tv)
|
||||
{
|
||||
#ifdef HAVE_PPOLL
|
||||
struct timeval start = ast_tvnow();
|
||||
struct timespec ts = { tv ? tv->tv_sec : 0, tv ? tv->tv_usec * 1000 : 0 };
|
||||
int res = ppoll(pArray, n_fds, tv ? &ts : NULL, NULL);
|
||||
struct timeval after = ast_tvnow();
|
||||
if (res > 0 && tv && ast_tvdiff_ms(ast_tvadd(*tv, start), after) > 0) {
|
||||
*tv = ast_tvsub(*tv, ast_tvsub(after, start));
|
||||
} else if (res > 0 && tv) {
|
||||
*tv = ast_tv(0, 0);
|
||||
}
|
||||
return res;
|
||||
#else
|
||||
ast_fdset read_descs, write_descs, except_descs;
|
||||
int ready_descriptors, max_fd = 0;
|
||||
|
||||
FD_ZERO(&read_descs);
|
||||
FD_ZERO(&write_descs);
|
||||
FD_ZERO(&except_descs);
|
||||
|
||||
if (pArray) {
|
||||
max_fd = map_poll_spec(pArray, n_fds, &read_descs, &write_descs, &except_descs);
|
||||
}
|
||||
|
||||
ready_descriptors = ast_select(max_fd + 1, &read_descs, &write_descs, &except_descs, tv);
|
||||
|
||||
if (ready_descriptors >= 0) {
|
||||
map_select_results(pArray, n_fds, &read_descs, &write_descs, &except_descs);
|
||||
}
|
||||
|
||||
return ready_descriptors;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* AST_POLL_COMPAT */
|
||||
|
||||
|
|
|
@ -397,8 +397,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
|
|||
for (retry = 0; retry < 3; retry++) { /* XXX make retries configurable */
|
||||
/* send request, possibly wait for reply */
|
||||
unsigned char reply_buf[1024];
|
||||
fd_set rfds;
|
||||
struct timeval to = { 3, 0 }; /* timeout, make it configurable */
|
||||
struct pollfd pfds = { .fd = s, .events = POLLIN };
|
||||
struct sockaddr_in src;
|
||||
socklen_t srclen;
|
||||
|
||||
|
@ -410,9 +409,7 @@ int ast_stun_request(int s, struct sockaddr_in *dst,
|
|||
}
|
||||
if (answer == NULL)
|
||||
break;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(s, &rfds);
|
||||
res = ast_select(s + 1, &rfds, NULL, NULL, &to);
|
||||
res = ast_poll(&pfds, 1, 3000);
|
||||
if (res <= 0) /* timeout or error */
|
||||
continue;
|
||||
memset(&src, 0, sizeof(src));
|
||||
|
|
|
@ -113,9 +113,9 @@ const char *ais_err2str(SaAisErrorT error)
|
|||
|
||||
static void *dispatch_thread_handler(void *data)
|
||||
{
|
||||
SaSelectionObjectT clm_fd, evt_fd, max_fd;
|
||||
SaSelectionObjectT clm_fd, evt_fd;
|
||||
int res;
|
||||
fd_set read_fds;
|
||||
struct pollfd pfd[2] = { { .events = POLLIN, }, { .events = POLLIN, } };
|
||||
SaAisErrorT ais_res;
|
||||
|
||||
ais_res = saClmSelectionObjectGet(clm_handle, &clm_fd);
|
||||
|
@ -132,24 +132,26 @@ static void *dispatch_thread_handler(void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
max_fd = clm_fd > evt_fd ? clm_fd : evt_fd;
|
||||
pfd[0].fd = clm_fd;
|
||||
pfd[1].fd = evt_fd;
|
||||
|
||||
while (!dispatch_thread.stop) {
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(clm_fd, &read_fds);
|
||||
FD_SET(evt_fd, &read_fds);
|
||||
pfd[0].revents = 0;
|
||||
pfd[1].revents = 0;
|
||||
|
||||
res = ast_select(max_fd + 1, &read_fds, NULL, NULL, NULL);
|
||||
res = ast_poll(pfd, 2, -1);
|
||||
if (res == -1 && errno != EINTR && errno != EAGAIN) {
|
||||
ast_log(LOG_ERROR, "Select error (%s) dispatch thread going away now, "
|
||||
"and the module will no longer operate.\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(clm_fd, &read_fds))
|
||||
if (pfd[0].revents & POLLIN) {
|
||||
saClmDispatch(clm_handle, SA_DISPATCH_ALL);
|
||||
if (FD_ISSET(evt_fd, &read_fds))
|
||||
}
|
||||
if (pfd[1].revents & POLLIN) {
|
||||
saEvtDispatch(evt_handle, SA_DISPATCH_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -1283,38 +1283,27 @@ static int aji_tls_handshake(struct aji_client *client)
|
|||
*/
|
||||
static int aji_io_recv(struct aji_client *client, char *buffer, size_t buf_len, int timeout)
|
||||
{
|
||||
int sock;
|
||||
fd_set fds;
|
||||
struct timeval tv, *tvptr = NULL;
|
||||
struct pollfd pfd = { .events = POLLIN };
|
||||
int len, res;
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (aji_is_secure(client)) {
|
||||
sock = SSL_get_fd(client->ssl_session);
|
||||
if (sock < 0) {
|
||||
pfd.fd = SSL_get_fd(client->ssl_session);
|
||||
if (pfd.fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
#endif /* HAVE_OPENSSL */
|
||||
sock = iks_fd(client->p);
|
||||
pfd.fd = iks_fd(client->p);
|
||||
|
||||
memset(&tv, 0, sizeof(struct timeval));
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(sock, &fds);
|
||||
tv.tv_sec = timeout;
|
||||
|
||||
/* NULL value for tvptr makes ast_select wait indefinitely */
|
||||
tvptr = (timeout != -1) ? &tv : NULL;
|
||||
|
||||
/* ast_select emulates linux behaviour in terms of timeout handling */
|
||||
res = ast_select(sock + 1, &fds, NULL, NULL, tvptr);
|
||||
res = ast_poll(&pfd, 1, timeout > 0 ? timeout * 1000 : -1);
|
||||
if (res > 0) {
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (aji_is_secure(client)) {
|
||||
len = SSL_read(client->ssl_session, buffer, buf_len);
|
||||
} else
|
||||
#endif /* HAVE_OPENSSL */
|
||||
len = recv(sock, buffer, buf_len, 0);
|
||||
len = recv(pfd.fd, buffer, buf_len, 0);
|
||||
|
||||
if (len > 0) {
|
||||
return len;
|
||||
|
|
|
@ -703,9 +703,8 @@ static void *do_pktccops(void *data)
|
|||
int res, nfds, len;
|
||||
struct copsmsg *recmsg, *sendmsg;
|
||||
struct copsmsg recmsgb, sendmsgb;
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
struct pktcobj *pobject;
|
||||
struct pollfd *pfds = NULL, *tmp;
|
||||
struct pktcobj *pobject;
|
||||
struct cops_cmts *cmts;
|
||||
struct cops_gate *gate;
|
||||
char *sobjp;
|
||||
|
@ -719,9 +718,8 @@ static void *do_pktccops(void *data)
|
|||
ast_debug(3, "COPS: thread started\n");
|
||||
|
||||
for (;;) {
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rfds);
|
||||
ast_free(pfds);
|
||||
pfds = NULL;
|
||||
nfds = 0;
|
||||
AST_LIST_LOCK(&cmts_list);
|
||||
AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
|
||||
|
@ -735,15 +733,27 @@ static void *do_pktccops(void *data)
|
|||
}
|
||||
}
|
||||
if (cmts->sfd > 0) {
|
||||
FD_SET(cmts->sfd, &rfds);
|
||||
if (cmts->sfd > nfds) nfds = cmts->sfd;
|
||||
if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
|
||||
continue;
|
||||
}
|
||||
pfds = tmp;
|
||||
pfds[nfds].fd = cmts->sfd;
|
||||
pfds[nfds].events = POLLIN;
|
||||
pfds[nfds].revents = 0;
|
||||
nfds++;
|
||||
} else {
|
||||
cmts->sfd = cops_connect(cmts->host, cmts->port);
|
||||
if (cmts->sfd > 0) {
|
||||
cmts->state = 1;
|
||||
if (cmts->sfd > 0) {
|
||||
FD_SET(cmts->sfd, &rfds);
|
||||
if (cmts->sfd > nfds) nfds = cmts->sfd;
|
||||
if (!(tmp = ast_realloc(pfds, (nfds + 1) * sizeof(*pfds)))) {
|
||||
continue;
|
||||
}
|
||||
pfds = tmp;
|
||||
pfds[nfds].fd = cmts->sfd;
|
||||
pfds[nfds].events = POLLIN;
|
||||
pfds[nfds].revents = 0;
|
||||
nfds++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -781,10 +791,11 @@ static void *do_pktccops(void *data)
|
|||
if (pktcreload == 2) {
|
||||
pktcreload = 0;
|
||||
}
|
||||
if ((res = select(nfds + 1, &rfds, NULL, NULL, &tv))) {
|
||||
if ((res = ast_poll(pfds, nfds, 1000))) {
|
||||
AST_LIST_LOCK(&cmts_list);
|
||||
AST_LIST_TRAVERSE(&cmts_list, cmts, list) {
|
||||
if (FD_ISSET(cmts->sfd, &rfds)) {
|
||||
int idx;
|
||||
if ((idx = ast_poll_fd_index(pfds, nfds, cmts->sfd)) > -1 && (pfds[idx].revents & POLLIN)) {
|
||||
len = cops_getmsg(cmts->sfd, recmsg);
|
||||
if (len > 0) {
|
||||
ast_debug(3, "COPS: got from %s:\n Header: versflag=0x%.2x opcode=%i clienttype=0x%.4x msglength=%i\n",
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2010, Digium, Inc.
|
||||
*
|
||||
* Tilghman Lesher <tlesher AT digium DOT com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \file
|
||||
* \brief Poll Tests
|
||||
*
|
||||
* \author\verbatim Tilghman Lesher <tlesher AT digium DOT com> \endverbatim
|
||||
*
|
||||
* Verify that the various poll implementations work as desired (ast_poll, ast_poll2)
|
||||
* \ingroup tests
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>TEST_FRAMEWORK</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/poll-compat.h"
|
||||
|
||||
#ifndef HAVE_SBIN_LAUNCHD
|
||||
static void *failsafe_cancel(void *vparent)
|
||||
{
|
||||
pthread_t parent = (pthread_t) (long) vparent;
|
||||
|
||||
sleep(1);
|
||||
pthread_testcancel();
|
||||
pthread_kill(parent, SIGURG);
|
||||
sleep(1);
|
||||
pthread_testcancel();
|
||||
pthread_kill(parent, SIGURG);
|
||||
sleep(1);
|
||||
pthread_testcancel();
|
||||
pthread_kill(parent, SIGURG);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
#define RESET for (i = 0; i < 4; i++) { pfd[i].revents = 0; }
|
||||
AST_TEST_DEFINE(poll_test)
|
||||
{
|
||||
#define FDNO 3
|
||||
int fd[2], res = AST_TEST_PASS, i, res2;
|
||||
int rdblocker[2];
|
||||
#if FDNO > 3
|
||||
int wrblocker[2], consec_interrupt = 0;
|
||||
#endif
|
||||
struct pollfd pfd[4] = { { .events = POLLOUT, }, { .events = POLLIN, }, { .events = POLLIN }, { .events = POLLOUT } };
|
||||
pthread_t failsafe_tid;
|
||||
struct timeval tv = { 0, 0 };
|
||||
#if FDNO > 3
|
||||
char garbage[256] =
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/"
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@/";
|
||||
#endif
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "poll_test";
|
||||
info->category = "main/poll/";
|
||||
info->summary = "unit test for the ast_poll() API";
|
||||
info->description =
|
||||
"Verifies behavior for the ast_poll() API call\n";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
ast_test_status_update(test, "Creating handle that should NEVER block on write\n");
|
||||
if ((fd[0] = open("/dev/null", O_WRONLY)) < 0) {
|
||||
ast_test_status_update(test, "Unable to open a writable handle to /dev/null: %s\n", strerror(errno));
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ast_test_status_update(test, "Creating handle that should NEVER block on read\n");
|
||||
if ((fd[1] = open("/dev/zero", O_RDONLY)) < 0) {
|
||||
ast_test_status_update(test, "Unable to open a readable handle to /dev/zero: %s\n", strerror(errno));
|
||||
close(fd[0]);
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ast_test_status_update(test, "Creating handle that should block on read\n");
|
||||
if (pipe(rdblocker) < 0) {
|
||||
ast_test_status_update(test, "Unable to open a pipe: %s\n", strerror(errno));
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
#if FDNO > 3
|
||||
ast_test_status_update(test, "Creating handle that should block on write\n");
|
||||
if (pipe(wrblocker) < 0) {
|
||||
ast_test_status_update(test, "Unable to open a pipe: %s\n", strerror(errno));
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
close(rdblocker[0]);
|
||||
close(rdblocker[1]);
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ast_test_status_update(test, "Starting thread to ensure we don't block forever\n");
|
||||
if (ast_pthread_create_background(&failsafe_tid, NULL, failsafe_cancel, (void *) (long) pthread_self())) {
|
||||
ast_test_status_update(test, "Unable to start failsafe thread\n");
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
close(fd[2]);
|
||||
close(rdblocker[0]);
|
||||
close(rdblocker[1]);
|
||||
close(wrblocker[0]);
|
||||
close(wrblocker[1]);
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
/* Fill the pipe full of data */
|
||||
ast_test_status_update(test, "Making pipe block on write\n");
|
||||
for (i = 0; i < 4096; i++) { /* 1MB of data should be more than enough for any pipe */
|
||||
errno = 0;
|
||||
if (write(wrblocker[1], garbage, sizeof(garbage)) < sizeof(garbage)) {
|
||||
ast_test_status_update(test, "Got %d\n", errno);
|
||||
if (errno == EINTR && ++consec_interrupt > 1) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
consec_interrupt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ast_test_status_update(test, "Cancelling failsafe thread.\n");
|
||||
pthread_cancel(failsafe_tid);
|
||||
pthread_kill(failsafe_tid, SIGURG);
|
||||
pthread_join(failsafe_tid, NULL);
|
||||
#endif
|
||||
|
||||
pfd[0].fd = fd[0];
|
||||
pfd[1].fd = fd[1];
|
||||
pfd[2].fd = rdblocker[0];
|
||||
#if FDNO > 3
|
||||
pfd[3].fd = wrblocker[1];
|
||||
#endif
|
||||
|
||||
/* Need to ensure the infinite timeout doesn't stall the process */
|
||||
ast_test_status_update(test, "Starting thread to ensure we don't block forever\n");
|
||||
if (ast_pthread_create_background(&failsafe_tid, NULL, failsafe_cancel, (void *) (long) pthread_self())) {
|
||||
ast_test_status_update(test, "Unable to start failsafe thread\n");
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
close(rdblocker[0]);
|
||||
close(rdblocker[1]);
|
||||
#if FDNO > 3
|
||||
close(wrblocker[0]);
|
||||
close(wrblocker[1]);
|
||||
#endif
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
RESET;
|
||||
if ((res2 = ast_poll(pfd, FDNO, -1)) != 2) {
|
||||
ast_test_status_update(test, "ast_poll does not return that only two handles are available (inf timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
RESET;
|
||||
if ((res2 = ast_poll2(pfd, FDNO, NULL)) != 2) {
|
||||
ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (inf timeout): %d %s\n", res2, res2 == -1 ? strerror(errno) : "");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ast_test_status_update(test, "Cancelling failsafe thread.\n");
|
||||
pthread_cancel(failsafe_tid);
|
||||
pthread_kill(failsafe_tid, SIGURG);
|
||||
pthread_join(failsafe_tid, NULL);
|
||||
|
||||
RESET;
|
||||
if (ast_poll(pfd, FDNO, 0) != 2) {
|
||||
ast_test_status_update(test, "ast_poll does not return that only two handles are available (0 timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
RESET;
|
||||
if (ast_poll2(pfd, FDNO, &tv) != 2) {
|
||||
ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (0 timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
RESET;
|
||||
if (ast_poll(pfd, FDNO, 1) != 2) {
|
||||
ast_test_status_update(test, "ast_poll does not return that only two handles are available (1ms timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
tv.tv_usec = 1000;
|
||||
if (ast_poll2(pfd, FDNO, &tv) != 2) {
|
||||
ast_test_status_update(test, "ast_poll2 does not return that only two handles are available (1ms timeout): %d, %s\n", res2, res2 == -1 ? strerror(errno) : "");
|
||||
res = AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
close(rdblocker[0]);
|
||||
close(rdblocker[1]);
|
||||
#if FDNO > 3
|
||||
close(wrblocker[0]);
|
||||
close(wrblocker[1]);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
#ifndef HAVE_SBIN_LAUNCHD
|
||||
AST_TEST_UNREGISTER(poll_test);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
#ifndef HAVE_SBIN_LAUNCHD
|
||||
AST_TEST_REGISTER(poll_test);
|
||||
#endif
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Poll test");
|
Reference in New Issue