static int writeBody(MprHttp *http, MprList *fields, MprList *files) { MprFile *file; char buf[MPR_HTTP_BUFSIZE], *path, *pair; int bytes, next, count, rc, len; rc = 0; mprSetSocketBlockingMode(http->sock, 1); if (upload) { if (mprWriteHttpUploadData(http, files, fields) < 0) { mprError(http, "Can't write upload data %s", mprGetHttpError(http)); mprSetSocketBlockingMode(http->sock, 0); return MPR_ERR_CANT_WRITE; } } else { if (fields) { count = mprGetListCount(fields); for (next = 0; !rc && (pair = mprGetNextItem(fields, &next)) != 0; ) { len = (int) strlen(pair); if (next < count) { len = (int) strlen(pair); if (mprWriteSocket(http->sock, pair, len) != len || mprWriteSocket(http->sock, "&", 1) != 1) { return MPR_ERR_CANT_WRITE; } } else { if (mprWriteSocket(http->sock, pair, len) != len) { return MPR_ERR_CANT_WRITE; } } } } if (files) { mprAssert(mprGetListCount(files) == 1); for (rc = next = 0; !rc && (path = mprGetNextItem(files, &next)) != 0; ) { file = mprOpen(http, path, O_RDONLY | O_BINARY, 0); if (file == 0) { mprError(http, "Can't open \"%s\"", path); return MPR_ERR_CANT_OPEN; } if (verbose && upload) { mprPrintf(http, "uploading: %s\n", path); } while ((bytes = mprRead(file, buf, sizeof(buf))) > 0) { if (mprWriteHttp(http, buf, bytes) != bytes) { mprFree(file); return MPR_ERR_CANT_WRITE; } } mprFree(file); } } if (mprFinalizeHttpWriting(http) < 0) { return MPR_ERR_CANT_WRITE; } } mprSetSocketBlockingMode(http->sock, 0); return rc; }
static int setContentLength(MprHttp *http, MprList *fields, MprList *files) { MprPath info; char *path, *pair; int64 len; int next; len = 0; if (upload) { /* Easier to use chunking than to calculate the full multipart-mime upload content */ mprSetHttpChunked(http, 1); mprEnableHttpUpload(http); return 0; } else { for (next = 0; (path = mprGetNextItem(files, &next)) != 0; ) { if (mprGetPathInfo(http, path, &info) < 0) { mprError(http, "Can't access file %s", path); return MPR_ERR_CANT_ACCESS; } len += info.size; } if (fields) { for (next = 0; (pair = mprGetNextItem(fields, &next)) != 0; ) { len += strlen(pair); } len += mprGetListCount(fields) - 1; } } if (len > (16 * MPR_HTTP_BUFSIZE)) { mprSetHttpChunked(http, 1); } else { mprSetHttpBody(http, NULL, (int) len); } return 0; }
static int reapJoins(Ejs *ejs, EjsVar *workers) { EjsWorker *worker; EjsArray *set; int i, completed; lock(ejs); if (workers == 0 || workers == ejs->nullValue) { completed = 0; for (i = 0; i < mprGetListCount(ejs->workers); i++) { worker = mprGetItem(ejs->workers, i); if (worker->state >= EJS_WORKER_COMPLETE) { completed++; } } if (completed == mprGetListCount(ejs->workers)) { unlock(ejs); return 1; } } else if (ejsIsArray(workers)) { set = (EjsArray*) workers; for (i = 0; i < set->length; i++) { worker = (EjsWorker*) set->data[i]; if (worker->state < EJS_WORKER_COMPLETE) { break; } } if (i >= set->length) { unlock(ejs); return 1; } } else if (workers->type == ejs->workerType) { worker = (EjsWorker*) workers; if (worker->state >= EJS_WORKER_COMPLETE) { unlock(ejs); return 1; } } unlock(ejs); return 0; }
/* Just the Mpr services are idle. Use mprIsIdle to determine if the entire process is idle */ bool mprServicesAreIdle(MprCtx ctx) { Mpr *mpr; int idle; mpr = mprGetMpr(ctx); idle = 1; #if BLD_FEATURE_CMD if (mprGetListCount(mpr->cmdService->cmds)) { idle = 0; } #endif #if BLD_FEATURE_MULTITHREAD if (mprGetListCount(mpr->workerService->busyThreads)) { idle = 0; } #endif if (mpr->dispatcher->flags & MPR_DISPATCHER_DO_EVENT) { idle = 0; } return idle; }
void maAddConn(MaHost *host, MaConn *conn) { lock(host); mprAddItem(host->connections, conn); conn->started = mprGetTime(conn); if ((host->whenCurrentDate + MPR_TICKS_PER_SEC) < conn->started) { updateCurrentDate(host); } if (mprGetListCount(host->connections) == 1) { startTimer(host); } unlock(host); }
MAIN(ejsMain, int argc, char **argv) #endif { Mpr *mpr; EcCompiler *cp; EjsService *vmService; Ejs *ejs; MprList *useModules, *files; cchar *cmd, *className, *methodName; char *argp, *searchPath, *modules, *name, *tok, *extraFiles, *spec; int nextArg, err, ecFlags, run, merge, bind, noout, debug, optimizeLevel, warnLevel; int compilerMode, lang; /* * Create the Embedthis Portable Runtime (MPR) and setup a memory failure handler */ mpr = mprCreate(argc, argv, ejsMemoryFailure); mprSetAppName(mpr, argv[0], 0, 0); setupSignals(); if (mprStart(mpr, MPR_START_EVENTS_THREAD) < 0) { mprError(mpr, "Can't start mpr services"); return EJS_ERR; } err = 0; className = 0; cmd = 0; methodName = 0; searchPath = 0; run = 1; merge = 0; bind = 1; noout = 1; debug = 1; warnLevel = 1; optimizeLevel = 9; compilerMode = PRAGMA_MODE_STANDARD; lang = BLD_FEATURE_EJS_LANG; useModules = mprCreateList(mpr); files = mprCreateList(mpr); for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (strcmp(argp, "--bind") == 0) { bind = 1; } else if (strcmp(argp, "--class") == 0) { if (nextArg >= argc) { err++; } else { className = argv[++nextArg]; } } else if (strcmp(argp, "--cmd") == 0 || strcmp(argp, "-c") == 0) { if (nextArg >= argc) { err++; } else { cmd = argv[++nextArg]; } } else if (strcmp(argp, "--debug") == 0) { debug = 1; } else if (strcmp(argp, "--lang") == 0) { if (nextArg >= argc) { err++; } else { spec = argv[++nextArg]; if (mprStrcmpAnyCase(spec, "ecma") == 0) { lang = EJS_SPEC_ECMA; } else if (mprStrcmpAnyCase(spec, "plus") == 0) { lang = EJS_SPEC_PLUS; } else if (mprStrcmpAnyCase(spec, "fixed") == 0) { lang = EJS_SPEC_FIXED; } } } else if (strcmp(argp, "--files") == 0 || strcmp(argp, "-f") == 0) { /* Compatibility with mozilla shell */ if (nextArg >= argc) { err++; } else { extraFiles = mprStrdup(mpr, argv[++nextArg]); name = mprStrTok(extraFiles, " \t", &tok); while (name != NULL) { mprAddItem(files, name); name = mprStrTok(NULL, " \t", &tok); } } } else if (strcmp(argp, "--log") == 0) { if (nextArg >= argc) { err++; } else { ejsStartLogging(mpr, argv[++nextArg]); } } else if (strcmp(argp, "--method") == 0) { if (nextArg >= argc) { err++; } else { methodName = argv[++nextArg]; } } else if (strcmp(argp, "--nobind") == 0) { bind = 0; } else if (strcmp(argp, "--nodebug") == 0) { debug = 0; } else if (strcmp(argp, "--optimize") == 0) { if (nextArg >= argc) { err++; } else { optimizeLevel = atoi(argv[++nextArg]); } } else if (strcmp(argp, "-s") == 0) { /* Compatibility with mozilla shell. Just ignore */ } else if (strcmp(argp, "--search") == 0 || strcmp(argp, "--searchpath") == 0) { if (nextArg >= argc) { err++; } else { searchPath = argv[++nextArg]; } } else if (strcmp(argp, "--standard") == 0) { compilerMode = PRAGMA_MODE_STANDARD; } else if (strcmp(argp, "--strict") == 0) { compilerMode = PRAGMA_MODE_STRICT; } else if (strcmp(argp, "--use") == 0) { if (nextArg >= argc) { err++; } else { modules = mprStrdup(mpr, argv[++nextArg]); name = mprStrTok(modules, " \t", &tok); while (name != NULL) { mprAddItem(useModules, name); name = mprStrTok(NULL, " \t", &tok); } } } else if (strcmp(argp, "--version") == 0 || strcmp(argp, "-V") == 0) { mprPrintfError(mpr, "%s %s-%s\n", BLD_NAME, BLD_VERSION, BLD_NUMBER); return 0; } else if (strcmp(argp, "--warn") == 0) { if (nextArg >= argc) { err++; } else { warnLevel = atoi(argv[++nextArg]); } } else { err++; break; } } if (err) { /* * If --method or --class is specified, then the named class.method will be run (method defaults to "main", class * defaults to first class with a "main"). * * Examples: * ejs * ejs script.es arg1 arg2 arg3 * ejs --class "Customer" --method "start" --files "script1.es script2.es" main.es */ mprPrintfError(mpr, "Usage: %s [options] script.es [arguments] ...\n" " Ejscript shell program options:\n" " --class className # Name of class containing method to run\n" " --cmd ejscriptCode # Literal ejscript statements to execute\n" " --debug # Use symbolic debugging information (default)\n" " --files \"files..\" # Extra source to compile\n" " --lang # Language compliance (ecma|plus|fixed)\n" " --log logSpec # Internal compiler diagnostics logging\n" " --method methodName # Name of method to run. Defaults to main\n" " --nodebug # Omit symbolic debugging information\n" " --optimize level # Set the optimization level (0-9 default is 9)\n" " --search ejsPath # Module search path\n" " --standard # Default compilation mode to standard (default)\n" " --strict # Default compilation mode to strict\n" " --use 'module, ...' # List of modules to pre-load\n" " --version # Emit the compiler version information\n" " --warn level # Set the warning message level (0-9 default is 0)\n\n", mpr->name); return -1; } vmService = ejsCreateService(mpr); if (vmService == 0) { return MPR_ERR_NO_MEMORY; } ecInitCompiler(vmService); ejs = ejsCreate(vmService, NULL, searchPath, 0); if (ejs == 0) { return MPR_ERR_NO_MEMORY; } ecFlags = 0; ecFlags |= (run) ? EC_FLAGS_RUN: 0; ecFlags |= (merge) ? EC_FLAGS_MERGE: 0; ecFlags |= (bind) ? EC_FLAGS_BIND: 0; ecFlags |= (noout) ? EC_FLAGS_NO_OUT: 0; ecFlags |= (debug) ? EC_FLAGS_DEBUG: 0; cp = ecCreateCompiler(ejs, ecFlags, lang); if (cp == 0) { return MPR_ERR_NO_MEMORY; } ecSetOptimizeLevel(cp, optimizeLevel); ecSetWarnLevel(cp, warnLevel); ecSetDefaultMode(cp, compilerMode); if (preloadModules(cp, useModules) < 0) { return EJS_ERR; } if (nextArg < argc) { mprAddItem(files, argv[nextArg]); } if (cmd) { if (interpretCommands(cp, cmd) < 0) { err++; } } else if (mprGetListCount(files) > 0) { if (interpretFiles(cp, files, argc - nextArg, &argv[nextArg], className, methodName, lang) < 0) { err++; } } else { /* * No args - run as an interactive shell */ if (interpretCommands(cp, NULL) < 0) { err++; } } #if VXWORKS mprFree(cp); mprFree(ejs); if (mprStop(mpr)) { mprFree(mpr); } #endif return err; }
static void sortList(MaConn *conn, MprList *list) { MaRequest *req; MaResponse *resp; MprDirEntry *tmp, **items; Dir *dir; int count, i, j, rc; req = conn->request; resp = conn->response; dir = resp->handler->stageData; if (dir->sortField == 0) { return; } count = mprGetListCount(list); items = (MprDirEntry**) list->items; if (mprStrcmpAnyCase(dir->sortField, "Name") == 0) { for (i = 1; i < count; i++) { for (j = 0; j < i; j++) { rc = strcmp(items[i]->name, items[j]->name); if (dir->foldersFirst) { if (items[i]->isDir && !items[j]->isDir) { rc = -dir->sortOrder; } else if (items[j]->isDir && !items[i]->isDir) { rc = dir->sortOrder; } } rc *= dir->sortOrder; if (rc < 0) { tmp = items[i]; items[i] = items[j]; items[j] = tmp; } } } } else if (mprStrcmpAnyCase(dir->sortField, "Size") == 0) { for (i = 1; i < count; i++) { for (j = 0; j < i; j++) { rc = (items[i]->size < items[j]->size) ? -1 : 1; if (dir->foldersFirst) { if (items[i]->isDir && !items[j]->isDir) { rc = -dir->sortOrder; } else if (items[j]->isDir && !items[i]->isDir) { rc = dir->sortOrder; } } rc *= dir->sortOrder; if (rc < 0) { tmp = items[i]; items[i] = items[j]; items[j] = tmp; } } } } else if (mprStrcmpAnyCase(dir->sortField, "Date") == 0) { for (i = 1; i < count; i++) { for (j = 0; j < i; j++) { rc = (items[i]->lastModified < items[j]->lastModified) ? -1: 1; if (dir->foldersFirst) { if (items[i]->isDir && !items[j]->isDir) { rc = -dir->sortOrder; } else if (items[j]->isDir && !items[i]->isDir) { rc = dir->sortOrder; } } rc *= dir->sortOrder; if (rc < 0) { tmp = items[i]; items[i] = items[j]; items[j] = tmp; } } } } }
/* * The host timer does maintenance activities and will fire per second while there is active requests. * When multi-threaded, the host timer runs as an event off the service thread. Because we lock the host here, * connections cannot be deleted while we are modifying the list. */ static void hostTimer(MaHost *host, MprEvent *event) { Mpr *mpr; MaStage *stage; MaConn *conn; MprModule *module; MaHttp *http; int next, count; mprAssert(event); http = host->server->http; /* * Locking ensures connections won't be deleted */ lock(host); updateCurrentDate(host); mprLog(host, 8, "hostTimer: %d active connections", mprGetListCount(host->connections)); /* * Check for any expired connections */ for (count = 0, next = 0; (conn = mprGetNextItem(host->connections, &next)) != 0; count++) { /* * Workaround for a GCC bug when comparing two 64bit numerics directly. Need a temporary. */ int64 diff = conn->expire - host->now; if (diff < 0 && !mprGetDebugMode(host)) { conn->keepAliveCount = 0; if (!conn->disconnected) { if (conn->request) { mprLog(host, 6, "Open request timed out due to inactivity: %s", conn->request->url); } else { mprLog(host, 6, "Idle connection timed out"); } conn->disconnected = 1; mprDisconnectSocket(conn->sock); } } } /* Check for unloadable modules - must be idle */ mpr = mprGetMpr(http); if (mprGetListCount(host->connections) == 0) { for (next = 0; (module = mprGetNextItem(mpr->moduleService->modules, &next)) != 0; ) { if (module->timeout) { if (module->lastActivity + module->timeout < host->now) { if ((stage = maLookupStage(http, module->name)) != 0) { mprLog(host, 2, "Unloading inactive module %s", module->name); if (stage->match) { mprError(conn, "Can't unload modules with match routines"); module->timeout = 0; } else { maUnloadModule(http, module->name); stage->flags |= MA_STAGE_UNLOADED; } } else { maUnloadModule(http, module->name); } } else { count++; } } } } if (count == 0) { mprFree(event); host->timer = 0; } unlock(host); }
/* * function Worker(script: String = null, options: Object = null) * * Script is optional. If supplied, the script is run immediately by a worker thread. This call * does not block. Options are: search and name. */ static EjsVar *workerConstructor(Ejs *ejs, EjsWorker *worker, int argc, EjsVar **argv) { Ejs *wejs; EjsVar *options, *value; EjsName qname; EjsWorker *self; cchar *search, *name; worker->ejs = ejs; worker->state = EJS_WORKER_BEGIN; options = (argc == 2) ? (EjsVar*) argv[1]: NULL; name = 0; search = ejs->ejsPath; if (options) { value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "search")); if (ejsIsString(value)) { search = ejsGetString(value); } value = ejsGetPropertyByName(ejs, options, ejsName(&qname, "", "name")); if (ejsIsString(value)) { name = ejsGetString(value); } } if (name) { worker->name = mprStrdup(worker, name); } else { worker->name = mprAsprintf(worker, -1, "worker-%d", mprGetListCount(ejs->workers)); } /* * Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker. */ wejs = ejsCreate(ejs->service, NULL, search, 0); if (wejs == 0) { ejsThrowMemoryError(ejs); return 0; } worker->pair = self = ejsCreateWorker(wejs); self->state = EJS_WORKER_BEGIN; self->ejs = wejs; self->inside = 1; self->pair = worker; self->name = mprStrcat(self, -1, "inside-", worker->name, NULL); ejsSetProperty(ejs, (EjsVar*) worker, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(ejs, self->name)); ejsSetProperty(wejs, (EjsVar*) self, ES_ejs_sys_Worker_name, (EjsVar*) ejsCreateString(wejs, self->name)); ejsSetProperty(wejs, wejs->global, ES_ejs_sys_worker_self, (EjsVar*) self); /* * Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...) */ ejsDefineReservedNamespace(wejs, wejs->globalBlock, 0, EJS_WORKER_NAMESPACE); /* * Make the inside worker permanent so we don't need to worry about whether worker->pair->ejs is valid */ self->obj.var.permanent = 1; if (argc > 0 && ejsIsPath(argv[0])) { addWorker(ejs, worker); worker->scriptFile = mprStrdup(worker, ((EjsPath*) argv[0])->path); worker->state = EJS_WORKER_STARTED; worker->obj.var.permanent = 1; if (mprStartWorker(ejs, (MprWorkerProc) workerMain, (void*) worker, MPR_NORMAL_PRIORITY) < 0) { ejsThrowStateError(ejs, "Can't start worker"); worker->obj.var.permanent = 0; return 0; } } return (EjsVar*) worker; }