def fetch(path=None,verbose=False): """ retrieves oui.txt from IEEE and writes to data file :param path: fullpath of oui.txt :param verbose: write updates to stdout """ # determine if data path is legit if path is None: ouipath = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.path.abspath('../data/oui.txt')) else: ouipath = path if not os.path.isdir(os.path.dirname(ouipath)): print "Path to data is incorrect {0}".format(ouipath) sys.exit(1) # fetch oui file from ieee fout = None #pattern = r'^([-|\w]*) \(hex\)\t\t(.*)\r' # set up url request ouiurl = 'http://standards-oui.ieee.org/oui.txt' req = urllib2.Request(ouiurl) req.add_header('User-Agent',"wraith-rt +https://github.com/wraith-wireless/wraith/") try: # retrieve the oui file and parse out generated date if verbose: print 'Fetching ', ouiurl res = urllib2.urlopen(req) if verbose: print "Parsing OUI file" if verbose: print "Opening data file {0} for writing".format(ouipath) fout = open(ouipath,'w') gen = ts2iso(time.time()) # use current time as the first line fout.write(gen+'\n') # pull out ouis t = time.time() cnt = 0 for l in res: if '(hex)' in l: # extract oui and manufacturer oui,manuf = l.split('(hex)') oui = oui.strip().replace('-',':') manuf = manuf.strip() if manuf.startswith("IEEE REGISTRATION AUTHORITY"): manuf = "IEEE REGISTRATION AUTHORITY" # write to file & update count fout.write('{0}\t{1}\n'.format(oui,manuf)) cnt += 1 if verbose: print "{0}:\t{1}\t{2}".format(cnt,oui,manuf) print "Wrote {0} OUIs in {1:.3} secs".format(cnt,time.time()-t) except urllib2.URLError as e: print "Error fetching oui file: {0}".format(e) except IOError as e: print "Error opening output file {0}".format(e) except Exception as e: print "Error parsing oui file: {0}".format(e) finally: if fout: fout.close()
def _send(self,t,ts,d): """ send - sends message msg m of type t with timestamp ts to Nidus t - message type ts - message timestamp d - data returns None on success otherwise returns reason for failure """ # convert the timestamp to utc isoformat before crafting ts = ts2iso(ts) # craft the message try: send = "\x01*%s:\x02" % t if t == 'DEVICE': send += self._craftdevice(ts,d) elif t == 'PLATFORM': send += self._craftplatform(d) elif t == 'RADIO': send += self._craftradio(ts,d) elif t == 'ANTENNA': send += self._craftantenna(ts,d) elif t == 'GPSD': send += self._craftgpsd(ts,d) elif t == 'FRAME': send += self._craftframe(ts,d) elif t == 'GPS': send += self._craftflt(ts,d,self._mgrs) elif t == 'RADIO_EVENT': send += self._craftradioevent(ts,d) send += "\x03\x12\x15\04" if not self._nidus.send(send): return "Nidus socket closed unexpectantly" return None except socket.error, ret: return ret
def submitdropped(self): """ sensor exited unexpectantly, close out open ended records """ if not self._sid: return try: # get current time ts = ts2iso(time.time()) # close out the sensor sql = """ update sensor set period = tstzrange(lower(period),%s) where session_id = %s; """ self._curs.execute(sql,(ts,self._sid)) # close out radios # get radios currently used by sensor sql = " select mac from using_radio where sid=%s;" self._curs.execute(sql,(self._sid,)) for row in self._curs.fetchall(): mac = row[0] # close out using_radio sql = """ update using_radio set period = tstzrange(lower(period),%s) where sid=%s and mac=%s; """ self._curs.execute(sql,(ts,self._sid,mac)) # close out gpsd sql = """ update using_gpsd set period = tstzrange(lower(period),%s) where sid=%s; """ self._curs.execute(sql,(ts,self._sid)) except: # don't raise an exception here, nidus is already exiting self._conn.rollback() else: self._conn.commit()
def submitdropped(self): """ sensor exited unexpectantly, close out open ended records """ if not self._sid: return try: # get current time ts = ts2iso(time.time()) # close out the sensor sql = """ update sensor set period = tstzrange(lower(period),%s) where session_id = %s; """ self._curs.execute(sql, (ts, self._sid)) # close out radios # get radios currently used by sensor sql = " select mac from using_radio where sid=%s;" self._curs.execute(sql, (self._sid, )) for row in self._curs.fetchall(): mac = row[0] # close out using_radio sql = """ update using_radio set period = tstzrange(lower(period),%s) where sid=%s and mac=%s; """ self._curs.execute(sql, (ts, self._sid, mac)) # close out gpsd sql = """ update using_gpsd set period = tstzrange(lower(period),%s) where sid=%s; """ self._curs.execute(sql, (ts, self._sid)) except: # don't raise an exception here, nidus is already exiting self._conn.rollback() else: self._conn.commit()
def run(self): """ switch channels based on associted dwell times """ # ignore signals being used by main program signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) # starting paused or scanning? if self._state == TUNE_PAUSE: self._qR.put((RDO_PAUSE, isots(), [-1, ' '])) else: self._qR.put((RDO_SCAN, isots(), [-1, self._chs])) # execution loop - wait on the internal connection for each channels # dwell time. IOT avoid a state where we would continue to scan the same # channel, i.e. 'state' commands, use a remaining time counter remaining = 0 # remaining dwell time counter dwell = self._ds[0] # save original dwell time while True: # set the poll timeout to remaining if we need to finish this scan # or to None if we are in a static state if self._state in [TUNE_PAUSE, TUNE_HOLD, TUNE_LISTEN]: to = None else: to = self._ds[self._i] if not remaining else remaining ts1 = time() # get timestamp if self._cI.poll( to): # we hold on the iyri connection during poll time tkn = self._cI.recv() ts = time() # tokens will have 2 flavor's POISON and 'cmd:cmdid:params' # where params is empty (for POISON) or a '-' separated list if tkn == POISON: # for a POISON, quit and notify the RadioController self._qR.put((POISON, ts2iso(ts), [-1, ' '])) break # calculate time remaining for this channel if not remaining: remaining = self._ds[self._i] - (ts - ts1) else: remaining -= (ts - ts1) # parse the requested command cmd, cid, ps = tkn.split(':') # force into 3 components cid = int(cid) # & convert id to int if cmd == 'state': self._qR.put((RDO_STATE, ts2iso(ts), [cid, self.meta])) elif cmd == 'scan': if self._state != TUNE_SCAN: self._state = TUNE_SCAN self._qR.put((RDO_SCAN, ts2iso(ts), [cid, self._chs])) else: self._qR.put( (CMD_ERR, ts2iso(ts), [cid, "redundant cmd"])) elif cmd == 'txpwr': err = "txpwr not currently supported" self._qR.put((CMD_ERR, ts2iso(ts), [cid, err])) elif cmd == 'spoof': err = "spoof not currently supported" self._qR.put((CMD_ERR, ts2iso(ts), [cid, err])) elif cmd == 'hold': if self._state != TUNE_HOLD: self._state = TUNE_HOLD self._qR.put( (RDO_HOLD, ts2iso(ts), [cid, self.channel])) else: self._qR.put( (CMD_ERR, ts2iso(ts), [cid, "redundant cmd"])) elif cmd == 'pause': if self._state != TUNE_PAUSE: self._state = TUNE_PAUSE self._qR.put( (RDO_PAUSE, ts2iso(ts), [cid, self.channel])) else: self._qR.put( (CMD_ERR, ts2iso(ts), [cid, "redundant cmd"])) elif cmd == 'listen': if self._state != TUNE_LISTEN: try: ch, chw = ps.split('-') if chw == 'None': chw = None self._rdo.setch(ch, chw) self._state = TUNE_LISTEN details = "{0}:{1}".format(ch, chw) self._qR.put( (RDO_LISTEN, ts2iso(ts), [cid, details])) except ValueError: err = "invalid param format" self._qR.put((CMD_ERR, ts2iso(ts), [cid, err])) except radio.RadioException as e: self._qR.put((CMD_ERR, ts2iso(ts), [cid, str(e)])) else: self._qR.put( (CMD_ERR, ts2iso(ts), [cid, "redundant cmd"])) else: err = "invalid command {0}".format(cmd) self._qR.put((CMD_ERR, ts2iso(ts), [cid, err])) else: try: # no token, go to next channel, reset remaining self._i = (self._i + 1) % len(self._chs) self._rdo.setch(self._chs[self._i][0], self._chs[self._i][1]) remaining = 0 # reset remaining timeout except radio.RadioException as e: self._qR.put((RDO_FAIL, isots(), [-1, e])) except Exception as e: # blanket exception self._qR.put((RDO_FAIL, isots(), [-1, e]))
def run(self): """ run execution loop """ # ignore signals being used by main program signal.signal(signal.SIGINT,signal.SIG_IGN) signal.signal(signal.SIGTERM,signal.SIG_IGN) # basic variables rmap = {} # radio map: maps callsigns to mac addr #bulk = {} # stored frames gpsid = None # id of gps device # send sensor up notification, platform details and gpsid ret = self._send('DEVICE',time.time(),['sensor',socket.gethostname(),1]) if ret: self._conn.send(('err','RTO','Nidus',ret)) else: ret = self._send('PLATFORM',time.time(),self._pfdetails()) if ret: self._conn.send(('err','RTO','Nidus',ret)) else: self._setgpsd() # execution loop while True: # 1. anything from DySKT if self._conn.poll() and self._conn.recv() == '!STOP!': break # 2. gps device/frontline trace? try: t,ts,msg = self._q.get_nowait() except (Empty,AttributeError): pass else: if t == '!DEV!': # device up message gpsid = msg['id'] self._conn.send(('info','RTO','GPSD',"%s initiated" % gpsid)) ret = self._send('GPSD',ts,msg) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif t == '!FLT!': # frontline trace ret = self._send('FLT',ts,msg) if ret: self._conn.send(('err','RTO','Nidus',ret)) # 3. queued data from internal comms ev = msg = None try: rpt = self._icomms.get(True,0.5) cs,ts,ev,msg = rpt[0],rpt[1],rpt[2],rpt[3] if ev == '!UP!': # should be the 1st message we get from radio(s) # NOTE: send the radio, nidus will take care of setting the # radio device status, initial radio events and using_radio. # Send each antenna separately rmap[cs] = msg['mac'] self._bulk[cs] = {'cob':None, # zlib compressobj 'mac':msg['mac'], # mac addr of collecting radio 'start':0, # time first frame was seen 'cnt':0, # ttl # of frames 'sz':0, # ttl size of uncompressed frames 'frames':''} # the compressed frames self._conn.send(('info','RTO','Radio',"%s initiated" % cs)) ret = self._send('RADIO',ts,msg) if ret: self._conn.send(('err','RTO','Nidus',ret)) else: # send antennas for i in xrange(msg['nA']): ret = self._send('ANTENNA',ts, {'mac':msg['mac'],'index':i, 'type':msg['type'][i],'gain':msg['gain'][i], 'loss':msg['loss'][i],'x':msg['x'][i], 'y':msg['y'][i],'z':msg['z'][i]}) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif ev == '!FAIL!': # send bulked frames, notify nidus & DySKT & delete cs ret = self._flushbulk(ts,rmap[cs],cs) if not ret: ret = self._send('RADIO_EVENT',ts,[rmap[cs],'fail',msg]) if ret: self._conn.send(('err','RTO','Nidus',ret)) del rmap[cs] del self._bulk[cs] elif ev == '!SCAN!': # compile the scan list into a string before sending sl = ",".join(["%d:%s" % (c,w) for (c,w) in msg]) ret = self._send('RADIO_EVENT',ts,[rmap[cs],'scan',sl]) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif ev == '!LISTEN!': ret = self._send('RADIO_EVENT',ts,[rmap[cs],'listen',msg]) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif ev == '!HOLD!': ret = self._send('RADIO_EVENT',ts,[rmap[cs],'hold',msg]) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif ev == '!PAUSE!': # send bulked frames ret = self._flushbulk(ts,rmap[cs],cs) if not ret: ret = self._send('RADIO_EVENT',ts,[rmap[cs],'pause',' ']) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif ev == '!SPOOF!': ret = self._send('RADIO_EVENT',ts,[rmap[cs],'spoof',msg]) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif ev == '!TXPWR!': ret = self._send('RADIO_EVENT',ts,[rmap[cs],'txpwr',msg]) if ret: self._conn.send(('err','RTO','Nidus',ret)) elif ev == '!FRAME!': # save the frame and update bulk details if self._bulk[cs]['cnt'] == 0: self._bulk[cs]['start'] = ts # reset start self._bulk[cs]['cob'] = zlib.compressobj() # new compression obj # add new frame and update metrics self._bulk[cs]['cnt'] += 1 self._bulk[cs]['sz'] += len(msg) self._bulk[cs]['frames'] += self._bulk[cs]['cob'].compress('%s \x1EFB\x1F%s\x1FFE\x1E' % (ts2iso(ts),msg)) # if we have hit our limit, compress and send the bulk frames if self._bulk[cs]['sz'] > _BSZ_ or (ts - self._bulk[cs]['start'])/1000 > _BTM_: self._flushbulk(ts,rmap[cs],cs) else: # unidentified event type, notify dyskt self._conn.send(('warn','RTO','Radio',"unknown event %s" % ev)) except Empty: # nothing on queue continue except IndexError as e: # something wrong with antenna indexing self._conn.send(('err','RTO',"Radio","misconfigured antennas")) except KeyError as e: # a radio sent a message without initiating self._conn.send(('warn','RTO','Radio %s' % e,"uninitiated data (%s)" % ev)) except Exception as e: # handle catchall error self._conn.send(('err','RTO','Unknown',e)) # any bulked frames not yet sent? for cs in rmap: self._flushbulk(time.time(),rmap[cs],cs) # notify Nidus of closing (radios,sensor,gpsd). hopefully no errors on send ts = time.time() for cs in rmap: self._send('DEVICE',ts,['radio',rmap[cs],0]) self._send('DEVICE',ts,['gpsd',gpsid,0]) self._send('DEVICE',ts,['sensor',socket.gethostname(),0]) # shut down if not self._shutdown(): try: self._conn.send(('warn','RTO','Shutdown',"Incomplete shutdown")) except IOError: # most likely DySKT(.py) closed their side of the pipe pass
def run(self): """ run execution loop """ # ignore signals being used by main program signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) # basic variables rmap = {} # radio map: maps callsigns to mac addr #bulk = {} # stored frames gpsid = None # id of gps device # send sensor up notification, platform details and gpsid ret = self._send('DEVICE', time.time(), ['sensor', socket.gethostname(), 1]) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) else: ret = self._send('PLATFORM', time.time(), self._pfdetails()) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) else: self._setgpsd() # execution loop while True: # 1. anything from DySKT if self._conn.poll() and self._conn.recv() == '!STOP!': break # 2. gps device/frontline trace? try: t, ts, msg = self._q.get_nowait() except (Empty, AttributeError): pass else: if t == '!DEV!': # device up message gpsid = msg['id'] self._conn.send( ('info', 'RTO', 'GPSD', "%s initiated" % gpsid)) ret = self._send('GPSD', ts, msg) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif t == '!FLT!': # frontline trace ret = self._send('FLT', ts, msg) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) # 3. queued data from internal comms ev = msg = None try: rpt = self._icomms.get(True, 0.5) cs, ts, ev, msg = rpt[0], rpt[1], rpt[2], rpt[3] if ev == '!UP!': # should be the 1st message we get from radio(s) # NOTE: send the radio, nidus will take care of setting the # radio device status, initial radio events and using_radio. # Send each antenna separately rmap[cs] = msg['mac'] self._bulk[cs] = { 'cob': None, # zlib compressobj 'mac': msg['mac'], # mac addr of collecting radio 'start': 0, # time first frame was seen 'cnt': 0, # ttl # of frames 'sz': 0, # ttl size of uncompressed frames 'frames': '' } # the compressed frames self._conn.send( ('info', 'RTO', 'Radio', "%s initiated" % cs)) ret = self._send('RADIO', ts, msg) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) else: # send antennas for i in xrange(msg['nA']): ret = self._send( 'ANTENNA', ts, { 'mac': msg['mac'], 'index': i, 'type': msg['type'][i], 'gain': msg['gain'][i], 'loss': msg['loss'][i], 'x': msg['x'][i], 'y': msg['y'][i], 'z': msg['z'][i] }) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif ev == '!FAIL!': # send bulked frames, notify nidus & DySKT & delete cs ret = self._flushbulk(ts, rmap[cs], cs) if not ret: ret = self._send('RADIO_EVENT', ts, [rmap[cs], 'fail', msg]) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) del rmap[cs] del self._bulk[cs] elif ev == '!SCAN!': # compile the scan list into a string before sending sl = ",".join(["%d:%s" % (c, w) for (c, w) in msg]) ret = self._send('RADIO_EVENT', ts, [rmap[cs], 'scan', sl]) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif ev == '!LISTEN!': ret = self._send('RADIO_EVENT', ts, [rmap[cs], 'listen', msg]) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif ev == '!HOLD!': ret = self._send('RADIO_EVENT', ts, [rmap[cs], 'hold', msg]) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif ev == '!PAUSE!': # send bulked frames ret = self._flushbulk(ts, rmap[cs], cs) if not ret: ret = self._send('RADIO_EVENT', ts, [rmap[cs], 'pause', ' ']) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif ev == '!SPOOF!': ret = self._send('RADIO_EVENT', ts, [rmap[cs], 'spoof', msg]) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif ev == '!TXPWR!': ret = self._send('RADIO_EVENT', ts, [rmap[cs], 'txpwr', msg]) if ret: self._conn.send(('err', 'RTO', 'Nidus', ret)) elif ev == '!FRAME!': # save the frame and update bulk details if self._bulk[cs]['cnt'] == 0: self._bulk[cs]['start'] = ts # reset start self._bulk[cs]['cob'] = zlib.compressobj( ) # new compression obj # add new frame and update metrics self._bulk[cs]['cnt'] += 1 self._bulk[cs]['sz'] += len(msg) self._bulk[cs]['frames'] += self._bulk[cs]['cob'].compress( '%s \x1EFB\x1F%s\x1FFE\x1E' % (ts2iso(ts), msg)) # if we have hit our limit, compress and send the bulk frames if self._bulk[cs]['sz'] > _BSZ_ or ( ts - self._bulk[cs]['start']) / 1000 > _BTM_: self._flushbulk(ts, rmap[cs], cs) else: # unidentified event type, notify dyskt self._conn.send( ('warn', 'RTO', 'Radio', "unknown event %s" % ev)) except Empty: # nothing on queue continue except IndexError as e: # something wrong with antenna indexing self._conn.send( ('err', 'RTO', "Radio", "misconfigured antennas")) except KeyError as e: # a radio sent a message without initiating self._conn.send(('warn', 'RTO', 'Radio %s' % e, "uninitiated data (%s)" % ev)) except Exception as e: # handle catchall error self._conn.send(('err', 'RTO', 'Unknown', e)) # any bulked frames not yet sent? for cs in rmap: self._flushbulk(time.time(), rmap[cs], cs) # notify Nidus of closing (radios,sensor,gpsd). hopefully no errors on send ts = time.time() for cs in rmap: self._send('DEVICE', ts, ['radio', rmap[cs], 0]) self._send('DEVICE', ts, ['gpsd', gpsid, 0]) self._send('DEVICE', ts, ['sensor', socket.gethostname(), 0]) # shut down if not self._shutdown(): try: self._conn.send( ('warn', 'RTO', 'Shutdown', "Incomplete shutdown")) except IOError: # most likely DySKT(.py) closed their side of the pipe pass