aboutsummaryrefslogtreecommitdiffstats
path: root/test/netlib/tservers.py
blob: b344e25c951a7c0ea82faadd1114e549feebde05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import threading
import queue
import io
import OpenSSL

from netlib import tcp
from netlib import tutils


class _ServerThread(threading.Thread):

    def __init__(self, server):
        self.server = server
        threading.Thread.__init__(self)

    def run(self):
        self.server.serve_forever()

    def shutdown(self):
        self.server.shutdown()


class _TServer(tcp.TCPServer):

    def __init__(self, ssl, q, handler_klass, addr, **kwargs):
        """
            ssl: A dictionary of SSL parameters:

                    cert, key, request_client_cert, cipher_list,
                    dhparams, v3_only
        """
        tcp.TCPServer.__init__(self, addr)

        if ssl is True:
            self.ssl = dict()
        elif isinstance(ssl, dict):
            self.ssl = ssl
        else:
            self.ssl = None

        self.q = q
        self.handler_klass = handler_klass
        if self.handler_klass is not None:
            self.handler_klass.kwargs = kwargs
        self.last_handler = None

    def handle_client_connection(self, request, client_address):
        h = self.handler_klass(request, client_address, self)
        self.last_handler = h
        if self.ssl is not None:
            cert = self.ssl.get(
                "cert",
                tutils.test_data.path("data/server.crt"))
            raw_key = self.ssl.get(
                "key",
                tutils.test_data.path("data/server.key"))
            key = OpenSSL.crypto.load_privatekey(
                OpenSSL.crypto.FILETYPE_PEM,
                open(raw_key, "rb").read())
            if self.ssl.get("v3_only", False):
                method = OpenSSL.SSL.SSLv3_METHOD
                options = OpenSSL.SSL.OP_NO_SSLv2 | OpenSSL.SSL.OP_NO_TLSv1
            else:
                method = OpenSSL.SSL.SSLv23_METHOD
                options = None
            h.convert_to_ssl(
                cert, key,
                method=method,
                options=options,
                handle_sni=getattr(h, "handle_sni", None),
                request_client_cert=self.ssl.get("request_client_cert", None),
                cipher_list=self.ssl.get("cipher_list", None),
                dhparams=self.ssl.get("dhparams", None),
                chain_file=self.ssl.get("chain_file", None),
                alpn_select=self.ssl.get("alpn_select", None)
            )
        h.handle()
        h.finish()

    def handle_error(self, connection, client_address, fp=None):
        s = io.StringIO()
        tcp.TCPServer.handle_error(self, connection, client_address, s)
        self.q.put(s.getvalue())


class ServerTestBase:
    ssl = None
    handler = None
    addr = ("localhost", 0)

    @classmethod
    def setup_class(cls, **kwargs):
        cls.q = queue.Queue()
        s = cls.makeserver(**kwargs)
        cls.port = s.address.port
        cls.server = _ServerThread(s)
        cls.server.start()

    @classmethod
    def makeserver(cls, **kwargs):
        ssl = kwargs.pop('ssl', cls.ssl)
        return _TServer(ssl, cls.q, cls.handler, cls.addr, **kwargs)

    @classmethod
    def teardown_class(cls):
        cls.server.shutdown()

    def teardown(self):
        self.server.server.wait_for_silence()

    @property
    def last_handler(self):
        return self.server.server.last_handler
t; YOSYS_NAMESPACE_BEGIN using namespace VERILOG_FRONTEND; static std::list<std::string> output_code; static std::list<std::string> input_buffer; static size_t input_buffer_charp; static void return_char(char ch) { if (input_buffer_charp == 0) input_buffer.push_front(std::string() + ch); else input_buffer.front()[--input_buffer_charp] = ch; } static void insert_input(std::string str) { if (input_buffer_charp != 0) { input_buffer.front() = input_buffer.front().substr(input_buffer_charp); input_buffer_charp = 0; } input_buffer.push_front(str); } static char next_char() { if (input_buffer.empty()) return 0; log_assert(input_buffer_charp <= input_buffer.front().size()); if (input_buffer_charp == input_buffer.front().size()) { input_buffer_charp = 0; input_buffer.pop_front(); return next_char(); } char ch = input_buffer.front()[input_buffer_charp++]; return ch == '\r' ? next_char() : ch; } static std::string skip_spaces() { std::string spaces; while (1) { char ch = next_char(); if (ch == 0) break; if (ch != ' ' && ch != '\t') { return_char(ch); break; } spaces += ch; } return spaces; } static std::string next_token(bool pass_newline = false) { std::string token; char ch = next_char(); if (ch == 0) return token; token += ch; if (ch == '\n') { if (pass_newline) { output_code.push_back(token); return ""; } return token; } if (ch == ' ' || ch == '\t') { while ((ch = next_char()) != 0) { if (ch != ' ' && ch != '\t') { return_char(ch); break; } token += ch; } } else if (ch == '"') { while ((ch = next_char()) != 0) { token += ch; if (ch == '"') break; if (ch == '\\') { if ((ch = next_char()) != 0) token += ch; } } if (token == "\"\"" && (ch = next_char()) != 0) { if (ch == '"') token += ch; else return_char(ch); } } else if (ch == '/') { if ((ch = next_char()) != 0) { if (ch == '/') { token += '*'; char last_ch = 0; while ((ch = next_char()) != 0) { if (ch == '\n') { return_char(ch); break; } if (last_ch != '*' || ch != '/') { token += ch; last_ch = ch; } } token += " */"; } else if (ch == '*') { token += '*'; int newline_count = 0; char last_ch = 0; while ((ch = next_char()) != 0) { if (ch == '\n') { newline_count++; token += ' '; } else token += ch; if (last_ch == '*' && ch == '/') break; last_ch = ch; } while (newline_count-- > 0) return_char('\n'); } else return_char(ch); } } else { const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789"; if (ch == '`' || strchr(ok, ch) != NULL) { char first = ch; ch = next_char(); if (first == '`' && (ch == '"' || ch == '`')) { token += ch; } else do { if (strchr(ok, ch) == NULL) { return_char(ch); break; } token += ch; } while ((ch = next_char()) != 0); } } return token; } static void input_file(std::istream &f, std::string filename) { char buffer[513]; int rc; insert_input(""); auto it = input_buffer.begin(); input_buffer.insert(it, "`file_push \"" + filename + "\"\n"); while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) { buffer[rc] = 0; input_buffer.insert(it, buffer); } input_buffer.insert(it, "\n`file_pop\n"); } static bool try_expand_macro(std::set<std::string> &defines_with_args, std::map<std::string, std::string> &defines_map, std::string &tok ) { if (tok == "`\"") { std::string literal("\""); // Expand string literal while (!input_buffer.empty()) { std::string ntok = next_token(); if (ntok == "`\"") { insert_input(literal+"\""); return true; } else if (!try_expand_macro(defines_with_args, defines_map, ntok)) { literal += ntok; } } return false; // error - unmatched `" } else if (tok.size() > 1 && tok[0] == '`' && defines_map.count(tok.substr(1)) > 0) { std::string name = tok.substr(1); // printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str()); std::string skipped_spaces = skip_spaces(); tok = next_token(false); if (tok == "(" && defines_with_args.count(name) > 0) { int level = 1; std::vector<std::string> args; args.push_back(std::string()); while (1) { skip_spaces(); tok = next_token(true); if (tok == ")" || tok == "}" || tok == "]") level--; if (level == 0) break; if (level == 1 && tok == ",") args.push_back(std::string()); else args.back() += tok; if (tok == "(" || tok == "{" || tok == "[") level++; } for (int i = 0; i < GetSize(args); i++) defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i]; } else { insert_input(tok); insert_input(skipped_spaces); } insert_input(defines_map[name]); return true; } else if (tok == "``") { // Swallow `` in macro expansion return true; } else return false; } std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> &pre_defines_map, dict<std::string, std::pair<std::string, bool>> &global_defines_cache, const std::list<std::string> &include_dirs) { std::set<std::string> defines_with_args; std::map<std::string, std::string> defines_map(pre_defines_map); std::vector<std::string> filename_stack; int ifdef_fail_level = 0; bool in_elseif = false; output_code.clear(); input_buffer.clear(); input_buffer_charp = 0; input_file(f, filename); defines_map["YOSYS"] = "1"; defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1"; for (auto &it : pre_defines_map) defines_map[it.first] = it.second; for (auto &it : global_defines_cache) { if (it.second.second) defines_with_args.insert(it.first); defines_map[it.first] = it.second.first; } while (!input_buffer.empty()) { std::string tok = next_token(); // printf("token: >>%s<<\n", tok != "\n" ? tok.c_str() : "NEWLINE"); if (tok == "`endif") { if (ifdef_fail_level > 0) ifdef_fail_level--; if (ifdef_fail_level == 0) in_elseif = false; continue; } if (tok == "`else") { if (ifdef_fail_level == 0) ifdef_fail_level = 1; else if (ifdef_fail_level == 1 && !in_elseif) ifdef_fail_level = 0; continue; } if (tok == "`elsif") { skip_spaces(); std::string name = next_token(true); if (ifdef_fail_level == 0) ifdef_fail_level = 1, in_elseif = true; else if (ifdef_fail_level == 1 && defines_map.count(name) != 0) ifdef_fail_level = 0, in_elseif = true; continue; } if (tok == "`ifdef") { skip_spaces(); std::string name = next_token(true); if (ifdef_fail_level > 0 || defines_map.count(name) == 0) ifdef_fail_level++; continue; } if (tok == "`ifndef") { skip_spaces(); std::string name = next_token(true); if (ifdef_fail_level > 0 || defines_map.count(name) != 0) ifdef_fail_level++; continue; } if (ifdef_fail_level > 0) { if (tok == "\n") output_code.push_back(tok); continue; } if (tok == "`include") { skip_spaces(); std::string fn = next_token(true); while (try_expand_macro(defines_with_args, defines_map, fn)) { fn = next_token(); } while (1) { size_t pos = fn.find('"'); if (pos == std::string::npos) break; if (pos == 0) fn = fn.substr(1); else fn = fn.substr(0, pos) + fn.substr(pos+1); } std::ifstream ff; ff.clear(); std::string fixed_fn = fn; ff.open(fixed_fn.c_str()); bool filename_path_sep_found; bool fn_relative; #ifdef _WIN32 // Both forward and backslash are acceptable separators on Windows. filename_path_sep_found = (filename.find_first_of("/\\") != std::string::npos); // Easier just to invert the check for an absolute path (e.g. C:\ or C:/) fn_relative = !(fn[1] == ':' && (fn[2] == '/' || fn[2] == '\\')); #else filename_path_sep_found = (filename.find('/') != std::string::npos); fn_relative = (fn[0] != '/'); #endif if (ff.fail() && fn.size() > 0 && fn_relative && filename_path_sep_found) { // if the include file was not found, it is not given with an absolute path, and the // currently read file is given with a path, then try again relative to its directory ff.clear(); #ifdef _WIN32 fixed_fn = filename.substr(0, filename.find_last_of("/\\")+1) + fn; #else fixed_fn = filename.substr(0, filename.rfind('/')+1) + fn; #endif ff.open(fixed_fn); } if (ff.fail() && fn.size() > 0 && fn_relative) { // if the include file was not found and it is not given with an absolute path, then // search it in the include path for (auto incdir : include_dirs) { ff.clear(); fixed_fn = incdir + '/' + fn; ff.open(fixed_fn); if (!ff.fail()) break; } } if (ff.fail()) { output_code.push_back("`file_notfound " + fn); } else { input_file(ff, fixed_fn); yosys_input_files.insert(fixed_fn); } continue; } if (tok == "`file_push") { skip_spaces(); std::string fn = next_token(true); if (!fn.empty() && fn.front() == '"' && fn.back() == '"') fn = fn.substr(1, fn.size()-2); output_code.push_back(tok + " \"" + fn + "\""); filename_stack.push_back(filename); filename = fn; continue; } if (tok == "`file_pop") { output_code.push_back(tok); filename = filename_stack.back(); filename_stack.pop_back(); continue; } if (tok == "`define") { std::string name, value; std::map<std::string, int> args; skip_spaces(); name = next_token(true); bool here_doc_mode = false; int newline_count = 0; int state = 0; if (skip_spaces() != "") state = 3; while (!tok.empty()) { tok = next_token(); if (tok == "\"\"\"") { here_doc_mode = !here_doc_mode; continue; } if (state == 0 && tok == "(") { state = 1; skip_spaces(); } else if (state == 1) { if (tok == ")") state = 2; else if (tok != ",") { int arg_idx = args.size()+1; args[tok] = arg_idx; } skip_spaces(); } else { if (state != 2) state = 3; if (tok == "\n") { if (here_doc_mode) { value += " "; newline_count++; } else { return_char('\n'); break; } } else if (tok == "\\") { char ch = next_char(); if (ch == '\n') { value += " "; newline_count++; } else { value += std::string("\\"); return_char(ch); } } else if (args.count(tok) > 0) value += stringf("`macro_%s_arg%d", name.c_str(), args.at(tok)); else value += tok; } } while (newline_count-- > 0) return_char('\n'); // printf("define: >>%s<< -> >>%s<<\n", name.c_str(), value.c_str()); defines_map[name] = value; if (state == 2) defines_with_args.insert(name); else defines_with_args.erase(name); global_defines_cache[name] = std::pair<std::string, bool>(value, state == 2); continue; } if (tok == "`undef") { std::string name; skip_spaces(); name = next_token(true); // printf("undef: >>%s<<\n", name.c_str()); defines_map.erase(name); defines_with_args.erase(name); global_defines_cache.erase(name); continue; } if (tok == "`timescale") { skip_spaces(); while (!tok.empty() && tok != "\n") tok = next_token(true); if (tok == "\n") return_char('\n'); continue; } if (tok == "`resetall") { defines_map.clear(); defines_with_args.clear(); global_defines_cache.clear(); continue; } if (try_expand_macro(defines_with_args, defines_map, tok)) continue; output_code.push_back(tok); } std::string output; for (auto &str : output_code) output += str; output_code.clear(); input_buffer.clear(); input_buffer_charp = 0; return output; } YOSYS_NAMESPACE_END