]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merged revisions 284478 via svnmerge from
authorTilghman Lesher <tilghman@meg.abyt.es>
Wed, 1 Sep 2010 22:59:50 +0000 (22:59 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Wed, 1 Sep 2010 22:59:50 +0000 (22:59 +0000)
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/
........

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.2@284593 65c4cc65-6c06-0410-ace0-fbb531ad65f3

16 files changed:
channels/chan_misdn.c
channels/chan_phone.c
channels/chan_usbradio.c
channels/console_video.c
configure.ac
include/asterisk/channel.h
include/asterisk/poll-compat.h
include/asterisk/select.h [new file with mode: 0644]
main/asterisk.c
main/features.c
main/poll.c
main/rtp.c
res/res_ais.c
res/res_jabber.c
tests/test_poll.c [new file with mode: 0644]
utils/clicompat.c

index cd48ef43b4caaf4ef4ca2dacfb1af8fcf00f3e51..71805123101a468d21f9c4c5081a86bb456aa3d0 100644 (file)
@@ -3033,15 +3033,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;
        }
@@ -3051,20 +3050,18 @@ static struct ast_frame *misdn_read(struct ast_channel *ast)
                return NULL;
        }
 
-       FD_ZERO(&rrfs);
-       FD_SET(tmp->pipe[0], &rrfs);
-
-       if (!(t = select(FD_SETSIZE, &rrfs, NULL, NULL, &tv))) {
-               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) {
@@ -5172,26 +5169,22 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
                        if (ch->ast) 
                                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 = ast_poll(&pfd, 1, 0);
 
-                       t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
-
-                       if (!t) {
-                               chan_misdn_log(9, bc->port, "Select Timed out\n");
+                       if (t < 0) {
+                               chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
                                break;
                        }
-                       
-                       if (t < 0) {
-                               chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
+
+                       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));
index 295d2eb89a9d05eaa92cdaa828a8d24dc10e3196..90420734514b380c8619270bcbcbbf3084ddad15 100644 (file)
@@ -1011,12 +1011,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 */
@@ -1030,33 +1030,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);
@@ -1065,26 +1070,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)) {
@@ -1092,15 +1099,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;
                                }
@@ -1110,7 +1129,6 @@ static void *do_monitor(void *data)
                ast_mutex_unlock(&iflock);
        }
        return NULL;
-       
 }
 
 static int restart_monitor()
index 4a0984cddb12e187db6815953c8c8f9d2d55139c..6b86222a3e9f040b89acb5ad96526d869d96e1c5 100644 (file)
@@ -1118,8 +1118,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) {
@@ -1155,63 +1154,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);
@@ -1219,38 +1204,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);
 }
 
@@ -1451,37 +1441,29 @@ static void *sound_thread(void *arg)
         */
        read(o->sounddev, ign, sizeof(ign));
        for (;;) {
-               fd_set rfds, wfds;
-               int maxfd, 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)
+               struct pollfd pfd[2] = { { .fd = o->sndcmd[0], .events = POLLIN }, { .fd = o->sounddev } };
+               int res;
+
+               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;
 
@@ -1494,14 +1476,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 */
index 88bf807d52e98c38a6cd689d6d78bde7da470059..c26ac983fec8419dc2afbe0ee37721917f28ccb7 100644 (file)
@@ -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
-
-       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);
+       {
+               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);
+               }
        }
-    }
        /*
         * 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;
+       {
+               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);
+
+               sws_freeContext(convert_ctx);
        }
-       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 */
-
-                       /* 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);
+                       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 */
+
+                               /* 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 */
index 160f3baa1673a45c27bdaa064aa42bf0ee3f60e4..7465a36bef27a99719454c95c13e546ab2d4d2e1 100644 (file)
@@ -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])
@@ -417,7 +418,7 @@ AC_FUNC_STRNLEN
 AC_FUNC_STRTOD
 AC_FUNC_UTIME_NULL
 AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([asprintf atexit closefrom dup2 eaccess endpwent euidaccess ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap 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 ftruncate getcwd gethostbyname gethostname getloadavg gettimeofday glob ioperm inet_ntoa isascii localtime_r memchr memmove memset mkdir munmap 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])
 
 # BSD might not have exp2, and/or log2
 AC_CHECK_LIB([m], [sqrt])
@@ -625,6 +626,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)
index 7dde431be7adcfb6bd43167d524699877e0cf3d3..208f88402a07a55c804c5a10d7c66ed5f302d791 100644 (file)
@@ -1742,42 +1742,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
- * 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)
 {
index 1156e694bdcbb5a74e4cb94d41bc2ebc9c8c57cc..c955f00bf6b01007fadd9c85bba0566edfb808cb 100644 (file)
@@ -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,10 @@ 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);
+
 #endif /* __AST_POLL_COMPAT_H */
diff --git a/include/asterisk/select.h b/include/asterisk/select.h
new file mode 100644 (file)
index 0000000..fea8c7a
--- /dev/null
@@ -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 */
index c8bed4a53e1cd4c5eb5368a4a29a4a3d7fc463f9..270668546779587ba0cd4bb20d6633cb25ae93b4 100644 (file)
@@ -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>
  *
@@ -269,6 +269,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;
@@ -3145,6 +3147,7 @@ int main(int argc, char *argv[])
        char *buf;
        const char *runuser = NULL, *rungroup = NULL;
        char *remotesock = NULL;
+       struct rlimit l;
 
        /* Remember original args for restart */
        if (argc > ARRAY_LEN(_argv) - 1) {
@@ -3320,7 +3323,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;
@@ -3329,6 +3331,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))
index d2f989835718d324cbf29ed1f3ae1163199d5f2e..8ebd44bbf72785bbfbd55bfc86c442ea6bc36327 100644 (file)
@@ -309,7 +309,7 @@ static void *dial_features_duplicate(void *data)
 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);
 
 
@@ -3066,9 +3066,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];
@@ -3091,16 +3092,18 @@ 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[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */
                                int i;
 
-                               if (cp) 
-                                       *cp = 0;
-                               ast_copy_string(peername_flat,peername,sizeof(peername_flat));
-                               for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
-                                       if (peername_flat[i] == '/') 
-                                               peername_flat[i]= '0';
+                               if (dash) {
+                                       *dash = '\0';
+                               }
+                               ast_copy_string(peername_flat, peername, sizeof(peername_flat));
+                               for (i = 0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
+                                       if (peername_flat[i] == '/') {
+                                               peername_flat[i] = '0';
+                                       }
                                }
                                con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
                                if (!con) {
@@ -3172,14 +3175,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 */
@@ -3219,22 +3241,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;
 }
 
@@ -3248,35 +3280,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 */
 }
 
index e52c117094f4d9dab9a891b21a66fe311e7e091a..5895058c1021a816be5f49d130ff51c9bd8cda3c 100644 (file)
@@ -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)
 
 #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;
 
 /*---------------------------------------------------------------------------*\
-                            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. */
@@ -141,34 +131,28 @@ static int map_poll_spec
 
        return max_fd;
 }
-\f
-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:
+
+          VALUE        MEANING
 
-       assert(pSelTimeout != (struct timeval *) NULL);
+          -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:
@@ -199,25 +183,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. */
@@ -227,59 +199,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 */
+
index 424912202006ce267087fa366097b17e3aa582fc..2ed67776976bd6bd76272669cb4adee568753ecc 100644 (file)
@@ -656,8 +656,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;
 
@@ -669,9 +668,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));
index adb3290e1deacab9e169033b7403db14a22a9791..9bcceeade9876ff94ed508f3516e880d112b1d2b 100644 (file)
@@ -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;
index fbcde691fb3bb1542516b2ad9fe6ad4d813404ff..7912f88ba7081e1e92a7e26d5efd7026de0d2e31 100644 (file)
@@ -668,37 +668,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)
-                       return -1;              
+               pfd.fd = SSL_get_fd(client->ssl_session);
+               if (pfd.fd < 0) {
+                       return -1;
+               }
        } else
 #endif /* HAVE_OPENSSL */
-               sock = 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;
+               pfd.fd = iks_fd(client->p);
 
-       /* 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;
diff --git a/tests/test_poll.c b/tests/test_poll.c
new file mode 100644 (file)
index 0000000..7fbf8cc
--- /dev/null
@@ -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");
index 33f90fae167b2eb9561000de71e4e69e3cff8b1c..bca401747d43c227cdef89207f63db3c784e0665 100644 (file)
@@ -14,3 +14,4 @@ int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
 {
        return 0;
 }
+