summaryrefslogtreecommitdiff
path: root/src/knot/server/tcp-handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/knot/server/tcp-handler.c')
-rw-r--r--src/knot/server/tcp-handler.c72
1 files changed, 35 insertions, 37 deletions
diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c
index 1f18abf..3ebdfe4 100644
--- a/src/knot/server/tcp-handler.c
+++ b/src/knot/server/tcp-handler.c
@@ -25,6 +25,9 @@
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
+#ifdef HAVE_SYS_UIO_H // struct iovec (OpenBSD)
+#include <sys/uio.h>
+#endif // HAVE_SYS_UIO_H
#ifdef HAVE_CAP_NG_H
#include <cap-ng.h>
#endif /* HAVE_CAP_NG_H */
@@ -403,44 +406,22 @@ static void tcp_loop_free(void *data)
int tcp_send(int fd, uint8_t *msg, size_t msglen)
{
-
- /*! \brief TCP corking.
- * \see http://vger.kernel.org/~acme/unbehaved.txt
- */
-#ifdef TCP_CORK
- int cork = 1;
- int uncork = setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork));
-#endif
-
- /* Flags. */
- int flags = 0;
-#ifdef MSG_NOSIGNAL
- flags |= MSG_NOSIGNAL;
-#endif
-
- /* Send message size. */
- unsigned short pktsize = htons(msglen);
- int sent = send(fd, &pktsize, sizeof(pktsize), flags);
- if (sent < 0) {
- return KNOT_ERROR;
- }
-
- /* Send message data. */
- sent = send(fd, msg, msglen, flags);
- if (sent < 0) {
+ /* Create iovec for gathered write. */
+ struct iovec iov[2];
+ uint16_t pktsize = htons(msglen);
+ iov[0].iov_base = &pktsize;
+ iov[0].iov_len = sizeof(uint16_t);
+ iov[1].iov_base = msg;
+ iov[1].iov_len = msglen;
+
+ /* Send. */
+ int total_len = iov[0].iov_len + iov[1].iov_len;
+ int sent = writev(fd, iov, 2);
+ if (sent != total_len) {
return KNOT_ERROR;
}
-#ifdef TCP_CORK
- /* Uncork only if corked successfuly. */
- if (uncork == 0) {
- cork = 0;
- if (setsockopt(fd, SOL_TCP, TCP_CORK, &cork, sizeof(cork)) < 0) {
- dbg_net("tcp: failed to uncork socket\n");
- }
- }
-#endif
- return sent;
+ return msglen; /* Do not count the size prefix. */
}
int tcp_recv(int fd, uint8_t *buf, size_t len, sockaddr_t *addr)
@@ -543,7 +524,16 @@ int tcp_loop_master(dthread_t *thread)
}
for (unsigned i = 0; nfds > 0 && i < set.n; ++i) {
- /* Skip inactive. */
+
+ /* Error events. */
+ if (set.pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ socket_close(set.pfd[i].fd);
+ fdset_remove(&set, i);
+ --nfds; /* Treat error event as activity. */
+ continue; /* Stay on the same index. */
+ }
+
+ /* Accept POLLIN events. */
if (!(set.pfd[i].revents & POLLIN))
continue;
@@ -611,6 +601,15 @@ int tcp_loop_worker(dthread_t *thread)
unsigned i = 0;
while (nfds > 0 && i < set->n) {
+ /* Terminate faulty connections. */
+ int fd = set->pfd[i].fd;
+ if (set->pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) {
+ fdset_remove(set, i);
+ close(fd);
+ --nfds; /* Treat error event as activity. */
+ continue; /* Stay on the same index. */
+ }
+
if (!(set->pfd[i].revents & set->pfd[i].events)) {
/* Skip inactive. */
++i;
@@ -621,7 +620,6 @@ int tcp_loop_worker(dthread_t *thread)
}
/* Register new TCP client or process a query. */
- int fd = set->pfd[i].fd;
if (fd == w->pipe[0]) {
tcp_loop_assign(fd, set);
} else {