/** call timeouts handlers, and return how long to wait for next one or -1 */ static void handle_timeouts(struct event_base* base, struct timeval* now, struct timeval* wait) { struct event* p; #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif while((rbnode_t*)(p = (struct event*)rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || (p->ev_timeout.tv_sec==now->tv_sec && p->ev_timeout.tv_usec > now->tv_usec)) { /* there is a next larger timeout. wait for it */ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; if(now->tv_usec > p->ev_timeout.tv_usec) { wait->tv_sec--; wait->tv_usec = 1000000 - (now->tv_usec - p->ev_timeout.tv_usec); } else { wait->tv_usec = p->ev_timeout.tv_usec - now->tv_usec; } return; } #endif /* event times out, remove it */ (void)rbtree_delete(base->times, p); p->ev_events &= ~EV_TIMEOUT; fptr_ok(fptr_whitelist_event(p->ev_callback)); (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); } }
/** handle is_signal events and see if signalled */ static void _getdns_handle_signal(struct _getdns_event* ev) { DWORD ret; //log_assert(ev->is_signal && ev->hEvent); /* see if the event is signalled */ ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */, 0 /* return immediately */, 0 /* not alertable for IOcomple*/); if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) { log_err("getdns: WSAWaitForMultipleEvents(signal) failed: %s", wsa_strerror(WSAGetLastError())); return; } if(ret == WSA_WAIT_TIMEOUT) { /* not signalled */ return; } /* reset the signal */ if(!WSAResetEvent(ev->hEvent)) log_err("getdns: WSAResetEvent failed: %s", wsa_strerror(WSAGetLastError())); /* do the callback (which may set the signal again) */ fptr_ok(fptr_whitelist_event(ev->ev_callback)); (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg); }
/** signal handler */ static RETSIGTYPE sigh(int sig) { struct event* ev; if(!signal_base || sig < 0 || sig >= MAX_SIG) return; ev = signal_base->signals[sig]; if(!ev) return; fptr_ok(fptr_whitelist_event(ev->ev_callback)); (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg); }
/** set content of event */ void event_set(struct event* ev, int fd, short bits, void (*cb)(int, short, void *), void* arg) { ev->node.key = ev; ev->ev_fd = fd; ev->ev_events = bits; ev->ev_callback = cb; fptr_ok(fptr_whitelist_event(ev->ev_callback)); ev->ev_arg = arg; ev->added = 0; }
/** call select and callbacks for that */ static int handle_select(struct event_base* base, struct timeval* wait) { fd_set r, w; int ret, i; #ifndef S_SPLINT_S if(wait->tv_sec==(time_t)-1) wait = NULL; #endif memmove(&r, &base->reads, sizeof(fd_set)); memmove(&w, &base->writes, sizeof(fd_set)); memmove(&base->ready, &base->content, sizeof(fd_set)); if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) { ret = errno; if(settime(base) < 0) return -1; errno = ret; if(ret == EAGAIN || ret == EINTR) return 0; return -1; } if(settime(base) < 0) return -1; for(i=0; i<base->maxfd+1; i++) { short bits = 0; if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) { continue; } if(FD_ISSET(i, &r)) { bits |= EV_READ; ret--; } if(FD_ISSET(i, &w)) { bits |= EV_WRITE; ret--; } bits &= base->fds[i]->ev_events; if(bits) { fptr_ok(fptr_whitelist_event( base->fds[i]->ev_callback)); (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd, bits, base->fds[i]->ev_arg); if(ret==0) break; } } return 0; }
/** call timeouts handlers, and return how long to wait for next one or -1 */ void _getdns_handle_timeouts(struct _getdns_event_base* base, struct timeval* now, struct timeval* wait) { struct _getdns_event* p; #ifndef S_SPLINT_S wait->tv_sec = (time_t)-1; #endif //verbose(VERB_CLIENT, "winsock_event handle_timeouts"); while((_getdns_rbnode_t*)(p = (struct _getdns_event*)_getdns_rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || (p->ev_timeout.tv_sec==now->tv_sec && p->ev_timeout.tv_usec > now->tv_usec)) { /* there is a next larger timeout. wait for it */ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec; if(now->tv_usec > p->ev_timeout.tv_usec) { wait->tv_sec--; wait->tv_usec = 1000000 - (now->tv_usec - p->ev_timeout.tv_usec); } else { wait->tv_usec = p->ev_timeout.tv_usec - now->tv_usec; } //verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d", // (long long)wait->tv_sec, (int)wait->tv_usec); return; } #endif /* event times out, remove it */ (void)_getdns_rbtree_delete(base->times, p); p->ev_events &= ~EV_TIMEOUT; fptr_ok(fptr_whitelist_event(p->ev_callback)); (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg); } //verbose(VERB_CLIENT, "winsock_event wait=(-1)"); }
int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) { DWORD timeout = 0; /* in milliseconds */ DWORD ret; WSANETWORKEVENTS netev; struct _getdns_event* eventlist[WSK_MAX_ITEMS]; int i, numwait = 0, startidx = 0, was_timeout = 0; int newstickies = 0; struct timeval nultm; printf("in handle select\n"); #ifndef S_SPLINT_S if(wait->tv_sec==(time_t)-1) wait = NULL; if (wait) // timeout = 10 + wait->tv_usec / 1000; timeout = wait->tv_sec * 1000 + wait->tv_usec / 1000; if(base->tcp_stickies) { wait = &nultm; nultm.tv_sec = 0; nultm.tv_usec = 0; timeout = 0; /* no waiting, we have sticky events */ } #endif /* prepare event array */ for(i=0; i<base->max; i++) { if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) continue; /* skip timer only events */ eventlist[numwait] = base->items[i]; base->waitfor[numwait++] = base->items[i]->hEvent; printf("winsock_event bmax=%d numwait=%d wait=%x " "timeout=%d hEvent %d\n", base->max, numwait, (int)wait, (int)timeout, base->items[i]->hEvent); if (numwait == WSK_MAX_ITEMS) break; /* sanity check */ } //log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); /* do the wait */ if(numwait == 0) { /* WSAWaitFor.. doesn't like 0 event objects */ if(wait) { Sleep(timeout); } was_timeout = 1; } else { //g do not sched udp write for (i = 0; i<base->max; i++) { if (!base->items[i]->is_tcp && base->items[i]->ev_events&EV_WRITE) { //gprintf("skip UDP sched\n"); (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, EV_WRITE & eventlist[i]->ev_events, eventlist[i]->ev_arg); return 0; } } //gprintf("before wait %d\n", base->items[0]->ev_events); ret = WSAWaitForMultipleEvents(numwait, base->waitfor, 0 /* do not wait for all, just one will do */, wait?timeout:WSA_INFINITE, 0); /* we are not alertable (IO completion events) */ //gprintf("after wait %d %d\n", ret, numwait); if(ret == WSA_WAIT_IO_COMPLETION) { //printf("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); return -1; } else if(ret == WSA_WAIT_FAILED) { //printf("getdns: WSAWaitForMultipleEvents failed: %s", // wsa_strerror(WSAGetLastError())); return -1; } else if(ret == WSA_WAIT_TIMEOUT) { //printf("timeout\n"); was_timeout = 1; } else startidx = ret - WSA_WAIT_EVENT_0; } ////verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d", // was_timeout, startidx); /* get new time after wait */ if(settime(base) < 0) return -1; /* callbacks */ if(base->tcp_stickies) startidx = 0; /* process all events, some are sticky */ for(i=startidx; i<numwait; i++) eventlist[i]->just_checked = 1; //verbose(VERB_CLIENT, "winsock_event signals"); for(i=startidx; i<numwait; i++) { if(!base->waitfor[i]) continue; /* was deleted */ if(eventlist[i]->is_signal) { eventlist[i]->just_checked = 0; _getdns_handle_signal(eventlist[i]); } } /* early exit - do not process network, exit quickly */ if(base->need_to_exit) return 0; //verbose(VERB_CLIENT, "winsock_event net"); for(i=startidx; i<numwait; i++) { short bits = 0; /* eventlist[i] fired */ /* see if eventlist[i] is still valid and just checked from * WSAWaitForEvents */ if(!base->waitfor[i]) continue; /* was deleted */ if(!eventlist[i]->just_checked) continue; /* added by other callback */ if(eventlist[i]->is_signal) continue; /* not a network event at all */ eventlist[i]->just_checked = 0; if(WSAEnumNetworkEvents(eventlist[i]->ev_fd, base->waitfor[i], /* reset the event handle */ /*NULL,*/ /* do not reset the event handle */ &netev) != 0) { log_err("getdns: WSAEnumNetworkEvents failed: %s", wsa_strerror(WSAGetLastError())); return -1; } if((netev.lNetworkEvents & FD_READ)) { if(netev.iErrorCode[FD_READ_BIT] != 0) printf("FD_READ_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_READ_BIT])); bits |= EV_READ; printf("FD_READ_BIT\n"); } if((netev.lNetworkEvents & FD_WRITE)) { if(netev.iErrorCode[FD_WRITE_BIT] != 0) printf("FD_WRITE_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_WRITE_BIT])); bits |= EV_WRITE; printf("FD_WRITE_BIT\n"); } if((netev.lNetworkEvents & FD_CONNECT)) { if(netev.iErrorCode[FD_CONNECT_BIT] != 0) printf("FD_CONNECT_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT])); bits |= EV_READ; bits |= EV_WRITE; printf("FD_CONNECT_BIT\n"); } if((netev.lNetworkEvents & FD_ACCEPT)) { if(netev.iErrorCode[FD_ACCEPT_BIT] != 0) printf("FD_ACCEPT_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT])); bits |= EV_READ; printf("FD_ACCEPT_BIT\n"); } if((netev.lNetworkEvents & FD_CLOSE)) { if(netev.iErrorCode[FD_CLOSE_BIT] != 0) printf("FD_CLOSE_BIT error: %s\n", wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT])); bits |= EV_READ; bits |= EV_WRITE; printf("FD_CLOSE_BIT\n"); } if(eventlist[i]->is_tcp && eventlist[i]->stick_events) { /* printf("winsock %d pass sticky %s%s\n", eventlist[i]->ev_fd, (eventlist[i]->old_events&EV_READ)?"EV_READ":"", (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); */ bits |= eventlist[i]->old_events; } if(eventlist[i]->is_tcp && bits) { eventlist[i]->old_events = bits; eventlist[i]->stick_events = 1; if((eventlist[i]->ev_events & bits)) { newstickies = 1; } /* printf("winsock %d store sticky %s%s", eventlist[i]->ev_fd, (eventlist[i]->old_events&EV_READ)?"EV_READ":"", (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); */ } if((bits & eventlist[i]->ev_events)) { /* printf( "winsock event callback %p fd=%d " "%s%s%s%s%s ; %s%s%s\n", eventlist[i], eventlist[i]->ev_fd, (netev.lNetworkEvents&FD_READ)?" FD_READ":"", (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"", (netev.lNetworkEvents&FD_CONNECT)? " FD_CONNECT":"", (netev.lNetworkEvents&FD_ACCEPT)? " FD_ACCEPT":"", (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"", (bits&EV_READ)?" EV_READ":"", (bits&EV_WRITE)?" EV_WRITE":"", (bits&EV_TIMEOUT)?" EV_TIMEOUT":""); */ fptr_ok(fptr_whitelist_event( eventlist[i]->ev_callback)); (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd, bits & eventlist[i]->ev_events, eventlist[i]->ev_arg); } /* if(eventlist[i]->is_tcp && bits) printf( "winsock %d got sticky %s%s\n", eventlist[i]->ev_fd, (eventlist[i]->old_events&EV_READ)?"EV_READ":"", (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":""); */ } //verbose(VERB_CLIENT, "winsock_event net"); if(base->tcp_reinvigorated) { printf("winsock_event reinvigorated\n"); base->tcp_reinvigorated = 0; newstickies = 1; } base->tcp_stickies = newstickies; //gprintf("winsock_event handle_select end\n"); return 0; }
/** call select and callbacks for that */ int _getdns_handle_select(struct _getdns_event_base* base, struct timeval* wait) { fd_set r, w; int ret, i, timeout = 0, numwait = 0; struct _getdns_event* eventlist[WSK_MAX_ITEMS]; #ifndef S_SPLINT_S if (wait->tv_sec == (time_t)-1) wait = NULL; #endif memmove(&r, &base->reads, sizeof(fd_set)); memmove(&w, &base->writes, sizeof(fd_set)); memmove(&base->ready, &base->content, sizeof(fd_set)); /* if ((ret = select(base->max + 1, &r, &w, NULL, wait)) == -1) { ret = errno; if (settime(base) < 0) return -1; errno = ret; if (ret == EAGAIN || ret == EINTR) return 0; return -1; } */ /* prepare event array */ for (i = 0; i<base->max; i++) { if (base->items[i]->ev_fd == -1 && !base->items[i]->is_signal) continue; /* skip timer only events */ eventlist[numwait] = base->items[i]; base->waitfor[numwait++] = base->items[i]->hEvent; if (numwait == WSK_MAX_ITEMS) break; /* sanity check */ } ret = WSAWaitForMultipleEvents(base->max, base->waitfor, 0 /* do not wait for all, just one will do */, wait ? timeout : WSA_INFINITE, 0); /* we are not alertable (IO completion events) */ if (ret == WSA_WAIT_IO_COMPLETION) { log_err("getdns: WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION"); return -1; } else if (ret == WSA_WAIT_FAILED) { log_err("getdns: WSAWaitForMultipleEvents failed: %s", wsa_strerror(WSAGetLastError())); return -1; } else if (ret == WSA_WAIT_TIMEOUT) { was_timeout = 1; } else startidx = ret - WSA_WAIT_EVENT_0; if (settime(base) < 0) return -1; for (i = 0; i<base->max + 1; i++) { short bits = 0; if (!base->items[i] || !(FD_ISSET(i, &base->ready))) { continue; } if (FD_ISSET(i, &r)) { bits |= EV_READ; ret--; } if (FD_ISSET(i, &w)) { bits |= EV_WRITE; ret--; } bits &= base->items[i]->ev_events; if (bits) { fptr_ok(fptr_whitelist_event( base->items[i]->ev_callback)); (*base->items[i]->ev_callback)(base->items[i]->ev_fd, bits, base->items[i]->ev_arg); if (ret == 0) break; } } return 0; }