Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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);
	}
}
Exemplo n.º 3
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;
    }
}
Exemplo n.º 4
0
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);
    }
}