]> PatchyGit - patchyircd.git/commitdiff
killConnection: never block
authorEgor <egor@patchysicp.xyz>
Thu, 19 Oct 2023 13:59:50 +0000 (16:59 +0300)
committerEgor <egor@patchysicp.xyz>
Thu, 19 Oct 2023 14:04:21 +0000 (17:04 +0300)
src/common.h
src/main.c
src/net.c
src/net.h

index 4750193..f857071 100644 (file)
@@ -56,6 +56,8 @@ struct client_data {
        unsigned want_write_for_read :1;
        unsigned want_read_for_write :1;
        unsigned want_write_for_write :1;
+       unsigned want_read_for_close :1;
+       unsigned want_write_for_close :1;
 };
 struct channel {
        char *key;
index fc9d75e..97dcffa 100644 (file)
@@ -323,8 +323,9 @@ int main(int argc, char *argv[])
                        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);
                }
 
@@ -365,10 +366,13 @@ int main(int argc, char *argv[])
                        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;
                }
        }
@@ -377,6 +381,8 @@ int main(int argc, char *argv[])
        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();
index 906bfc8..e17a167 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -7,34 +7,9 @@ struct client_data *allocClient()
        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) {
@@ -44,17 +19,27 @@ void killConnection(struct client_data *cl, int byChoice) {
        // 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));
@@ -66,6 +51,12 @@ void killConnection(struct client_data *cl, int byChoice) {
                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 {
index c147b03..d0d4bde 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -6,6 +6,7 @@ void sendbuf(struct client_data *client);
 void sendbuf_visible(struct client_data *client);
 struct client_data *allocClient();
 void killConnection(struct client_data *client, int byChoice);
+void killConnectionPart2(struct client_data *cl);
 void recvProc(struct client_data *cl);
 void sendClient(struct client_data *cl, const char *buf, size_t len);