📄 mal_session.mx
字号:
@' The contents of this file are subject to the MonetDB Public License@' Version 1.1 (the "License"); you may not use this file except in@' compliance with the License. You may obtain a copy of the License at@' http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html@'@' Software distributed under the License is distributed on an "AS IS"@' basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the@' License for the specific language governing rights and limitations@' under the License.@'@' The Original Code is the MonetDB Database System.@'@' The Initial Developer of the Original Code is CWI.@' Portions created by CWI are Copyright (C) 1997-2007 CWI.@' All Rights Reserved.@a M. Kersten@v 0.0@- Server BootstrappingThe MonetDB server uses a startup script to boot the system.This script is an ordinary MAL program, but will mostlyconsist of include statements to load modules of general interest.The startup script is ran as user Admin.Its location is described in Monet configuration file.The default location is: !!!###%%% TODO %%%###!!! <-- FIXMEIt may overwritten using a command line argument.@{@h#ifndef _MAL_SESSION_H#define _MAL_SESSION_H#include "mal_scenario.h"mal_export int malBootstrap(void);mal_export void MSserveClient(void *dummy);mal_export void MSinitClientPrg(Client cntxt, str mod, str nme);mal_export void MSscheduleClient(str command, str challenge, bstream *fin, stream *fout);mal_export str MALreader(Client c);mal_export str MALexitClient(Client c);mal_export str MALexitSession(Client c);mal_export str MALparser(Client c);mal_export str MALengine(Client c);mal_export void MSresetInstructions(MalBlkPtr mb, int start);mal_export void MSresetVariables(MalBlkPtr mb, MalStkPtr glb, int start);mal_export int MALcommentsOnly(MalBlkPtr mb);#endif /* _MAL_SESSION_H */@c#include "mal_config.h"#include "mal_session.h"#include "mal_instruction.h" /* for pushEndInstruction() */#include "mal_interpreter.h" /* for showErrors(), runMAL(), garbageElement(), garbageCollector() */#include "mal_linker.h" /* for initLibraries() */#include "mal_parser.h" /* for parseMAL() */#include "mal_namespace.h"#include "mal_readline.h"#include "mal_authorize.h"#include <gdk.h> /* for opendir and friends */intmalBootstrap(){ Client c; str bootfile = "mal_init", bf; c = MCinitClient((oid)0, 0, 0); c->nspace = newModule(NULL, putName("user", 4)); initLibraries(); if (defaultScenario(c)) { GDKfatal("Failed to initialise default scenario"); return 0; } bf = GDKgetenv("mal_bootstrap"); if (bf) bootfile = bf; MSinitClientPrg(c,"user", "main"); malInclude(c, bootfile, 0); mal_scope = c->nspace; pushEndInstruction(c->curprg->def); trimMalBlk(c->curprg->def); chkProgram(c->nspace, c->curprg->def); if (c->curprg->def->errors) { showErrors(); GDKfatal("Failed to initialise system"); return 0; } MALengine(c); return 1;}@+ Client main routineEvery client has a 'main' function to collect the statements.Once the END instruction has been found, it is added to thesymbol table and a fresh container is being constructed.Note, this scheme makes testing for recursive function calls alittle more difficult. Therefore, type checking should be performedafterwards.In interactive mode, the closing statement is never reached.The 'main' procedure is typically cleaned between successive externalmessages except for its variables, which are considerd global.This storage container is re-used when during the previous callnothing was added.At the end of the session we have to garbage collect the BATsintroduced.@cvoidMSinitClientPrg(Client cntxt, str mod, str nme){ InstrPtr p; MalBlkPtr mb; int i, cnt = 1; if (cntxt->curprg && idcmp(nme, cntxt->curprg->name) == 0) { mb = cntxt->curprg->def; for (i = 1; i < mb->stop; i++) if (mb->stmt[i]->token == REMsymbol) cnt++; if (mb->stop <= cnt + 1) { /* complete comments */ mb->typefixed = 0; mb->flowfixed = 0; mb->stop = 1; cntxt->glb = 0; return; } } cntxt->curprg = newFunction(putName(nme, strlen(nme)), FUNCTIONsymbol); mb = cntxt->curprg->def; p = getSignature(cntxt->curprg); if( mod ) setModuleId(p,mod); else setModuleScope(p, cntxt->nspace); setVarType(mb, findVariable(mb, nme), TYPE_void); insertSymbol(cntxt->nspace, cntxt->curprg); cntxt->glb = 0; assert(cntxt->curprg->def != NULL);}@}@+ Client authorizationThe default method to interact with the database server is toconnect using a port number. The first line received should containauthorization information, such as user name and a possible session key.No encryption scheme is performed yet.An example initialization string would be "guest:23" which indicates accessof the client named 'guest' to a session previously started under identity 23.@{The scheduleClient receives a challenge response consisting ofBIG:user:password:lang:database:.@cvoidMSscheduleClient(str command, str challenge, bstream *fin, stream *fout){ char *user = command, *algo = NULL, *passwd = NULL, *lang = NULL; char *database = NULL, *s; int key = 0; Client c; MT_Id p; /* decode BIG/LIT:user:{cypher}passwordchal:lang:database: line */ /* byte order */ s = strchr(user, ':'); if (s) { *s = 0; stream_set_byteorder(fin->s, strcmp(user, "BIG") == 0); user = s + 1; } else { stream_printf(fout, "!incomplete challenge '%s'\n", user); stream_flush(fout); GDKfree(command); return; } /* passwd */ s = strchr(user, ':'); if (s) { *s = 0; passwd = s + 1; /* decode algorithm, i.e. {plain}mypasswordchallenge */ if (*passwd != '{') { stream_printf(fout, "!invalid password entry\n"); stream_flush(fout); GDKfree(command); return; } algo = passwd + 1; s = strchr(algo, '}'); if (!s) { stream_printf(fout, "!invalid password entry\n"); stream_flush(fout); GDKfree(command); return; } *s = 0; passwd = s + 1; } else { stream_printf(fout, "!incomplete challenge '%s'\n", user); stream_flush(fout); GDKfree(command); return; } /* lang */ s = strchr(passwd, ':'); if (s) { *s = 0; lang = s + 1; } else { stream_printf(fout, "!incomplete challenge, missing language\n"); stream_flush(fout); GDKfree(command); return; } /* database */ s = strchr(lang, ':'); if (s) { *s = 0; database = s + 1; /* we can have stuff following, make it void */ s = strchr(database, ':'); if (s) *s = 0; } if (database && database[0] != '\0' && strcmp(database, GDKgetenv("gdk_dbname")) != 0) { DIR *d; struct dirent *e; int found = 0; str buf = alloca(sizeof(char) * (PATHLENGTH + 1)); str p; int len; FILE *f; str err = NULL; str redir; buf[PATHLENGTH] = '\0'; /* scan the parent for directories */ d = opendir(".."); while ((e = readdir(d)) != NULL) { /* skip if not the database we're looking for */ if (strcmp(e->d_name, database) != 0) continue; /* ok, look for some files we're interested in, start * checking if the server is connectable */ snprintf(buf, PATHLENGTH, "../%s/.conn", e->d_name); if ((f = fopen(buf, "r")) == NULL) { err = "database not available or cannot be connected to"; break; /* we don't have to look further any more */ } if ((len = fread(buf, 1, PATHLENGTH, f)) <= 0) { /* ok, won't work */ fclose(f); err = "database cannot be connected to"; break; } buf[len] = '\0'; /* note: in theory, multiple addresses can be in this file. * We ignore this for now, and just connect to the first one */ if ((p = strchr(buf, '\n')) == NULL) { /* somehow doesn't work */ fclose(f); err = "database cannot be connected to"; break; } *p = '\0'; fclose(f); /* alloc some space */ redir = alloca(sizeof(char) * (strlen(buf) + 2)); sprintf(redir, "^%s", buf); /* see if the server supports the language we're asking for */ snprintf(buf, PATHLENGTH, "../%s/.scen", e->d_name); if ((f = fopen(buf, "r")) == NULL) { err = "language not supported"; break; } if ((len = fread(buf, 1, PATHLENGTH, f)) <= 0) { /* ok, won't work */ fclose(f); err = "database cannot be connected to"; break; } buf[len] = '\0'; while ((p = strchr(buf, '\n')) != NULL) { *p = '\0'; if (strcmp(buf, lang) == 0) { found = 1; break; } buf = p + 1; } fclose(f); if (found == 1) { stream_printf(fout, "%s%s?lang=%s&user=%s\n", redir, database, buf, user); /* flush redirect and return */ stream_flush(fout); closedir(d); GDKfree(command); return; } else { err = "language not supported"; break; } } (void) closedir(d); if (err == NULL) err = "database does not exist"; stream_printf(fout, "!redirect to database '%s': %s\n", database, err); /* flush the error to the client, and abort further execution */ stream_flush(fout); GDKfree(command); return; } else { str err; oid uid; /* access control: verify the credentials supplied by the user, * no need to check for database stuff, because that is done per * database itself (one gets a redirect) */ err = AUTHcheckCredentials(&uid, &user, &passwd, &challenge, &algo, &lang); if (err != MAL_SUCCEED) { stream_printf(fout, "!%s\n", err); stream_flush(fout); GDKfree(command); return; } c = MCinitClient(uid, fin, fout);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -