UByte PancakeNetworkActivate() { UInt16 i; if(!numListenSockets) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "No network interfaces configured"); return 0; } for(i = 0; i < numListenSockets; i++) { PancakeSocket *sock = listenSockets[i]; // Start listening on socket if(listen(sock->fd, (Int32) (UNative) sock->data) == -1) { Byte *name = PancakeNetworkGetInterfaceName(sock->localAddress); PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Can't listen on %s: %s", name, strerror(errno)); PancakeFree(name); return 0; } sock->data = NULL; } return 1; }
STATIC UByte PancakeAuthenticationBackendConfiguration(UByte step, config_setting_t *setting, PancakeConfigurationScope **scope) { PancakeAuthenticationConfiguration *config = (PancakeAuthenticationConfiguration*) setting->parent->hook; if(step == PANCAKE_CONFIGURATION_INIT) { UInt32 length = strlen(setting->value.sval); HASH_FIND(hh, PancakeAuthenticationBackends, setting->value.sval, length, config->backend); if(config->backend == NULL) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Unknown authentication backend %s", setting->value.sval); return 0; } // Call onConfiguration handler if(config->backend->onConfiguration) { config->backend->onConfiguration(config); } // Save some memory free(setting->value.sval); setting->type = CONFIG_TYPE_NONE; } return 1; }
STATIC UByte PancakeHTTPRewriteSetHTTPVersion(PancakeSocket *sock, PancakeHTTPRewriteVariable *var, PancakeHTTPRewriteValue *value) { PancakeHTTPRequest *request = (PancakeHTTPRequest*) sock->data; if(UNEXPECTED(value->intv < 10 || value->intv > 11)) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Bad value for $HTTPVersion: must be 10 or 11"); return 0; } if(UNEXPECTED(value->intv == 11 && request->HTTPVersion < PANCAKE_HTTP_11)) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Can't set $HTTPVersion to higher value than supported by client"); return 0; } request->HTTPVersion = value->intv == 10 ? PANCAKE_HTTP_10 : PANCAKE_HTTP_11; return 1; }
STATIC UByte PancakeHTTPRewriteSetHTTPAnswerCode(PancakeSocket *sock, PancakeHTTPRewriteVariable *var, PancakeHTTPRewriteValue *value) { PancakeHTTPRequest *request = (PancakeHTTPRequest*) sock->data; if(UNEXPECTED(value->intv < 100 || value->intv > 599)) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Value for $HTTPAnswerCode is out of range (100 - 599)"); return 0; } request->answerCode = (UInt16) value->intv; return 1; }
STATIC UByte PancakeNetworkInterfaceNetworkConfiguration(UByte step, config_setting_t *setting, PancakeConfigurationScope **scope) { if(step == PANCAKE_CONFIGURATION_INIT) { PancakeSocket *sock = (PancakeSocket*) setting->parent->hook; Int32 value = 1; // Check family if(!strcmp(setting->value.sval, "ip4")) { struct sockaddr_in *addr = (struct sockaddr_in*) sock->localAddress; sock->localAddress->sa_family = AF_INET; addr->sin_family = AF_INET; } else if(!strcmp(setting->value.sval, "ip6")) { struct sockaddr_in6 *addr = (struct sockaddr_in6*) sock->localAddress; sock->localAddress->sa_family = AF_INET6; addr->sin6_family = AF_INET6; } else if(!strcmp(setting->value.sval, "unix")) { struct sockaddr_un *addr = (struct sockaddr_un*) sock->localAddress; sock->localAddress->sa_family = AF_UNIX; addr->sun_family = AF_UNIX; } else { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Invalid network family %s", setting->value.sval); return 0; } sock->fd = socket(sock->localAddress->sa_family, SOCK_STREAM, sock->localAddress->sa_family == AF_UNIX ? 0 : SOL_TCP); if(sock->fd == -1) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Can't create socket: %s", strerror(errno)); return 0; } // Set SO_REUSEADDR setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(Int32)); } return 1; }
STATIC UByte PancakeLinuxPollServerInitialize() { // Just test epoll here, to make sure everything will work // The actual epoll instance must be created in the workers as it can't be shared // Initialize with size 32 on old kernels PancakeLinuxPollFD = epoll_create(32); if(PancakeLinuxPollFD == -1) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Can't create epoll instance: %s", strerror(errno)); return 0; } close(PancakeLinuxPollFD); PancakeLinuxPollFD = -1; return 1; }
STATIC UByte PancakeAuthenticationConfigurationConfiguration(UByte step, config_setting_t *setting, PancakeConfigurationScope **scope) { PancakeAuthenticationConfiguration *config = NULL; if(step == PANCAKE_CONFIGURATION_INIT) { UInt32 length = strlen(setting->value.sval); HASH_FIND(hh, PancakeAuthenticationConfigurations, setting->value.sval, length, config); if(config == NULL) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Unknown authentication configuration %s", setting->value.sval); return 0; } free(setting->value.sval); setting->type = CONFIG_TYPE_SPECIAL; setting->value.sval = (void*) config; } else { // Make library happy setting->type = CONFIG_TYPE_NONE; } return 1; }
STATIC void PancakeLinuxPollWait() { // Initialize with size 32 on old kernels PancakeLinuxPollFD = epoll_create(32); if(PancakeLinuxPollFD == -1) { PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "Can't create epoll instance: %s", strerror(errno)); return; } // Activate listen sockets PancakeNetworkActivateListenSockets(); while(1) { struct epoll_event events[32]; Int32 numEvents, i; numEvents = epoll_wait(PancakeLinuxPollFD, events, 32, PancakeSchedulerGetNextExecutionTimeOffset() * 1000); if(UNEXPECTED(numEvents == -1)) { if(PancakeDoShutdown) { return; } if(errno == EINTR) { continue; } PancakeLoggerFormat(PANCAKE_LOGGER_ERROR, 0, "epoll_wait failed: %s", strerror(errno)); return; } // Network events first for(i = 0; i < numEvents; i++) { PancakeSocket *sock = (PancakeSocket*) events[i].data.ptr; if(((events[i].events & EPOLLHUP) && !(events[i].events & EPOLLRDHUP)) || (events[i].events & EPOLLERR)) { sock->onRemoteHangup(sock); PancakeCheckHeap(); continue; } currentSocket = sock; if(events[i].events & EPOLLIN) { sock->onRead(sock); PancakeCheckHeap(); } if(events[i].events & EPOLLOUT) { // Socket has been closed in onRead() if(!currentSocket) { continue; } sock->onWrite(sock); PancakeCheckHeap(); } if(events[i].events & EPOLLRDHUP) { // Socket has been closed in onWrite() if(!currentSocket) { continue; } sock->onRemoteHangup(sock); PancakeCheckHeap(); } } // Scheduler events second PancakeSchedulerRun(); if(UNEXPECTED(PancakeDoShutdown)) { return; } } }