/src/hobbes/include/hobbes/ipc/net.H
Line | Count | Source |
1 | | /******** |
2 | | * net : I/O for a "net REPL" between processes |
3 | | ********/ |
4 | | |
5 | | #ifndef HOBBES_EVENTS_NET_HPP_INCLUDED |
6 | | #define HOBBES_EVENTS_NET_HPP_INCLUDED |
7 | | |
8 | | #include <hobbes/lang/type.H> |
9 | | #include <string> |
10 | | #include <map> |
11 | | #include <queue> |
12 | | |
13 | | namespace hobbes { |
14 | | |
15 | | // get the port number associated with a named port |
16 | | int lookupPort(const std::string&); |
17 | | |
18 | | // create a socket listening on a port |
19 | | int allocateServer(int port, const std::string& host = ""); |
20 | | int allocateServer(const std::string& port); |
21 | | |
22 | | // connect to a host/port |
23 | | int connectSocket(const std::string& host, int port); |
24 | | int connectSocket(const std::string& hostport); |
25 | | |
26 | | // create a unix domain socket backed by a file |
27 | | int allocateFileSocketServer(const std::string& filepath); |
28 | | |
29 | | // get the name of the host on the other end of this socket |
30 | | std::string remoteHostname(int socket); |
31 | | |
32 | | // get the port on the remote end of this socket |
33 | | int remotePort(int socket); |
34 | | |
35 | | // run a REPL server at some port, either indirectly or directly with a compiler |
36 | | using RawData = std::vector<uint8_t>; |
37 | | using exprid = uint32_t; |
38 | | using ReWriteExprFn = std::function<ExprPtr (const ExprPtr &)>; |
39 | | |
40 | | struct Server { |
41 | | virtual void connect (int conn) = 0; |
42 | | virtual ExprPtr readExpr (const std::string&) = 0; |
43 | | virtual MonoTypePtr prepare (int conn, exprid, const ExprPtr&, const MonoTypePtr&) = 0; |
44 | | virtual void evaluate (int conn, exprid) = 0; |
45 | | virtual void disconnect(int conn) = 0; |
46 | | }; |
47 | | |
48 | | int installNetREPL(int port, Server*); |
49 | | int installNetREPL(const std::string& host, int port, Server*); |
50 | | // install a net repl on a unix domain socket (using file paths) |
51 | | int installNetREPL(const std::string& /*filepath*/, Server*); |
52 | | |
53 | | class cc; |
54 | | int installNetREPL(int port, cc*, ReWriteExprFn const& = [](ExprPtr const& e) -> ExprPtr { return e; }); |
55 | | int installNetREPL(const std::string& host, int port, cc*, ReWriteExprFn const& = [](ExprPtr const& e) -> ExprPtr { return e; }); |
56 | | // install a net repl on a unix domain socket (using file paths) |
57 | | int installNetREPL(const std::string& /*filepath*/, cc*, ReWriteExprFn const& = [](ExprPtr const& e) -> ExprPtr { return e; }); |
58 | | |
59 | | // How long to wait for a peer to answer a compile-time type query (the |
60 | | // (Connect ...)/(Invoke ...) exchanges), in milliseconds; 0 or less waits |
61 | | // forever, as it used to. This wait happens with the process-wide compiler |
62 | | // lock held, so an unbounded one stops every thread in the process from |
63 | | // compiling -- always, if the peer is served by this same process, since |
64 | | // answering needs that very lock. Reads made while *evaluating* a remote |
65 | | // call are not affected. Defaults to 30s. |
66 | | void setRemoteTypeQueryTimeoutMS(long ms); |
67 | | long getRemoteTypeQueryTimeoutMS(); |
68 | | |
69 | | // connect to a running net REPL somewhere |
70 | | class Client { |
71 | | public: |
72 | | /* init/compile-time methods */ |
73 | | Client(const std::string& hostport); |
74 | | ~Client(); |
75 | | const std::string& remoteHost() const; |
76 | | |
77 | | exprid remoteExpr(const ExprPtr&, const MonoTypePtr& inty); |
78 | | |
79 | | MonoTypePtr input(exprid) const; |
80 | | MonoTypePtr output(exprid) const; |
81 | | MonoTypePtr output(const ExprPtr&, const MonoTypePtr& inty); |
82 | | |
83 | 0 | inline int fd() const { return this->c; } |
84 | | private: |
85 | | int c; |
86 | | std::string hostport; |
87 | | exprid eid; |
88 | | |
89 | | // A compile-time query that does not complete leaves the peer's reply, or |
90 | | // the tail of it, still to come on this socket. Reusing the connection |
91 | | // after that would read the abandoned reply as the answer to the next |
92 | | // question, so an abandoned exchange retires the connection instead. |
93 | | bool usable = true; |
94 | | std::string unusableWhy; |
95 | | void retire(const std::string& why); |
96 | | void requireUsable() const; |
97 | | |
98 | | struct ExprDef { |
99 | | ExprPtr expr; |
100 | | MonoTypePtr inty; |
101 | | MonoTypePtr outty; |
102 | | }; |
103 | | using ExprDefs = std::map<exprid, ExprDef>; |
104 | | ExprDefs exprDefs; |
105 | | |
106 | | using ExprTy = std::pair<const void *, const void *>; |
107 | | using ExprTyToID = std::map<ExprTy, exprid>; |
108 | | ExprTyToID exprTyToID; |
109 | | public: |
110 | | /* run-time methods */ |
111 | | void show(std::ostream&) const; |
112 | | |
113 | | // append a receive function to the end of the sequence of receive handlers |
114 | | // these functions will be applied in order to read values from the remote process |
115 | | using ReadFn = char *(*)(int); |
116 | | size_t appendReadFn(ReadFn); |
117 | | |
118 | | // read a result (reading and discarding any intermediate results) |
119 | | char* readValue(size_t); |
120 | | |
121 | | // only used by generated code |
122 | | static size_t unsafeAppendReadFn(size_t, ReadFn); |
123 | | static char* unsafeRead(size_t, size_t); |
124 | | private: |
125 | | using ReadFns = std::queue<ReadFn>; |
126 | | ReadFns readFns; |
127 | | size_t rbno; |
128 | | size_t reno; |
129 | | }; |
130 | | |
131 | | // true iff c points to a Client created by makeConnection and still registered |
132 | | // (defined with the connection registry in lib/hobbes/ipc/nbindings.C) |
133 | | bool isAllocatedConnection(Client*); |
134 | | |
135 | | } |
136 | | |
137 | | #endif |
138 | | |