int main(int argc, char **argv) { int opt, sockfd; int background_flag = 1; int if_index = 0; fd_set rfds; struct timeval timeout; while ((opt = getopt(argc, argv, "fi:")) != -1) { switch (opt) { case 'f': /* foreground */ background_flag = 0; break; case 'i': if_index = if_nametoindex(optarg); break; default: usage(); exit(EXIT_FAILURE); } } openlog("routeradv_listend", LOG_CONS|LOG_PERROR, LOG_DAEMON); sockfd = init_icmp_socket(if_index); if (sockfd < 0) return 1; if (background_flag) daemonize(sockfd); init_routers(); for (;;) { FD_ZERO(&rfds); FD_SET(sockfd, &rfds); memset(&timeout, 0, sizeof(timeout)); timeout.tv_sec = next_timeout(); if (select(sockfd + 1, &rfds, NULL, NULL, &timeout) < 0) { /* select() might have failed because we received a signal, so we need to check */ if (errno != EINTR) { syslog(LOG_CRIT, "select: %s", strerror(errno)); return 1; } /* handle signals */ continue; /* our file descriptor sets are undefined, so select again */ } if (FD_ISSET (sockfd, &rfds)) recv_icmp_msg(sockfd); handle_routers(); } return 0; }
int loop_start (evLoop *loop, int type){ while (loop->active_handles){ /* closing handles */ QUEUE *q; evHandle *handle; while ( !QUEUE_EMPTY(&loop->closing_queue) ){ q = QUEUE_HEAD(&(loop)->closing_queue); QUEUE_REMOVE(q); handle = QUEUE_DATA(q, evHandle, queue); assert(handle); if (handle->close != NULL){ handle->close(handle); } _free_handle(handle); } loop_update_time(loop); int timeout; if (type == 1){ timeout = 0; } else { timeout = next_timeout(loop); } loop_run_timers(loop); loop_run_immediate(loop); if (QUEUE_EMPTY(&loop->io_queue)) { #ifdef _WIN32 Sleep(timeout); #else usleep(1000 * timeout); #endif } else { io_poll(loop, timeout); } /* run once */ if (type == 1){ break; } } return loop->active_handles > 0; }
int loop_start (evLoop *loop, int type){ while (loop->active_handles){ /* closing handles */ loop_run_closing_handles(loop); loop_update_time(loop); int timeout; timeout = next_timeout(loop); if (type == 1 && timeout > 1){ timeout = 1; } loop_run_timers(loop); loop_run_immediate(loop); if (QUEUE_EMPTY(&loop->io_queue)) { #ifdef _WIN32 Sleep(timeout); #else usleep(1000 * timeout); #endif } else { io_poll(loop, timeout); } /* run once */ if (type == 1){ loop_update_time(loop); loop_run_timers(loop); break; } } /* check closing handles one last time*/ loop_run_closing_handles(loop); return loop->active_handles > 0; }
// thread main! int uart_unix_main(void* arg) { dthread_t* self = (dthread_t*) arg; dthread_t* other = (dthread_t*) self->arg; dmessage_t* mp = NULL; dthread_poll_event_t ev, *evp; size_t nev; dterm_t term; uart_ctx_t ctx; ErlDrvTermData mp_from; ErlDrvTermData mp_ref; dthread_t* mp_source; int tmo; int r; DEBUGF("uart_unix: thread started"); uart_init(&ctx, self, other); dterm_init(&term); again_tmo: tmo = next_timeout(&ctx); again: nev = 0; evp = NULL; if (ctx.fd >= 0) { ev.event = (ErlDrvEvent) ((long)ctx.fd); ev.events = 0; if ((ctx.option.active != UART_PASSIVE) || ctx.recv) { ev.events |= ERL_DRV_READ; if (ctx.option.ptypkt && (ctx.fd != ctx.tty_fd)) ev.events |= ERL_DRV_EXCEP; } if (ctx.oq.mesg) ev.events |= ERL_DRV_WRITE; if (ev.events) { evp = &ev; nev = 1; } DEBUGF("ctx.fd=%d, ev.events=%d", ctx.fd, ev.events); } DEBUGF("uart_unix_main: nev=%d, events=%x, timeout = %d", nev, ev.events, tmo); r = dthread_poll(self, evp, &nev, tmo); if (r < 0) { DEBUGF("uart_unix_main: dthread_poll failed=%d", r); goto again_tmo; } else { DEBUGF("uart_unix_main: nev=%d, r=%d", nev, r); if (evp && (nev == 1)) { if (evp->revents & ERL_DRV_WRITE) process_output(&ctx, self); if (evp->revents & (ERL_DRV_READ|ERL_DRV_EXCEP)) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } } tmo = next_timeout(&ctx); DEBUGF("uart_unix_main: timeout = %d", tmo); if (ctx.recv) { if (tmo == 0) { uart_async_error_am(&ctx, ctx.dport, ctx.caller, am_timeout); clear_timeout(&ctx); ctx.remain = 0; } } if (r == 0) goto again; // r>0 (number of messages) DEBUGF("about to receive message r=%d", r); if ((mp = dthread_recv(self, NULL)) == NULL) { DEBUGF("uart_unix_main: message was NULL"); goto again; } mp_from = mp->from; mp_ref = mp->ref; mp_source = mp->source; switch (mp->cmd) { case DTHREAD_STOP: DEBUGF("uart_unix_main: STOP"); close_device(&ctx); uart_final(&ctx); dmessage_free(mp); DEBUGF("uart_unix_main: EXIT"); dthread_exit(0); break; case DTHREAD_OUTPUT: // async send! DEBUGF("uart_unix_main: OUTPUT"); if (ctx.fd < 0) { dmessage_free(mp); goto again; } if (enq_output(&ctx, self, mp, 0) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_CONNECT: { ErlDrvTermData owner; if (mp->used != 0) goto badarg; owner = driver_connected(self->port); self->owner = owner; other->owner = owner; goto ok; } case UART_CMD_CLOSE: DEBUGF("uart_unix_main: CLOSE"); close_device(&ctx); goto ok; case UART_CMD_SEND: // sync send DEBUGF("uart_unix_main: SEND"); if (ctx.fd < 0) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_SENDCHAR: // sync send DEBUGF("uart_unix_main: SENDCHAR"); if (ctx.fd < 0) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_RECV: { // <<Time:32, Length:32>> Time=0xffffffff=inf uint32_t tm; int len; DEBUGF("uart_unix_main: RECV"); if (ctx.fd < 0) goto ebadf; if (ctx.recv) goto ealready; if (mp->used != 8) goto badarg; if (ctx.option.active != UART_PASSIVE) goto badarg; tm = get_uint32((uint8_t*) mp->buffer); len = (int) get_uint32((uint8_t*) (mp->buffer+4)); if ((len < 0) || (len > UART_MAX_PACKET_SIZE)) goto badarg; ctx.ref = mp_ref; ctx.caller = mp_from; set_timeout(&ctx, tm); ctx.recv = 1; DEBUGF("recv timeout %lu", tm); process_input(&ctx, self, len); dmessage_free(mp); goto again_tmo; } case UART_CMD_UNRECV: { // argument is data to push back uart_buf_push(&ctx.ib, mp->buffer, mp->used); DEBUGF("unrecived %d bytes", ctx.ib.ptr - ctx.ib.ptr_start); if (ctx.option.active != UART_PASSIVE) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_SETOPTS: { uart_com_state_t state = ctx.state; uart_opt_t option = ctx.option; uint32_t sflags = ctx.sflags; // parse & update options in state,option and sflag if (uart_parse_opts(mp->buffer, mp->used, &state, &option, &sflags) < 0) goto badarg; // apply the changed values if ((r=apply_opts(&ctx, &state, &option, sflags)) < 0) goto error; if (r == 1) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_GETOPTS: { dterm_mark_t m1; dterm_mark_t m2; // {Ref, {ok,List}} || {Ref, {error,Reason}} dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); if (uart_get_opts(&term, &ctx,(uint8_t*)mp->buffer,mp->used) < 0) { dterm_reset(&term); goto badarg; } } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_GET_MODEM: { dterm_mark_t m1; dterm_mark_t m2; uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (get_modem_state(ctx.tty_fd, &mstate) < 0) goto error; dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); modem_state_dterm(&term, mstate); } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_SET_MODEM: { uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.tty_fd, mstate, 1) < 0) goto error; goto ok; } case UART_CMD_CLR_MODEM: { uart_modem_state_t mstate; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.tty_fd, mstate, 0) < 0) goto error; goto ok; } case UART_CMD_HANGUP: { struct termios tio; int r; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 0) goto badarg; if ((r = tcgetattr(ctx.tty_fd, &tio)) < 0) { INFOF("tcgetattr: error=%s\n", strerror(errno)); goto badarg; } cfsetispeed(&tio, B0); cfsetospeed(&tio, B0); if ((r = tcsetattr(ctx.tty_fd, TCSANOW, &tio)) < 0) { INFOF("tcsetattr: error=%s\n", strerror(errno)); goto badarg; } goto ok; } case UART_CMD_BREAK: { int duration; if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 4) goto badarg; duration = (int) get_uint32((uint8_t*) mp->buffer); if (tcsendbreak(ctx.tty_fd, duration) < 0) goto error; goto ok; } case UART_CMD_FLOW: if (ctx.tty_fd < 0) goto ebadf; if (mp->used != 1) goto badarg; switch(mp->buffer[0]) { case 0: r = tcflow(ctx.tty_fd, TCIOFF); break; case 1: r = tcflow(ctx.tty_fd, TCION); break; case 2: r = tcflow(ctx.tty_fd, TCOOFF); break; case 3: r = tcflow(ctx.tty_fd, TCOON); break; default: goto badarg; break; } if (r < 0) goto error; goto ok; default: goto badarg; } } ok: dthread_port_send_ok(mp_source, self, mp_from, mp_ref); if (mp) dmessage_free(mp); goto again; ebadf: errno = EBADF; goto error; badarg: errno = EINVAL; goto error; ealready: errno = EALREADY; goto error; error: dthread_port_send_error(mp_source, self, mp_from, mp_ref, uart_errno(&ctx)); if (mp) dmessage_free(mp); goto again; }
// thread main! int uart_win32_main(void* arg) { dthread_t* self = (dthread_t*) arg; dthread_t* other = (dthread_t*) self->arg; dmessage_t* mp = NULL; dthread_poll_event_t ev[3]; dthread_poll_event_t* evp; size_t nev; dterm_t term; uart_ctx_t ctx; ErlDrvTermData mp_from; ErlDrvTermData mp_ref; dthread_t* mp_source; int tmo; int r; DEBUGF("uart_win32: thread started"); uart_init(&ctx, self, other); dterm_init(&term); again_tmo: tmo = next_timeout(&ctx); again: nev = 0; if (ctx.writing) { ev[nev].event = (ErlDrvEvent) ctx.out.hEvent; ev[nev].events = ERL_DRV_READ; // yepp, even for write nev++; } while(!ctx.reading && (ctx.recv || (ctx.option.active != UART_PASSIVE))) process_input(&ctx, self, 0); if (ctx.reading) { ev[nev].event = (ErlDrvEvent) ctx.in.hEvent; ev[nev].events = ERL_DRV_READ; nev++; } evp = nev ? &ev[0] : NULL; DEBUGF("uart_win32_main: ctx.fh=%d, nev=%u, timeout = %d", ctx.fh, nev, tmo); r = dthread_poll(self, evp, &nev, tmo); if (r < 0) { DEBUGF("uart_win32_main: dthread_poll failed=%d", r); goto again_tmo; } else { DWORD i; DEBUGF("uart_win32_main: nev=%u, r=%d", nev, r); for (i = 0; i < nev; i++) { if (ev[i].revents & ERL_DRV_READ) { if (ev[i].event == (ErlDrvEvent) ctx.in.hEvent) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } else if (ev[i].event == (ErlDrvEvent) ctx.out.hEvent) { process_output(&ctx, self); } } } tmo = next_timeout(&ctx); DEBUGF("uart_win32_main: timeout = %d", tmo); if (ctx.recv) { if (tmo == 0) { uart_async_error_am(&ctx, ctx.dport, ctx.caller, am_timeout); clear_timeout(&ctx); ctx.remain = 0; } } if (r == 0) goto again; // r>0 (number of messages) DEBUGF("about to receive message r=%d", r); if ((mp = dthread_recv(self, NULL)) == NULL) { DEBUGF("uart_win32_main: message was NULL"); goto again; } mp_from = mp->from; mp_ref = mp->ref; mp_source = mp->source; switch (mp->cmd) { case DTHREAD_STOP: DEBUGF("uart_win32_main: STOP"); close_device(&ctx); uart_final(&ctx); dmessage_free(mp); DEBUGF("uart_win32_main: EXIT"); dthread_exit(0); break; case DTHREAD_OUTPUT: // async send! DEBUGF("uart_win32_main: OUTPUT"); if (ctx.fh == INVALID_HANDLE_VALUE) { dmessage_free(mp); goto again; } if (enq_output(&ctx, self, mp, 0) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_CONNECT: { ErlDrvTermData owner; if (mp->used != 0) goto badarg; owner = driver_connected(self->port); self->owner = owner; other->owner = owner; goto ok; } case UART_CMD_CLOSE: DEBUGF("uart_win32_main: CLOSE"); close_device(&ctx); goto ok; case UART_CMD_SEND: // sync send DEBUGF("uart_win32_main: SEND"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_SENDCHAR: // sync send DEBUGF("uart_win32_main: SENDCHAR"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (enq_output(&ctx, self, mp, mp_from) < 0) { mp = NULL; goto error; } goto again; case UART_CMD_RECV: { // <<Time:32, Length:32>> Time=0xffffffff=inf uint32_t tm; int len; DEBUGF("uart_win32_main: RECV"); if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (ctx.recv) goto ealready; if (mp->used != 8) goto badarg; if (ctx.option.active != UART_PASSIVE) goto badarg; tm = get_uint32((uint8_t*) mp->buffer); len = (int) get_uint32((uint8_t*) (mp->buffer+4)); if ((len < 0) || (len > UART_MAX_PACKET_SIZE)) goto badarg; ctx.ref = mp_ref; ctx.caller = mp_from; set_timeout(&ctx, tm); ctx.recv = 1; DEBUGF("recv timeout %lu", tm); process_input(&ctx, self, len); dmessage_free(mp); goto again_tmo; } case UART_CMD_UNRECV: { // argument is data to push back uart_buf_push(&ctx.ib, mp->buffer, mp->used); DEBUGF("unrecived %d bytes", ctx.ib.ptr - ctx.ib.ptr_start); if (ctx.option.active != UART_PASSIVE) { while((process_input(&ctx, self, 0) == 1) && (ctx.option.active != UART_PASSIVE)) ; } goto ok; } case UART_CMD_SETOPTS: { uart_com_state_t state = ctx.state; uart_opt_t option = ctx.option; uint32_t sflags = ctx.sflags; // parse & update options in state,option and sflag if (uart_parse_opts(mp->buffer, mp->used, &state, &option, &sflags) < 0) goto badarg; // apply the changed values if ((r=apply_opts(&ctx, &state, &option, sflags)) < 0) { goto error; } goto ok; } case UART_CMD_GETOPTS: { dterm_mark_t m1; dterm_mark_t m2; // {Ref, {ok,List}} || {Ref, {error,Reason}} dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); if (uart_get_opts(&term, &ctx,(uint8_t*)mp->buffer,mp->used) < 0) { dterm_reset(&term); goto badarg; } } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_GET_MODEM: { dterm_mark_t m1; dterm_mark_t m2; uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (get_modem_state(ctx.fh, &mstate) < 0) goto error; dterm_tuple_begin(&term, &m1); { dterm_uint(&term, mp_ref); dterm_tuple_begin(&term, &m2); { dterm_atom(&term, am_ok); modem_state_dterm(&term, mstate); } dterm_tuple_end(&term, &m2); } dterm_tuple_end(&term, &m1); dthread_port_send_dterm(mp_source, self, mp_from, &term); dterm_reset(&term); dmessage_free(mp); goto again; } case UART_CMD_SET_MODEM: { uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.fh, mstate, 1) < 0) goto error; goto ok; } case UART_CMD_CLR_MODEM: { uart_modem_state_t mstate; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; mstate = (uart_modem_state_t) get_uint32((uint8_t*) mp->buffer); if (set_modem_state(ctx.fh, mstate, 0) < 0) goto error; goto ok; } case UART_CMD_HANGUP: { if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 0) goto badarg; // FIXME? goto ok; } case UART_CMD_BREAK: { int duration; if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 4) goto badarg; duration = (int) get_uint32((uint8_t*) mp->buffer); if (!EscapeCommFunction(ctx.fh, SETBREAK)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } Sleep(duration); if (!EscapeCommFunction(ctx.fh, CLRBREAK)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } goto ok; } case UART_CMD_FLOW: if (ctx.fh == INVALID_HANDLE_VALUE) goto ebadf; if (mp->used != 1) goto badarg; switch(mp->buffer[0]) { case 0: if (!EscapeCommFunction(ctx.fh, SETXOFF)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } break; case 1: if (!EscapeCommFunction(ctx.fh, SETXON)) { DEBUG_ERROR("EscapeCommFunction: error %d", GetLastError()); goto error; } break; case 2: // TransmitCommChar(ctx.fh, XOFF); break; case 3: // TransmitCommChar(ctx.fh, XON); break; default: goto badarg; } goto ok; default: goto badarg; } } ok: dthread_port_send_ok(mp_source, self, mp_from, mp_ref); if (mp) dmessage_free(mp); goto again; ebadf: errno = EBADF; goto error; badarg: errno = EINVAL; goto error; ealready: errno = EBUSY; goto error; error: dthread_port_send_error(mp_source, self, mp_from, mp_ref, uart_errno(&ctx)); if (mp) dmessage_free(mp); goto again; }
static void *Run( void *data ) { intf_thread_t *p_intf = data; intf_sys_t *p_sys = p_intf->p_sys; int canc = vlc_savecancel(); for( ;; ) { vlc_mutex_lock( &p_sys->lock ); int i_watches = vlc_array_count( p_sys->p_watches ); struct pollfd fds[i_watches]; memset(fds, 0, sizeof fds); int i_fds = GetPollFds( p_intf, fds ); int timeout = next_timeout(p_intf); vlc_mutex_unlock( &p_sys->lock ); /* thread cancellation is allowed while the main loop sleeps */ vlc_restorecancel( canc ); while (poll(fds, i_fds, timeout) == -1) { if (errno != EINTR) goto error; } canc = vlc_savecancel(); /* Was the main loop woken up manually ? */ if (fds[0].revents & POLLIN) { char buf; (void)read( fds[0].fd, &buf, 1 ); } /* We need to lock the mutex while building lists of events, * timeouts and watches to process but we can't keep the lock while * processing them, or else we risk a deadlock: * * The signal functions could lock mutex X while p_events is locked; * While some other function in vlc (playlist) might lock mutex X * and then set a variable which would call AllCallback(), which itself * needs to lock p_events to add a new event. */ vlc_mutex_lock( &p_intf->p_sys->lock ); process_timeouts(p_intf); /* Get the list of watches to process */ i_watches = vlc_array_count( p_sys->p_watches ); DBusWatch *p_watches[i_watches ? i_watches : 1]; for( int i = 0; i < i_watches; i++ ) { p_watches[i] = vlc_array_item_at_index( p_sys->p_watches, i ); } /* Get the list of events to process */ int i_events = vlc_array_count( p_intf->p_sys->p_events ); callback_info_t* p_info[i_events ? i_events : 1]; for( int i = i_events - 1; i >= 0; i-- ) { p_info[i] = vlc_array_item_at_index( p_intf->p_sys->p_events, i ); vlc_array_remove( p_intf->p_sys->p_events, i ); } /* now we can release the lock and process what's pending */ vlc_mutex_unlock( &p_intf->p_sys->lock ); ProcessEvents( p_intf, p_info, i_events ); ProcessWatches( p_intf, p_watches, i_watches, fds, i_fds ); DispatchDBusMessages( p_intf ); } error: vlc_restorecancel(canc); return NULL; }