Initial commit

This commit is contained in:
Sebastian Lohff 2011-10-30 01:22:45 +02:00
commit 50faf05cd9
12 changed files with 990 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.pyc
.*.swp

5
Readme Normal file
View File

@ -0,0 +1,5 @@
Documentation
http://www.kernel.org/doc/Documentation/networking/tuntap.txt

2
__init__.py Normal file
View File

@ -0,0 +1,2 @@
from ether2any import Ether2Any
import helper

87
ether2any.py Normal file
View File

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
import commands
import select
import pytap
import logging
from pytap import TapDevice
class Ether2Any:
""" Baseclass for writing arbitrary Ethernet/IP Tunnels using TUN/TAP device.
This class handles a TUN/TAP devices and runs a select loop for it and,
if given, a set of sockets. To use this class at least sendToNet() has
to be implemented by a subclass. """
def __init__(self, tap=True, readSockets=[]):
""" Constructor for Ether2Any.
isTap defines if the managed device should be a tap (ethernet tunnel)
or a tun (IP tunnel). """
self.readSockets = readSockets
# create device
self.dev = TapDevice(tap=tap)
self.timeout = None
def setupLogging(self, name):
l = logging.getLogger(name)
fmt = logging.Formatter("%(asctime)s - [%(levelname)s] (%(name)s) - %(message)s")
ch = logging.StreamHandler()
ch.setFormatter(fmt)
l.addHandler(ch)
return l
def addSocket(self, sock):
""" Add socket to readSockets set. """
self.readSockets.append(sock)
def delSocket(self, socket):
""" Remove socket from readSockets set. """
try:
self.readSockets.remove(socket)
except ValueError:
pass
# outgoing data
def sendToNet(self, packet):
""" This function has to be implemented to handle outgoing
data (read from the TUN/TAP device) """
raise NotImplementedError("You need to overload sendToNet()")
# incoming data
def sendToDev(self, sock):
""" This function has to be implemented to handle incoming
data which is read from the extra sockets (self.readSockets).
It will not be called when no extra readSockets are specified. """
raise NotImplementedError("You need to overload sendToDev()")
def setTimeout(self, t):
""" Set select timeout. """
self.timeout = t
def callAfterSelect(self):
""" Will be called as last operation of the mainloop when
handling of the select result / the select timeout is hit.
"""
pass
def run(self):
""" Run main select-loop. """
try:
while True:
sockets = [self.dev.getFD()] + self.readSockets
(readFDs, _, _) = select.select(sockets, [], [], self.timeout)
for readFD in readFDs:
if readFD == self.dev.getFD():
self.sendToNet(self.dev.read())
elif readFD in self.readSockets:
self.sendToDev(readFD)
self.callAfterSelect()
except KeyboardInterrupt:
self.quit()
self.dev.close()
def quit(self):
""" Will be called after the run-select() and its processing is done. """
pass

24
helper.py Normal file
View File

@ -0,0 +1,24 @@
def getSrcMacFromPkt(packet):
if len(packet) < 16:
return None
return packet[10:16]
def getDstMacFromPkt(packet):
if len(packet) < 10:
return None
return packet[4:10]
def binToHexStr(binmac):
return "".join(["%02x" % ord(i) for i in binmac])
# checks if packet is a broadcast packet
def isBroadcast(packet):
binmac = getDstMacFromPkt(packet)
# normal broadcast
if binmac == '\xff\xff\xff\xff\xff\xff':
return True
# v6 multicast
if binmac.startswith('\x33\x33'):
return True
return False

114
pytap.py Normal file
View File

@ -0,0 +1,114 @@
from fcntl import ioctl
import subprocess
import os
import struct
class TapDevice:
""" TUN/TAP device class """
# magic numbers and structlayout
TUNSETIFF = 0x400454ca
IFF_TUN = 0x0001
IFF_TAP = 0x0002
DEVPATH = "/dev/net/tun"
_ifreq = "16sh"
def __init__(self, name='', tap=True, conf=None):
""" Constructor for the device.
name - the device name, use a %d for a generated device numer
tap - if this device should be a tap device
conf - conf to pass to the ifconfig function of this class
(if None ifconfig() won't be called)
"""
self._mode = (tap and self.IFF_TAP) or self.IFF_TUN
self._fd = None
self._name = None
self._tap = tap
self._mac = None
self._mtu = 1500
self.conf = conf
if name == '':
self._nametpl = (tap and "tap%d") or "tun%d"
self._createDev()
if self.conf:
self.ifconfig(**conf)
def _createDev(self):
if self._fd:
self.close()
self._fd = os.open(self.DEVPATH, os.O_RDWR)
ifreq = struct.pack(self._ifreq, self._nametpl, self._mode)
ret = ioctl(self._fd, self.TUNSETIFF, ifreq)
# retmode should be the same as self._mode
(retname, retmode) = struct.unpack(self._ifreq, ret)
self._name = retname.strip("\x00")
def _ifconfig(self, params):
args = ["/sbin/ifconfig"] + params
ret = subprocess.Popen(args).wait()
if ret != 0:
raise PyTapException("Command '%s' did not return 0" % (" ".join(args),))
def ifconfig(self, **kwargs):
""" Calls ifconfig for the device.
All arguments will be passed to ifconfig. Use 'address' for the device address.
E.g. device.ifconfig(address="12.34.56.78", mtu=1500)
"""
args = [self._name]
if kwargs.has_key("address"):
args.append(kwargs["address"])
del(kwargs["address"])
args = reduce(lambda l, key: l+[key, str(kwargs[key])],
kwargs, args)
self._ifconfig(args)
def getMac(self):
""" Get the device mac """
# this "could" be buffered, but we never know who when changed the mac
# ==> we re-get the mac on every request
proc = subprocess.Popen("LC_ALL=C /sbin/ifconfig %s|head -n 1|egrep -o '([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}'" % self.getName(), shell=True, stdout=subprocess.PIPE)
mac = proc.stdout.read().strip()
return mac
def up(self):
""" Bring the device up """
self._ifconfig([self._name, "up"])
def down(self):
""" Bring the device down """
self._ifconfig([self._name, "down"])
def getFD(self):
""" Get the device file descriptor (e.g. to use in select()) """
return self._fd
def getName(self):
""" Get the (real) name of the device """
return self._name
def read(self):
""" Read a packet from the device """
readSize = self._mtu
if self._tap:
# don't forget the ethernet frame (not included in MTU)
readSize += 18
data = os.read(self._fd, self._mtu)
return data
def write(self, data):
""" Write a packet to the device """
os.write(self._fd, data)
def close(self):
""" Close the device """
os.close(self._fd)
self._fd = self._name = None
class PyTapException(Exception):
pass

83
tunnel/ircvpn/conf.py Normal file
View File

@ -0,0 +1,83 @@
# ___________________________________________________
# | |
# | ircvpn - irc virtual public network configuration |
# |___________________________________________________|
# config options
# IRC
# - server (ip, port, ssl)
# - channel
# - nick prefix
# - maximum line length
# Network
# - device: ip, netmask, mtu
# - dhclient instead of static ip?
# - routing?
# - dns?
# Tunnel
# - security settings
# - mode (hub or switch)
import os
Conf = {
# ======== network settings ========
# ipsettings for the device
'devname': '',
'network':
{
'address': '10.10.10.74',
'netmask': '255.255.255.0',
#gateway: '',
'mtu': 1400,
},
# hubbed ("HUB")/switched("SWITCH") Network
# HUB: communicate only over broadcastchan
# SWITCH: use query for non broadcast packages
'mode': "HUB",
# ======== IRC settings ========
# irc-server to use
#ircserver = ('irc.someserver.de', 6667)
#ircserver = ('testine.someserver.de', 6667)
#ircserver = ('192.168.56.1', 6667)
'ircserver': ('testine.someserver.de', 6667),
# broadcast domain (where to meet other clients)
'broadcastchan': '#broadcastchan',
# nick prefix (needs to be the same on all clients)
'nickPrefix': 'VPN',
# maximum msg len
'ircmsglen': 400,
# NOT IMPLEMENTED: reconnect on server disconnect
'ircReconnect': False,
'ircReconnectDelay': 3,
# ======== security settings ========
# accept packages if virtual mac != package mac
'acceptNonMatchingMac': True,
# ignore messages from non-mac user names
'ignoreNonMacUser': True,
# drop non broadcast packages from broadcast when
# in switched network mode
'strictSwichedNetwork': False,
# ======== extra tools settings ========
'voicebot':
{
'name': 'flowControl',
'voiceword': 'requesting network access',
},
# ======== misc settings ========
# executed after being connected to the server
# arguments: <command> <device>
'postConnectCmd': '/sbin/dhclient -v %s',
}

View File

@ -0,0 +1,184 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# TODO
# Reconnecting to IRC-Server
# Complete switched networks
# Reduce debug output / add good output
# For more security use packet id + srcnick as key for fragmented packages
from conf import *
import pytap
from pytap import TapDevice
import select
import time
import irclib
import commands
import re
import base64
import random
dev = None
headerlen = 1 + 5 + 1 # flag + number + whitespace
packets = {}
def getMacFromIf(iface):
mac = commands.getoutput("/sbin/ifconfig %s|grep %s|egrep -o '([a-fA-F0-9]{2}(:|.)){6}'" % (iface, iface))
print "Debug: %s has mac address %s" % (iface, mac)
return mac
def getDstMacFromPkt(packet):
if len(packet) < 10:
return None
return packet[4:10]
def binToHexStr(binmac):
return "".join(["%02x" % ord(i) for i in binmac])
def isBroadcast(packet):
binmac = getDstMacFromPkt(packet)
# normal broadcast
if binmac == '\xff\xff\xff\xff\xff\xff':
return True
# v6 multicast
if binmac.startswith('\x33\x33'):
return True
return False
def sendToIRC(dev, server):
msg = dev.read()
oldencmsg = encmsg = base64.encodestring(msg).replace("\n", "")
slices = []
encmsglen = ircmsglen-headerlen
msgid = "%05d" % random.randint(0, 99999)
while len(encmsg) > encmsglen:
slices.append(encmsg[:encmsglen])
encmsg = encmsg[encmsglen:]
slices.append(encmsg)
# HUB or SWITCH?
if mode == "SWITCH" and not isBroadcast(package):
target = "VPN-%s" % (binToHexStr(getDstMacFromPkt(packet)),)
else:
target = broadcastchan
if len(slices) == 0:
print "DEBUG: EMPTY PACKAGE FROM DEV?"
elif len(slices) == 1:
print "Debug: Sending oneliner to dev"
server.privmsg(target, "o%s %s" % (msgid, slices[0]))
else:
print "Debug: Sending fragmented package to dev"
print " ---- COMPLETE MESSAGE BEFORE SLICES ---- "
print oldencmsg
print " ---- SLICES SLICES SLICES ---- "
print "\n".join(slices)
print " ---- SLICES SLICES SLICES ---- "
server.privmsg(target, "b%s %s" % (msgid, slices.pop(0)))
while len(slices) > 1:
server.privmsg(target, "c%s %s" % (msgid, slices.pop(0)))
server.privmsg(target, "e%s %s" % (msgid, slices.pop(0)))
def sendToDev(dev, server, isBroadcast, c, e):
parsed = pkgre.match(e.arguments()[0])
if not parsed:
print "message could not be parsed", e.arguments()[0]
return
(flag, msgid, basemsg) = parsed.groups()
print "flag: %s msgid: %s msg: %s" % (flag, msgid, basemsg)
try:
msgid = int(msgid)
except ValueError:
print "Debug: messageid was not a number"
return
if not ignoreNonMacUser:
# FIXME: ignore the non prefix-mac user
if not nickre.match():
print "is not allowed in our network"
print e.arguments(), irclib.nm_to_n(e.source()), e.target()
if flag == "o":
# oneliner!
print "Debug: Writing onliner to dev"
try:
msg = base64.decodestring(basemsg)
except base64.binascii.Error, e:
print "Debug: Error decoding base64 irc message (%s)" % e
return
#FIXME if packetAllowed(, , chan)
dev.write(msg)
elif flag == 'b':
if packets.has_key(msgid):
print "Warning: Overwriting lost package with id %s" % msgid
packets[msgid] = basemsg
elif flag in ('c', 'e'):
if not packets.has_key(msgid):
print "Error: Continue package has no matching entry in packets, discarding!"
else:
packets[msgid] += basemsg
if flag == 'e':
arrmsg = packets[msgid]
del(packets[msgid])
try:
print "arrmsg is", arrmsg.replace("\n", "\n\n\n")
msg = base64.decodestring(arrmsg)
except base64.binascii.Error, e:
print "Debug: Error decoding base64 irc message (%s)" % e
return
print "Debug: writing fragmented package to dev"
print binToHexStr(msg)
dev.write(msg)
#print "GOT in %s (broadcast %s) from %s msg %s" (e.target(), isBroadcast, irclib.nm_to_n(e.source()), e.arguments()[0])
def packetAllowed(src, nick, packet):
if not acceptNonMatchingMac:
# check if user-mac == packetmac
# FIXME if not getDstMacFromPkt(packet) ==
pass
# FIXME: Maybe move nick check to here
if mode != "HUB" and strictSwichedNetwork:
if src.startswith("#"): # its a channel
return False
return True
def startup():
# setup the tap device
dev = TapDevice(pytap.IFF_TAP)
dev.ifconfig(address=ip, netmask=netmask)
if gateway != "":
print "Setting default route %s" % gateway
os.sys("route add default gw %s")
# setup IRC foo
ircnick = nickPrefix + getMacFromIf(dev.name).replace(":", "")
print "Debug: Connectiong to %s as %s" % (ircserver, ircnick)
irc = irclib.IRC()
irc.add_global_handler("privmsg", lambda c, e: sendToDev(dev, server, False, c, e), -20)
irc.add_global_handler("pubmsg", lambda c, e: sendToDev(dev, server, True, c, e), -20)
server = irc.server()
server.connect(ircserver[0], ircserver[1], ircnick)
server.join(broadcastchan)
try:
while True:
sockets = [dev.__fd__]
# get private irc sockets :)
sockets.extend(map(lambda x: x._get_socket(), irc.connections))
sockets = filter(lambda x: x != None, sockets)
print "sockets", sockets
(readFDs, _, _) = select.select(sockets, [], [])
for readFD in readFDs:
print "EVENT BY", readFD
if readFD == dev.__fd__:
sendToIRC(dev, server)
else:
print "IRC event"
irc.process_once(0.1)
except KeyboardInterrupt:
pass
print "Shutting down!"
server.quit("RST")
if __name__ == '__main__':
startup()

186
tunnel/ircvpn/ircvpn.py Executable file
View File

@ -0,0 +1,186 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
sys.path.append("../../../")
from ether2any import Ether2Any
from conf import Conf
import time
import irclib
import re
import base64
import random
import logging
import subprocess
from ether2any.helper import getDstMacFromPkt, isBroadcast, binToHexStr
# TODO
# replace base64 with something better
# write switching part
class IrcVPN(Ether2Any):
headerlen = 1 + 5 + 1 # flag + number + whitespace
pkgre = re.compile("^([a-zA-Z])(\d{5}) (.*)$")
def __init__(self):
Ether2Any.__init__(self, tap=True)
self.irclog = self.setupLogging("IrcVPN")
self.irclog.setLevel(logging.WARN)
# === Load config values ===
network = Conf.get("network", {'mtu': 1500})
self.ircmsglen = Conf.get("ircmsglen", 400)
self.ircserver = Conf.get("ircserver")
self.broadcastchan = Conf.get("broadcastchan")
self.nickPrefix = Conf.get("nickPrefix", "VPN")
self.postConnectCmd = Conf.get("postConnectCmd", None)
self.voiceWord = Conf.get("voicebot", None)
if self.voiceWord:
self.voiceWord = self.voiceWord.get("voiceword", None)
self.mode = Conf.get("mode", "HUB")
self.ignoreNonMacUser = Conf.get("ignoreNonMacUser", True)
self.acceptNonMatchingMac = Conf.get("acceptNonMatchingMac", True)
self.strictSwichedNetwork = Conf.get("strictSwichedNetwork", False)
if self.mode not in ("HUB", "SWITCH"):
raise ValueError("mode needs to be either HUB or SWITCH")
self.irclog.info("Starting the IRC Public Network")
self.packets = {}
self._setupIrc()
self.nickre = re.compile("^%s[a-fA-F0-9]{12}$" % (self.nickPrefix,))
self.dev.ifconfig(**network)
self.dev.up()
def sendToNet(self, packet):
# split message so that it's not longer than ircmsglen
oldencmsg = encmsg = base64.b64encode(packet).strip("\n")
slices = []
encmsglen = self.ircmsglen-self.headerlen
msgid = "%05d" % random.randint(0, 99999)
while len(encmsg) > encmsglen:
slices.append(encmsg[:encmsglen])
encmsg = encmsg[encmsglen:]
slices.append(encmsg)
# HUB or SWITCH?
if self.mode == "SWITCH" and not isBroadcast(packet):
target = "%s%s" % (self.nickPrefix, binToHexStr(getDstMacFromPkt(packet)),)
else:
target = self.broadcastchan
self.irclog.info("Sending %d packet(s) (total len %d) to %s" % (len(slices), len(oldencmsg), target))
if len(slices) == 0:
self.irclog.error("Got EMPTY packet from dev!")
elif len(slices) == 1:
# send in one line (o)
self.server.privmsg(target, "o%s %s" % (msgid, slices[0]))
else:
# send fragmented (b, c, e)
self.server.privmsg(target, "b%s %s" % (msgid, slices.pop(0)))
while len(slices) > 1:
self.server.privmsg(target, "c%s %s" % (msgid, slices.pop(0)))
self.server.privmsg(target, "e%s %s" % (msgid, slices.pop(0)))
def sendToDev(self, socket):
# proc one irc event
self.irclog.debug("Processing irc event")
self.irc.process_once(0.1)
def sendToDevIrcCallback(self, isBroadcast, c, e):
parsed = self.pkgre.match(e.arguments()[0])
nick = irclib.nm_to_n(e.source())
target = e.target()
if not parsed:
self.irclog.debug("irc-input: Message could not be parsed (\"%s\")" % (e.arguments()[0],))
return
(flag, msgid, basemsg) = parsed.groups()
self.irclog.debug("irc-input: source: %s target: %s flag: %s msgid: %s msg: %s" % (nick, target, flag, msgid, basemsg))
if self.ignoreNonMacUser:
if not self.nickre.match(nick):
self.irclog.debug("%s is not allowed in our network" % nick)
return
if flag == "o":
# oneliner!
try:
msg = base64.b64decode(basemsg)
except base64.binascii.Error, e:
self.irclog.warning("Error decoding base64 irc message (%s)" % e)
return
if self.packetAllowed(nick, target, msg):
self.dev.write(msg)
elif flag == 'b':
if self.packets.has_key(msgid):
self.irclog.warning("Overwriting lost package with id %s" % msgid)
try:
# we need to decode at least part of the ethernet header
# choosing 64 chars at random (shouldn't break padding)
partmsg = base64.b64decode(basemsg[:64])
if len(partmsg) < 24:
raise ValueError()
except base64.binascii.Error, ValueError:
self.irclog.warning("Could not decode parted base64 message, discarding")
return
self.packets[msgid] = basemsg
elif flag in ('c', 'e'):
if not self.packets.has_key(msgid):
self.irclog.warning("Continue package with id %d has no matching entry in packets, discarding!" % msgid)
else:
self.packets[msgid] += basemsg
if flag == 'e':
arrmsg = self.packets[msgid]
del(self.packets[msgid])
try:
msg = base64.b64decode(arrmsg)
except base64.binascii.Error, e:
self.irclog.debug("Error decoding base64 irc message (%s)" % e)
return
if self.packetAllowed(nick, target, msg):
self.dev.write(msg)
self.irclog.debug("Packet written")
def packetAllowed(self, nick, target, packet):
if not self.acceptNonMatchingMac and not binToHexStr(getDstMacFromPkt(packet)) == nick[-12:]:
return False
if self.mode != "HUB" and self.strictSwichedNetwork:
if target.startswith("#"): # its a channel
return False
return True
def printNotice(self, c, e):
self.irclog.info("NOTICE: %s %s" % (e.source(), e.arguments()[0]))
def _setupIrc(self):
ircnick = self.nickPrefix + self.dev.getMac().replace(":", "")
self.irc = irclib.IRC()
self.irc.add_global_handler("privmsg", lambda c, e: self.sendToDevIrcCallback(False, c, e), -20)
self.irc.add_global_handler("pubmsg", lambda c, e: self.sendToDevIrcCallback(True, c, e), -20)
self.irc.add_global_handler("privnotice", self.printNotice, -20)
self.server = self.irc.server()
self.server.connect(self.ircserver[0], self.ircserver[1], ircnick)
self.server.join(self.broadcastchan)
if self.voiceWord:
self.irclog.info("Sending voiceword to %s" % self.broadcastchan)
self.server.privmsg(self.broadcastchan, self.voiceWord)
# add sockets
self.readSockets = map(lambda x: x._get_socket(), self.irc.connections)
self.readSockets = filter(lambda x: x != None, self.readSockets)
# execute post connect command
if self.postConnectCmd:
cmd = self.postConnectCmd
if cmd.find("%s") >= 0:
print cmd
cmd = cmd % (self.dev.getName(),)
subprocess.Popen(cmd, shell=True)
def quit(self):
self.server.quit("RST")
if __name__ == '__main__':
ircvpn = IrcVPN()
ircvpn.run()

37
tunnel/ircvpn/voicebot.py Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/python
import irclib
from conf import Conf
def voiceThem(chan, voiceword, c, e):
if e.arguments()[0] == voiceword:
c.mode(chan, "+v "+irclib.nm_to_n(e.source()))
def main():
botname = None
voiceword = None
ircserver = None
broadcastchan = None
try:
cfg = Conf.get('voicebot')
botname = cfg.get('name')
voiceword = cfg.get('voiceword')
ircserver = Conf.get('ircserver')
broadcastchan = Conf.get('broadcastchan')
except:
print "Error: Bad Configuration!"
print ""
print "You need a voicebot section with a name and voiceword configured"
print "Also, ircserver and broadcastchan are needed"
return 1
print "Voicebot is starting.."
irc = irclib.IRC()
irc.add_global_handler("pubmsg", lambda c, e: voiceThem(broadcastchan, voiceword, c, e), -20)
server = irc.server()
server.connect(ircserver[0], ircserver[1], botname)
server.join(broadcastchan)
print "Connected, joining eventloop."
irc.process_forever()
if __name__ == '__main__':
main()

19
tunnel/qrnet/qrconf.py Executable file
View File

@ -0,0 +1,19 @@
import os
netmask = "255.255.255.0"
mtu = 417
ip = ""
camnum = 0
packetDrop = 20
if os.popen("hostname", "r").read().strip() in ("navi", ):
ip = "10.44.13.1"
camnum = 0
else:
ip = "10.44.13.2"
camnum = 2
if __name__ == '__main__':
print ip

247
tunnel/qrnet/qrnet.py Executable file
View File

@ -0,0 +1,247 @@
#!/usr/bin/python
import sys
import os
import re
import time
import struct
import base64
import StringIO
import opencv
from opencv import highgui, adaptors
import qrencode
import zbar
from PIL import Image
import gtk
import gobject
import urllib
import socket
import subprocess
import Queue
import threading
import mutex
sys.path.append("../../../")
from ether2any import Ether2Any
from conf import Conf
mqueueMutex = threading.Lock()
squeueMutex = threading.Lock()
class QrDisplay(gtk.Window):
def __init__(self, mqueue, squeue, displog, timeout=250):
super(QrDisplay, self).__init__()
self.fullscreen()
self.qrimgPadding = 20
(wx, wy) = self.getHackySize()
self.timeout = timeout
self.mqueue = mqueue
self.squeue = squeue
self.displog = displog
# build up gui
self.vbox = gtk.VBox(False, 0)
self.qrimg = gtk.Image()
self.qrimg.show()
self.vbox.pack_start(self.qrimg, True, True, self.qrimgPadding)
self.vbox.show()
self.pbar = gtk.ProgressBar()
self.pbar.show()
self.vbox.pack_start(self.pbar, False, False, 0)
self.add(self.vbox)
# connect signals
self.connect("destroy", gtk.main_quit)
self.set_size_request(wx, wy)
self.maximize()
self.set_position(gtk.WIN_POS_CENTER)
self.show()
self.qrSet("")
gobject.timeout_add(self.timeout, self.checkQueue)
def checkQueue(self):
#print "Check queue...",
mqueueMutex.acquire()
if not self.mqueue.empty():
print "new data available"
bmsg = self.mqueue.get()
self.qrSet(bmsg)
mqueueMutex.release()
#else:
# print "no new data available"
# progress
squeueMutex.acquire()
if not self.squeue.empty():
(frames, success) = self.squeue.get()
if frames > 0:
self.pbar.set_fraction(success/float(frames))
self.pbar.set_text("%02d / %02d (%03.02f)" % (success, frames, success / float(frames) * 100.0))
print frames, success
squeueMutex.release()
return True
def getHackySize(self):
""" Obtain current size of screen via xrandr. """
#p = subprocess.Popen(["bash", "-c", 'xrandr|egrep "\*+"|egrep -o "[0-9]+x[0-9]+"'], stdout=subprocess.PIPE)
p = subprocess.Popen('xrandr|egrep "\*+"|egrep -o "[0-9]+x[0-9]+"', stdout=subprocess.PIPE)
p.wait()
(myout, myin) = p.communicate()
return map(lambda x: int(x)-self.qrimgPadding, myout.strip().split("x"))
def image2pixbuf(self, im):
(a, b, c, d) = self.qrimg.get_allocation()
# correct size, must be 1:1 (so select the smaller one)
x = min(c-a, d-b)
if(x < 10):
x = 100
imgSize = (x, x)
im = im.resize(imgSize)
file1 = StringIO.StringIO()
im.save(file1, "ppm")
contents = file1.getvalue()
file1.close()
loader = gtk.gdk.PixbufLoader("pnm")
loader.write(contents, len(contents))
pixbuf = loader.get_pixbuf()
loader.close()
return pixbuf
def qrSet(self, msg):
""" Set content of displayed qr image. """
if msg == None or msg == "":
msg = "Katze"
(qrVersion, qrSize, qrImg) = qrencode.encode(msg, 0)
self.qrimg.set_from_pixbuf(self.image2pixbuf(qrImg))
class DisplayThread(threading.Thread):
""" Thread that runs the GTK-GUI to display outgoing network qr codes. """
def __init__(self, dev, mqueue, squeue, displog):
threading.Thread.__init__(self)
self.dev = dev
self.quit = False
self.qrdisplay = QrDisplay(mqueue, squeue, )
self.mqueue = mqueue
self.squeue = squeue
self.displog = displog
def run(self):
self.displog.info("Display GTK Gui is up and running.")
gtk.main()
class CamThread(threading.Thread):
""" Captures images from a webcam and decodes them.
Captures images from the first webcam it can find, decodes them
and writes them to the interface. """
def __init__(self, dev, squeue, camlog):
threading.Thread.__init__(self)
self.dev = dev
self.squeue = squeue
self.camlog = camlog
self.frame = 0
self.reportAfter = 20 # frames
self.quit = False
self.success = 0
self.lastPacket = ""
self.reader = highgui.cvCreateCameraCapture(camnum)
self.scanner = zbar.ImageScanner()
self.scanner.parse_config('enable')
def run(self):
while not self.quit:
frame = highgui.cvQueryFrame(self.reader)
self.frame += 1
frame = opencv.cvGetMat(frame)
img = adaptors.Ipl2PIL(frame)
width, height = img.size
zimg = zbar.Image(width, height, 'Y800', img.convert("L").tostring())
self.scanner.scan(zimg)
data = None
for symbol in zimg:
data = symbol.data
self.camlog.debug("Data is: %s" % data)
self.success += 1
# handle data
if not self.lastPacket == data:
self.lastPacket = data
try:
msg = base64.b64decode(data)
(rawtime, packet) = (msg[0:8], msg[8:])
ptime = struct.unpack("<d", rawtime)
self.camlog.debug("Network packet! Heade (time) is %s" % (ptime,))
self.dev.write(packet)
except base64.binascii.Error:
print " ==> base64 error"
self.camlog.error("Base64 error - could not decode packet")
except struct.error:
self.camlog.error("Header error - could not extract header information")
else:
# packet is already known, discard
pass
# status report to gui
if self.frame % self.reportAfter == 0:
self.frame = self.success = 0
# too much status codes? flush 'em
squeueMutex.acquire()
if self.squeue.qsize() > self.reportAfter/2:
while not self.squeue.empty():
self.squeue.get()
# add new status code
self.squeue.put((self.frame, self.success))
squeueMutex.release()
class QrNet(Ether2Any):
pidlen = 16
def __init__(self):
# device
Ether2Any.__init__(self, tap=True)
self.qrlog = self.setupLogging("QrNet")
self.dev.ifconfig(address=ip, netmask=netmask, mtu=mtu)
self.packetDrop = packetDrop
self.mqueue = Queue.Queue()
self.squeue = Queue.Queue()
# thread starting...
gtk.gdk.threads_init()
self.cam = CamThread(self.dev, self.squeue, self.setupLogging("CamThread"))
self.cam.start()
self.display = DisplayThread(self.dev, self.mqueue, self.squeue, self.setupLogging("DisplayThread"))
self.display.start()
def sendToNet(self):
# prepare data for queue && display
self.qrlog.debug("Data from the device")
msg = self.dev.read()
# add acttime to generate "unique" images
acttime = struct.pack("<d", time.time())
bmsg = base64.b64encode(acttime + msg)
self.qrlog.debug("==>" + bmsg)
# add packet to queue, maybe drop packet
mqueueMutex.acquire()
if self.mqueue.qsize() < self.packetDrop:
self.mqueue.put(bmsg)
else:
self.qrlog.debug("Dropping packet!")
mqueueMutex.release()
def quit(self):
self.display.quit = True
self.cam.quit = True
if __name__ == '__main__':
qrnet = QrNet()
qrnet.run()