-
Notifications
You must be signed in to change notification settings - Fork 0
/
darwin.py
82 lines (61 loc) · 2.3 KB
/
darwin.py
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
import os
import select
import logging
from threading import Thread, Event
import evergreen
import evergreen.tasks
import evergreen.queue
from .util import get_free_tun_interface
log = logging.getLogger(__name__)
loop = evergreen.EventLoop()
# TODO: make this a persistent task that writes to the queue, or something.
def _write_to_queue(pkt, q, evt):
q.put(pkt, True)
evt.set()
# Apparently this must be run in a thread, using the real select() call,, or it
# does strange things. Whatever - do it anyway.
def read_from_tuntap(fileno, q):
evt = Event()
while True:
try:
rlist, wlist, xlist = select.select([fileno], [], [])
except select.error:
continue
if len(rlist) > 0 and rlist[0] == fileno:
packet = os.read(fileno, 65535)
# Put on the queue. Note that we DO want to block here - though
# only this current task will block.
# HACK HACK GIANT FREAKING HACK
loop.call_from_thread(evergreen.tasks.spawn, _write_to_queue,
packet, q, evt)
evt.wait()
class DarwinTunTapDevice(object):
def __init__(self):
# Find a free TUN device.
self.name = get_free_tun_interface()
# Open the device.
log.debug("Opening device: %s", "/dev/" + self.name)
self.dev = os.open('/dev/' + self.name, os.O_RDWR)
# Our queue is of size 1, as we want the thread (above) to block when
# the queue already has a packet.
self.queue = evergreen.queue.Queue(1)
self.thread = Thread(target=read_from_tuntap,
args=(self.dev, self.queue))
def setup(self):
"""Call this once the TUN device is configured, to start reading."""
self.thread.daemon = True
self.thread.start()
def send_packet(self, packet):
self.dev.write(packet)
def get_packet(self, timeout=None):
if timeout is None:
return self.queue.get(True)
else:
try:
return self.queue.get(False, timeout)
except evergreen.queue.Empty:
return None
def close(self):
os.close(self.dev)
# This is the name we actually instantiate, for cross-platform compatibility.
TunTapDevice = DarwinTunTapDevice