#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);
}
// 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;
}
}
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) {
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));
}
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;
}
}
-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;
break;
if (rv == -1) {
if (net_wouldblock()) {
- block(cl, 1);
- continue;
+ cl->want_write_for_write = 1;
+ return len;
} else {
break;
}
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;
}