/* * ssl_handshake - let OpenSSL initialize the protocol. Register for * read/write events if necessary. */ static void ssl_handshake(int fd, struct Client *client_p) { int ret = SSL_accept(client_p->localClient->fd.ssl); X509 *cert; if ((cert = SSL_get_peer_certificate(client_p->localClient->fd.ssl)) != NULL) { int res = SSL_get_verify_result(client_p->localClient->fd.ssl); if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE || res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { /* The client sent a certificate which verified OK */ base16_encode(client_p->certfp, sizeof(client_p->certfp), (const char*)cert->sha1_hash, sizeof(cert->sha1_hash)); } else { ilog(L_WARN, "Client %s!%s@%s gave bad SSL client certificate: %d", client_p->name, client_p->username, client_p->host, res); } X509_free(cert); } if (ret <= 0) { if((CurrentTime - client_p->firsttime) > 30) { exit_client(client_p, client_p, "Timeout during SSL handshake"); return; } switch (SSL_get_error(client_p->localClient->fd.ssl, ret)) { case SSL_ERROR_WANT_WRITE: comm_setselect(&client_p->localClient->fd, COMM_SELECT_WRITE, (PF *) ssl_handshake, client_p, 30); return; case SSL_ERROR_WANT_READ: comm_setselect(&client_p->localClient->fd, COMM_SELECT_READ, (PF *) ssl_handshake, client_p, 30); return; default: exit_client(client_p, client_p, "Error during SSL handshake"); return; } } comm_settimeout(&client_p->localClient->fd, 0, NULL, NULL); execute_callback(auth_cb, client_p); }
/* Called to close a given filedescriptor */ void fd_close(int fd) { fde_t *F = &fd_table[fd]; s_assert(F->flags.open); /* All disk fd's MUST go through file_close() ! */ s_assert(F->type != FD_FILE); if(F->type == FD_FILE) { s_assert(F->read_handler == NULL); s_assert(F->write_handler == NULL); } comm_setselect(F->fd, FDLIST_NONE, COMM_SELECT_WRITE | COMM_SELECT_READ, NULL, NULL, 0); comm_setflush(F->fd, 0, NULL, NULL); if (F->dns_query != NULL) { delete_adns_queries(F->dns_query); MyFree(F->dns_query); F->dns_query = NULL; } F->flags.open = 0; fdlist_update_biggest(fd, 0); number_fd--; memset(F, '\0', sizeof(fde_t)); F->timeout = 0; /* Unlike squid, we're actually closing the FD here! -- adrian */ close(fd); }
/* * comm_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, i; static struct kevent ke[KE_LENGTH]; struct timespec poll_time; void (*hdl)(fde_t *, void *); fde_t *F; /* * remember we are doing NANOseconds here, not micro/milli. God knows * why jlemon used a timespec, but hey, he wrote the interface, not I * -- Adrian */ poll_time.tv_sec = 0; poll_time.tv_nsec = SELECT_DELAY * 1000000; num = kevent(kqfd.fd, kq_fdlist, kqoff, ke, KE_LENGTH, &poll_time); kqoff = 0; set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (i = 0; i < num; i++) { F = lookup_fd(ke[i].ident); if (F == NULL || !F->flags.open || (ke[i].flags & EV_ERROR)) continue; if (ke[i].filter == EVFILT_READ) { if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if (ke[i].filter == EVFILT_WRITE) { if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* static void comm_connect_tryconnect(int fd, void *notused) * Input: The fd, the handler data(unused). * Output: None. * Side-effects: Try and connect with pending connect data for the FD. If * we succeed or get a fatal error, call the callback. * Otherwise, it is still blocking or something, so register * to select for a write event on this FD. */ static void comm_connect_tryconnect(int fd, void *notused) { int retval; fde_t *F = &fd_table[fd]; if(F->connect.callback == NULL) return; /* Try the connect() */ retval = connect(fd, (struct sockaddr *) &fd_table[fd].connect.hostaddr, GET_SS_LEN(fd_table[fd].connect.hostaddr)); /* Error? */ if(retval < 0) { /* * If we get EISCONN, then we've already connect()ed the socket, * which is a good thing. * -- adrian */ if(errno == EISCONN) comm_connect_callback(F->fd, COMM_OK); else if(ignoreErrno(errno)) /* Ignore error? Reschedule */ comm_setselect(F->fd, FDLIST_SERVER, COMM_SELECT_WRITE|COMM_SELECT_RETRY, comm_connect_tryconnect, NULL, 0); else /* Error? Fail with COMM_ERR_CONNECT */ comm_connect_callback(F->fd, COMM_ERR_CONNECT); return; } /* If we get here, we've suceeded, so call with COMM_OK */ comm_connect_callback(F->fd, COMM_OK); }
static void serv_connect_callback(fde_t *fd, int status, void *data) { struct Client *client = (struct Client*)data; struct Server *server = NULL; assert(client != NULL); server = client->server; assert(server != NULL); assert(&server->fd == fd); if(status != COMM_OK) { ilog(L_CRIT, "serv_connect_callback: Connect failed :("); exit(1); } ilog(L_DEBUG, "serv_connect_callback: Connect succeeded!"); comm_setselect(fd, COMM_SELECT_READ, read_packet, client, 0); dlinkAdd(client, &client->node, &global_server_list); execute_callback(connected_cb, client); }
/* void dns_select(void) * Input: None. * Output: None * Side effects: Re-register ADNS fds with the fd system. Also calls the * callbacks into core ircd. */ void dns_select(void) { struct adns_pollfd pollfds[MAXFD_POLL]; int npollfds, i, fd; adns__consistency(dns_state, 0, cc_entex); npollfds = adns__pollfds(dns_state, pollfds); for (i = 0; i < npollfds; i++) { fd = pollfds[i].fd; if(pollfds[i].events & ADNS_POLLIN) comm_setselect(fd, FDLIST_SERVER, COMM_SELECT_READ, dns_readable, NULL); if(pollfds[i].events & ADNS_POLLOUT) comm_setselect(fd, FDLIST_SERVICE, COMM_SELECT_WRITE, dns_writeable, NULL); } }
/* * comm_select * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, ci; void (*hdl)(fde_t *, void *); fde_t *F; num = poll(pollfds, pollnum, SELECT_DELAY); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (ci = 0; ci < pollnum && num > 0; ci++) { int revents = pollfds[ci].revents; if (revents == 0) continue; num--; F = lookup_fd(pollfds[ci].fd); assert(F); if (!F->flags.open) continue; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { struct timeval to; int num, fd; fde_t *F; PF *hdl; /* Copy over the read/write sets so we don't have to rebuild em */ memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set)); memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set)); to.tv_sec = 0; to.tv_usec = SELECT_DELAY * 1000; num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); #endif return; } for (fd = 0; fd <= highest_fd && num > 0; fd++) if (FD_ISSET(fd, &tmpreadfds) || FD_ISSET(fd, &tmpwritefds)) { num--; F = lookup_fd(fd); if (F == NULL || !F->flags.open) continue; if (FD_ISSET(fd, &tmpreadfds)) if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } if (FD_ISSET(fd, &tmpwritefds)) if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num; struct pollfd pollfds[128]; struct dvpoll dopoll; void (*hdl)(fde_t *, void *); dopoll.dp_timeout = SELECT_DELAY; dopoll.dp_nfds = 128; dopoll.dp_fds = &pollfds[0]; num = ioctl(devpoll_fd, DP_POLL, &dopoll); event_time_set(); if (num < 0) { const struct timespec req = { .tv_sec = 0, .tv_nsec = 50000000 }; nanosleep(&req, NULL); /* Avoid 99% CPU in comm_select */ return; } for (int i = 0; i < num; ++i) { fde_t *F = &fd_table[dopoll.dp_fds[i].fd]; if (F->flags.open == false) continue; if ((dopoll.dp_fds[i].revents & POLLIN)) { if ((hdl = F->read_handler)) { F->read_handler = NULL; hdl(F, F->read_data); if (F->flags.open == false) continue; } } if ((dopoll.dp_fds[i].revents & POLLOUT)) { if ((hdl = F->write_handler)) { F->write_handler = NULL; hdl(F, F->write_data); if (F->flags.open == false) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, i; struct pollfd pollfds[128]; struct dvpoll dopoll; void (*hdl)(fde_t *, void *); fde_t *F; dopoll.dp_timeout = SELECT_DELAY; dopoll.dp_nfds = 128; dopoll.dp_fds = &pollfds[0]; num = ioctl(dpfd.fd, DP_POLL, &dopoll); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (i = 0; i < num; i++) { F = lookup_fd(dopoll.dp_fds[i].fd); if (F == NULL || !F->flags.open) continue; if ((dopoll.dp_fds[i].revents & POLLIN)) { if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if ((dopoll.dp_fds[i].revents & POLLOUT)) { if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* void dns_select(void) * Input: None. * Output: None * Side effects: Re-register ADNS fds with the fd system. Also calls the * callbacks into core ircd. */ void dns_select(void) { struct adns_pollfd pollfds[MAXFD_POLL]; int npollfds, i, fd; adns__consistency(dns_state,0,cc_entex); npollfds = adns__pollfds(dns_state, pollfds); for(i = 0; i < npollfds; i++) { fd = pollfds[i].fd; if (pollfds[i].events & ADNS_POLLIN) comm_setselect(fd, FDLIST_SERVER, COMM_SELECT_READ, dns_readable, NULL, 0); if (pollfds[i].events & ADNS_POLLOUT) comm_setselect(fd, FDLIST_SERVICE, COMM_SELECT_WRITE, dns_writeable, NULL, 0); } /* Call our callbacks, now that they may have some relevant data... */ /* *dns_do_callbacks(); */ }
/* * comm_select * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { int num, ci, revents; PF *hdl; fde_t *F; /* XXX kill that +1 later ! -- adrian */ num = poll(pollfds, pollmax + 1, SELECT_DELAY); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (ci = 0; ci <= pollmax && num > 0; ci++) { if ((revents = pollfds[ci].revents) == 0 || pollfds[ci].fd == -1) continue; num--; F = lookup_fd(pollfds[ci].fd); if (F == NULL || !F->flags.open) continue; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select() * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { struct epoll_event ep_fdlist[128]; int num, i; void (*hdl)(fde_t *, void *); fde_t *F; num = epoll_wait(efd.fd, ep_fdlist, 128, SELECT_DELAY); set_time(); if (num < 0) { const struct timespec req = { .tv_sec = 0, .tv_nsec = 50000000 }; nanosleep(&req, NULL); /* Avoid 99% CPU in comm_select */ return; } for (i = 0; i < num; i++) { F = lookup_fd(ep_fdlist[i].data.fd); if (F == NULL || !F->flags.open) continue; if ((ep_fdlist[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))) { if ((hdl = F->read_handler)) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } } if ((ep_fdlist[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))) { if ((hdl = F->write_handler)) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } } comm_setselect(F, 0, NULL, NULL, 0); } }
/* * comm_select() * * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(void) { struct epoll_event ep_fdlist[128]; int num, i; PF *hdl; fde_t *F; num = epoll_wait(efd.fd, ep_fdlist, 128, SELECT_DELAY); set_time(); if (num < 0) { #ifdef HAVE_USLEEP usleep(50000); /* avoid 99% CPU in comm_select */ #endif return; } for (i = 0; i < num; i++) { F = lookup_fd(ep_fdlist[i].data.fd); if (F == NULL || !F->flags.open) continue; if ((ep_fdlist[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))) if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (!F->flags.open) continue; } if ((ep_fdlist[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))) if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (!F->flags.open) continue; } comm_setselect(F, 0, NULL, NULL, 0); } }
/* static void comm_connect_tryconnect(int fd, void *notused) * Input: The fd, the handler data(unused). * Output: None. * Side-effects: Try and connect with pending connect data for the FD. If * we succeed or get a fatal error, call the callback. * Otherwise, it is still blocking or something, so register * to select for a write event on this FD. */ static void comm_connect_tryconnect(fde_t *fd, void *notused) { int retval; /* This check is needed or re-entrant s_bsd_* like sigio break it. */ if (fd->connect.callback == NULL) return; /* Try the connect() */ retval = connect(fd->fd, (struct sockaddr *) &fd->connect.hostaddr, fd->connect.hostaddr.ss_len); /* Error? */ if (retval < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif /* * If we get EISCONN, then we've already connect()ed the socket, * which is a good thing. * -- adrian */ if (errno == EISCONN) comm_connect_callback(fd, COMM_OK); else if (ignoreErrno(errno)) /* Ignore error? Reschedule */ comm_setselect(fd, COMM_SELECT_WRITE, comm_connect_tryconnect, NULL, 0); else /* Error? Fail with COMM_ERR_CONNECT */ comm_connect_callback(fd, COMM_ERR_CONNECT); return; } /* If we get here, we've suceeded, so call with COMM_OK */ comm_connect_callback(fd, COMM_OK); }
/* Called to close a given filedescriptor */ void fd_close(fde_t *F) { unsigned int hashv = hash_fd(F->fd); if (F == fd_next_in_loop) fd_next_in_loop = F->hnext; if (F->flags.is_socket) comm_setselect(F, COMM_SELECT_WRITE | COMM_SELECT_READ, NULL, NULL, 0); delete_resolver_queries(F); #ifdef HAVE_LIBCRYPTO if (F->ssl) SSL_free(F->ssl); #endif if (fd_hash[hashv] == F) fd_hash[hashv] = F->hnext; else { fde_t *prev; /* let it core if not found */ for (prev = fd_hash[hashv]; prev->hnext != F; prev = prev->hnext) ; prev->hnext = F->hnext; } /* Unlike squid, we're actually closing the FD here! -- adrian */ close(F->fd); number_fd--; memset(F, 0, sizeof(fde_t)); }
static void accept_connection(int pfd, void *data) { static time_t last_oper_notice = 0; struct irc_sockaddr sai; struct irc_inaddr addr; int fd; int pe; struct Listener * listener = data; assert(listener != NULL); if(listener == NULL) return; /* * There may be many reasons for error return, but * in otherwise correctly working environment the * probable cause is running out of file descriptors * (EMFILE, ENFILE or others?). The man pages for * accept don't seem to list these as possible, * although it's obvious that it may happen here. * Thus no specific errors are tested at this * point, just assume that connections cannot * be accepted until some old is closed first. */ fd = comm_accept(listener->fd, &sai); copy_s_addr(IN_ADDR(addr), S_ADDR(sai)); #ifdef IPV6 if((IN6_IS_ADDR_V4MAPPED(&IN_ADDR2(addr))) || (IN6_IS_ADDR_V4COMPAT(&IN_ADDR2(addr)))) { memmove(&addr.sins.sin.s_addr, addr.sins.sin6.s6_addr+12, sizeof(struct in_addr)); sai.sins.sin.sin_family = AF_INET; } #endif if (fd < 0) { /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); return; } /* * check for connection limit */ if ((MAXCONNECTIONS - 10) < fd) { ++ServerStats->is_ref; /* * slow down the whining to opers bit */ if((last_oper_notice + 20) <= CurrentTime) { sendto_realops_flags(UMODE_ALL, L_ALL,"All connections in use. (%s)", get_listener_name(listener)); last_oper_notice = CurrentTime; } send(fd, "ERROR :All connections in use\r\n", 32, 0); fd_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); return; } /* Do an initial check we aren't connecting too fast or with too many * from this IP... */ if ((pe = conf_connect_allowed(&addr, sai.sins.sin.sin_family)) != 0) { ServerStats->is_ref++; /* XXX - this can only be BANNED_CLIENT? */ switch (pe) { case BANNED_CLIENT: send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0); break; } fd_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); return; } ServerStats->is_ac++; add_connection(listener, fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener, 0); }
static void accept_connection(int pfd, void *data) { static time_t last_oper_notice = 0; struct irc_sockaddr_storage sai; socklen_t addrlen = sizeof(sai); int fd; struct Listener *listener = data; struct ConfItem *aconf; char buf[BUFSIZE]; s_assert(listener != NULL); if(listener == NULL) return; for(;;) /* loop until something breaks us out */ { /* * There may be many reasons for error return, but * in otherwise correctly working environment the * probable cause is running out of file descriptors * (EMFILE, ENFILE or others?). The man pages for * accept don't seem to list these as possible, * although it's obvious that it may happen here. * Thus no specific errors are tested at this * point, just assume that connections cannot * be accepted until some old is closed first. */ fd = comm_accept(listener->fd, (struct sockaddr *) &sai, &addrlen); /* This needs to be done here, otherwise we break dlines */ mangle_mapped_sockaddr((struct sockaddr *) &sai); if(fd < 0) { /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); return; } /* * check for connection limit */ if((maxconnections - 10) < fd) { ++ServerStats->is_ref; /* * slow down the whining to opers bit */ if((last_oper_notice + 20) <= CurrentTime) { sendto_realops_flags(UMODE_ALL, L_ALL, "All connections in use. (%s)", get_listener_name(listener)); last_oper_notice = CurrentTime; } write(fd, "ERROR :All connections in use\r\n", 32); comm_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); return; } /* Do an initial check we aren't connecting too fast or with too many * from this IP... */ if((aconf = conf_connect_allowed((struct sockaddr *) &sai, sai.ss_family)) != NULL) { ServerStats->is_ref++; if(ConfigFileEntry.dline_with_reason) { if(ircsnprintf (buf, sizeof(buf), "ERROR :*** Banned: %s\r\n", aconf->passwd) >= (sizeof(buf) - 1)) { buf[sizeof(buf) - 3] = '\r'; buf[sizeof(buf) - 2] = '\n'; buf[sizeof(buf) - 1] = '\0'; } } else ircsprintf(buf, "ERROR :You have been D-lined.\r\n"); write(fd, buf, strlen(buf)); comm_close(fd); /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); return; } ServerStats->is_ac++; add_connection(listener, fd, (struct sockaddr *) &sai); } /* Re-register a new IO request for the next accept .. */ comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ, accept_connection, listener); }
/* * Handler for Win32 messages. */ static LRESULT CALLBACK hybrid_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_SOCKET: { fde_t *F = lookup_fd((int) wParam); PF *hdl; if (F != NULL && F->flags.open) switch (WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT: case FD_CLOSE: case FD_READ: if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); if (F->flags.open) comm_setselect(F, 0, NULL, NULL, 0); } break; case FD_CONNECT: case FD_WRITE: if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); if (F->flags.open) comm_setselect(F, 0, NULL, NULL, 0); } } return 0; } case WM_DNS: { dlink_node *ptr; DLINK_FOREACH(ptr, dns_queries.head) if (((struct DNSQuery *) ptr->data)->handle == wParam) { struct DNSQuery *query = ptr->data; struct DNSReply *reply = NULL; dlinkDelete(&query->node, &dns_queries); if (WSAGETASYNCERROR(lParam) == 0) { struct hostent *h = (struct hostent *) &query->reply; static struct DNSReply _reply; reply = &_reply; reply->h_name = h->h_name; reply->addr.ss.ss_family = h->h_addrtype; switch (h->h_addrtype) { case AF_INET: memcpy(&((struct sockaddr_in *) &reply->addr)->sin_addr, h->h_addr_list[0], h->h_length); break; #ifdef IPV6 case AF_INET6: memcpy(&((struct sockaddr_in6 *) &reply->addr)->sin6_addr, h->h_addr_list[0], h->h_length); break; #endif default: /* shouldn't happen */ reply = NULL; } } query->callback(query->ptr, reply); return 0; } return 0; } case WM_REHASH: dorehash = 1; return 0; case WM_REMOTD: doremotd = 1; return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } }