int nb_writex(int handle, int offset, int size, int ret_size) { int i; ssize_t status; char FileName[128]; char temp[512]; unsigned char magic = (unsigned char)getpid(); sprintf(FileName, "Thread_%05d.log", ProcessNumber); if (IoBuffer[0] != magic || IoBuffer[1] != magic || IoBuffer[2] != magic || IoBuffer[3] != magic) memset(IoBuffer, magic, BufferSize); if ((i = FindHandle(handle)) == -1) return(-1); StartFirstTimer(); status = nb_write(ftable[i].fd, IoBuffer, offset, size); if (status != ret_size) { EndFirstTimer(CMD_WRITEX, 0); LeaveThread(0, "", CMD_WRITEX); if (status == 0) sprintf(temp, "File: %s. wrote %d bytes, got %d bytes\n", ftable[i].name, size, status); if (status == -1) sprintf(temp, "File: %s. On write, cannot set file pointer\n", ftable[i].name); if (verbose) printf("%s", temp); nb_close(handle); if (verbose) printf("%s", temp); LogMessage(ProcessNumber, HostName, FileName, temp, LogID); return(-1); } EndFirstTimer(CMD_WRITEX, 1); ftable[i].writes++; return(0); }
/* * Broker a CGI process child. * Return zero on failure and non-zero on success. */ static int dochild_cgi(kcgi_regress_server child, void *carg) { int in, fd[2], rc; const char *msg; pid_t pid; char *vec, *end, *start, *cp, *ovec; size_t vecsz, headsz; void *pp; char buf[BUFSIZ]; ssize_t ssz; if (-1 == (in = dochild_prepare())) return(0); /* * We need to do some filtering from the CGI script's output * (just its Status message), so create a socketpair which we'll * use to scrub its output. * This is because the CGI protocol is stupid: it would have * been a lot easier to just require an HTTP status message, but * I guess the intent was to make the web server worry about * formatting for various versions of HTTP. * Whatever. */ if (-1 == socketpair(PF_LOCAL, SOCK_STREAM, 0, fd)) { perror("socketpair"); close(in); return(0); } /* Launch the actual CGI process. */ if (-1 == (pid = fork())) { perror("fork"); close(fd[0]); close(fd[1]); close(in); return(0); } else if (0 == pid) { close(fd[1]); /* * First, we suck down the HTTP headeres into our CGI * environment and run the child. * Next, re-assign our stdin to be the server's file * descriptor "in". * Then assign our stdout to be fd[0]. */ if ( ! dochild_params(in, NULL, NULL, dochild_params_cgi)) { close(in); close(fd[0]); return(0); } if (STDIN_FILENO != dup2(in, STDIN_FILENO)) { perror("dup2"); close(in); close(fd[0]); _exit(EXIT_FAILURE); } close(in); if (STDOUT_FILENO != dup2(fd[0], STDOUT_FILENO)) { perror("dup2"); close(fd[0]); return(0); } close(fd[0]); child(carg); _exit(in ? EXIT_SUCCESS : EXIT_FAILURE); } /* * We're in the parent. * Read and buffer the output of the CGI process until we get * its Status value. * Do so by copying through a static buffer into a growable * vector that we'll scan for the Status message to re-write. * Of course, if the CGI process is ill-designed, we'll consume * all of our memory and die. */ close(fd[0]); vecsz = 0; vec = end = NULL; rc = 0; while ((ssz = read(fd[1], buf, sizeof(buf))) > 0) { pp = realloc(vec, vecsz + ssz); if (NULL == pp) { perror("realloc"); goto out; } vec = pp; memcpy(vec + vecsz, buf, ssz); vecsz += ssz; end = memmem(vec, vecsz, "\r\n\r\n", 4); if (NULL != end) break; } if (ssz < 0) { perror("read"); goto out; } /* * Now all our headers are in vec plus extra; of if it's NULL, * we reached the end of input without getting headers. * Now we start to scan for the status line or dump. */ if (NULL != end) { /* Look for the status field. */ headsz = (size_t)(end - vec); start = memmem(vec, headsz, "Status:", 7); if (NULL == start) { /* * No status field. * This is Ok (according to CGI). * However, we do not provide a valid status, so * do what others do and 200 it. */ msg = "HTTP/1.1 200 OK\r\n"; if ( ! nb_write(in, msg, strlen(msg))) goto out; fprintf(stderr, "CGI script did " "not specify status\n"); ovec = vec; } else { /* * We found the status. * Print it out now, then everything that came * before it. */ msg = "HTTP/1.1"; if ( ! nb_write(in, msg, strlen(msg))) goto out; cp = start + 7; while (cp < end) { if ( ! nb_write(in, cp, 1)) goto out; cp++; if ('\n' == cp[-1]) break; } if ( ! nb_write(in, vec, (size_t)(start - vec))) goto out; vecsz -= (cp - vec); ovec = cp; } /* * Print everything else in our vector array, then poll * on the CGI script til its dry. */ if ( ! nb_write(in, ovec, vecsz)) goto out; while ((ssz = read(fd[1], buf, sizeof(buf))) > 0) if ( ! nb_write(in, buf, ssz)) goto out; if (ssz < 0) { perror("read"); goto out; } } else { if ( ! nb_write(in, vec, vecsz)) goto out; fprintf(stderr, "CGI script did " "not terminate headers\n"); } rc = 1; out: if (-1 == waitpid(pid, NULL, 0)) perror("waitpid"); free(vec); close(in); close(fd[1]); return(rc); }
/* run a test that simulates an approximate netbench client load */ static bool run_netbench(struct torture_context *tctx, struct smbcli_state *cli, int client) { int torture_nprocs = torture_setting_int(tctx, "nprocs", 4); int i; char line[1024]; char *cname; FILE *f; bool correct = true; double target_rate = torture_setting_double(tctx, "targetrate", 0); int n; if (target_rate != 0 && client == 0) { printf("Targetting %.4f MByte/sec\n", target_rate); } nb_setup(cli, client); if (torture_nprocs == 1) { if (!read_only) { NB_RETRY(torture_setup_dir(cli, "\\clients")); } } asprintf(&cname, "client%d", client+1); f = fopen(loadfile, "r"); if (!f) { perror(loadfile); return false; } again: nbio_time_reset(); while (fgets(line, sizeof(line)-1, f)) { NTSTATUS status; const char **params0, **params; nbench_line_count++; line[strlen(line)-1] = 0; all_string_sub(line,"client1", cname, sizeof(line)); params = params0 = str_list_make_shell(NULL, line, " "); i = str_list_length(params); if (i > 0 && isdigit(params[0][0])) { double targett = strtod(params[0], NULL); if (target_rate != 0) { nbio_target_rate(target_rate); } else { nbio_time_delay(targett); } params++; i--; } else if (target_rate != 0) { nbio_target_rate(target_rate); } if (i < 2 || params[0][0] == '#') continue; if (!strncmp(params[0],"SMB", 3)) { printf("ERROR: You are using a dbench 1 load file\n"); nb_exit(1); } if (strncmp(params[i-1], "NT_STATUS_", 10) != 0 && strncmp(params[i-1], "0x", 2) != 0) { printf("Badly formed status at line %d\n", nbench_line_count); talloc_free(params); continue; } /* accept numeric or string status codes */ if (strncmp(params[i-1], "0x", 2) == 0) { status = NT_STATUS(strtoul(params[i-1], NULL, 16)); } else { status = nt_status_string_to_code(params[i-1]); } DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1])); if (!strcmp(params[0],"NTCreateX")) { NB_RETRY(nb_createx(params[1], ival(params[2]), ival(params[3]), ival(params[4]), status)); } else if (!strcmp(params[0],"Close")) { NB_RETRY(nb_close(ival(params[1]), status)); } else if (!read_only && !strcmp(params[0],"Rename")) { NB_RETRY(nb_rename(params[1], params[2], status, n>0)); } else if (!read_only && !strcmp(params[0],"Unlink")) { NB_RETRY(nb_unlink(params[1], ival(params[2]), status, n>0)); } else if (!read_only && !strcmp(params[0],"Deltree")) { NB_RETRY(nb_deltree(params[1], n>0)); } else if (!read_only && !strcmp(params[0],"Rmdir")) { NB_RETRY(nb_rmdir(params[1], status, n>0)); } else if (!read_only && !strcmp(params[0],"Mkdir")) { NB_RETRY(nb_mkdir(params[1], status, n>0)); } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) { NB_RETRY(nb_qpathinfo(params[1], ival(params[2]), status)); } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) { NB_RETRY(nb_qfileinfo(ival(params[1]), ival(params[2]), status)); } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) { NB_RETRY(nb_qfsinfo(ival(params[1]), status)); } else if (!read_only && !strcmp(params[0],"SET_FILE_INFORMATION")) { NB_RETRY(nb_sfileinfo(ival(params[1]), ival(params[2]), status)); } else if (!strcmp(params[0],"FIND_FIRST")) { NB_RETRY(nb_findfirst(params[1], ival(params[2]), ival(params[3]), ival(params[4]), status)); } else if (!read_only && !strcmp(params[0],"WriteX")) { NB_RETRY(nb_writex(ival(params[1]), ival(params[2]), ival(params[3]), ival(params[4]), status)); } else if (!read_only && !strcmp(params[0],"Write")) { NB_RETRY(nb_write(ival(params[1]), ival(params[2]), ival(params[3]), ival(params[4]), status)); } else if (!strcmp(params[0],"LockX")) { NB_RETRY(nb_lockx(ival(params[1]), ival(params[2]), ival(params[3]), status)); } else if (!strcmp(params[0],"UnlockX")) { NB_RETRY(nb_unlockx(ival(params[1]), ival(params[2]), ival(params[3]), status)); } else if (!strcmp(params[0],"ReadX")) { NB_RETRY(nb_readx(ival(params[1]), ival(params[2]), ival(params[3]), ival(params[4]), status)); } else if (!strcmp(params[0],"Flush")) { NB_RETRY(nb_flush(ival(params[1]), status)); } else if (!strcmp(params[0],"Sleep")) { nb_sleep(ival(params[1]), status); } else { printf("[%d] Unknown operation %s\n", nbench_line_count, params[0]); } if (n > nb_max_retries) { printf("Maximum reconnect retries reached for op '%s'\n", params[0]); nb_exit(1); } talloc_free(params0); if (nb_tick()) goto done; } rewind(f); goto again; done: fclose(f); if (!read_only && torture_nprocs == 1) { smbcli_deltree(cli->tree, "\\clients"); } if (!torture_close_connection(cli)) { correct = false; } return correct; }
/* * 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); }