Server maintains a queue of outbound packets for each user
-Packets which are older than MAX_QUEUE_TIME are discarded
+Packets which are older than the applicable max_queue_time are discarded
-Each incoming request to the server takes up to MAX_BATCH_DOWN bytes
+Each incoming request to the server takes up to max_batch_down bytes
from the queue and returns them as the POST response body payload
-Each incoming request contains up to MAX_BATCH_UP bytes of payload.
+Each incoming request contains up to max_batch_up bytes of payload.
It's a multipart/form-data.
Authentication: for now, plaintext password
-Sever side configuration:
-
- [<client-ipaddr>] or [default]
- max_batch_down
- max_queue_time
- max_request_time
- password
-
- [global]
- max_batch_down
- max_queue_time
- max_request_time
-
- [virtual]
- network # required
- host # default is first host in network (eg <network>.1)
- relay # default is first host in network not equal to server
- mtu # default is 1500
-
-Client side configuration;
- MAX_BATCH_DOWN MAX_QUEUE_TIME PASSWORD
-
Routing assistance: none needed; secnet polypath will DTRT
-Client form parameters:
- i ip address (textual)
- p password
+Client form parameters (multipart/form-data):
+ m metadata, newline-separated list (text file) of
+ client ip address (textual)
+ password
+ target_requests_outstanding
d data (SLIP format)
- mbd mqt mrt config updates
from hippotat import *
-defcfg = '''
-[DEFAULT]
-max_requests_outstanding = 4
-
-[virtual]
-mtu = 1500
-# [server] # maybe computed from `network' (see server defaults)
-# [routes] # default is none
-
-[server]
-# url # maybe computed from `addrs' and `port' (see server defaults)
-
-# [<my ip address>]
-# password = <password>
-'''
-
client_cs = None
def set_client(ci,cs,pw):
process_cfg_clients(set_client)
- try:
- c.routes = cfg.get('virtual','routes')
- except NoOptionError:
- c.routes = ''
+ c.routes = cfg.get('virtual','routes')
+ c.max_queue_time = cfg.get(client_cs, 'max_queue_time')
process_cfg_ipif(client_cs,
(('local', 'client'),
('peer', 'server'),
('rnets', 'routes')))
+outstanding = 0
+
+def start_client():
+ global queue
+ queue = PacketQueue(c.max_queue_time)
+
def outbound(packet, saddr, daddr):
- print('OUT ', saddr, daddr, repr(packet))
- pass
+ #print('OUT ', saddr, daddr, repr(packet))
+ queue.append(packet)
+ check_outbound()
+
+def check_outbound():
+ while True:
+ if outstanding >= c.max_outstanding: break
+ elements = { }
+ if not queue.nonempty():
+ if outstanding >= c.target_
+
+ while (outstanding < and
+ (queue.notempty() or outstanding < c.
common_startup(defcfg)
process_cfg()
import collections
+defcfg = '''
+[DEFAULT]
+#[<client>] overrides
+max_batch_down = 65536 # used by server, subject to [limits]
+max_queue_time = 10 # used by server, subject to [limits]
+max_request_time = 54 # used by server, subject to [limits]
+target_requests_outstanding = 3 # must match; subject to [limits] on server
+max_requests_outstanding = 4 # used by client
+max_batch_up = 4000 # used by client
+
+#[server] or [<client>] overrides
+ipif = userv root ipif %(local)s,%(peer)s,%(mtu)s,slip %(rnets)s
+# extra interpolations: %(local)s %(peer)s %(rnet)s
+# obtained on server [virtual]server [virtual]relay [virtual]network
+# from on client <client> [virtual]server [virtual]routes
+
+[virtual]
+mtu = 1500
+routes = ''
+# network = <prefix>/<len> # mandatory for server
+# server = <ipaddr> # used by both, default is computed from `network'
+# relay = <ipaddr> # used by server, default from `network' and `server'
+# default server is first host in network
+# default relay is first host which is not server
+
+[server]
+# addrs = 127.0.0.1 ::1 # mandatory for server
+port = 80 # used by server
+# url # used by client; default from first `addrs' and `port'
+
+# [<client-ip4-or-ipv6-address>]
+# password = <password> # used by both, must match
+
+[limits]
+max_batch_down = 262144 # used by server
+max_queue_time = 121 # used by server
+max_request_time = 121 # used by server
+target_requests_outstanding = 10 # used by server
+'''
+
# these need to be defined here so that they can be imported by import *
cfg = ConfigParser()
optparser = OptionParser()
for packet in packets:
if not len(packet): continue
(saddr, daddr) = packet_addrs(packet)
+ if saddr.is_link_local or daddr.is_link_local:
+ log_discard(packet, saddr, daddr, 'link-local')
+ continue
self._router(packet, saddr, daddr)
def processEnded(self, status):
status.raiseException()
clients = { }
-defcfg = '''
-[DEFAULT]
-max_batch_down = 65536
-max_queue_time = 10
-max_request_time = 54
-target_requests_outstanding = 3
-ipif = userv root ipif %(local)s,%(peer)s,%(mtu)s,slip %(rnets)s
-
-[virtual]
-mtu = 1500
-# network
-# [server]
-# [relay]
-
-[server]
-addrs = 127.0.0.1 ::1
-port = 8099
-
-[limits]
-max_batch_down = 262144
-max_queue_time = 121
-max_request_time = 121
-target_requests_outstanding = 10
-'''
-
#---------- "router" ----------
def route(packet, saddr, daddr):
except KeyError: dclient = None
if dclient is not None:
dclient.queue_outbound(packet)
- elif saddr.is_link_local or daddr.is_link_local:
- log_discard(packet, saddr, daddr, 'link-local')
elif daddr == c.server or daddr not in c.network:
print('TRACE INBOUND ', saddr, daddr, packet)
queue_inbound(packet)
req = cfg.getint(cs, k)
limit = cfg.getint('limits',k)
self.__dict__[k] = min(req, limit)
+
self._pq = PacketQueue(self.max_queue_time)
if ip in clients:
def queue_outbound(self, packet):
self._pq.append(packet)
+ self._check_outbound()
def http_request(self, request):
request.setHeader('Content-Type','application/octet-stream')
if pw != c.pw: raise ValueError('bad password')
# update config
+
+ xxx check sanity, do not update
for r, w in (('mbd', 'max_batch_down'),
('mqt', 'max_queue_time'),
('mrt', 'max_request_time'),