-
Notifications
You must be signed in to change notification settings - Fork 2
/
readme
188 lines (128 loc) · 5.92 KB
/
readme
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
Tcp-striper
-----------
(from "to stripe")
-- SUMMARY --
Have
+--------+ +--------+
| | | |
| Peer A | <------[ TCP connection ]------> | Peer B |
| | | |
+--------+ +--------+
Want
+--------+ +---+ +---+ +--------+
| | | | <----> | | | |
| Peer A | <--> | P | <----> | P | <--> | Peer B |
| | | | <----> | | | |
+--------+ +---+ +---+ +--------+
That is - to splice a pair of intermediate proxies into a TCP
connection and then have them talk to each other via multiple
TCP streams in parallel.
In particular, if an active stream between the proxies gets
congested, they would switch to another non-congested stream.
This should help proxies push more traffic through if/when
there are per-stream caps on the route between A and B. Like
the ones that certain cable provider has ;)
-- STATUS --
26/09/14
Added datagram pipe - that is a transport layer that
implements standard pipe semantics *and* preserves
boundaries of packets send()/recv() by the peers.
If A sends out 3, 123, 4 bytes, then with plain TCP
its peer may end up receiving a single packet of 130
bytes. However, if they are talking over a datagram
pipe, the recv() is guaranteed to retrieve 3 chunks,
respectively - 3, 123 and 4 byte in size.
To play with this, use 'tcp-proxy'.
1. Start a client-facing proxy first:
./tcp-proxy -c 0.0.0.0:11111 127.0.0.1 22222
This will accept a connection on port 11111, connect
out to port 22222 and then wrap all data received from
11111 into datagrams before sending them out to 22222.
It will also obviously strip the datagram packaging in
reverse direction.
2. Start a server-facing proxy second:
./tcp-proxy -s 0.0.0.0:22222 127.0.0.1:22
This will accept a connection on 22222, use it to
speak the datagram protocol with a peer and forward
raw payloads to the sshd on port 22.
3. Point your ssh at 11111 and observe the magic -
ssh -p 11111 localhost
Altogether, the contraption will look like this
+--------------+ +--------------------+
| ssh -p 11111 | -- ssh/tcp --> | tcp-proxy -c 11111 |
+--------------+ +--------------------+
|
|
ssh/dgm/tcp
|
v
+--------------+ +--------------------+
| sshd | <-- ssh/tcp -- | tcp-proxy -s 22222 |
+--------------+ +--------------------+
which is getting close to the original goal. All that's
left is to replace "datagram" protocol with "striped"
delivery across several connections.
20/09/14
Formalized io_pipe semantics, see /io/inc/libp/io_pipe.h
for details. In particular, added support for send_fin()
cases where FIN cannot be sent out right away.
Cleaned up io_bridge code.
15/09/14
-- 1 --
Re-organized the code as follows:
/core - basic type imports, macros, assert() and logging
/data - data containers (list and unbalanced map for now)
/evl - event loop (select-based for now)
/io - IO pipes & Co. - that's where the magic is
/sys - the platform glue (socket interface, termio, etc)
Each of these has the following structure:
./inc/libp/ <portable-headers>
./inc.$OS/libp/ <os-specific-version-of-the-same>
./src/ <portable-sources>
./src.$OS <os-specific-sources>
Then, setting INCLUDE path to ./inc.linux, ./inc and will
make the compiler pick an OS-specific version of a header
when it encounters
#include <libp/foo.h>
if such version is present. Otherwise it falls back to a
generic portable version. See Makefile for details.
-- 2 --
The bestest part is in the /io. The io_pipe interface is a
stateful IO abstraction based on TCP, but also allowing
extension of the send/recv behavior. For example, a pipe
of certain type can provide datagram framing, another type
- SSL encryption, third - atomic send() behavior, etc. So
you could attach these pipes one to another and get a
a reliable encrypted datagram-based connection.
Moreover, it becomes possible to write a generalized bridge
between any two pipes, which reads from one, writes to
another, minds the congestion and properly handles passing
of the FINs between the peers. That's io_bridge.
This is what tcp-striper does at the moment - it's a simple
TCP proxy that accepts a connection on 0.0.0.0:55555, opens
another one to 127.0.0.1:22 and then just bridges them
together. In other words, it's a TCP relay.
The next step would be to add a special pipe type that
maintains 2+ connections towards the peer and then stripes
all data passed to it via send() between these connections.
On the peer's end there'll be a complimentary pipe that
would reverse the striping, re-assemble the data into a
single stream and pass it to the app's io_bridge for
relaying out.
Easy-peasy.
28/08/14
* Initial public offering (via github upload)
27/08/14
* Simple TCP proxy with tracking of per-leg congestion
(proxy_types.*)
26/08/14
* Select-based event loop
(event_loop/*)
25/08/14
* Abstracted socket API (glue/*/socket.h)
* Basic data containers (map is unbalanced!)
* Basic app scaffolding (asserts, types, macros)
* Makefile
--------------------------------------------------------------
Work in progress, a weekend project.
--------------------------------------------------------------