/** @return a string representing the address and port to connect to. */ static void initAngel(struct Pipe* asClientPipe, struct Interface* asCoreIface, char* asCorePipeName, struct EventBase* eventBase, struct Log* logger, struct Allocator* alloc, struct Random* rand) { Dict admin = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST("127.0.0.1")), Dict_CONST( String_CONST("corePipeName"), String_OBJ(String_CONST(asCorePipeName)), Dict_CONST( String_CONST("pass"), String_OBJ(String_CONST("abcd")), NULL ))); Dict message = Dict_CONST( String_CONST("admin"), Dict_OBJ(&admin), NULL ); struct Allocator* tempAlloc = Allocator_child(alloc); struct Message* toAngel = Message_new(0, 1024, tempAlloc); BencMessageWriter_write(&message, toAngel, NULL); Log_info(logger, "Writing intial configuration to angel on [%s]", asClientPipe->name); Interface_sendMessage(&asClientPipe->iface, toAngel); // This is client->angel->core data, we can throw this away. //struct Message* angelToCore = InterfaceWaiter_waitForData(asCoreIface, eventBase, tempAlloc, NULL); // unterminated string //Log_info(logger, "Init message from angel to core: [%s]", angelToCore->bytes); // Send response on behalf of core. Dict* coreToAngelResp = Dict_new(tempAlloc); Dict_putString(coreToAngelResp, String_CONST("error"), String_CONST("none"), tempAlloc); struct Message* coreToAngelMsg = Message_new(0, 256, tempAlloc); BencMessageWriter_write(coreToAngelResp, coreToAngelMsg, NULL); Interface_sendMessage(asCoreIface, coreToAngelMsg); // This is angel->client data, it will tell us which port was bound. struct Message* angelToClient = InterfaceWaiter_waitForData(&asClientPipe->iface, eventBase, tempAlloc, NULL); uint8_t lastByte = angelToClient->bytes[angelToClient->length-1]; angelToClient->bytes[angelToClient->length-1] = '\0'; printf("Response from angel to client: [%s%c]\n", angelToClient->bytes, (char)lastByte); Allocator_free(tempAlloc); return; }
static Dict* getInitialConfig(struct Interface* iface, struct EventBase* eventBase, struct Allocator* alloc, struct Except* eh) { struct Message* m = InterfaceWaiter_waitForData(iface, eventBase, alloc, eh); struct Reader* reader = ArrayReader_new(m->bytes, m->length, alloc); Dict* config = Dict_new(alloc); if (StandardBencSerializer_get()->parseDictionary(reader, alloc, config)) { Except_raise(eh, -1, "Failed to parse initial configuration."); } return config; }
/** @return a string representing the address and port to connect to. */ static String* initAngel(int fromAngel, int toAngel, int corePipes[2][2], struct PipeInterface** piOut, struct EventBase* eventBase, struct Log* logger, struct Allocator* alloc, struct Random* rand) { #define TO_CORE (corePipes[0][1]) #define FROM_CORE (corePipes[1][0]) #define TO_ANGEL_AS_CORE (corePipes[1][1]) #define FROM_ANGEL_AS_CORE (corePipes[0][0]) Dict core = Dict_CONST( String_CONST("fromCore"), Int_OBJ(FROM_CORE), Dict_CONST( String_CONST("toCore"), Int_OBJ(TO_CORE), NULL )); Dict admin = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST("127.0.0.1")), Dict_CONST( String_CONST("core"), Dict_OBJ(&core), Dict_CONST( String_CONST("pass"), String_OBJ(String_CONST("abcd")), NULL ))); Dict message = Dict_CONST( String_CONST("admin"), Dict_OBJ(&admin), NULL ); struct Allocator* tempAlloc; BufferAllocator_STACK(tempAlloc, 1024); #define BUFFER_SZ 1023 uint8_t buff[BUFFER_SZ + 1] = {0}; struct Writer* w = ArrayWriter_new(buff, BUFFER_SZ, tempAlloc); StandardBencSerializer_get()->serializeDictionary(w, &message); Log_info(logger, "Writing intial configuration to angel on [%d] config: [%s]", toAngel, buff); write(toAngel, buff, w->bytesWritten(w)); // This is angel->core data, we can throw this away. //Waiter_getData(buff, BUFFER_SZ, fromAngel, eventBase, NULL); //Log_info(logger, "Init message from angel to core: [%s]", buff); Bits_memset(buff, 0, BUFFER_SZ); struct PipeInterface* pi = PipeInterface_new(FROM_ANGEL_AS_CORE, TO_ANGEL_AS_CORE, eventBase, logger, alloc, rand); *piOut = pi; Log_info(logger, "PipeInterface [%p] is now ready.", (void*)pi); // Make sure the angel sends data to the core. InterfaceWaiter_waitForData(&pi->generic, eventBase, alloc, NULL); // Send response on behalf of core. char coreToAngelResponse[128] = " PADDING " "\xff\xff\xff\xff" "d" "5:error" "4:none" "e"; char* start = strchr(coreToAngelResponse, '\xff'); struct Message m = { .bytes = (uint8_t*) start, .length = strlen(start), .padding = start - coreToAngelResponse }; pi->generic.sendMessage(&m, &pi->generic); // This is angel->client data, it will tell us which port was bound. Waiter_getData(buff, BUFFER_SZ, fromAngel, eventBase, NULL); printf("Response from angel to client: [%s]\n", buff); struct Reader* reader = ArrayReader_new(buff, BUFFER_SZ, tempAlloc); Dict configStore; Dict* config = &configStore; Assert_true(!StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, config)); Dict* responseAdmin = Dict_getDict(config, String_CONST("admin")); String* bind = Dict_getString(responseAdmin, String_CONST("bind")); Assert_true(bind); return String_clone(bind, alloc); } /** * This spawns itself as the Angel process which spawns itself again as the core process. * The "core process" pipes all of its inputs back to the originating process */ struct AdminTestFramework* AdminTestFramework_setUp(int argc, char** argv) { if (argc > 1 && !strcmp("angel", argv[1])) { exit(AngelInit_main(argc, argv)); } struct Allocator* alloc = CanaryAllocator_new(MallocAllocator_new(1<<20), NULL); struct Writer* logwriter = FileWriter_new(stdout, alloc); Assert_always(logwriter); struct Log* logger = WriterLog_new(logwriter, alloc); struct EventBase* eventBase = EventBase_new(alloc); struct Random* rand = Random_new(alloc, NULL); int fromAngel; int toAngel; int corePipes[2][2]; if (Pipe_createUniPipe(corePipes[0]) || Pipe_createUniPipe(corePipes[1])) { Except_raise(NULL, -1, "Failed to create pipes [%s]", Errno_getString()); } spawnAngel(&fromAngel, &toAngel); struct PipeInterface* pi; String* addrStr = initAngel(fromAngel, toAngel, corePipes, &pi, eventBase, logger, alloc, rand); Log_info(logger, "Angel initialized."); String* password = String_new("abcd", alloc); struct Admin* admin = Admin_new(&pi->generic, alloc, logger, eventBase, password); // Now setup the client. struct sockaddr_storage addr; int addrLen = sizeof(struct sockaddr_storage); Bits_memset(&addr, 0, sizeof(struct sockaddr_storage)); Assert_true(!evutil_parse_sockaddr_port(addrStr->bytes, (struct sockaddr*) &addr, &addrLen)); struct AdminClient* client = AdminClient_new((uint8_t*) &addr, addrLen, password, eventBase, logger, alloc); Assert_always(client); return alloc->clone(sizeof(struct AdminTestFramework), alloc, &(struct AdminTestFramework) { .admin = admin, .client = client, .alloc = alloc, .eventBase = eventBase, .logger = logger, .addr = alloc->clone(addrLen, alloc, &addr), .addrLen = addrLen, .angelInterface = &pi->generic }); }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif if (argc < 2) { // Fall through. } else if (!CString_strcmp("angel", argv[1])) { return AngelInit_main(argc, argv); } else if (!CString_strcmp("core", argv[1])) { return Core_main(argc, argv); } Assert_ifParanoid(argc > 0); struct Except* eh = NULL; // Allow it to allocate 8MB struct Allocator* allocator = MallocAllocator_new(1<<23); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if ((CString_strcmp(argv[1], "--help") == 0) || (CString_strcmp(argv[1], "-h") == 0)) { return usage(allocator, argv[0]); } else if (CString_strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (CString_strcmp(argv[1], "--pidfile") == 0) { // deprecated fprintf(stderr, "'--pidfile' option is deprecated.\n"); return 0; } else if (CString_strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (CString_strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if ((CString_strcmp(argv[1], "--version") == 0) || (CString_strcmp(argv[1], "-v") == 0)) { printf("Cjdns protocol version: %d\n", Version_CURRENT_PROTOCOL); return 0; } else if (CString_strcmp(argv[1], "--cleanconf") == 0) { // Performed after reading configuration } else if (CString_strcmp(argv[1], "--nobg") == 0) { // Performed while reading configuration } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments [%s]\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); // because of '--pidfile $filename'? if (CString_strcmp(argv[1], "--pidfile") == 0) { fprintf(stderr, "\n'--pidfile' option is deprecated.\n"); } return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(allocator, argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } if (argc == 2 && CString_strcmp(argv[1], "--cleanconf") == 0) { struct Writer* stdoutWriter = FileWriter_new(stdout, allocator); JsonBencSerializer_get()->serializeDictionary(stdoutWriter, &config); printf("\n"); return 0; } int forceNoBackground = 0; if (argc == 2 && CString_strcmp(argv[1], "--nobg") == 0) { forceNoBackground = 1; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = CString_strlen(adminPass->bytes); } if (!adminBind) { Except_throw(eh, "You must specify admin.bind in the cjdroute.conf file."); } // --------------------- Welcome to cjdns ---------------------- // char* archInfo = ArchInfo_describe(ArchInfo_detect(), allocator); char* sysInfo = SysInfo_describe(SysInfo_detect(), allocator); Log_info(logger, "Cjdns %s %s", archInfo, sysInfo); // --------------------- Check for running instance --------------------- // Log_info(logger, "Checking for running instance..."); checkRunningInstance(allocator, eventBase, adminBind, adminPass, logger, eh); // --------------------- Setup Pipes to Angel --------------------- // char angelPipeName[64] = "client-angel-"; Random_base32(rand, (uint8_t*)angelPipeName+13, 31); Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); struct Pipe* angelPipe = Pipe_named(angelPipeName, eventBase, eh, allocator); Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); angelPipe->logger = logger; char* args[] = { "angel", angelPipeName, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); char* corePath = Process_getPath(allocator); if (!corePath) { Except_throw(eh, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_throw(eh, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath, args, eventBase, allocator); // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; securityConf && i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), String_new(corePath, allocator), allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } Dict* logging = Dict_getDict(&config, String_CONST("logging")); if (logging) { Dict_putDict(preConf, String_CONST("logging"), logging, allocator); } struct Message* toAngelMsg = Message_new(0, 1024, allocator); BencMessageWriter_write(preConf, toAngelMsg, eh); Interface_sendMessage(&angelPipe->iface, toAngelMsg); Log_debug(logger, "Sent [%d] bytes to angel process", toAngelMsg->length); // --------------------- Get Response from Angel --------------------- // struct Message* fromAngelMsg = InterfaceWaiter_waitForData(&angelPipe->iface, eventBase, allocator, eh); Dict* responseFromAngel = BencMessageReader_read(fromAngelMsg, allocator, eh); // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_throw(eh, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_throw(eh, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check, Pipe_named() creates 2 events, see above. Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); // --------------------- noBackground ------------------------ // int64_t* noBackground = Dict_getInt(&config, String_CONST("noBackground")); if (forceNoBackground || (noBackground && *noBackground)) { EventBase_beginLoop(eventBase); } //Allocator_free(allocator); return 0; }
static void sendConfToCore(struct Interface* toCoreInterface, struct Allocator* alloc, Dict* config, struct Except* eh, struct Log* logger) { #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE + 32] = {0}; uint8_t* start = buff + 32; struct Writer* writer = ArrayWriter_new(start, CONFIG_BUFF_SIZE - 33, alloc); if (StandardBencSerializer_get()->serializeDictionary(writer, config)) { Except_raise(eh, -1, "Failed to serialize pre-configuration for core."); } struct Message m = { .bytes = start, .length = writer->bytesWritten(writer), .padding = 32 }; Log_keys(logger, "Sent [%d] bytes to core [%s].", m.length, m.bytes); toCoreInterface->sendMessage(&m, toCoreInterface); } static void setUser(char* user, struct Log* logger, struct Except* eh) { struct Jmp jmp; Jmp_try(jmp) { Security_setUser(user, logger, &jmp.handler); } Jmp_catch { if (jmp.code == Security_setUser_PERMISSION) { return; } Except_raise(eh, jmp.code, "%s", jmp.message); } } /** * Input: * { * "admin": { * "core": "/path/to/core/binary", * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * for example: * d5:admind4:core30:./build/admin/angel/cjdns-core4:bind15:127.0.0.1:123454:pass4:abcdee * * Pre-existing core mode: * { * "admin": { * "core": { * "fromCore": 12, * "toCore": 14 * }, * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * * If "core" is a dictionary, the angel will behave as though the core is already spawned and * it will read from the core on the file descriptor given by "fromCore" and write to the file * given by "toCore". * * "user" is optional, if set the angel will setuid() that user's uid. */ int AngelInit_main(int argc, char** argv) { struct Except* eh = NULL; int inFromClientNo; int outToClientNo; if (argc < 3 || (inFromClientNo = atoi(argv[2])) == 0) { inFromClientNo = STDIN_FILENO; } if (argc < 4 || (outToClientNo = atoi(argv[3])) == 0) { outToClientNo = STDOUT_FILENO; } struct Allocator* alloc = MallocAllocator_new(1<<21); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Random* rand = Random_new(alloc, logger, eh); alloc = CanaryAllocator_new(alloc, rand); struct Allocator* tempAlloc = Allocator_child(alloc); struct EventBase* eventBase = EventBase_new(alloc); Log_debug(logger, "Initializing angel with input [%d] and output [%d]", inFromClientNo, outToClientNo); Log_debug(logger, "Getting pre-configuration from client"); #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; Waiter_getData(buff, CONFIG_BUFF_SIZE, inFromClientNo, eventBase, eh); Log_debug(logger, "Finished getting pre-configuration from client"); struct Reader* reader = ArrayReader_new(buff, CONFIG_BUFF_SIZE, tempAlloc); Dict config; if (StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, &config)) { Except_raise(eh, -1, "Failed to parse configuration."); } Dict* admin = Dict_getDict(&config, String_CONST("admin")); String* core = Dict_getString(admin, String_CONST("core")); String* bind = Dict_getString(admin, String_CONST("bind")); String* pass = Dict_getString(admin, String_CONST("pass")); String* user = Dict_getString(admin, String_CONST("user")); int toCore = -1; int fromCore = -1; if (!core) { Dict* coreDict = Dict_getDict(admin, String_CONST("core")); int64_t* toCorePtr = Dict_getInt(coreDict, String_CONST("toCore")); int64_t* fromCorePtr = Dict_getInt(coreDict, String_CONST("fromCore")); toCore = (toCorePtr) ? *toCorePtr : -1; fromCore = (fromCorePtr) ? *fromCorePtr : -1; } if (!bind || !pass || (!core && (toCore == -1 || fromCore == -1))) { Except_raise(eh, -1, "missing configuration params in preconfig. [%s]", buff); } if (core) { Log_info(logger, "Initializing core [%s]", core->bytes); initCore(core->bytes, &toCore, &fromCore, eh); } Log_debug(logger, "Sending pre-configuration to core."); struct PipeInterface* pif = PipeInterface_new(fromCore, toCore, eventBase, logger, alloc, rand); struct Interface* coreIface = &pif->generic; PipeInterface_waitUntilReady(pif); sendConfToCore(coreIface, tempAlloc, &config, eh, logger); struct Message* coreResponse = InterfaceWaiter_waitForData(coreIface, eventBase, tempAlloc, eh); if (write(outToClientNo, coreResponse->bytes, coreResponse->length)) { // Ignore the result of write() without the compiler complaining. } #ifdef Log_KEYS uint8_t lastChar = coreResponse->bytes[coreResponse->length-1]; coreResponse->bytes[coreResponse->length-1] = 0; Log_keys(logger, "Sent [%s%c] to client.", coreResponse->bytes, lastChar); coreResponse->bytes[coreResponse->length-1] = lastChar; #endif if (user) { setUser(user->bytes, logger, eh); } Allocator_free(tempAlloc); Angel_start(coreIface, eventBase, logger, alloc); return 0; }
/** @return a string representing the address and port to connect to. */ static void initAngel(struct Pipe* asClientPipe, struct Interface* asCoreIface, char* asCorePipeName, struct EventBase* eventBase, struct Log* logger, struct Allocator* alloc, struct Random* rand) { Dict admin = Dict_CONST( String_CONST("bind"), String_OBJ(String_CONST("127.0.0.1")), Dict_CONST( String_CONST("corePipeName"), String_OBJ(String_CONST(asCorePipeName)), Dict_CONST( String_CONST("pass"), String_OBJ(String_CONST("abcd")), NULL ))); Dict message = Dict_CONST( String_CONST("admin"), Dict_OBJ(&admin), NULL ); struct Allocator* tempAlloc = Allocator_child(alloc); #define BUFFER_SZ 1023 uint8_t buff[BUFFER_SZ + 1] = {0}; struct Writer* w = ArrayWriter_new(buff, BUFFER_SZ, tempAlloc); StandardBencSerializer_get()->serializeDictionary(w, &message); struct Message* toAngel = Allocator_malloc(tempAlloc, sizeof(struct Message) + w->bytesWritten); toAngel->bytes = (uint8_t*) (&toAngel[1]); toAngel->length = toAngel->capacity = w->bytesWritten; toAngel->padding = 0; toAngel->alloc = tempAlloc; Bits_memcpy(toAngel->bytes, buff, toAngel->length); Log_info(logger, "Writing intial configuration to angel on [%s] config: [%s]", asClientPipe->name, buff); Interface_sendMessage(&asClientPipe->iface, toAngel); // This is client->angel->core data, we can throw this away. //struct Message* angelToCore = InterfaceWaiter_waitForData(asCoreIface, eventBase, tempAlloc, NULL); // unterminated string //Log_info(logger, "Init message from angel to core: [%s]", angelToCore->bytes); // Send response on behalf of core. char* coreToAngelResponse = " PADDING " "d" "5:error" "4:none" "e"; struct Message* m = &(struct Message) { .bytes = (uint8_t*) coreToAngelResponse, .length = strlen(coreToAngelResponse), .padding = 0, .capacity = strlen(coreToAngelResponse) }; Message_shift(m, -24, NULL); m = Message_clone(m, tempAlloc); Interface_sendMessage(asCoreIface, m); // This is angel->client data, it will tell us which port was bound. struct Message* angelToClient = InterfaceWaiter_waitForData(&asClientPipe->iface, eventBase, tempAlloc, NULL); printf("Response from angel to client: [%s]\n", angelToClient->bytes); Allocator_free(tempAlloc); return; }
int main(int argc, char** argv) { Assert_ifParanoid(argc > 0); struct Allocator* allocator = MallocAllocator_new(1<<23); if (argc != 6 || (argc == 2 && (!(CString_strcmp(argv[1], "--help") == 0) || (CString_strcmp(argv[1], "-h") == 0)))) { return usage(allocator, argv[0]); } struct Except* eh = NULL; struct EventBase* eventBase = EventBase_new(allocator); struct Log* logger = FileWriterLog_new(stdout, allocator); String* privateKey = String_new(argv[3], allocator); String* adminBind = String_new(argv[4], allocator); String* adminPass = String_new(argv[5], allocator); String* logTo = String_new("stdout", allocator); // --------------------- Welcome to cjdns ---------------------- // char* sysInfo = SysInfo_describe(SysInfo_detect(), allocator); Log_info(logger, "Cjdns %s %s", ArchInfo_getArchStr(), sysInfo); // --------------------- Setup Pipes to Angel --------------------- // struct Allocator* corePipeAlloc = Allocator_child(allocator); String* corePipeDir = String_new(argv[1], allocator); String* corePipeName = String_new(argv[2], allocator); if (!Defined(win32) && access(corePipeDir->bytes, W_OK)) { Except_throw(eh, "Don't have write permission to [%s].", corePipeDir->bytes); } Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); struct Pipe* corePipe = Pipe_named(corePipeDir->bytes, corePipeName->bytes, eventBase, eh, corePipeAlloc); Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); corePipe->logger = logger; // --------------------- Pre-Configure Core ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict* logPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putDict(preConf, String_CONST("logging"), logPreConf, allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); Dict_putString(logPreConf, String_CONST("logTo"), logTo, allocator); struct Message* toCoreMsg = Message_new(0, 1024, allocator); BencMessageWriter_write(preConf, toCoreMsg, eh); Iface_CALL(corePipe->iface.send, toCoreMsg, &corePipe->iface); Log_debug(logger, "Sent [%d] bytes to core.", toCoreMsg->length); // --------------------- Get Response from Core --------------------- // struct Message* fromCoreMsg = InterfaceWaiter_waitForData(&corePipe->iface, eventBase, allocator, eh); Dict* responseFromCore = BencMessageReader_read(fromCoreMsg, allocator, eh); // --------------------- Close the Core Pipe --------------------- // Allocator_free(corePipeAlloc); corePipe = NULL; // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromCoreAdmin = Dict_getDict(responseFromCore, String_CONST("admin")); adminBind = Dict_getString(responseFromCoreAdmin, String_CONST("bind")); if (!adminBind) { Except_throw(eh, "Didn't get ADMIN_BIND back from cjdroute."); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_throw(eh, "Unable to parse [%s] as an IP address:port.", adminBind->bytes); } Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); Log_info(logger, "Admin API ready at [%s].", adminBind->bytes); return 0; }
/** * Input: * { * "admin": { * "core": "/path/to/core/binary", * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * for example: * d5:admind4:core30:./build/admin/angel/cjdns-core4:bind15:127.0.0.1:123454:pass4:abcdee * * Pre-existing core mode: * { * "admin": { * "core": { * "fromCore": 12, * "toCore": 14 * }, * "bind": "127.0.0.1:12345", * "pass": "******", * "user": "******" * } * } * * If "core" is a dictionary, the angel will behave as though the core is already spawned and * it will read from the core on the file descriptor given by "fromCore" and write to the file * given by "toCore". * * "user" is optional, if set the angel will setuid() that user's uid. */ int AngelInit_main(int argc, char** argv) { struct Except* eh = NULL; struct Allocator* alloc = MallocAllocator_new(1<<21); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Random* rand = Random_new(alloc, logger, eh); MallocAllocator_setCanary(alloc, (long)Random_int64(rand)); struct Allocator* tempAlloc = Allocator_child(alloc); struct EventBase* eventBase = EventBase_new(alloc); struct Pipe* clientPipe = getClientPipe(argc, argv, eventBase, eh, alloc); clientPipe->logger = logger; Log_debug(logger, "Getting pre-configuration from client"); struct Message* preConf = InterfaceWaiter_waitForData(&clientPipe->iface, eventBase, alloc, eh); Log_debug(logger, "Finished getting pre-configuration from client"); struct Reader* reader = ArrayReader_new(preConf->bytes, preConf->length, tempAlloc); Dict config; if (StandardBencSerializer_get()->parseDictionary(reader, tempAlloc, &config)) { Except_raise(eh, -1, "Failed to parse configuration."); } Dict* admin = Dict_getDict(&config, String_CONST("admin")); String* core = Dict_getString(admin, String_CONST("core")); String* bind = Dict_getString(admin, String_CONST("bind")); String* pass = Dict_getString(admin, String_CONST("pass")); String* user = Dict_getString(admin, String_CONST("user")); String* corePipeName = Dict_getString(admin, String_CONST("corePipeName")); if (!bind || !pass || (!core && !corePipeName)) { Except_raise(eh, -1, "missing configuration params in preconfig. [%s]", preConf->bytes); } if (!corePipeName) { char name[32] = {0}; Random_base32(rand, (uint8_t*)name, 31); corePipeName = String_new(name, tempAlloc); } struct Pipe* corePipe = Pipe_named(corePipeName->bytes, eventBase, eh, alloc); corePipe->logger = logger; corePipe->onClose = coreDied; struct Interface* coreIface = FramingInterface_new(65535, &corePipe->iface, alloc); if (core) { Log_info(logger, "Initializing core [%s]", core->bytes); initCore(core->bytes, corePipeName, eventBase, alloc, eh); } Log_debug(logger, "Sending pre-configuration to core."); sendConfToCore(coreIface, tempAlloc, &config, eh, logger); struct Message* coreResponse = InterfaceWaiter_waitForData(coreIface, eventBase, tempAlloc, eh); Interface_sendMessage(&clientPipe->iface, coreResponse); #ifdef Log_KEYS uint8_t lastChar = coreResponse->bytes[coreResponse->length-1]; coreResponse->bytes[coreResponse->length-1] = 0; Log_keys(logger, "Sent [%s%c] to client.", coreResponse->bytes, lastChar); coreResponse->bytes[coreResponse->length-1] = lastChar; #endif if (user) { setUser(user->bytes, logger, eh); } Allocator_free(tempAlloc); Angel_start(coreIface, eventBase, logger, alloc); return 0; }