ObjectPtr findObject(int type, const void *key, int key_size) { int h; ObjectPtr object; if(key_size >= 50000) return NULL; h = hash(type, key, key_size, log2ObjectHashTableSize); object = objectHashTable[h]; if(!object) return NULL; if(object->type != type || object->key_size != key_size || memcmp(object->key, key, key_size) != 0) { return NULL; } if(object->next) object->next->previous = object->previous; if(object->previous) object->previous->next = object->next; if(object_list == object) object_list = object->next; if(object_list_end == object) object_list_end = object->previous; object->previous = NULL; object->next = object_list; if(object_list) object_list->previous = object; object_list = object; if(!object_list_end) object_list_end = object; return retainObject(object); }
static void fillSpecialObject(ObjectPtr object, void (*fn) (FILE *, char *), void *closure) { int rc; int filedes[2]; pid_t pid; sigset_t ss, old_mask; if (object->flags & OBJECT_INPROGRESS) return; rc = pipe(filedes); if (rc < 0) { do_log_error(L_ERROR, errno, "Couldn't create pipe"); abortObject(object, 503, internAtomError(errno, "Couldn't create pipe")); return; } fflush(stdout); fflush(stderr); flushLog(); interestingSignals(&ss); do { rc = sigprocmask(SIG_BLOCK, &ss, &old_mask); } while (rc < 0 && errno == EINTR); if (rc < 0) { do_log_error(L_ERROR, errno, "Sigprocmask failed"); abortObject(object, 503, internAtomError(errno, "Sigprocmask failed")); close(filedes[0]); close(filedes[1]); return; } pid = fork(); if (pid < 0) { do_log_error(L_ERROR, errno, "Couldn't fork"); abortObject(object, 503, internAtomError(errno, "Couldn't fork")); close(filedes[0]); close(filedes[1]); do { rc = sigprocmask(SIG_SETMASK, &old_mask, NULL); } while (rc < 0 && errno == EINTR); if (rc < 0) { do_log_error(L_ERROR, errno, "Couldn't restore signal mask"); s_serverExit(); } return; } if (pid > 0) { SpecialRequestPtr request; close(filedes[1]); do { rc = sigprocmask(SIG_SETMASK, &old_mask, NULL); } while (rc < 0 && errno == EINTR); if (rc < 0) { do_log_error(L_ERROR, errno, "Couldn't restore signal mask"); s_serverExit(); return; } request = malloc(sizeof(SpecialRequestRec)); if (request == NULL) { kill(pid, SIGTERM); close(filedes[0]); abortObject(object, 503, internAtom("Couldn't allocate request\n")); notifyObject(object); } else { request->buf = get_chunk(); if (request->buf == NULL) { kill(pid, SIGTERM); close(filedes[0]); free(request); abortObject(object, 503, internAtom ("Couldn't allocate request\n")); notifyObject(object); } } object->flags |= OBJECT_INPROGRESS; retainObject(object); request->object = object; request->fd = filedes[0]; request->pid = pid; request->offset = 0; do_stream(IO_READ, filedes[0], 0, request->buf, CHUNK_SIZE, specialRequestHandler, request); } else { close(filedes[0]); uninitEvents(); do { rc = sigprocmask(SIG_SETMASK, &old_mask, NULL); } while (rc < 0 && errno == EINTR); if (rc < 0) exit(1); if (filedes[1] != 1) dup2(filedes[1], 1); (*fn) (stdout, closure); exit(0); } }
static int really_do_dns(AtomPtr name, ObjectPtr object) { int rc; DnsQueryPtr query; AtomPtr message = NULL; int id; AtomPtr a = NULL; if(a == NULL) { if(name == atomLocalhost || name == atomLocalhostDot) { char s[1 + sizeof(HostAddressRec)]; memset(s, 0, sizeof(s)); s[0] = DNS_A; s[1] = 4; s[2] = 127; s[3] = 0; s[4] = 0; s[5] = 1; a = internAtomN(s, 1 + sizeof(HostAddressRec)); if(a == NULL) { abortObject(object, 501, internAtom("Couldn't allocate address")); notifyObject(object); errno = ENOMEM; return -1; } } } if(a == NULL) { struct in_addr ina; rc = inet_aton(name->string, &ina); if(rc == 1) { char s[1 + sizeof(HostAddressRec)]; memset(s, 0, sizeof(s)); s[0] = DNS_A; s[1] = 4; memcpy(s + 2, &ina, 4); a = internAtomN(s, 1 + sizeof(HostAddressRec)); if(a == NULL) { abortObject(object, 501, internAtom("Couldn't allocate address")); notifyObject(object); errno = ENOMEM; return -1; } } } #ifdef HAVE_IPv6 if(a == NULL) a = rfc2732(name); #endif if(a) { object->headers = a; object->age = current_time.tv_sec; object->expires = current_time.tv_sec + 240; object->flags &= ~(OBJECT_INITIAL | OBJECT_INPROGRESS); notifyObject(object); return 0; } rc = establishDnsSocket(); if(rc < 0) { do_log_error(L_ERROR, -rc, "Couldn't establish DNS socket.\n"); message = internAtomError(-rc, "Couldn't establish DNS socket"); goto fallback; } /* The id is used to speed up detecting replies to queries that are no longer current -- see dnsReplyHandler. */ id = (idSeed++) & 0xFFFF; query = malloc(sizeof(DnsQueryRec)); if(query == NULL) { do_log(L_ERROR, "Couldn't allocate DNS query.\n"); message = internAtom("Couldn't allocate DNS query"); goto fallback; } query->id = id; query->inet4 = NULL; query->inet6 = NULL; query->name = name; query->time = current_time.tv_sec; query->object = retainObject(object); query->timeout = 4; query->timeout_handler = NULL; query->next = NULL; query->timeout_handler = scheduleTimeEvent(query->timeout, dnsTimeoutHandler, sizeof(query), &query); if(query->timeout_handler == NULL) { do_log(L_ERROR, "Couldn't schedule DNS timeout handler.\n"); message = internAtom("Couldn't schedule DNS timeout handler"); goto free_fallback; } insertQuery(query); object->flags |= OBJECT_INPROGRESS; rc = sendQuery(query); if(rc < 0) { if(rc != -EWOULDBLOCK && rc != -EAGAIN && rc != -ENOBUFS) { object->flags &= ~OBJECT_INPROGRESS; message = internAtomError(-rc, "Couldn't send DNS query"); goto remove_fallback; } /* else let it timeout */ } releaseAtom(message); return 1; remove_fallback: removeQuery(query); free_fallback: releaseObject(query->object); cancelTimeEvent(query->timeout_handler); free(query); fallback: if(dnsUseGethostbyname >= 1) { releaseAtom(message); do_log(L_WARN, "Falling back on gethostbyname.\n"); return really_do_gethostbyname(name, object); } else { abortObject(object, 501, message); notifyObject(object); return 1; } }
static void fillSpecialObject(ObjectPtr object, void (*fn)(FILE*, char*), void* closure) { int rc; int filedes[2]; pid_t pid; sigset_t ss, old_mask; if(object->flags & OBJECT_INPROGRESS) return; rc = pipe(filedes); if(rc < 0) { do_log_error(L_ERROR, errno, "Couldn't create pipe"); abortObject(object, 503, internAtomError(errno, "Couldn't create pipe")); return; } fflush(stdout); fflush(stderr); flushLog(); /* Block signals that we handle specially until the child can disable the handlers. */ interestingSignals(&ss); /* I'm a little confused. POSIX doesn't allow EINTR here, but I think that both Linux and SVR4 do. */ do { rc = sigprocmask(SIG_BLOCK, &ss, &old_mask); } while (rc < 0 && errno == EINTR); if(rc < 0) { do_log_error(L_ERROR, errno, "Sigprocmask failed"); abortObject(object, 503, internAtomError(errno, "Sigprocmask failed")); close(filedes[0]); close(filedes[1]); return; } pid = fork(); if(pid < 0) { do_log_error(L_ERROR, errno, "Couldn't fork"); abortObject(object, 503, internAtomError(errno, "Couldn't fork")); close(filedes[0]); close(filedes[1]); do { rc = sigprocmask(SIG_SETMASK, &old_mask, NULL); } while (rc < 0 && errno == EINTR); if(rc < 0) { do_log_error(L_ERROR, errno, "Couldn't restore signal mask"); polipoExit(); } return; } if(pid > 0) { SpecialRequestPtr request; close(filedes[1]); do { rc = sigprocmask(SIG_SETMASK, &old_mask, NULL); } while (rc < 0 && errno == EINTR); if(rc < 0) { do_log_error(L_ERROR, errno, "Couldn't restore signal mask"); polipoExit(); return; } request = malloc(sizeof(SpecialRequestRec)); if(request == NULL) { kill(pid, SIGTERM); close(filedes[0]); abortObject(object, 503, internAtom("Couldn't allocate request\n")); notifyObject(object); return; } else { request->buf = get_chunk(); if(request->buf == NULL) { kill(pid, SIGTERM); close(filedes[0]); free(request); abortObject(object, 503, internAtom("Couldn't allocate request\n")); notifyObject(object); return; } } object->flags |= OBJECT_INPROGRESS; retainObject(object); request->object = object; request->fd = filedes[0]; request->pid = pid; request->offset = 0; /* Under any sensible scheduler, the child will run before the parent. So no need for IO_NOTNOW. */ do_stream(IO_READ, filedes[0], 0, request->buf, CHUNK_SIZE, specialRequestHandler, request); } else { /* child */ close(filedes[0]); uninitEvents(); do { rc = sigprocmask(SIG_SETMASK, &old_mask, NULL); } while (rc < 0 && errno == EINTR); if(rc < 0) exit(1); if(filedes[1] != 1) dup2(filedes[1], 1); (*fn)(stdout, closure); exit(0); } }