Pārlūkot izejas kodu

Start clients module. Parse manifest to generate the list of ingestion and storage servers.

Sajin Sasy 1 gadu atpakaļ
vecāks
revīzija
3545e021ec
4 mainītis faili ar 321 papildinājumiem un 3 dzēšanām
  1. 1 1
      App/mkconfig.py
  2. 87 0
      Client/clientlaunch
  3. 204 0
      Client/clients.cpp
  4. 29 2
      Makefile

+ 1 - 1
App/mkconfig.py

@@ -47,7 +47,7 @@ def create_json(manifestfile, pubkeysfile, nodelist, params_override):
         nodeconf['pubkey'] = pubkeys[node]
         nodeconf['listen'] = m['listen']
         # Optional fields
-        for f in ['clisten', 'weight']:
+        for f in ['clisten', 'weight', 'role']:
             if f in m:
                 nodeconf[f] = m[f]
         config['nodes'].append(nodeconf)

+ 87 - 0
Client/clientlaunch

@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import shlex
+import subprocess
+import sys
+import threading
+import yaml
+sys.path.insert(0, os.getcwd())
+sys.path.insert(1, './../App/')
+import mkconfig
+
+# The default manifest file
+MANIFEST = "./../App/manifest.yaml"
+
+# The default pubkeys file
+PUBKEYS = "./../App/pubkeys.yaml"
+
+#The client binary
+CLIENTS = "./clients"
+
+def launch(manifest, config, cmd):
+    cmdline = ''
+    cmdline += CLIENTS + ""
+    proc = subprocess.Popen(shlex.split(cmdline) + cmd,
+        stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+        stderr=subprocess.STDOUT, bufsize=0)
+    print(cmdline)
+    proc.stdin.write(config.encode('utf-8'))
+    while True:
+        line = proc.stdout.readline()
+        if not line:
+            break
+        print(line.decode('utf-8'), end='', flush=True)
+
+
+if __name__ == "__main__":
+    print("In clientlaunch")
+    aparse = argparse.ArgumentParser(
+        description='Launch CLIENTS'
+    )
+    aparse.add_argument('-m', default=MANIFEST,
+        help='manifest.yaml file')
+    aparse.add_argument('-p', default=PUBKEYS,
+        help='pubkeys.yaml file')
+    aparse.add_argument('-z', default=None,
+        help='override message size')
+    aparse.add_argument('-u', default=None,
+        help='override max number of users')
+    aparse.add_argument('-B', default=None,
+        help='override max number of outgoing private messages per user per epoch')
+    aparse.add_argument('-b', default=None,
+        help='override max number of incoming private messages per user per epoch')
+    aparse.add_argument('-C', default=None,
+        help='override max number of outgoing public messages per user per epoch')
+    aparse.add_argument('-c', default=None,
+        help='override max number of incoming public messages per user per epoch')
+    aparse.add_argument('-n', nargs='*', help='nodes to include')
+    aparse.add_argument('cmd', nargs='*', help='experiment to run')
+    args = aparse.parse_args()
+
+    with open(args.m) as mf:
+        manifest = yaml.safe_load(mf)
+
+    params_overrides = {
+        'msg_size': args.z,
+        'user_count': args.u,
+        'priv_out': args.B,
+        'priv_in': args.b,
+        'pub_out': args.C,
+        'pub_in': args.c,
+    }
+
+    config = mkconfig.create_json(args.m, args.p, args.n, params_overrides)
+
+    # There must not be any newlines in the config json string
+    if "\n" in config:
+        print("Error: config.json must not contain embedded newlines")
+        sys.exit(1)
+    # Now add a trailing newline
+    config += "\n"
+
+    thread = threading.Thread(target=launch,
+        args=(manifest, config, args.cmd))
+    thread.start()
+    thread.join()

+ 204 - 0
Client/clients.cpp

@@ -0,0 +1,204 @@
+#include <iostream>
+#include "../App/appconfig.hpp"
+
+// The next line suppresses a deprecation warning within boost
+#define BOOST_BIND_GLOBAL_PLACEHOLDERS
+#include "boost/property_tree/ptree.hpp"
+#include "boost/property_tree/json_parser.hpp"
+
+// Split a hostport string like "127.0.0.1:12000" at the rightmost colon
+// into a host part "127.0.0.1" and a port part "12000".
+static bool split_host_port(std::string &host, std::string &port,
+    const std::string &hostport)
+{
+    size_t colon = hostport.find_last_of(':');
+    if (colon == std::string::npos) {
+        std::cerr << "Cannot parse \"" << hostport << "\" as host:port\n";
+        return false;
+    }
+    host = hostport.substr(0, colon);
+    port = hostport.substr(colon+1);
+    return true;
+}
+
+// Convert a single hex character into its value from 0 to 15. Return
+// true on success, false if it wasn't a hex character.
+static inline bool hextoval(unsigned char &val, char hex)
+{
+    if (hex >= '0' && hex <= '9') {
+        val = ((unsigned char)hex)-'0';
+    } else if (hex >= 'a' && hex <= 'f') {
+        val = ((unsigned char)hex)-'a'+10;
+    } else if (hex >= 'A' && hex <= 'F') {
+        val = ((unsigned char)hex)-'A'+10;
+    } else {
+        return false;
+    }
+    return true;
+}
+
+// Convert a 2*len hex character string into a len-byte buffer. Return
+// true on success, false on failure.
+static bool hextobuf(unsigned char *buf, const char *str, size_t len)
+{
+    if (strlen(str) != 2*len) {
+        std::cerr << "Hex string was not the expected size\n";
+        return false;
+    }
+    for (size_t i=0;i<len;++i) {
+        unsigned char hi, lo;
+        if (!hextoval(hi, str[2*i]) || !hextoval(lo, str[2*i+1])) {
+            std::cerr << "Cannot parse string as hex\n";
+            return false;
+        }
+        buf[i] = (unsigned char)((hi << 4) + lo);
+    }
+    return true;
+}
+
+
+bool config_parse(Config &config, const std::string configstr,
+    std::vector<NodeConfig> &ingestion_nodes,
+    std::vector<NodeConfig> &storage_nodes)
+{
+    bool found_params = false;
+    bool ret = true;
+
+    std::istringstream configstream(configstr);
+    boost::property_tree::ptree conftree;
+
+    read_json(configstream, conftree);
+
+    for (auto & entry : conftree) {
+        if (!entry.first.compare("params")) {
+            for (auto & pentry : entry.second) {
+                if (!pentry.first.compare("msg_size")) {
+                    config.msg_size = pentry.second.get_value<uint16_t>();
+                } else if (!pentry.first.compare("user_count")) {
+                    config.user_count = pentry.second.get_value<uint32_t>();
+                } else if (!pentry.first.compare("priv_out")) {
+                    config.m_priv_out = pentry.second.get_value<uint8_t>();
+                } else if (!pentry.first.compare("priv_in")) {
+                    config.m_priv_in = pentry.second.get_value<uint8_t>();
+                } else if (!pentry.first.compare("pub_out")) {
+                    config.m_pub_out = pentry.second.get_value<uint8_t>();
+                } else if (!pentry.first.compare("pub_in")) {
+                    config.m_pub_in = pentry.second.get_value<uint8_t>();
+                // Currently hardcoding an AES key for client -> server communication
+                } else if (!pentry.first.compare("client_aes_key")) {
+                    std::string hex_key = pentry.second.data();
+                    memcpy(config.client_aes_key, hex_key.c_str(), SGX_AESGCM_KEY_SIZE);
+
+                } else {
+                    std::cerr << "Unknown field in params: " <<
+                        pentry.first << "\n";
+                    ret = false;
+                }
+            }
+            found_params = true;
+        } else if (!entry.first.compare("nodes")) {
+            for (auto & node : entry.second) {
+                NodeConfig nc;
+                // All nodes need to be assigned their role in manifest.yaml
+                nc.roles = 0;
+                for (auto & nentry : node.second) {
+                    if (!nentry.first.compare("name")) {
+                        nc.name = nentry.second.get_value<std::string>();
+                    } else if (!nentry.first.compare("pubkey")) {
+                        ret &= hextobuf((unsigned char *)&nc.pubkey,
+                            nentry.second.get_value<std::string>().c_str(),
+                            sizeof(nc.pubkey));
+                    } else if (!nentry.first.compare("weight")) {
+                        nc.weight = nentry.second.get_value<std::uint8_t>();
+                    } else if (!nentry.first.compare("listen")) {
+                        ret &= split_host_port(nc.listenhost, nc.listenport,
+                            nentry.second.get_value<std::string>());
+                    } else if (!nentry.first.compare("clisten")) {
+                        ret &= split_host_port(nc.clistenhost, nc.clistenport,
+                            nentry.second.get_value<std::string>());
+                    } else if (!nentry.first.compare("role")) {
+                        nc.roles = nentry.second.get_value<std::uint8_t>();
+                    } else {
+                        std::cerr << "Unknown field in host config: " <<
+                            nentry.first << "\n";
+                        ret = false;
+                    }
+                }
+                if(nc.roles == ROLE_INGESTION) {
+                    ingestion_nodes.push_back(std::move(nc));
+                } else if(nc.roles == ROLE_STORAGE) {
+                    storage_nodes.push_back(std::move(nc));
+                }
+            }
+        } else {
+            std::cerr << "Unknown key in config: " <<
+                entry.first << "\n";
+            ret = false;
+        }
+    }
+
+    if (!found_params) {
+        std::cerr << "Could not find params in config\n";
+        ret = false;
+    }
+
+    return ret;
+}
+
+static void usage(const char *argv0)
+{
+    fprintf(stderr, "%s [-t nthreads] < config.json\n",
+        argv0);
+    exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+    // Unbuffer stdout
+    setbuf(stdout, NULL);
+
+    uint16_t nthreads = 1;
+    const char *progname = argv[0];
+    std::vector<NodeConfig> ingestion_nodes, storage_nodes;
+    ++argv;
+
+    // Parse options
+    while (*argv && (*argv)[0] == '-') {
+        if (!strcmp(*argv, "-t")) {
+            if (argv[1] == NULL) {
+                usage(progname);
+            }
+            nthreads = uint16_t(atoi(argv[1]));
+            argv += 2;
+        } else {
+            usage(progname);
+        }
+    }
+
+    // Read the config.json from the first line of stdin.  We have to do
+    // this before outputting anything to avoid potential deadlock with
+    // the launch program.
+    std::string configstr;
+    std::getline(std::cin, configstr);
+
+    Config config;
+
+    if (!config_parse(config, configstr, ingestion_nodes, storage_nodes)) {
+       exit(1);
+    }
+
+    printf("Number of ingestion_nodes = %ld, Number of storage_node = %ld\n",
+        ingestion_nodes.size(), storage_nodes.size());
+
+
+    /*
+        Spin config.user_client actual clients. Each client:
+        1) Retrieve messages and tokens from their storage server
+        2) Send all their messages to the ingestion server
+        3) Wait for a predetermined EPOCH_DURATION time
+        4) Repeat from 1)
+    */
+
+}
+

+ 29 - 2
Makefile

@@ -107,6 +107,20 @@ App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o)
 
 App_Name := App/teems
 
+######## Client Settings ########
+
+Client_Cpp_Files := $(wildcard Client/*.cpp)
+
+Client_Include_Paths := -IApp -IUntrusted -I$(SGX_SDK)/include
+
+Client_Cpp_Flags := -fPIC -Wno-attributes $(Client_Include_Paths)
+
+Client_Cpp_Objects := $(Client_Cpp_Files:.cpp=.o)
+
+Client_Link_Flags := -lboost_thread -lpthread
+
+Client_Name := Client/clients
+
 ######## Enclave Settings ########
 
 Enclave_Version_Script := Enclave/Enclave_debug.lds
@@ -184,7 +198,7 @@ all: .config_$(Build_Mode)_$(SGX_ARCH)
 	@$(MAKE) target
 
 ifeq ($(Build_Mode), HW_RELEASE)
-target: $(App_Name) $(Enclave_Name)
+target: $(App_Name) $(Enclave_Name) $(Client_Name)
 	@echo "The project has been built in release hardware mode."
 	@echo "Please sign the $(Enclave_Name) first with your signing key before you run the $(App_Name) to launch and access the enclave."
 	@echo "To sign the enclave use the command:"
@@ -192,7 +206,7 @@ target: $(App_Name) $(Enclave_Name)
 	@echo "You can also sign the enclave using an external signing tool."
 	@echo "To build the project in simulation mode set SGX_MODE=SIM. To build the project in prerelease mode set SGX_PRERELEASE=1 and SGX_MODE=HW."
 else
-target: $(App_Name) $(Signed_Enclave_Name)
+target: $(App_Name) $(Signed_Enclave_Name) $(Client_Name)
 ifeq ($(Build_Mode), HW_DEBUG)
 	@echo "The project has been built in debug hardware mode."
 else ifeq ($(Build_Mode), SIM_DEBUG)
@@ -271,6 +285,19 @@ endif
 	@echo "SIGN =>  $@"
 	@$(SGX_ENCLAVE_SIGNER) sign -key $(Enclave_Test_Key) -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File)
 
+######## Client Objects ########
+
+Clients/clients.o: Clients/clients.cpp
+
+Client/%.o: Client/%.cpp
+	@echo "CXX  <=  $<"
+	@$(CXX) $(App_Cpp_Flags) -c $< -o $@
+
+$(Client_Name): $(Client_Cpp_Objects)
+	@echo "LINK =>  $@"
+	@$(CXX) $^ -o $@ $(Client_Link_Flags)
+
+
 .PHONY: clean
 
 clean: