void *tcp_server(void *arg) { sock_t *s = (sock_t *) arg; int i,fd,try_to_read,received; struct tcp_client *clients,*client; struct pollfd *pfds = NULL; volatile nfds_t nfds; setnonblocking(s->socket); nfds = 1; pfds = mallocz_or_die(nfds * sizeof(struct pollfd)); pfds->fd = s->socket; pfds->events = POLLIN; clients = NULL; RELAY_ATOMIC_AND( RECEIVED_STATS.active_connections, 0); int rc; for (;;) { rc = poll(pfds,nfds,CONFIG.polling_interval_ms); if (rc == -1) { if (rc == EINTR) continue; WARN_ERRNO("poll"); goto out; } for (i = 0; i < nfds; i++) { if (!pfds[i].revents) continue; if (pfds[i].fd == s->socket) { fd = accept(s->socket, NULL, NULL); if (fd == -1) { WARN_ERRNO("accept"); goto out; } setnonblocking(fd); RELAY_ATOMIC_INCREMENT( RECEIVED_STATS.active_connections, 1 ); pfds = realloc_or_die(pfds, (nfds + 1) * sizeof(*pfds)); clients = realloc_or_die(clients,(nfds + 1) * sizeof(*clients)); clients[nfds].pos = 0; clients[nfds].buf = mallocz_or_die(ASYNC_BUFFER_SIZE); // WARN("[%d] CREATE %p fd: %d",i,clients[nfds].buf,fd); pfds[nfds].fd = fd; pfds[nfds].events = POLLIN; pfds[nfds].revents = 0; nfds++; } else { client = &clients[i]; try_to_read = ASYNC_BUFFER_SIZE - client->pos; // try to read as much as possible if (try_to_read <= 0) { WARN("disconnecting, try to read: %d, pos: %d", try_to_read, client->pos); goto disconnect; } received = recv(pfds[i].fd, client->buf + client->pos, try_to_read,0); if (received <= 0) { if (received == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) continue; disconnect: shutdown(pfds[i].fd,SHUT_RDWR); close(pfds[i].fd); // WARN("[%d] DESTROY %p %d %d fd: %d vs %d",i,client->buf,client->x,i,pfds[i].fd,client->fd); free(client->buf); // shft left memcpy(pfds + i,pfds + i + 1, (nfds - i - 1) * sizeof(struct pollfd)); memcpy(clients + i,clients + i + 1, (nfds - i - 1) * sizeof(struct tcp_client)); nfds--; pfds = realloc_or_die(pfds, nfds * sizeof(struct pollfd)); clients = realloc_or_die(clients, nfds * sizeof(struct tcp_client)); RELAY_ATOMIC_DECREMENT( RECEIVED_STATS.active_connections, 1 ); continue; } client->pos += received; try_to_consume_one_more: if (client->pos < EXPECTED_HEADER_SIZE) continue; if (EXPECTED(client) > MAX_CHUNK_SIZE) { WARN("received frame (%d) > MAX_CHUNK_SIZE(%d)",EXPECTED(client),MAX_CHUNK_SIZE); goto disconnect; } if (client->pos >= EXPECTED(client) + EXPECTED_HEADER_SIZE) { buf_to_blob_enqueue(client->buf,EXPECTED(client)); client->pos -= EXPECTED(client) + EXPECTED_HEADER_SIZE; if (client->pos < 0) { WARN("BAD PACKET wrong 'next' position(< 0) pos: %d expected packet size:%d header_size: %d", client->pos, EXPECTED(client),EXPECTED_HEADER_SIZE); goto disconnect; } if (client->pos > 0) { // [ h ] [ h ] [ h ] [ h ] [ D ] [ D ] [ D ] [ h ] [ h ] [ h ] [ h ] [ D ] // ^ pos(12) // after we remove the first packet + header it becomes: // [ h ] [ h ] [ h ] [ h ] [ D ] [ D ] [ D ] [ h ] [ h ] [ h ] [ h ] [ D ] // ^ pos (5) // and then we copy from header + data, to position 0, 5 bytes // // [ h ] [ h ] [ h ] [ h ] [ D ] // ^ pos (5) memmove(client->buf, client->buf + EXPECTED_HEADER_SIZE + EXPECTED(client), client->pos); if (client->pos >= EXPECTED_HEADER_SIZE) goto try_to_consume_one_more; } } } } } out: for (i = 0; i < nfds; i++) { if (pfds[i].fd != s->socket) free(clients[i].buf); shutdown(pfds[i].fd, SHUT_RDWR); close(pfds[i].fd); } free(pfds); free(clients); set_aborted(); pthread_exit(NULL); }
void unset_abort_bits(uint32_t v) { v= ~v; RELAY_ATOMIC_AND(ABORT, v); }