Exemplo n.º 1
0
int nb_readx(int handle, int offset, int size, int ret_size)
{
    int     i;
    ssize_t ret;
    char    FileName[128];
    char    temp[512];
    DWORD   gle;

    sprintf(FileName, "Thread_%05d.log", ProcessNumber);

    if ((i = FindHandle(handle)) == -1)
        return(-1);

    StartFirstTimer();
    ret = nb_read(ftable[i].fd, IoBuffer, offset, size);
    gle = GetLastError();
    if ((ret != size) && (ret != ret_size))
    {
        EndFirstTimer(CMD_READX, 0);
        LeaveThread(0, "", CMD_READX);
        if (ret == 0)
            sprintf(temp, "File: read failed on index=%d, offset=%d ReadSize=%d ActualRead=%d handle=%p GLE(0x%x)\n",
                    handle, offset, size, ret, ftable[i].fd, gle);
        if (ret == -1)
            sprintf(temp, "File: %s. On read, cannot set file pointer GLE(0x%x)\n", ftable[i].name, gle);
        if (verbose)
            printf("%s", temp);
        nb_close(handle);
        LogMessage(ProcessNumber, HostName, FileName, temp, LogID);
        return(-1);
    }
    EndFirstTimer(CMD_READX, 1);
    ftable[i].reads++;
    return(0);
}
Exemplo n.º 2
0
/*
 * Broker a FastCGI process child.
 * Return zero on failure and non-zero on success.
 */
static int
dochild_fcgi(kcgi_regress_server child, void *carg)
{
	int			 in, rc, fd;
	size_t			 sz, len;
	pid_t			 pid;
	struct sockaddr_un	 sun;
	struct sockaddr		*ss;
	ssize_t			 ssz;
	extern char		*__progname;
	char			 sfn[22];
	char			 buf[BUFSIZ];
	struct fcgi_hdr		 hdr;
	mode_t		  	 mode;

	/* 
	 * Create a temporary file, close it, then unlink it.
	 * The child will recreate this as a socket.
	 */

	strlcpy(sfn, "/tmp/kfcgi.XXXXXXXXXX", sizeof(sfn));

	/* This shuts up Coverity. */

	mode = umask(S_IXUSR | S_IRWXG | S_IRWXO);
	if (-1 == (fd = mkstemp(sfn))) {
		perror(sfn);
		return(0);
	} else if (-1 == close(fd) || -1 == unlink(sfn)) {
		perror(sfn);
		return(0);
	}
	umask(mode);

	/* Do the usual dance to set up UNIX sockets. */

	ss = (struct sockaddr *)&sun;
	memset(&sun, 0, sizeof(sun));
	sun.sun_family = AF_UNIX;
	sz = strlcpy(sun.sun_path, sfn, sizeof(sun.sun_path));
	if (sz >= sizeof(sun.sun_path)) {
		fprintf(stderr, "socket path to long\n");
		return(0);
	}
#ifndef __linux__
	sun.sun_len = sz;
#endif

	if (-1 == (fd = socket(AF_UNIX, SOCK_STREAM, 0))) {
		perror("socket");
		return(0);
	} else if (-1 == bind(fd, ss, sizeof(sun))) {
		perror(sfn);
		close(fd);
		return(0);
	} else if (-1 == listen(fd, 5)) {
		perror(sfn);
		close(fd);
		return(0);
	}

	/*
	 * Now fork the FastCGI process.
	 * We need to use a separate process because we're going to
	 * package the request as a FastCGI request and ship it into the
	 * UNIX socket.
	 */

	if (-1 == (pid = fork())) {
		perror("fork");
		unlink(sfn);
		close(fd);
		return(0);
	} else if (0 == pid) {
		if (-1 == dup2(fd, STDIN_FILENO))
			_exit(EXIT_FAILURE);
		close(fd);
		return(child(carg));
	}

	/* 
	 * Close the socket, as we're going to connect to it.
	 * The child has a reference to the object (via its dup2), so
	 * we're not going to totally remove the file.
	 */

	close(fd);
	fd = in = -1;
	rc = 0;

	/* Get the next incoming connection and FILE-ise it. */

	if (-1 == (in = dochild_prepare())) 
		goto out;

	/*
	 * Open a new socket to the FastCGI object and connect to it,
	 * reusing the prior socket address.
	 * Then remove the object, as nobody needs it any more.
	 */

	if (-1 == (fd = socket(AF_UNIX, SOCK_STREAM, 0))) {
		perror(sfn);
		goto out;
	} else if (-1 == connect(fd, ss, sizeof(sun))) {
		perror(sfn);
		goto out;
	} else if (-1 == unlink(sfn)) {
		perror(sfn);
		goto out;
	} 
	sfn[0] = '\0';

	/* Write the request, its parameters, and all data. */

	if ( ! fcgi_begin_write(fd))
		goto out;
	else if ( ! dochild_params(in, &fd, &len, dochild_params_fcgi))
		goto out;

	/*
	 * We might not have any data to read from the server, so
	 * remember whether a Content-Type was stipulated and only
	 * download data if it was.
	 * This is required because we'll just sit here waiting for data
	 * otherwise.
	 * Note: "in" is non-blocking, so be respectful.
	 */

	while (len > 0) {
		ssz = nb_read(in, buf, 
			len < sizeof(buf) ? len : sizeof(buf));
		if (ssz < 0) {
			perror("read");
			goto out;
		} else if (0 == ssz)
			break;

		if ( ! fcgi_data_write(fd, buf, ssz)) {
			fprintf(stderr, "%s: stdout\n", __func__);
			goto out;
		}
		len -= ssz;
	}

	/* Indicate end of input. */

	if ( ! fcgi_data_write(fd, NULL, 0)) {
		fprintf(stderr, "%s: stdout (FIN)\n", __func__);
		goto out;
	}

	/*
	 * Now we read the response, funneling it to the output.
	 * Stop reading on error or when we receive the end of data
	 * token from the FastCGI client.
	 */

	while (fcgi_hdr_read(fd, &hdr)) {
		if (3 == hdr.type) {
			/* End of message. */
			if ( ! fcgi_end_read(fd, &rc)) {
				fprintf(stderr, "%s: bad fin\n", __func__);
				goto out;
			}
			break;
		} else if (6 != hdr.type) {
			fprintf(stderr, "%s: bad type: %" 
				PRIu8 "\n", __func__, hdr.type);
			goto out;
		}

		/* Echo using a temporary buffer. */

		while (hdr.contentLength > 0) {
			sz = hdr.contentLength > BUFSIZ ? 
				BUFSIZ : hdr.contentLength;
			if (fcgi_read(fd, buf, sz)) {
				if ( ! nb_write(in, buf, sz))
					goto out;
				hdr.contentLength -= sz;
				continue;
			} else
				fprintf(stderr, "%s: bad read\n", __func__);
			goto out;
		}
		if (0 == fcgi_ignore(fd, hdr.paddingLength)) {
			fprintf(stderr, "%s: bad ignore\n", __func__);
			goto out;
		} 
	}
out:
	/* 
	 * Begin by asking the child to exit.
	 * Then close all of our comm channels.
	 */

	kill(pid, SIGTERM);
	if (-1 != in)
		close(in);
	if ('\0' != sfn[0])
		unlink(sfn);
	if (-1 != fd)
		close(fd);

	/*
	 * Now mandate that the child dies and reap its resources.
	 * FIXME: we might kill the process before it's done actually
	 * terminating, which is unfair and will raise spurious
	 * warnings elsewhere.
	 */

	if (-1 == waitpid(pid, NULL, 0))
		perror("waitpid");
	return(rc);
}
Exemplo n.º 3
0
/*
 * Parse HTTP header lines from input.
 * This obviously isn't the best way of doing things, but it's simple
 * and easy to fix for the purposes of this regression suite.
 * This will continually parse lines from `fd' until it reaches a blank
 * line, at which point it will return control.
 * It returns zero on failure (read failure, or possibly write failure
 * when serialising to the CGI context) or non-zero on success.
 */
static int
dochild_params(int fd, void *arg, size_t *length,
	int (*fp)(const char *, const char *, void *)) 
{
	int		 first;
	char		 head[BUFSIZ], buf[BUFSIZ];
	ssize_t		 ssz;
	size_t		 sz;
	char		*cp, *path, *query, *key, *val;
	char		 c;
	extern char	*__progname;

	if (NULL != length)
		*length = 0;

	if ( ! fp("SCRIPT_NAME", __progname, arg))
		return(0);

	/*
	 * Read header lines without buffering and clobbering the data
	 * yet to be read on the wire.
	 * Process them as the environment input to our CGI.
	 */

	for (first = 1;;) {
		/*
		 * Start by reading the header itself into a
		 * fixed-length buffer, making sure to respect that the
		 * descriptor is non-blocking.
		 */

		for (sz = 0; sz < BUFSIZ; ) {
			ssz = nb_read(fd, &c, 1);
			if (ssz < 0) {
				perror("read");
				return(0);
			} else if (0 == ssz || '\n' == (head[sz++] = c))
				break;
		}

		/* Strip CRLF. */

		if (sz < 2 || sz == BUFSIZ) {
			fprintf(stderr, "Bad HTTP header\n");
			return(0);
		} else if ('\r' != head[sz - 2]) {
			fprintf(stderr, "Bad HTTP header CRLF\n");
			return(0);
		}
		head[sz - 2] = '\0';

		/* Empty line: now we're at the CGI document. */

		if ('\0' == head[0])
			break;

		/* Process our header. */

		if (first) {
			/* Snarf the first GET/POST line. */

			if (0 == strncmp(head, "GET ", 4)) {
				if ( ! fp("REQUEST_METHOD", "GET", arg))
					return(0);
				path = head + 4;
			} else if (0 == strncmp(head, "POST ", 5)) {
				if ( ! fp("REQUEST_METHOD", "POST", arg))
					return(0);
				path = head + 5;
			} else {
				fprintf(stderr, "Unknown HTTP "
					"first line: %s\n", head);
				return(0);
			}

			/* Split this into the path and query. */

			cp = path;
			while ('\0' != *cp && ! isspace((int)*cp))
				cp++;
			*cp = '\0';
			if (NULL != (query = strchr(path, '?')))
				*query++ = '\0';

			first = 0;
			if ( ! fp("PATH_INFO", path, arg))
				return(0);
			if (NULL != query)
				if ( ! fp("QUERY_STRING", query, arg))
					return(0);
			continue;
		}

		/* 
		 * Split headers into key/value parts.
		 * Strip the leading spaces on the latter. 
		 * Let baddies (no value) just go by.
		 */

		key = head;
		if (NULL == (val = strchr(key, ':')))
			continue;
		*val++ = '\0';
		while ('\0' != *val && isspace((int)*val))
			val++;

		/* Recognise some attributes... */

		if (0 == strcmp(key, "Content-Length")) {
			if (NULL != length)
				*length = atoi(val);
			if ( ! fp("CONTENT_LENGTH", val, arg))
				return(0);
			continue;
		} else if (0 == strcmp(key, "Content-Type")) {
			if ( ! fp("CONTENT_TYPE", val, arg))
				return(0);
			continue;
		}

		/*
		 * Now we have "regular" attributes that we want to cast
		 * directly as HTTP attributes in the CGI environment.
		 */

		strlcpy(buf, "HTTP_", sizeof(buf));
		sz = strlcat(buf, key, sizeof(buf));
		assert(sz < sizeof(buf));
		for (cp = buf; '\0' != *cp; cp++) 
			if ('-' == *cp)
				*cp = '_';
			else if (isalpha((int)*cp))
				*cp = toupper((int)*cp);

		if ( ! fp(buf, val, arg))
			return(0);
	}

	return(1);
}