From: Egor Date: Wed, 18 Oct 2023 20:00:17 +0000 (+0300) Subject: sendClient: never block X-Git-Url: https://git.patchysicp.xyz/?a=commitdiff_plain;h=5c16fd843059d825acb622460131932dadaab4f0;p=patchyircd.git sendClient: never block --- diff --git a/common.h b/common.h index 3c5243b..6681546 100644 --- a/common.h +++ b/common.h @@ -43,6 +43,8 @@ struct client_data { unsigned short peerport; char buf[2048]; size_t bufLen; + char wbuf[8192]; + size_t wbufLen; char umode; char regstate; struct trie_node *channels; @@ -51,7 +53,9 @@ struct client_data { time_t signon; time_t lastactivity; unsigned int caps; - char want_write_for_read; + char want_write_for_read :1; + char want_read_for_write :1; + char want_write_for_write :1; }; struct channel { char *key; diff --git a/main.c b/main.c index b7f1743..c00c1ac 100644 --- a/main.c +++ b/main.c @@ -321,7 +321,7 @@ int main(int argc, char *argv[]) #endif for (struct client_data *cl = clients; cl; cl = cl->next) { FD_SET(cl->FD, &readfds); - if (cl->want_write_for_read) + if (cl->want_write_for_read || cl->want_write_for_write) FD_SET(cl->FD, &writefds); } @@ -360,8 +360,12 @@ int main(int argc, char *argv[]) // Respond to already connected clients for (struct client_data *cl = clients; cl;) { struct client_data *next = cl->next; - if (FD_ISSET(cl->FD, &readfds) || (cl->want_write_for_read && FD_ISSET(cl->FD, &writefds))) + 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_write && isr) || (cl->want_write_for_write && isw)) + sendClient(cl, 0, 0); cl = next; } } diff --git a/net.c b/net.c index 76c91e6..90d4c3c 100644 --- a/net.c +++ b/net.c @@ -12,6 +12,26 @@ struct client_data *allocClient(){ return NewClient; }; +#ifdef HAS_TLS +static void block(struct client_data *cl, int out) +{ +#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, bool byChoice) { if (!cl) return; for (struct client_data **next = &clients; *next; next = &(*next)->next) { @@ -34,9 +54,13 @@ void killConnection(struct client_data *cl, bool byChoice) { if (cl->cctx) { // FIXME: this blocks int rv; - do { + for (;;) { rv = tls_close(cl->cctx); - } while (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT); + if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT) + block(cl, rv == TLS_WANT_POLLOUT); + else + break; + } if (rv == -1) { fprintf(stderr, "tls_close (%"PRISocket"): %s\n", cl->FD, tls_error(cl->cctx)); } @@ -78,24 +102,6 @@ void killConnection(struct client_data *cl, bool byChoice) { free(cl); } -static void block(struct client_data *cl, int out) -{ -#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 -} - void recvProc(struct client_data *cl) { ssize_t bytesRead; char *x; @@ -157,24 +163,27 @@ void recvProc(struct client_data *cl) { } } -void sendClient(struct client_data *cl, const char *buf, size_t len) +/* returns the count of bytes which were not sent */ +static int sendClientRaw(struct client_data *cl, const char *buf, size_t len) { + cl->want_read_for_write = 0; + cl->want_write_for_write = 0; if (cl->FD == (SOCKET)INVALID_SOCKET) - return; + return 0; fprintf(stderr, "SERVER %"PRISocket": %.*s", cl->FD, (int)len, (char*)buf); - // TODO: error handling - // FIXME: blocks, probably the reason why server is slow + /* FIXME: error handling */ #ifdef HAS_TLS if (cl->cctx) { while (len) { int rv = tls_write(cl->cctx, buf, len); - if (!rv) - break; - if (rv == -1) + if (rv == 0 || rv == -1) { break; - if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT) { - block(cl, rv == TLS_WANT_POLLOUT); - continue; + } else if (rv == TLS_WANT_POLLIN) { + cl->want_read_for_write = 1; + return len; + } else if (rv == TLS_WANT_POLLOUT) { + cl->want_write_for_write = 1; + return len; } buf += rv; len -= rv; @@ -188,8 +197,8 @@ void sendClient(struct client_data *cl, const char *buf, size_t len) break; if (rv == -1) { if (net_wouldblock()) { - block(cl, 1); - continue; + cl->want_write_for_write = 1; + return len; } else { break; } @@ -198,4 +207,30 @@ void sendClient(struct client_data *cl, const char *buf, size_t len) len -= rv; } } + return len; +} + +void sendClient(struct client_data *cl, const char *buf, size_t len) +{ + if (cl->wbufLen + len > sizeof(cl->wbuf)) { + /* Buffer overrun */ + /* FIXME: probably should terminate the connection at this point */ + len = 0; + /* we don't return here, because we still want to push old data if possible */ + } + if (!cl->wbufLen) { + if (len) { + int left = sendClientRaw(cl, buf, len); + memcpy(cl->wbuf, buf+len-left, left); + cl->wbufLen = left; + } + return; + } + if (len) { + memcpy(cl->wbuf + cl->wbufLen, buf, len); + cl->wbufLen += len; + } + int left = sendClientRaw(cl, cl->wbuf, cl->wbufLen); + memmove(cl->wbuf, cl->wbuf+cl->wbufLen-left, left); + cl->wbufLen = left; }