static void gracefulShutdown(MprTime timeout) { HWND hwnd; hwnd = FindWindow(BLD_PRODUCT, BLD_NAME); if (hwnd) { PostMessage(hwnd, WM_QUIT, 0, 0L); /* Wait for up to ten seconds while the service exits */ while (timeout > 0 && hwnd) { mprSleep(100); timeout -= 100; hwnd = FindWindow(BLD_PRODUCT, BLD_NAME); if (hwnd == 0) { return; } } } if (app->servicePid) { TerminateProcess((HANDLE) app->servicePid, MPR_EXIT_GRACEFUL); app->servicePid = 0; } }
/* Callback from httpLogin to verify credentials using the password defined in the database. */ static bool verifyUser(HttpStream *stream, cchar *username, cchar *password) { HttpAuth *auth; HttpUser *user; HttpRx *rx; EdiRec *urec; rx = stream->rx; auth = rx->route->auth; if ((urec = readRecWhere("user", "username", "==", username)) == 0) { httpLog(stream->trace, "auth.login.error", "error", "msg: 'Cannot verify user', username: '******'", username); return 0; } if (!mprCheckPassword(password, getField(urec, "password"))) { httpLog(stream->trace, "auth.login.error", "error", "msg: 'Password failed to authenticate', username: '******'", username); mprSleep(500); return 0; } /* Cache the user and define the user roles. Thereafter, the app can use "httpCanUser" to test if the user has the required abilities (defined by their roles) to perform a given request or operation. */ if ((user = httpLookupUser(auth, username)) == 0) { user = httpAddUser(auth, username, 0, ediGetFieldValue(urec, "roles")); } /* Define this as the authenticated and authorized user for this session */ httpSetStreamUser(stream, user); httpLog(stream->trace, "auth.login.authenticated", "context", "msg: 'User authenticated', username: '******'", username); return 1; }
/* This is called when unloading a view or controller module */ bool espUnloadModule(cchar *module, MprTime timeout) { MprModule *mp; MprTime mark; Esp *esp; /* MOB - should this suspend new requests */ if ((mp = mprLookupModule(module)) != 0) { esp = MPR->espService; mark = mprGetTime(); do { lock(esp); /* Own request will count as 1 */ if (esp->inUse <= 1) { mprUnloadModule(mp); unlock(esp); return 1; } unlock(esp); mprSleep(10); /* Defaults to 10 secs */ } while (mprGetRemainingTime(mark, timeout) > 0); } return 0; }
static bool stopService(int cmd) { int exitCode; app->exiting = 1; app->serviceStopped = 1; gracefulShutdown(10 * 1000); if (cmd == SERVICE_CONTROL_SHUTDOWN) { return 1; } /* Wakeup service event. This will make it exit. */ SetEvent(app->serviceThreadEvent); svcStatus.dwCurrentState = SERVICE_STOP_PENDING; tellSCM(svcStatus.dwCurrentState, NO_ERROR, 1000); exitCode = 0; GetExitCodeThread(app->threadHandle, (ulong*) &exitCode); while (exitCode == STILL_ACTIVE) { GetExitCodeThread(app->threadHandle, (ulong*) &exitCode); mprSleep(100); tellSCM(svcStatus.dwCurrentState, NO_ERROR, 125); } svcStatus.dwCurrentState = SERVICE_STOPPED; tellSCM(svcStatus.dwCurrentState, exitCode, 0); return 1; }
int Mpr::killMpr() { HWND hwnd; int i; hwnd = FindWindow(getAppName(), getAppTitle()); if (hwnd) { PostMessage(hwnd, WM_QUIT, 0, 0L); // // Wait for up to ten seconds while winAppWeb exits // for (i = 0; hwnd && i < 100; i++) { mprSleep(100); hwnd = FindWindow(getAppName(), getAppTitle()); } if (hwnd == 0) { return 0; } } else { mprError(MPR_L, MPR_USER, "Can't find %s to kill", getAppName()); } return -1; }
int MprWinService::stop(int cmd) { int exitCode; svcStopped++; mprGetMpr()->terminate(1); if (cmd == SERVICE_CONTROL_SHUTDOWN) { return 0; } SetEvent(waitEvent); svcStatus.dwCurrentState = SERVICE_STOP_PENDING; tellScm(svcStatus.dwCurrentState, NO_ERROR, 1000); exitCode = 0; GetExitCodeThread(threadHandle, (ulong*) &exitCode); while (exitCode == STILL_ACTIVE) { GetExitCodeThread(threadHandle, (ulong*) &exitCode); mprSleep(100); tellScm(svcStatus.dwCurrentState, NO_ERROR, 125); } svcStatus.dwCurrentState = SERVICE_STOPPED; tellScm(svcStatus.dwCurrentState, exitCode, 0); return 0; }
static int windowsServiceOps() { winService = new MprWinService(APPWEB_SERVICE_NAME); switch (serviceOp) { case MPR_INSTALL_SERVICE: char path[MPR_MAX_FNAME], cmd[MPR_MAX_FNAME]; GetModuleFileName(0, path, sizeof(path)); mprSprintf(cmd, sizeof(cmd), "\"%s\" %s", path, serviceCmdLine); winService->install(APPWEB_SERVICE_DISPLAY, cmd); break; case MPR_UNINSTALL_SERVICE: winService->remove(1); break; case MPR_GO_SERVICE: winService->start(); // // Give time for service to actually start // mprSleep(2000); break; case MPR_STOP_SERVICE: winService->remove(0); break; } if (isService) { mprGetMpr()->setService(1); } return 0; }
/* This is called when unloading a view or controller module All of ESP must be quiesced. */ static bool espUnloadModule(cchar *module, MprTicks timeout) { MprModule *mp; MprTicks mark; if ((mp = mprLookupModule(module)) != 0) { mark = mprGetTicks(); esp->reloading = 1; do { lock(esp); /* Own request will count as 1 */ if (esp->inUse <= 1) { if (mprUnloadModule(mp) < 0) { mprLog("error esp", 0, "Cannot unload module %s", mp->name); unlock(esp); } esp->reloading = 0; unlock(esp); return 1; } unlock(esp); mprSleep(10); } while (mprGetRemainingTicks(mark, timeout) > 0); esp->reloading = 0; } return 0; }
PUBLIC bool httpConfigure(HttpConfigureProc proc, void *data, MprTicks timeout) { Http *http; MprTicks mark; http = HTTP; mark = mprGetTicks(); if (timeout < 0) { timeout = http->serverLimits->requestTimeout; } else if (timeout == 0) { timeout = MAXINT; } do { lock(http->connections); /* Own request will count as 1 */ if (mprGetListLength(http->connections) == 0) { (proc)(data); unlock(http->connections); return 1; } unlock(http->connections); mprSleep(10); /* Defaults to 10 secs */ } while (mprGetRemainingTicks(mark, timeout) > 0); return 0; }
/* * Gracefull shutdown for Appweb */ static void shutdownAppweb(int timeout) { HWND hwnd; hwnd = FindWindow(BLD_PRODUCT, BLD_NAME); if (hwnd) { PostMessage(hwnd, WM_QUIT, 0, 0L); /* * Wait for up to ten seconds while the service exits */ while (timeout > 0 && hwnd) { mprSleep(mpr, 100); timeout -= 100; hwnd = FindWindow(BLD_PRODUCT, BLD_NAME); if (hwnd == 0) { return; } } } if (servicePid) { TerminateProcess((HANDLE) servicePid, 2); servicePid = 0; } }
/* * Remove the application service. */ static int removeService(int removeFromScmDb) { SC_HANDLE svc, mgr; exiting = 1; mgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (! mgr) { mprError(mpr, "Can't open service manager"); return MPR_ERR_CANT_ACCESS; } svc = OpenService(mgr, serviceName, SERVICE_ALL_ACCESS); if (! svc) { CloseServiceHandle(mgr); mprError(mpr, "Can't open service"); return MPR_ERR_CANT_OPEN; } /* * Gracefull shutdown */ shutdownAppweb(0); if (ControlService(svc, SERVICE_CONTROL_STOP, &svcStatus)) { mprSleep(mpr, 500); while (QueryServiceStatus(svc, &svcStatus)) { if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) { mprSleep(mpr, 250); } else { break; } } if (svcStatus.dwCurrentState != SERVICE_STOPPED) { mprError(mpr, "Can't stop service: %x", GetLastError()); } } if (removeFromScmDb && !DeleteService(svc)) { mprError(mpr, "Can't delete service: %x", GetLastError()); } CloseServiceHandle(svc); CloseServiceHandle(mgr); return 0; }
int MprWinService::remove(int removeFromScmDb) { SC_HANDLE svc, mgr; mgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (! mgr) { mprError(MPR_L, MPR_LOG, "Can't open service manager"); return MPR_ERR_CANT_ACCESS; } svc = OpenService(mgr, svcName, SERVICE_ALL_ACCESS); if (! svc) { CloseServiceHandle(mgr); mprError(MPR_L, MPR_LOG, "Can't open service"); return MPR_ERR_CANT_OPEN; } // // Stop the application // mprGetMpr()->killMpr(); if (ControlService(svc, SERVICE_CONTROL_STOP, &svcStatus)) { mprSleep(500); while (QueryServiceStatus(svc, &svcStatus)) { if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) { mprSleep(250); } else { break; } } if (svcStatus.dwCurrentState != SERVICE_STOPPED) { mprError(MPR_L, MPR_LOG, "Can't stop service: %x", GetLastError()); } } if (removeFromScmDb && !DeleteService(svc)) { mprError(MPR_L, MPR_LOG, "Can't delete service: %x", GetLastError()); } CloseServiceHandle(svc); CloseServiceHandle(mgr); return 0; }
void MprLogToFile::logConfig() { Mpr *mpr; time_t now; char timeText[80]; mpr = mprGetMpr(); if (mpr == 0) { return; } now = time(0); mprCtime(&now, timeText, sizeof(timeText)); mprLog(MPR_CONFIG, "Configuration for %s\n", mpr->getAppTitle()); mprLog(MPR_CONFIG, "--------------------------------------------\n"); mprLog(MPR_CONFIG, "Host: %s\n", mpr->getHostName()); mprLog(MPR_CONFIG, "CPU: %s\n", mpr->getCpu()); mprLog(MPR_CONFIG, "OS: %s\n", mpr->getOs()); mprLog(MPR_CONFIG, "Distribution: %s %s\n", BLD_HOST_DIST, BLD_HOST_DIST_VER); mprLog(MPR_CONFIG, "OS: %s\n", mpr->getOs()); mprLog(MPR_CONFIG, "Version: %s.%d\n", mpr->getVersion(), mpr->getBuildNumber()); mprLog(MPR_CONFIG, "BuildType: %s\n", mpr->getBuildType()); mprLog(MPR_CONFIG, "Started at: %s", timeText); mprLog(MPR_CONFIG, "Log rotation count: %d\n", rotationCount); mprLog(MPR_CONFIG, "--------------------------------------------\n"); #if BLD_DEBUG #if BLD_FEATURE_HIRES_TIME int64 elapsed = mprGetElapsedTime(); mprSleep(250); elapsed = mprGetElapsedTime(); mprLog(4, "1 second is ~%,16Ld cycles\n", elapsed * 4); #else int elapsed = mprGetTime(0); mprSleep(250); elapsed = mprGetTime(0) - elapsed; mprLog(4, "1 second is ~%,8d cycles\n", elapsed * 4); #endif #endif }
int MaOpenSslSocket::write(char *buf, int len) { int rc, written, totalWritten; if (bio == 0 || ssl == 0 || len <= 0) { return -1; } BIO_clear_retry_flags(bio); totalWritten = 0; do { written = BIO_write(bio, buf, len); mprLog(7, "written %d, len %d\n", written, len); if (written >= 0) { do { rc = BIO_flush(bio); mprLog(7, "BIO_flush rc %d\n", rc); if (rc > 0) { // Success break; } // // Nap to prevent busy waiting. // mprSleep(10); } while (rc <= 0 && BIO_should_retry(bio)); totalWritten += written; buf += written; len -= written; } mprLog(7, "write: len %d, written %d, total %d, should_retry %d\n", len, written, totalWritten, BIO_should_retry(bio)); /* * If written is < 0 and an error occurred, then BIO_should_retry * will return false. */ } while (len > 0 && (written > 0 || BIO_should_retry(bio))); if (totalWritten <= 0 && BIO_should_retry(bio) == 0) { mprLog(7, "connection closed\n"); /* * If totalWritten is not Zero, then we don't return an Error. * Next time this function is called, it will return an Error. */ return -1; // return Error ( connection closed ) } return totalWritten; }
/* Remove the application service */ static bool removeService(int removeFromScmDb) { SC_HANDLE svc, mgr; app->exiting = 1; mgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (! mgr) { mprError("Can't open service manager"); return 0; } svc = OpenService(mgr, app->serviceName, SERVICE_ALL_ACCESS); if (! svc) { CloseServiceHandle(mgr); mprError("Can't open service"); return 0; } gracefulShutdown(0); if (ControlService(svc, SERVICE_CONTROL_STOP, &svcStatus)) { mprSleep(500); while (QueryServiceStatus(svc, &svcStatus)) { if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) { mprSleep(250); } else { break; } } if (svcStatus.dwCurrentState != SERVICE_STOPPED) { mprError("Can't stop service: 0x%x", GetLastError()); } } if (removeFromScmDb && !DeleteService(svc)) { if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) { mprError("Can't delete service: 0x%x", GetLastError()); } } CloseServiceHandle(svc); CloseServiceHandle(mgr); return 1; }
int MprThreadService::stop(int timeout) { // // Wait until all threads (except main thread) have exited // while (threads.getNumItems() > 1 && timeout > 0) { mprSleep(10); timeout -= 10; } return 0; }
int MprTestSession::runTests(MprTestResult *result) { int i; #if BLD_FEATURE_MULTITHREAD MprThread *tp; #endif for (i = 0; i < numThreads; i++) { if (sessions[i]->init() < 0) { return MPR_ERR_CANT_INITIALIZE; } } #if BLD_FEATURE_MULTITHREAD // // Now clone this session object for all other threads // for (i = 1; i < numThreads; i++) { char tName[64]; mprSprintf(tName, sizeof(tName), "test.%d", i); tp = new MprThread(runWrapper, MPR_NORMAL_PRIORITY, sessions[i], tName); if (tp->start() < 0) { break; } } #endif runWrapper(sessions[0], 0); #if BLD_FEATURE_MULTITHREAD // // Wait for all the threads to complete (simple but effective) // while (result->getThreadCount() > 1) { mprSleep(75); } #endif sessions[0]->terminateClasses(result); #if BLD_FEATURE_MULTITHREAD for (i = 1; i < numThreads; i++) { sessions[i]->term(); delete sessions[i]; } #endif mprFree(sessions); #if BLD_FEATURE_LOG mpr->logService->removeListener(logger); delete logger; #endif return 0; }
int MprCmd::waitInner(int timeout) { int err, status; lock(); if (handle == 0) { mprAssert(handle != 0); unlock(); return 0; } if (timeout) { if (WaitForSingleObject((HANDLE) handle, timeout) != WAIT_OBJECT_0) { mprAssert(0); unlock(); return MPR_ERR_TIMEOUT; } } do { if (GetExitCodeProcess((HANDLE) handle, (ulong*) &status) != 0) { if (status != STILL_ACTIVE) { mprLog(5, log, "waitInner: pid %d, status %d\n", pid, status); exitStatus = status; unlock(); return 0; } else { mprLog(5, log, "waitInner: pid %d, still active\n", pid); } } else { err = GetLastError(); mprAssert(0); unlock(); return MPR_ERR_BAD_STATE; } // // Seems we can wakeup from the wait and there still not be status // pending // mprSleep(50); } while (timeout > 0); // Should never get here unlock(); return MPR_ERR_TIMEOUT; }
static void testTimeBasics(MprTestGroup *gp) { MprTime mark, now, remaining, elapsed; mark = mprGetTime(gp); assert(mark != 0); remaining = mprGetRemainingTime(gp, mark, 30000); assert(0 <= remaining && remaining <= 30000); elapsed = mprGetElapsedTime(gp, mark); assert(0 <= elapsed && elapsed < 30000); mprSleep(gp, 20); now = mprGetTime(gp); assert(mprCompareTime(mark, now) < 0); }
/* Gracefull shutdown for Appweb */ static void shutdownAppweb() { HWND hwnd; int i; hwnd = FindWindow(MPR->name, MPR->name); if (hwnd) { PostMessage(hwnd, WM_QUIT, 0, 0L); /* Wait for up to ten seconds while the service exits */ for (i = 0; hwnd && i < 100; i++) { mprSleep(100); hwnd = FindWindow(MPR->name, MPR->name); } } else { mprError("appweb monitor", "Cannot find %s to kill", MPR->name); return; } }
/* Gracefull shutdown for Appweb */ static void shutdownAppweb() { HWND hwnd; int i; hwnd = FindWindow(app->serviceWindowName, app->serviceWindowTitle); if (hwnd) { PostMessage(hwnd, WM_QUIT, 0, 0L); /* Wait for up to ten seconds while the service exits */ for (i = 0; hwnd && i < 100; i++) { mprSleep(100); hwnd = FindWindow(app->serviceWindowName, app->serviceWindowTitle); } } else { mprError("Can't find %s to kill", app->serviceWindowTitle); return; } }
int Mpr::killMpr() { HWND hwnd; int i; hwnd = FindWindow(getAppName(), getAppTitle()); if (hwnd) { PostMessage(hwnd, WM_QUIT, 0, 0L); // // Wait for up to ten seconds while winAppweb exits // for (i = 0; hwnd && i < 100; i++) { mprSleep(100); hwnd = FindWindow(getAppName(), getAppTitle()); } if (hwnd = 0) { return 0; } } return -1; }
MprCmdFiles::~MprCmdFiles() { int j, i, rc, err; for (i = 0; i < MPR_CMD_MAX_FD; i++) { if (clientFd[i] >= 0) { close(clientFd[i]); clientFd[i] = -1; } if (serverFd[i] >= 0) { close(serverFd[i]); serverFd[i] = -1; } if (name[i]) { // // Windows seems to be very slow in cleaning up the child's // hold on the standard I/O file descriptors. Despite having // waited for the child to exit and having received exit status, // this unlink sometimes still gets a sharing violation. Ugh !!! // We need to retry here (for up to 60 seconds). Under extreme // load -- this may fail to unlink the file. // for (j = 0; j < 1000; j++) { rc = unlink(name[i]); if (rc == 0) { break; } err = GetLastError(); mprSleep(60); } if (j == 1000) { mprLog(0, "File busy, failed to unlink %s\n", name[i]); } mprFree(name[i]); } } }
/* * Stop the service in the current process. */ static int stopService(int cmd) { int exitCode; exiting = 1; serviceStopped = 1; /* * Gracefull shutdown */ shutdownAppweb(10 * 1000); if (cmd == SERVICE_CONTROL_SHUTDOWN) { return 0; } /* * Wakeup service event. This will make it exit. */ SetEvent(serviceThreadEvent); svcStatus.dwCurrentState = SERVICE_STOP_PENDING; tellSCM(svcStatus.dwCurrentState, NO_ERROR, 1000); exitCode = 0; GetExitCodeThread(threadHandle, (ulong*) &exitCode); while (exitCode == STILL_ACTIVE) { GetExitCodeThread(threadHandle, (ulong*) &exitCode); mprSleep(mpr, 100); tellSCM(svcStatus.dwCurrentState, NO_ERROR, 125); } svcStatus.dwCurrentState = SERVICE_STOPPED; tellSCM(svcStatus.dwCurrentState, exitCode, 0); return 0; }
/* * Collect the child's exit status. The initiating thread must do this on uClibc. * Return zero if the exit status is successfully reaped. Return -1 if an error * and return > 0 if process still running. */ int mprReapCmd(MprCmd *cmd, int timeout) { MprTime mark; mprAssert(cmd->pid); if (timeout < 0) { timeout = MAXINT; } mark = mprGetTime(cmd); while (cmd->pid) { #if BLD_UNIX_LIKE int status, waitrc; status = 0; if ((waitrc = waitpid(cmd->pid, &status, WNOHANG | __WALL)) < 0) { mprAssert(0); mprLog(cmd, 0, "waitpid failed for pid %d, errno %d", cmd->pid, errno); return MPR_ERR_CANT_READ; } else if (waitrc == cmd->pid) { if (!WIFSTOPPED(status)) { if (WIFEXITED(status)) { cmd->status = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { cmd->status = WTERMSIG(status); } cmd->pid = 0; } break; } else { mprAssert(waitrc == 0); } #endif #if VXWORKS /* * The command exit status (cmd->status) is set in cmdTaskEntry */ if (semTake(cmd->exitCond, MPR_TIMEOUT_STOP_TASK) != OK) { mprError(cmd, "cmd: child %s did not exit, errno %d", cmd->program); return MPR_ERR_CANT_CREATE; } semDelete(cmd->exitCond); cmd->exitCond = 0; cmd->pid = 0; #endif #if BLD_WIN_LIKE int status, rc; if ((rc = WaitForSingleObject(cmd->process, 10)) != WAIT_OBJECT_0) { if (rc == WAIT_TIMEOUT) { return -MPR_ERR_TIMEOUT; } mprLog(cmd, 6, "cmd: WaitForSingleObject no child to reap rc %d, %d", rc, GetLastError()); return MPR_ERR_CANT_READ; } if (GetExitCodeProcess(cmd->process, (ulong*) &status) == 0) { mprLog(cmd, 7, "cmd: GetExitProcess error"); return MPR_ERR_CANT_READ; } if (status != STILL_ACTIVE) { cmd->status = status; CloseHandle(cmd->process); CloseHandle(cmd->thread); cmd->process = 0; cmd->pid = 0; break; } #endif if (mprGetElapsedTime(cmd, mark) > timeout) { break; } /* Prevent busy waiting */ mprSleep(cmd, 10); } return (cmd->pid == 0) ? 0 : 1; }
int APIENTRY WinMain(HINSTANCE inst, HINSTANCE junk, char *args, int junk2) { char **argv, *argp, *serviceArgs, *homeDir; int argc, err, nextArg, installFlag; mpr = mprCreate(0, NULL, NULL); appInst = inst; serviceArgs = 0; err = 0; exiting = 0; installFlag = 0; homeDir = 0; heartBeatPeriod = HEART_BEAT_PERIOD; initService(); mprSetAppName(mpr, BLD_PRODUCT "Angel", BLD_NAME "Angel", BLD_VERSION); appName = mprGetAppName(mpr); appTitle = mprGetAppTitle(mpr); mprSetLogHandler(mpr, logHandler, NULL); /* * Create the window */ if (initWindow() < 0) { mprError(mpr, "Can't initialize application Window"); return FALSE; } /* * Parse command line arguments */ if (mprMakeArgv(mpr, "", args, &argc, &argv) < 0) { return FALSE; } for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-' || strcmp(argp, "--") == 0) { break; } if (strcmp(argp, "--args") == 0) { /* * Args to pass to service when it starts */ if (nextArg >= argc) { err++; } else { serviceArgs = argv[++nextArg]; } } else if (strcmp(argp, "--console") == 0) { /* * Allow the service to interact with the console */ createConsole++; } else if (strcmp(argp, "--daemon") == 0) { /* Ignored on windows */ } else if (strcmp(argp, "--heartBeat") == 0) { /* * Set the heart beat period */ if (nextArg >= argc) { err++; } else { heartBeatPeriod = atoi(argv[++nextArg]) * 1000; } } else if (strcmp(argp, "--home") == 0) { /* * Change to this directory before starting the service */ if (nextArg >= argc) { err++; } else { homeDir = argv[++nextArg]; } } else if (strcmp(argp, "--program") == 0) { if (nextArg >= argc) { err++; } else { serviceProgram = argv[++nextArg]; } } else if (strcmp(argp, "--install") == 0) { installFlag++; } else if (strcmp(argp, "--start") == 0) { /* * Start the angel */ if (startService() < 0) { return FALSE; } mprSleep(mpr, 2000); /* Time for service to really start */ } else if (strcmp(argp, "--stop") == 0) { /* * Stop the angel */ if (removeService(0) < 0) { return FALSE; } } else if (strcmp(argp, "--uninstall") == 0) { /* * Remove the angel */ if (removeService(1) < 0) { return FALSE; } } else if (strcmp(argp, "--verbose") == 0 || strcmp(argp, "-v") == 0) { verbose++; } else { err++; } if (err) { mprUserError(mpr, "Bad command line: %s\n" " Usage: %s [options] [program args]\n" " Switches:\n" " --args # Args to pass to service\n" " --console # Display the service console\n" " --heartBeat interval # Heart beat interval period (secs)\n" " --home path # Home directory for service\n" " --install # Install the service\n" " --program # Service program to start\n" " --start # Start the service\n" " --stop # Stop the service\n" " --uninstall # Uninstall the service", args, appName); return -1; } } if (installFlag) { /* * Install the angel */ if (installService(homeDir, serviceArgs) < 0) { return FALSE; } } if (argc <= 1) { /* * This will block if we are a service and are being started by the * service control manager. While blocked, the svcMain will be called * which becomes the effective main program. */ startDispatcher(serviceMain); } return 0; }
int main(int argc, char *argv[]) { double elapsed; char *programName, *argp, *logSpec; int c, errflg, start; #if BLD_FEATURE_LOG MprLogToFile *logger; #endif #if BLD_FEATURE_MULTITHREAD MprThread *threadp; #endif programName = mprGetBaseName(argv[0]); method = "GET"; fileList = cmpDir = writeDir = 0; verbose = continueOnErrors = outputHeader = errflg = 0; poolThreads = 4; // Need at least one to run efficiently httpVersion = 1; // HTTP/1.1 success = 1; trace = 0; host = "localhost"; logSpec = "stdout:1"; postData = 0; postLen = 0; retries = MPR_HTTP_CLIENT_RETRIES; iterations = HTTP_DEFAULT_ITERATIONS; loadThreads = HTTP_DEFAULT_LOAD_THREADS; timeout = MPR_HTTP_CLIENT_TIMEOUT; #if BLD_FEATURE_MULTITHREAD mutex = new MprMutex(); #endif // // FUTURE: switch to GNU style --args with a better usage message // MprCmdLine cmdLine(argc, argv, "bC:cDd:f:Hh:i:l:M:mqo:r:st:T:vV:w:"); while ((c = cmdLine.next(&argp)) != EOF) { switch(c) { case 'b': benchmark++; break; case 'c': continueOnErrors++; break; case 'C': cmpDir = argp; break; case 'd': postData = argp; postLen = strlen(postData); break; case 'D': mprSetDebugMode(1); break; case 'f': fileList = argp; break; case 'h': host = argp; break; case 'H': outputHeader++; break; case 'i': iterations = atoi(argp); break; case 'l': logSpec = argp; break; case 'm': mprRequestMemStats(1); break; case 'M': method = argp; break; case 'o': timeout = atoi(argp); break; case 'q': quietMode++; break; case 'r': retries = atoi(argp); break; case 's': singleStep++; break; case 't': loadThreads = atoi(argp); break; case 'T': poolThreads = atoi(argp); break; case 'v': verbose++; trace++; break; case 'V': httpVersion = atoi(argp); break; case 'w': writeDir = argp; break; default: errflg++; break; } } if (writeDir && (loadThreads > 1)) { errflg++; } if (errflg) { mprFprintf(MPR_STDERR, "usage: %s [-bcHMmqsTv] [-C cmpDir] [-d postData] [-f fileList]\n" " [-i iterations] [-l logSpec] [-M method] [-o timeout]\n" " [-h host] [-r retries] [-t threads] [-T poolThreads]\n" " [-V httpVersion] [-w writeDir] [urls...]\n", programName); exit(2); } saveArgc = argc - cmdLine.firstArg(); saveArgv = &argv[cmdLine.firstArg()]; mpr = new Mpr(programName); #if BLD_FEATURE_LOG tMod = new MprLogModule("httpClient"); logger = new MprLogToFile(); mpr->addListener(logger); if (mpr->setLogSpec(logSpec) < 0) { mprFprintf(MPR_STDERR, "Can't open log file %s\n", logSpec); exit(2); } #endif // // Alternatively, set the configuration manually // mpr->setAppTitle("Embedthis HTTP Client"); #if BLD_FEATURE_MULTITHREAD mpr->setMaxPoolThreads(poolThreads); #endif // // Start the Timer, Socket and Pool services // if (mpr->start(MPR_SERVICE_THREAD) < 0) { mprError(MPR_L, MPR_USER, "Can't start MPR for %s", mpr->getAppTitle()); delete mpr; exit(2); } // // Create extra test threads to run the tests as required. We use // the main thread also (so start with j==1) // start = mprGetTime(0); #if BLD_FEATURE_MULTITHREAD activeLoadThreads = loadThreads; for (int j = 1; j < loadThreads; j++) { char name[64]; mprSprintf(name, sizeof(name), "t.%d", j - 1); threadp = new MprThread(doTests, MPR_NORMAL_PRIORITY, (void*) j, name); threadp->start(); } #endif doTests(0, 0); // // Wait for all the threads to complete (simple but effective). Keep // servicing events as we wind down. // while (activeLoadThreads > 1) { mprSleep(100); } if (benchmark && success) { elapsed = (mprGetTime(0) - start); if (fetchCount == 0) { elapsed = 0; fetchCount = 1; } mprPrintf("\tThreads %d, Pool Threads %d \t%13.2f\t%12.2f\t%6d\n", loadThreads, poolThreads, elapsed * 1000.0 / fetchCount, elapsed / 1000.0, fetchCount); mprPrintf("\nTime elapsed: %13.4f sec\n", elapsed / 1000.0); mprPrintf("Time per request: %13.4f sec\n", elapsed / 1000.0 / fetchCount); mprPrintf("Requests per second: %13.4f\n", fetchCount * 1.0 / (elapsed / 1000.0)); } if (! quietMode) { mprPrintf("\n"); } mpr->stop(0); #if BLD_FEATURE_MULTITHREAD delete mutex; #endif #if BLD_FEATURE_LOG delete tMod; #endif delete mpr; #if BLD_FEATURE_LOG delete logger; #endif mprMemClose(); return (success) ? 0 : 255; }
/* Convert this Manager to a Deaemon */ static int makeDaemon() { struct sigaction act, old; int pid, status; /* Ignore child death signals */ memset(&act, 0, sizeof(act)); act.sa_sigaction = (void (*)(int, siginfo_t*, void*)) SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO; if (sigaction(SIGCHLD, &act, &old) < 0) { mprError("Can't initialize signals"); return MPR_ERR_BAD_STATE; } /* Fork twice to get a free child with no parent */ if ((pid = fork()) < 0) { mprError("Fork failed for background operation"); return MPR_ERR; } else if (pid == 0) { if ((pid = fork()) < 0) { mprError("Second fork failed"); exit(127); } else if (pid > 0) { /* Parent of second child -- must exit */ exit(0); } /* This is the real child that will continue as a daemon */ setsid(); if (sigaction(SIGCHLD, &old, 0) < 0) { mprError("Can't restore signals"); return MPR_ERR_BAD_STATE; } mprLog(2, "Switching to background operation"); return 0; } /* Original process waits for first child here. Must get child death notification with a successful exit status */ while (waitpid(pid, &status, 0) != pid) { if (errno == EINTR) { mprSleep(100); continue; } mprError("Can't wait for daemon parent."); exit(0); } if (WEXITSTATUS(status) != 0) { mprError("Daemon parent had bad exit status."); exit(0); } if (sigaction(SIGCHLD, &old, 0) < 0) { mprError("Can't restore signals"); return MPR_ERR_BAD_STATE; } exit(0); }
static void runService() { MprTime mark; char **av, *env[3], **argv; int err, i, status, ac, next; app->servicePid = 0; atexit(cleanup); mprLog(1, "%s: Watching over %s", app->appName, app->serviceProgram); if (access(app->serviceProgram, X_OK) < 0) { mprError("start: can't access %s, errno %d", app->serviceProgram, mprGetOsError()); return; } if (writePid(getpid()) < 0) { return; } mark = mprGetTime(); while (!mprIsStopping()) { if (mprGetElapsedTime(mark) > (3600 * 1000)) { mark = mprGetTime(); app->restartCount = 0; app->restartWarned = 0; } if (app->servicePid == 0) { if (app->restartCount >= app->retries) { if (! app->restartWarned) { mprError("Too many restarts for %s, %d in ths last hour", app->serviceProgram, app->restartCount); mprError("Suspending restarts for one hour"); app->restartWarned++; } mprSleep(60 * 1000); continue; } /* Create the child */ app->servicePid = vfork(); if (app->servicePid < 0) { mprError("Can't fork new process to run %s", app->serviceProgram); continue; } else if (app->servicePid == 0) { /* Child */ umask(022); setsid(); mprLog(1, "%s: Change dir to %s", app->appName, app->serviceHome); if (chdir(app->serviceHome) < 0) {} for (i = 3; i < 128; i++) { close(i); } if (app->serviceArgs && *app->serviceArgs) { ac = mprMakeArgv(app->serviceArgs, &av, 0); } else { ac = 0; } argv = mprAlloc(sizeof(char*) * (6 + ac)); env[0] = sjoin("LD_LIBRARY_PATH=", app->serviceHome, NULL); env[1] = sjoin("PATH=", getenv("PATH"), NULL); env[2] = 0; next = 0; argv[next++] = app->serviceProgram; if (app->logSpec) { argv[next++] = "--log"; argv[next++] = (char*) app->logSpec; } for (i = 0; i < ac; i++) { argv[next++] = av[i]; } argv[next++] = 0; mprLog(1, "%s: Running %s", app->appName, app->serviceProgram); for (i = 1; argv[i]; i++) { mprLog(1, "%s: argv[%d] = %s", app->appName, i, argv[i]); } execve(app->serviceProgram, argv, (char**) &env); /* Should not get here */ err = errno; mprError("%s: Can't exec %s, err %d, cwd %s", app->appName, app->serviceProgram, err, app->serviceHome); exit(MPR_ERR_CANT_INITIALIZE); } /* Parent */ mprLog(1, "%s: create child %s at pid %d", app->appName, app->serviceProgram, app->servicePid); app->restartCount++; waitpid(app->servicePid, &status, 0); mprLog(1, "%s: %s has exited with status %d", app->appName, app->serviceProgram, WEXITSTATUS(status)); if (!mprIsStopping()) { mprLog(1, "%s: Restarting %s (%d/%d)...", app->appName, app->serviceProgram, app->restartCount, app->retries); } app->servicePid = 0; } } }
int main(int argc, char *argv[], char *envp[]) #endif { char *cp, *method; int i, j, err; err = 0; outputArgs = outputQuery = outputEnv = outputPost = 0; outputBytes = outputHeaderLines = responseStatus = 0; outputLocation = 0; nonParsedHeader = 0; responseMsg = 0; hasError = 0; timeout = 0; queryBuf = 0; queryLen = 0; numQueryKeys = numPostKeys = 0; originalArgc = argc; originalArgv = argv; mpr = mprCreate(argc, argv, NULL); #if _WIN32 && !WINCE _setmode(0, O_BINARY); _setmode(1, O_BINARY); _setmode(2, O_BINARY); #endif if (strncmp(mprGetPathBase(mpr, argv[0]), "nph-", 4) == 0) { nonParsedHeader++; } if (getArgv(mpr, &argc, &argv, originalArgc, originalArgv) < 0) { error(mpr, "Can't read CGI input"); } for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { continue; } for (cp = &argv[i][1]; *cp; cp++) { switch (*cp) { case 'a': outputArgs++; break; case 'b': if (++i >= argc) { err = __LINE__; } else { outputBytes = atoi(argv[i]); } break; case 'e': outputEnv++; break; case 'h': if (++i >= argc) { err = __LINE__; } else { outputHeaderLines = atoi(argv[i]); nonParsedHeader++; } break; case 'l': if (++i >= argc) { err = __LINE__; } else { outputLocation = argv[i]; if (responseStatus == 0) { responseStatus = 302; } } break; case 'n': nonParsedHeader++; break; case 'p': outputPost++; break; case 'q': outputQuery++; break; case 's': if (++i >= argc) { err = __LINE__; } else { responseStatus = atoi(argv[i]); } break; case 't': if (++i >= argc) { err = __LINE__; } else { timeout = atoi(argv[i]); } break; default: err = __LINE__; break; } } } if (err) { mprError(mpr, "usage: cgiProgram -aenp [-b bytes] [-h lines]\n" "\t[-l location] [-s status] [-t timeout]\n" "\tor set the HTTP_SWITCHES environment variable\n"); mprError(mpr, "Error at cgiProgram:%d\n", __LINE__); exit(255); } method = getenv("REQUEST_METHOD") ; if (method == 0) { method = "GET"; } else { if (strcmp(method, "POST") == 0) { postBuf = mprCreateBuf(mpr, -1, -1); if (getPostData(mpr, postBuf) < 0) { error(mpr, "Can't read CGI input"); } if (strcmp(safeGetenv("CONTENT_TYPE"), "application/x-www-form-urlencoded") == 0) { numPostKeys = getVars(mpr, &postKeys, mprGetBufStart(postBuf), mprGetBufLength(postBuf)); } } } if (hasError) { if (! nonParsedHeader) { mprPrintf(mpr, "HTTP/1.0 %d %s\r\n\r\n", responseStatus, responseMsg); mprPrintf(mpr, "<HTML><BODY><p>Error: %d -- %s</p></BODY></HTML>\r\n", responseStatus, responseMsg); } exit(2); } if (nonParsedHeader) { if (responseStatus == 0) { mprPrintf(mpr, "HTTP/1.0 200 OK\r\n"); } else { mprPrintf(mpr, "HTTP/1.0 %d %s\r\n", responseStatus, responseMsg ? responseMsg: ""); } mprPrintf(mpr, "Connection: close\r\n"); mprPrintf(mpr, "X-CGI-CustomHeader: Any value at all\r\n"); } mprPrintf(mpr, "Content-type: %s\r\n", "text/html"); if (outputHeaderLines) { j = 0; for (i = 0; i < outputHeaderLines; i++) { mprPrintf(mpr, "X-CGI-%d: A loooooooooooooooooooooooong string\r\n", i); } } if (outputLocation) { mprPrintf(mpr, "Location: %s\r\n", outputLocation); } if (responseStatus) { mprPrintf(mpr, "Status: %d\r\n", responseStatus); } mprPrintf(mpr, "\r\n"); if ((outputBytes + outputArgs + outputEnv + outputQuery + outputPost + outputLocation + responseStatus) == 0) { outputArgs++; outputEnv++; outputQuery++; outputPost++; } if (outputBytes) { j = 0; for (i = 0; i < outputBytes; i++) { putchar('0' + j); j++; if (j > 9) { if (++outputBytes > 0) { putchar('\r'); } if (++outputBytes > 0) { putchar('\n'); } j = 0; } } } /* else */ { mprPrintf(mpr, "<HTML><TITLE>cgiProgram: Output</TITLE><BODY>\r\n"); if (outputArgs) { #if _WIN32 mprPrintf(mpr, "<P>CommandLine: %s</P>\r\n", GetCommandLine()); #endif mprPrintf(mpr, "<H2>Args</H2>\r\n"); for (i = 0; i < argc; i++) { mprPrintf(mpr, "<P>ARG[%d]=%s</P>\r\n", i, argv[i]); } } #if !VXWORKS && !WINCE if (outputEnv) { printEnv(envp); } #endif if (outputQuery) { printQuery(); } if (outputPost) { printPost(postBuf); } if (timeout) { mprSleep(mpr, timeout * MPR_TICKS_PER_SEC); } mprPrintf(mpr, "</BODY></HTML>\r\n"); } #if VXWORKS /* * VxWorks pipes need an explicit eof string */ write(1, MPR_CMD_VXWORKS_EOF, MPR_CMD_VXWORKS_EOF_LEN); write(2, MPR_CMD_VXWORKS_EOF, MPR_CMD_VXWORKS_EOF_LEN); /* * Must not call exit(0) in Vxworks as that will exit the task before the CGI handler can cleanup. Must use return 0. */ #endif return 0; }