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); }
/* * 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); }
/* * 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); }