#include "client.h" #include "proxy.h" #include "epoll.h" #include "helper.h" #include "asn1.h" #include #include #include #include #include #define MAX_SEND_BUFFER 100000 static void client_flush(epoll_client_t *client); static void client_free(epoll_client_t *client) { proxy_removeClient(client); if (client->sendBuffer != NULL) free(client->sendBuffer); if (client->fd != -1) { //ePoll_remove(client->fd); // epoll would remove closed descriptors automatically, but just to be sure we don't cause use after free, we remove it explicitly close(client->fd); } free(client); } void client_callback(void *data, int haveIn, int haveOut, int doCleanup) { epoll_client_t *client = (epoll_client_t*)data; if (doCleanup) { printf("Client gone.\n"); client_free(client); return; } // Anything to read? if (haveIn) { for (;;) { if (client->rbPos >= REQLEN) { printf("[C->Proxy] Read buffer overflow. Disconnecting.\n"); client_free(client); return; } const size_t buflen = REQLEN - client->rbPos; const ssize_t ret = read(client->fd, client->readBuffer + client->rbPos, buflen); if (ret < 0 && errno == EINTR) continue; if (ret < 0 && errno == EAGAIN) break; if (ret <= 0) { printf("Client gone while reading.\n"); client_free(client); return; } client->rbPos += ret; // Request complete? for (;;) { size_t consumed, len; consumed = scan_asn1SEQUENCE(client->readBuffer, client->readBuffer + client->rbPos, &len); if (consumed == 0) break; // Length-Header not complete len += consumed; if (len > client->rbPos) break; // Body not complete yet printf("Received complete requrest...\n"); if (proxy_fromClient(client, len) == -1) { printf("Error parsing request from client.\n"); client_free(client); return; } // Shift remaining buffer contents if (len == client->rbPos) { client->rbPos = 0; break; } memmove(client->readBuffer, client->readBuffer + len, client->rbPos - len); client->rbPos -= len; } if ((ssize_t)buflen > ret) break; // Read less than buffer len, epoll will fire again } } // Anything to send? if (haveOut) client_flush(client); } static void client_flush(epoll_client_t *client) { while (client->sbPos < client->sbFill) { const int tosend = client->sbFill - client->sbPos; const int ret = write(client->fd, client->sendBuffer + client->sbPos, tosend); if (ret < 0 && errno == EINTR) continue; if (ret < 0 && errno == EAGAIN) return; if (ret <= 0) { printf("Cannot send to client (ret: %d, errno: %d)\n", ret, errno); return; } client->sbPos += ret; if (ret != tosend) return; // Sent less than requested -> buffer full, epoll will trigger us again } client->sbPos = client->sbFill = 0; } int client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork) { if (client->sbFill == 0 && !cork) { // Nothing in send buffer, fire away const int ret = write(client->fd, buffer, len); if (ret == 0 || (ret < 0 && errno != EINTR && errno != EAGAIN)) { printf("Client gone when trying to send.\n"); return -1; } if (ret == (int)len) return 0; // Couldn't send everything, continue with buffering logic below if (ret > 0) { buffer += ret; len -= (size_t)ret; } } // Sanity if ((client->sbLen - client->sbPos) + len > MAX_SEND_BUFFER) { printf("Dropping client as the send buffer would exceed %d bytes.\n", (int)MAX_SEND_BUFFER); return -1; } // Buffer... if (client->sbLen - client->sbFill < len) { // Buffer too small? if (client->sbPos != 0) { // See if we can compact it memmove(client->sendBuffer, client->sendBuffer + client->sbPos, client->sbFill - client->sbPos); client->sbFill -= client->sbPos; client->sbPos = 0; } if (client->sbLen - client->sbFill < len) { // Still too small after compacting? realloc if (helper_realloc(&client->sendBuffer, &client->sbLen, client->sbLen + len + 1500, "client_send") == -1) return -1; } } // Finally append to buffer memcpy(client->sendBuffer + client->sbFill, buffer, len); client->sbFill += len; if (!cork) client_flush(client); return 0; }