From: Tilghman Lesher Date: Wed, 1 Sep 2010 22:59:50 +0000 (+0000) Subject: Merged revisions 284478 via svnmerge from X-Git-Tag: 1.6.2.14-rc1~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=59f700a9b24369cd0558bc60a39a3174f445b23a;p=thirdparty%2Fasterisk.git 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/ ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.2@284593 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index cd48ef43b4..7180512310 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -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)); diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 295d2eb89a..9042073451 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -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() diff --git a/channels/chan_usbradio.c b/channels/chan_usbradio.c index 4a0984cddb..6b86222a3e 100644 --- a/channels/chan_usbradio.c +++ b/channels/chan_usbradio.c @@ -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 */ diff --git a/channels/console_video.c b/channels/console_video.c index 88bf807d52..c26ac983fe 100644 --- a/channels/console_video.c +++ b/channels/console_video.c @@ -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 */ diff --git a/configure.ac b/configure.ac index 160f3baa16..7465a36bef 100644 --- a/configure.ac +++ b/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]) @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +], [[ + 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 +#include +#include +], [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) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 7dde431be7..208f88402a 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -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) { diff --git a/include/asterisk/poll-compat.h b/include/asterisk/poll-compat.h index 1156e694bd..c955f00bf6 100644 --- a/include/asterisk/poll-compat.h +++ b/include/asterisk/poll-compat.h @@ -79,6 +79,8 @@ #ifndef __AST_POLL_COMPAT_H #define __AST_POLL_COMPAT_H +#include "asterisk/select.h" + #ifndef AST_POLL_COMPAT #include @@ -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 index 0000000000..fea8c7aff9 --- /dev/null +++ b/include/asterisk/select.h @@ -0,0 +1,110 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Tilghman Lesher + * + * 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 +#include +#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 */ diff --git a/main/asterisk.c b/main/asterisk.c index c8bed4a53e..2706685467 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 1999 - 2008, Digium, Inc. + * Copyright (C) 1999 - 2010, Digium, Inc. * * Mark Spencer * @@ -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)) diff --git a/main/features.c b/main/features.c index d2f9898357..8ebd44bbf7 100644 --- a/main/features.c +++ b/main/features.c @@ -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; xfds[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 -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 */ } diff --git a/main/poll.c b/main/poll.c index e52c117094..5895058c10 100644 --- a/main/poll.c +++ b/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,50 +73,40 @@ #include "asterisk.h" -#include /* standard Unix definitions */ -#include /* system types */ -#include /* time definitions */ -#include /* assertion macros */ -#include /* string functions */ +#include /* standard Unix definitions */ +#include /* system types */ +#include /* time definitions */ +#include /* assertion macros */ +#include /* string functions */ +#include #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; } - -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 */ + diff --git a/main/rtp.c b/main/rtp.c index 4249122020..2ed6777697 100644 --- a/main/rtp.c +++ b/main/rtp.c @@ -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)); diff --git a/res/res_ais.c b/res/res_ais.c index adb3290e1d..9bcceeade9 100644 --- a/res/res_ais.c +++ b/res/res_ais.c @@ -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; diff --git a/res/res_jabber.c b/res/res_jabber.c index fbcde691fb..7912f88ba7 100644 --- a/res/res_jabber.c +++ b/res/res_jabber.c @@ -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 index 0000000000..7fbf8cc514 --- /dev/null +++ b/tests/test_poll.c @@ -0,0 +1,253 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Digium, Inc. + * + * Tilghman Lesher + * + * 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 \endverbatim + * + * Verify that the various poll implementations work as desired (ast_poll, ast_poll2) + * \ingroup tests + */ + +/*** MODULEINFO + TEST_FRAMEWORK + ***/ + +#include "asterisk.h" +#include +#include +#include +#include +#include +#include + +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"); diff --git a/utils/clicompat.c b/utils/clicompat.c index 33f90fae16..bca401747d 100644 --- a/utils/clicompat.c +++ b/utils/clicompat.c @@ -14,3 +14,4 @@ int ast_cli_register_multiple(struct ast_cli_entry *e, int len) { return 0; } +