FD_SET(self_sock, &readfds);
#endif
for (struct client_data *cl = clients; cl; cl = cl->next) {
- FD_SET(cl->FD, &readfds);
- if (cl->want_write_for_read || cl->want_write_for_write)
+ if (!cl->want_write_for_close)
+ FD_SET(cl->FD, &readfds);
+ if (cl->want_write_for_read || cl->want_write_for_write || cl->want_write_for_close)
FD_SET(cl->FD, &writefds);
}
struct client_data *next = cl->next;
int isr = FD_ISSET(cl->FD, &readfds);
int isw = FD_ISSET(cl->FD, &writefds);
- if (isr || (cl->want_write_for_read && isw))
- recvProc(cl);
+ if (!cl->want_read_for_close && !cl->want_write_for_close)
+ if (isr || (cl->want_write_for_read && isw))
+ recvProc(cl);
if ((cl->want_read_for_write && isr) || (cl->want_write_for_write && isw))
sendClient(cl, 0, 0);
+ if ((cl->want_read_for_close && isr) || (cl->want_write_for_close && isw))
+ killConnectionPart2(cl);
cl = next;
}
}
for (struct client_data *cl = clients; cl;) {
struct client_data *next = cl->next;
killConnection(cl, 0);
+ /* FIXME: who is going to wait for these connections to actually get
+ * killed? */
cl = next;
}
net_cleanup();
return calloc(1, sizeof(struct client_data));
}
-#ifdef HAS_TLS
-static void block(struct client_data *cl, int out)
+void killConnection(struct client_data *cl, int byChoice)
{
-#ifdef _WIN32
- fd_set fds;
- FD_ZERO(&fds);
- FD_SET(cl->FD, &fds);
- if (out)
- select(cl->FD+1, 0, &fds, 0, 0);
- else
- select(cl->FD+1, &fds, 0, 0, 0);
-#else
- struct pollfd pfd;
- pfd.fd = cl->FD;
- pfd.events = out ? POLLOUT : POLLIN;
- poll(&pfd, 1, 0);
-#endif
-}
-#endif
-
-void killConnection(struct client_data *cl, int byChoice) {
if (!cl) return;
- for (struct client_data **next = &clients; *next; next = &(*next)->next) {
- if (*next == cl) {
- *next = cl->next;
- break;
- }
- }
if (cl->peername)
fprintf(stderr, "Client disconnected from Socket: %"PRISocket", IP: %s PORT: %d\n", cl->FD, cl->peername, cl->peerport);
if(!byChoice && cl->nick && cl->username) {
// Send error to client informing them that they will be disconnected
msg_error("Closing Link");
sendbuf(cl);
+ killConnectionPart2(cl);
+}
+void killConnectionPart2(struct client_data *cl)
+{
+ /* FIXME: we have to flush existing data somehow */
+ /* A better implementation would be to keep a separate list of disconnected
+ * clients. This way we can do all PARTing right away and only concern
+ * ourselves with tls_write/tls_close. */
+ cl->want_read_for_close = 0;
+ cl->want_write_for_close = 0;
if (cl->FD != INVALID_SOCKET) {
#ifdef HAS_TLS
if (cl->cctx) {
- // FIXME: this blocks
- int rv;
- for (;;) {
- rv = tls_close(cl->cctx);
- if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
- block(cl, rv == TLS_WANT_POLLOUT);
- else
- break;
+ int rv = tls_close(cl->cctx);
+ if (rv == TLS_WANT_POLLIN) {
+ cl->want_read_for_close = 1;
+ return;
+ }
+ if (rv == TLS_WANT_POLLOUT) {
+ cl->want_write_for_close = 1;
+ return;
}
if (rv == -1) {
fprintf(stderr, "tls_close (%"PRISocket"): %s\n", cl->FD, tls_error(cl->cctx));
shutdown(cl->FD, SHUT_RDWR);
closesocket(cl->FD);
}
+ for (struct client_data **next = &clients; *next; next = &(*next)->next) {
+ if (*next == cl) {
+ *next = cl->next;
+ break;
+ }
+ }
struct trie_find *f = NULL;
if (trie_findfirst(&f, &cl->channels) == 1)
do {