These either remain from openbsc.git or slipped in while applying recent patches from openbsc.git and do not belong in osmo-msc. Empty out contrib: remove things that are either obviously unrelated to osmo-msc, or seem old and/or esoteric. Change-Id: I49957769e09eed6d723bf7c3777024b62b3480fdchanges/01/3801/3
parent
d6d90ce259
commit
47cd0d2687
@ -1,170 +0,0 @@ |
||||
-- Split trace based on SCCP Source |
||||
-- There are still bugs to find... bugs bugs bugs... hmm |
||||
do |
||||
local function init_listener() |
||||
print("CREATED LISTENER") |
||||
local tap = Listener.new("ip", "sccp && (ip.src == 172.16.1.81 || ip.dst == 172.16.1.81)") |
||||
local sccp_type_field = Field.new("sccp.message_type") |
||||
local sccp_src_field = Field.new("sccp.slr") |
||||
local sccp_dst_field = Field.new("sccp.dlr") |
||||
local msg_type_field = Field.new("gsm_a.dtap_msg_mm_type") |
||||
local lu_rej_field = Field.new("gsm_a.dtap.rej_cause") |
||||
local ip_src_field = Field.new("ip.src") |
||||
local ip_dst_field = Field.new("ip.dst") |
||||
|
||||
-- |
||||
local bssmap_msgtype_field = Field.new("gsm_a.bssmap_msgtype") |
||||
-- assignment failure 0x03 |
||||
-- |
||||
|
||||
-- |
||||
local dtap_cause_field = Field.new("gsm_a_dtap.cause") |
||||
local dtap_cc_field = Field.new("gsm_a.dtap_msg_cc_type") |
||||
|
||||
local connections = {} |
||||
|
||||
function check_failure(con) |
||||
check_lu_reject(con) |
||||
check_disconnect(con) |
||||
check_failures(con) |
||||
end |
||||
|
||||
-- cipher mode reject |
||||
function check_failures(con) |
||||
local msgtype = bssmap_msgtype_field() |
||||
if not msgtype then |
||||
return |
||||
end |
||||
|
||||
msgtype = tonumber(msgtype) |
||||
if msgtype == 89 then |
||||
print("Cipher mode reject") |
||||
con[4] = true |
||||
elseif msgtype == 0x03 then |
||||
print("Assignment failure") |
||||
con[4] = true |
||||
elseif msgtype == 0x22 then |
||||
print("Clear Request... RF failure?") |
||||
con[4] = true |
||||
end |
||||
end |
||||
|
||||
-- check if a DISCONNECT is normal |
||||
function check_disconnect(con) |
||||
local msg_type = dtap_cc_field() |
||||
if not msg_type then |
||||
return |
||||
end |
||||
|
||||
if tonumber(msg_type) ~= 0x25 then |
||||
return |
||||
end |
||||
|
||||
local cause = dtap_cause_field() |
||||
if not cause then |
||||
return |
||||
end |
||||
|
||||
cause = tonumber(cause) |
||||
if cause ~= 0x10 then |
||||
print("DISCONNECT != Normal") |
||||
con[4] = true |
||||
end |
||||
end |
||||
|
||||
-- check if we have a LU Reject |
||||
function check_lu_reject(con) |
||||
local msg_type = msg_type_field() |
||||
if not msg_type then |
||||
return |
||||
end |
||||
|
||||
msg_type = tonumber(tostring(msg_type)) |
||||
if msg_type == 0x04 then |
||||
print("LU REJECT with " .. tostring(lu_rej_field())) |
||||
con[4] = true |
||||
end |
||||
end |
||||
|
||||
function tap.packet(pinfo,tvb,ip) |
||||
local ip_src = tostring(ip_src_field()) |
||||
local ip_dst = tostring(ip_dst_field()) |
||||
local sccp_type = tonumber(tostring(sccp_type_field())) |
||||
local sccp_src = sccp_src_field() |
||||
local sccp_dst = sccp_dst_field() |
||||
|
||||
local con |
||||
|
||||
if sccp_type == 0x01 then |
||||
elseif sccp_type == 0x2 then |
||||
local src = string.format("%s-%s", ip_src, tostring(sccp_src)) |
||||
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst)) |
||||
local datestring = os.date("%Y%m%d%H%M%S") |
||||
local pcap_name = string.format("alink_trace_%s-%s_%s.pcap", src, dst, datestring) |
||||
local dumper = Dumper.new_for_current(pcap_name) |
||||
|
||||
local con = { ip_src, tostring(sccp_src), tostring(sccp_dst), false, dumper, pcap_name } |
||||
|
||||
dumper:dump_current() |
||||
connections[src] = con |
||||
connections[dst] = con |
||||
elseif sccp_type == 0x4 then |
||||
-- close a connection... remove it from the list |
||||
local src = string.format("%s-%s", ip_src, tostring(sccp_src)) |
||||
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst)) |
||||
|
||||
local con = connections[src] |
||||
if not con then |
||||
return |
||||
end |
||||
|
||||
con[5]:dump_current() |
||||
con[5]:flush() |
||||
|
||||
-- this causes a crash on unpacted wireshark |
||||
con[5]:close() |
||||
|
||||
-- the connection had a failure |
||||
if con[4] == true then |
||||
local datestring = os.date("%Y%m%d%H%M%S") |
||||
local new_name = string.format("alink_failure_%s_%s-%s.pcap", datestring, con[2], con[3]) |
||||
os.rename(con[6], new_name) |
||||
else |
||||
os.remove(con[6]) |
||||
end |
||||
|
||||
|
||||
-- clear the old connection |
||||
connections[src] = nil |
||||
connections[dst] = nil |
||||
|
||||
elseif sccp_type == 0x5 then |
||||
-- not handled yet... we should verify stuff here... |
||||
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst)) |
||||
local con = connections[dst] |
||||
if not con then |
||||
return |
||||
end |
||||
con[5]:dump_current() |
||||
elseif sccp_type == 0x6 then |
||||
local dst = string.format("%s-%s", ip_dst, tostring(sccp_dst)) |
||||
local con = connections[dst] |
||||
if not con then |
||||
print("DON'T KNOW THIS CONNECTION for " .. ip_dst) |
||||
return |
||||
end |
||||
con[5]:dump_current() |
||||
check_failure(con) |
||||
end |
||||
|
||||
end |
||||
function tap.draw() |
||||
print("DRAW") |
||||
end |
||||
function tap.reset() |
||||
print("RESET") |
||||
end |
||||
end |
||||
|
||||
init_listener() |
||||
end |
@ -1 +0,0 @@ |
||||
Some crazy scripts call testing... and MSC link failure simulation |
@ -1,8 +0,0 @@ |
||||
ABORT BUSY |
||||
ABORT 'NO CARRIER' |
||||
ABORT 'OK' |
||||
|
||||
'' AT |
||||
SAY "Dialing a number\n" |
||||
'OK' ATD05660066; |
||||
|
@ -1,11 +0,0 @@ |
||||
#!/bin/sh |
||||
# Evil dial script.. |
||||
|
||||
while true; |
||||
do |
||||
chat -v -f all_dial < /dev/ttyACM0 > /dev/ttyACM0 |
||||
sleep 5s |
||||
chat -v -f hangup < /dev/ttyACM0 > /dev/ttyACM0 |
||||
sleep 2s |
||||
done |
||||
|
@ -1,6 +0,0 @@ |
||||
#!/bin/sh |
||||
sleep 3 |
||||
echo "enable" |
||||
sleep 1 |
||||
echo "drop bts connection 0 oml" |
||||
sleep 1 |
@ -1,8 +0,0 @@ |
||||
#!/bin/sh |
||||
|
||||
while true; |
||||
do |
||||
echo "Going to drop the OML connection" |
||||
./drop-oml.sh | telnet 127.0.0.1 4242 |
||||
sleep 58m |
||||
done |
@ -1,4 +0,0 @@ |
||||
TIMEOUT 10 |
||||
'' ^Z |
||||
SAY "Waiting for hangup confirm\n" |
||||
'' ATH; |
@ -1,8 +0,0 @@ |
||||
#!/bin/sh |
||||
|
||||
while true; |
||||
do |
||||
echo "Kill the osmo-bsc" |
||||
/usr/bin/kill -s SIGUSR2 `pidof osmo-bsc` |
||||
sleep 58s |
||||
done |
@ -1,120 +0,0 @@ |
||||
#!/usr/bin/python |
||||
# -*- mode: python-mode; py-indent-tabs-mode: nil -*- |
||||
""" |
||||
/* |
||||
* Copyright (C) 2016 sysmocom s.f.m.c. GmbH |
||||
* |
||||
* All Rights Reserved |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along |
||||
* with this program; if not, write to the Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
*/ |
||||
""" |
||||
|
||||
from optparse import OptionParser |
||||
from ipa import Ctrl |
||||
import socket |
||||
|
||||
verbose = False |
||||
|
||||
def connect(host, port): |
||||
if verbose: |
||||
print "Connecting to host %s:%i" % (host, port) |
||||
|
||||
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
sck.setblocking(1) |
||||
sck.connect((host, port)) |
||||
return sck |
||||
|
||||
def do_set_get(sck, var, value = None): |
||||
(r, c) = Ctrl().cmd(var, value) |
||||
sck.send(c) |
||||
answer = Ctrl().rem_header(sck.recv(4096)) |
||||
return (answer,) + Ctrl().verify(answer, r, var, value) |
||||
|
||||
def set_var(sck, var, val): |
||||
(a, _, _) = do_set_get(sck, var, val) |
||||
return a |
||||
|
||||
def get_var(sck, var): |
||||
(_, _, v) = do_set_get(sck, var) |
||||
return v |
||||
|
||||
def _leftovers(sck, fl): |
||||
""" |
||||
Read outstanding data if any according to flags |
||||
""" |
||||
try: |
||||
data = sck.recv(1024, fl) |
||||
except socket.error as (s_errno, strerror): |
||||
return False |
||||
if len(data) != 0: |
||||
tail = data |
||||
while True: |
||||
(head, tail) = Ctrl().split_combined(tail) |
||||
print "Got message:", Ctrl().rem_header(head) |
||||
if len(tail) == 0: |
||||
break |
||||
return True |
||||
return False |
||||
|
||||
if __name__ == '__main__': |
||||
parser = OptionParser("Usage: %prog [options] var [value]") |
||||
parser.add_option("-d", "--host", dest="host", |
||||
help="connect to HOST", metavar="HOST") |
||||
parser.add_option("-p", "--port", dest="port", type="int", |
||||
help="use PORT", metavar="PORT", default=4249) |
||||
parser.add_option("-g", "--get", action="store_true", |
||||
dest="cmd_get", help="perform GET operation") |
||||
parser.add_option("-s", "--set", action="store_true", |
||||
dest="cmd_set", help="perform SET operation") |
||||
parser.add_option("-v", "--verbose", action="store_true", |
||||
dest="verbose", help="be verbose", default=False) |
||||
parser.add_option("-m", "--monitor", action="store_true", |
||||
dest="monitor", help="monitor the connection for traps", default=False) |
||||
|
||||
(options, args) = parser.parse_args() |
||||
|
||||
verbose = options.verbose |
||||
|
||||
if options.cmd_set and options.cmd_get: |
||||
parser.error("Get and set options are mutually exclusive!") |
||||
|
||||
if not (options.cmd_get or options.cmd_set or options.monitor): |
||||
parser.error("One of -m, -g, or -s must be set") |
||||
|
||||
if not (options.host): |
||||
parser.error("Destination host and port required!") |
||||
|
||||
sock = connect(options.host, options.port) |
||||
|
||||
if options.cmd_set: |
||||
if len(args) < 2: |
||||
parser.error("Set requires var and value arguments") |
||||
_leftovers(sock, socket.MSG_DONTWAIT) |
||||
print "Got message:", set_var(sock, args[0], ' '.join(args[1:])) |
||||
|
||||
if options.cmd_get: |
||||
if len(args) != 1: |
||||
parser.error("Get requires the var argument") |
||||
_leftovers(sock, socket.MSG_DONTWAIT) |
||||
(a, _, _) = do_set_get(sock, args[0]) |
||||
print "Got message:", a |
||||
|
||||
if options.monitor: |
||||
while True: |
||||
if not _leftovers(sock, 0): |
||||
print "Connection is gone." |
||||
break |
||||
sock.close() |
@ -1,33 +0,0 @@ |
||||
#!/usr/bin/env python |
||||
|
||||
import os |
||||
|
||||
f = open("unbalanced") |
||||
lines = [] |
||||
for line in f: |
||||
lines.append(line) |
||||
|
||||
filenames = {} |
||||
|
||||
output = [] |
||||
for line in lines: |
||||
if "[0x" in line: |
||||
start = line.find("[") |
||||
end = line.find("]") |
||||
addr = line[start+1:end] |
||||
try: |
||||
file = filenames[addr] |
||||
except KeyError: |
||||
r = os.popen("addr2line -fs -e ./bsc_hack %s" % addr) |
||||
all = r.read().replace("\n", ",") |
||||
file = all |
||||
filenames[addr] = file |
||||
|
||||
line = line.replace(addr, file) |
||||
output.append(line) |
||||
|
||||
g = open("unbalanced.2", "w") |
||||
g.write("".join(output)) |
||||
|
||||
|
||||
|
@ -1,37 +0,0 @@ |
||||
#!/usr/bin/env python |
||||
|
||||
# |
||||
# Convert ETSI documents to an enum |
||||
# |
||||
|
||||
import re, sys |
||||
|
||||
def convert(string): |
||||
string = string.strip().replace(" ", "").rjust(8, "0") |
||||
var = 0 |
||||
offset = 7 |
||||
for char in string: |
||||
assert offset >= 0 |
||||
var = var | (int(char) << offset) |
||||
offset = offset - 1 |
||||
|
||||
return var |
||||
|
||||
def string(name): |
||||
name = name.replace(" ", "_") |
||||
name = name.replace('"', "") |
||||
name = name.replace('/', '_') |
||||
name = name.replace('(', '_') |
||||
name = name.replace(')', '_') |
||||
return "%s_%s" % (sys.argv[2], name.upper()) |
||||
|
||||
file = open(sys.argv[1]) |
||||
|
||||
|
||||
for line in file: |
||||
m = re.match(r"[ \t]*(?P<value>[01 ]+)[ ]+(?P<name>[a-zA-Z /0-9()]+)", line[:-1]) |
||||
|
||||
if m: |
||||
print "\t%s\t\t= %d," % (string(m.groupdict()["name"]), convert(m.groupdict()["value"])) |
||||
else: |
||||
print line[:-1] |
@ -1,147 +0,0 @@ |
||||
#!/usr/bin/python2 |
||||
|
||||
mod_license = ''' |
||||
/* |
||||
* Copyright (C) 2016 sysmocom s.f.m.c. GmbH |
||||
* |
||||
* All Rights Reserved |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License along |
||||
* with this program; if not, write to the Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
*/ |
||||
''' |
||||
|
||||
import sys, argparse, random, logging, tornado.ioloop, tornado.web, tornado.tcpclient, tornado.httpclient, eventsource, bsc_control |
||||
from eventsource import listener, request |
||||
|
||||
''' |
||||
N. B: this is not an example of building proper REST API or building secure web application. |
||||
It's only purpose is to illustrate conversion of Osmocom's Control Interface to web-friendly API. |
||||
Exposing this to Internet while connected to production network might lead to all sorts of mischief and mayhem |
||||
from NSA' TAO breaking into your network to zombie apocalypse. Do NOT do that. |
||||
''' |
||||
|
||||
token = None |
||||
stream = None |
||||
url = None |
||||
|
||||
''' |
||||
Returns json according to following schema - see http://json-schema.org/documentation.html for details: |
||||
{ |
||||
"title": "Ctrl Schema", |
||||
"type": "object", |
||||
"properties": { |
||||
"variable": { |
||||
"type": "string" |
||||
}, |
||||
"varlue": { |
||||
"type": "string" |
||||
} |
||||
}, |
||||
"required": ["interface", "variable", "value"] |
||||
} |
||||
Example validation from command-line: |
||||
json validate --schema-file=schema.json --document-file=data.json |
||||
The interface is represented as string because it might look different for IPv4 vs v6. |
||||
''' |
||||
|
||||
def read_header(data): |
||||
t_length = bsc_control.ipa_ctrl_header(data) |
||||
if (t_length): |
||||
stream.read_bytes(t_length - 1, callback = read_trap) |
||||
else: |
||||
print >> sys.stderr, "protocol error: length missing in %s!" % data |
||||
|
||||
@tornado.gen.coroutine |
||||
def read_trap(data): |
||||
(t, z, v, p) = data.split() |
||||
if (t != 'TRAP' or int(z) != 0): |
||||
print >> sys.stderr, "protocol error: TRAP != %s or 0! = %d" % (t, int(z)) |
||||
else: |
||||
yield tornado.httpclient.AsyncHTTPClient().fetch(tornado.httpclient.HTTPRequest(url = "%s/%s/%s" % (url, "ping", token), |
||||
method = 'POST', |
||||
headers = {'Content-Type': 'application/json'}, |
||||
body = tornado.escape.json_encode({ 'variable' : v, 'value' : p }))) |
||||
stream.read_bytes(4, callback = read_header) |
||||
|
||||
@tornado.gen.coroutine |
||||
def trap_setup(host, port, target_host, target_port, tk): |
||||
global stream |
||||
global url |
||||
global token |
||||
token = tk |
||||
url = "http://%s:%s/sse" % (host, port) |
||||
stream = yield tornado.tcpclient.TCPClient().connect(target_host, target_port) |
||||
stream.read_bytes(4, callback = read_header) |
||||
|
||||
def get_v(s, v): |
||||
return { 'variable' : v, 'value' : bsc_control.get_var(s, tornado.escape.native_str(v)) } |
||||
|
||||
class CtrlHandler(tornado.web.RequestHandler): |
||||
def initialize(self): |
||||
self.skt = bsc_control.connect(self.settings['ctrl_host'], self.settings['ctrl_port']) |
||||
|
||||
def get(self, v): |
||||
self.write(get_v(self.skt, v)) |
||||
|
||||
def post(self): |
||||
self.write(get_v(self.skt, self.get_argument("variable"))) |
||||
|
||||
class SetCtrl(CtrlHandler): |
||||
def get(self, var, val): |
||||
bsc_control.set_var(self.skt, tornado.escape.native_str(var), tornado.escape.native_str(val)) |
||||
super(SetCtrl, self).get(tornado.escape.native_str(var)) |
||||
|
||||
def post(self): |
||||
bsc_control.set_var(self.skt, tornado.escape.native_str(self.get_argument("variable")), tornado.escape.native_str(self.get_argument("value"))) |
||||
super(SetCtrl, self).post() |
||||
|
||||
class Slash(tornado.web.RequestHandler): |
||||
def get(self): |
||||
self.write('<html><head><title>%s</title></head><body>Using Tornado framework v%s' |
||||
'<form action="/get" method="POST">' |
||||
'<input type="text" name="variable">' |
||||
'<input type="submit" value="GET">' |
||||
'</form>' |
||||
'<form action="/set" method="POST">' |
||||
'<input type="text" name="variable">' |
||||
'<input type="text" name="value">' |
||||
'<input type="submit" value="SET">' |
||||
'</form>' |
||||
'</body></html>' % ("Osmocom Control Interface Proxy", tornado.version)) |
||||
|
||||
if __name__ == '__main__': |
||||
p = argparse.ArgumentParser(description='Osmocom Control Interface proxy.') |
||||
p.add_argument('-c', '--control-port', type = int, default = 4252, help = "Target Control Interface port") |
||||
p.add_argument('-a', '--control-host', default = 'localhost', help = "Target Control Interface adress") |
||||
p.add_argument('-b', '--host', default = 'localhost', help = "Adress to bind proxy's web interface") |
||||
p.add_argument('-p', '--port', type = int, default = 6969, help = "Port to bind proxy's web interface") |
||||
p.add_argument('-d', '--debug', action='store_true', help = "Activate debugging (default off)") |
||||
p.add_argument('-t', '--token', default = 'osmocom', help = "Token to be used by SSE client in URL e. g. http://127.0.0.1:8888/poll/osmocom where 'osmocom' is default token value") |
||||
p.add_argument('-k', '--keepalive', type = int, default = 5000, help = "Timeout betwwen keepalive messages, in milliseconds, defaults to 5000") |
||||
args = p.parse_args() |
||||
random.seed() |
||||
tornado.netutil.Resolver.configure('tornado.netutil.ThreadedResolver') # Use non-blocking resolver |
||||
logging.basicConfig() |
||||
application = tornado.web.Application([ |
||||
(r"/", Slash), |
||||
(r"/get", CtrlHandler), |
||||
(r"/get/(.*)", CtrlHandler), |
||||
(r"/set", SetCtrl), |
||||
(r"/set/(.*)/(.*)", SetCtrl), |
||||
(r"/sse/(.*)/(.*)", listener.EventSourceHandler, dict(event_class = listener.JSONIdEvent, keepalive = args.keepalive)), |
||||
], debug = args.debug, ctrl_host = args.control_host, ctrl_port = args.control_port) |
||||
application.listen(address = args.host, port = args.port) |
||||
trap_setup(args.host, args.port, application.settings['ctrl_host'], application.settings['ctrl_port'], args.token) |
||||
tornado.ioloop.IOLoop.instance().start() |
@ -1,58 +0,0 @@ |
||||
#!/usr/bin/env python |
||||
|
||||
""" |
||||
demonstrate a unblock bug on the GB Proxy.. |
||||
""" |
||||
|
||||
bts_ns_reset = "\x02\x00\x81\x01\x01\x82\x1f\xe7\x04\x82\x1f\xe7" |
||||
ns_reset_ack = "\x03\x01\x82\x1f\xe7\x04\x82\x1f\xe7" |
||||
|
||||
bts_ns_unblock = "\x06" |
||||
ns_unblock_ack = "\x07" |
||||
|
||||
bts_bvc_reset_0 = "\x00\x00\x00\x00\x22\x04\x82\x00\x00\x07\x81\x03\x3b\x81\x02" |
||||
ns_bvc_reset_0_ack = "\x00\x00\x00\x00\x23\x04\x82\x00\x00" |
||||
|
||||
bts_bvc_reset_8167 = "\x00\x00\x00\x00\x22\x04\x82\x1f\xe7\x07\x81\x08\x08\x88\x72\xf4\x80\x10\x1c\x00\x9c\x40" |
||||
|
||||
|
||||
import socket |
||||
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
||||
socket.bind(("0.0.0.0", 0)) |
||||
socket.setblocking(1) |
||||
|
||||
|
||||
import sys |
||||
port = int(sys.argv[1]) |
||||
print "Sending data to port: %d" % port |
||||
|
||||
def send_and_receive(packet): |
||||
socket.sendto(packet, ("127.0.0.1", port)) |
||||
|
||||
try: |
||||
data, addr = socket.recvfrom(4096) |
||||
except socket.error, e: |
||||
print "ERROR", e |
||||
import sys |
||||
sys.exit(0) |
||||
return data |
||||
|
||||
#send stuff once |
||||
|
||||
to_send = [ |
||||
(bts_ns_reset, ns_reset_ack, "reset ack"), |
||||
(bts_ns_unblock, ns_unblock_ack, "unblock ack"), |
||||
(bts_bvc_reset_0, ns_bvc_reset_0_ack, "BVCI=0 reset ack"), |
||||
] |
||||
|
||||
|
||||
for (out, inp, type) in to_send: |
||||
res = send_and_receive(out) |
||||
if res != inp: |
||||
print "Failed to get the %s" % type |
||||
sys.exit(-1) |
||||
|
||||
import time |
||||
time.sleep(3) |
||||
res = send_and_receive(bts_bvc_reset_8167) |
||||
print "Sent all messages... check wireshark for the last response" |
@ -1,78 +0,0 @@ |
||||
-- Simple LUA script to print the size of BSSGP messages over their type... |
||||
|
||||
do |
||||
local ip_bucket = {} |
||||
|
||||
local pdu_types = {} |
||||
pdu_types[ 6] = "PAGING" |
||||
pdu_types[11] = "SUSPEND" |
||||
pdu_types[12] = "SUSPEND-ACK" |
||||
pdu_types[32] = "BVC-BLOCK" |
||||
pdu_types[33] = "BVC-BLOCK-ACK" |
||||
pdu_types[34] = "BVC-RESET" |
||||
pdu_types[35] = "BVC-RESET-ACK" |
||||
pdu_types[36] = "UNBLOCK" |
||||
pdu_types[37] = "UNBLOCK-ACK" |
||||
pdu_types[38] = "FLOW-CONTROL-BVC" |
||||
pdu_types[39] = "FLOW-CONTROL-BVC-ACK" |
||||
pdu_types[40] = "FLOW-CONTROL-MS" |
||||
pdu_types[41] = "FLOW-CONTROL-MS-ACK" |
||||
pdu_types[44] = "LLC-DISCARDED" |
||||
|
||||
local function init_listener() |
||||
-- handle the port as NS over IP |
||||
local udp_port_table = DissectorTable.get("udp.port") |
||||
local gprs_ns_dis = Dissector.get("gprs_ns") |
||||
udp_port_table:add(23000,gprs_ns_dis) |
||||
|
||||
-- bssgp filters |
||||
local bssgp_pdu_get = Field.new("bssgp.pdu_type") |
||||
local udp_length_get = Field.new("udp.length") |
||||
|
||||
local tap = Listener.new("ip", "udp.port == 23000") |
||||
function tap.packet(pinfo,tvb,ip) |
||||
local pdu = bssgp_pdu_get() |
||||
local len = udp_length_get() |
||||
|
||||
-- only handle bssgp, but we also want the IP frame |
||||
if not pdu then |
||||
return |
||||
end |
||||
|
||||
pdu = tostring(pdu) |
||||
if tonumber(pdu) == 0 or tonumber(pdu) == 1 then |
||||
return |
||||
end |
||||
|
||||
local ip_src = tostring(ip.ip_src) |
||||
local bssgp_histo = ip_bucket[ip_src] |
||||
if not bssgp_histo then |
||||
bssgp_histo = {} |
||||
ip_bucket[ip_src] = bssgp_histo |
||||
end |
||||
|
||||
local key = pdu |
||||
local bucket = bssgp_histo[key] |
||||
if not bucket then |
||||
bucket = {} |
||||
bssgp_histo[key] = bucket |
||||
end |
||||
|
||||
table.insert(bucket, tostring(len)) |
||||
print("IP: " .. ip_src .. " PDU: " .. pdu_types[tonumber(pdu)] .. " Length: " .. tostring(len)) |
||||
end |
||||
|
||||
function tap.draw() |
||||
-- well... this will not be called... |
||||
-- for ip,bssgp_histo in pairs(dumpers) do |
||||
-- print("IP " .. ip) |
||||
-- end |
||||
end |
||||
|
||||
function tap.reset() |
||||
-- well... this will not be called... |
||||
end |
||||
end |
||||
|
||||
init_listener() |
||||
end |
@ -1,80 +0,0 @@ |
||||
-- I count the buffer space needed for LLC PDUs in the worse case and print it |
||||
|
||||
do |
||||
local function init_listener() |
||||
-- handle the port as NS over IP |
||||
local udp_port_table = DissectorTable.get("udp.port") |
||||
local gprs_ns_dis = Dissector.get("gprs_ns") |
||||
udp_port_table:add(23000,gprs_ns_dis) |
||||
|
||||
-- bssgp filters |
||||
local bssgp_pdu_get = Field.new("bssgp.pdu_type") |
||||
local bssgp_delay_get = Field.new("bssgp.delay_val") |
||||
local llcgprs_get = Field.new("llcgprs") |
||||
local pdus = nil |
||||
|
||||
print("START...") |
||||
|
||||
local tap = Listener.new("ip", "udp.port == 23000 && bssgp.pdu_type == 0") |
||||
function tap.packet(pinfo,tvb,ip) |
||||
local pdu = bssgp_pdu_get() |
||||
local len = llcgprs_get().len |
||||
local delay = bssgp_delay_get() |
||||
|
||||
-- only handle bssgp, but we also want the IP frame |
||||
if not pdu then |
||||
return |
||||
end |
||||
|
||||
if tonumber(tostring(delay)) == 65535 then |
||||
pdus = { next = pdus, |
||||
len = len, |
||||
expires = -1 } |
||||
else |
||||
local off = tonumber(tostring(delay)) / 100.0 |
||||
pdus = { next = pdus, |
||||
len = len, |
||||
expires = pinfo.rel_ts + off } |
||||
end |
||||
local now_time = tonumber(tostring(pinfo.rel_ts)) |
||||
local now_size = 0 |
||||
local l = pdus |
||||
local prev = nil |
||||
local count = 0 |
||||
while l do |
||||
if now_time < l.expires or l.expires == -1 then |
||||
now_size = now_size + l.len |
||||
prev = l |
||||
l = l.next |
||||
count = count + 1 |
||||
else |
||||
-- delete things |
||||
if prev == nil then |
||||
pdus = nil |
||||
l = nil |
||||
else |
||||
prev.next = l.next |
||||
l = l.next |
||||
end |
||||
end |
||||
end |
||||
-- print("TOTAL: " .. now_time .. " PDU_SIZE: " .. now_size) |
||||
print(now_time .. " " .. now_size / 1024.0 .. " " .. count) |
||||
-- print("NOW: " .. tostring(pinfo.rel_ts) .. " Delay: " .. tostring(delay) .. " Length: " .. tostring(len)) |
||||
end |
||||
|
||||
function tap.draw() |
||||
-- well... this will not be called... |
||||
-- for ip,bssgp_histo in pairs(dumpers) do |
||||
-- print("IP " .. ip) |
||||
-- end |
||||
print("END") |
||||
end |
||||
|
||||
function tap.reset() |
||||
-- well... this will not be called... |
||||
end |
||||
end |
||||
|
||||
init_listener() |
||||
end |
@ -1,46 +0,0 @@ |
||||
-- Create a file named by_ip/''ip_addess''.cap with all ip traffic of each ip host. (works for tshark only) |
||||
-- Dump files are created for both source and destination hosts |
||||
do |
||||
local dir = "by_tlli" |
||||
local dumpers = {} |
||||
local function init_listener() |
||||
local udp_port_table = DissectorTable.get("udp.port") |
||||
local gprs_ns_dis = Dissector.get("gprs_ns") |
||||
udp_port_table:add(23000,gprs_ns_dis) |
||||
|
||||
local field_tlli = Field.new("bssgp.tlli") |
||||
local tap = Listener.new("ip", "udp.port == 23000") |
||||
|
||||
-- we will be called once for every IP Header. |
||||
-- If there's more than one IP header in a given packet we'll dump the packet once per every header |
||||
function tap.packet(pinfo,tvb,ip) |
||||
local tlli = field_tlli() |
||||
if not tlli then |
||||
return |
||||
end |
||||
|
||||
local tlli_str = tostring(tlli) |
||||
tlli_dmp = dumpers[tlli_str] |
||||
if not tlli_dmp then |
||||
local tlli_hex = string.format("0x%x", tonumber(tlli_str)) |
||||
print("Creating dump for TLLI " .. tlli_hex) |
||||
tlli_dmp = Dumper.new_for_current(dir .. "/" .. tlli_hex .. ".pcap") |
||||
dumpers[tlli_str] = tlli_dmp |
||||
end |
||||
tlli_dmp:dump_current() |
||||
tlli_dmp:flush() |
||||
end |
||||
function tap.draw() |
||||
for tlli,dumper in pairs(dumpers) do |
||||
dumper:flush() |
||||
end |
||||
end |
||||
function tap.reset() |
||||
for tlli,dumper in pairs(dumpers) do |
||||
dumper:close() |
||||
end |
||||
dumpers = {} |
||||
end |
||||
end |
||||
init_listener() |
||||
end |
@ -1,59 +0,0 @@ |
||||
-- This script verifies that the N(U) is increasing... |
||||
-- |
||||
do |
||||
local nu_state_src = {} |
||||
|
||||
local function init_listener() |
||||
-- handle the port as NS over IP |
||||
local udp_port_table = DissectorTable.get("udp.port") |
||||
local gprs_ns_dis = Dissector.get("gprs_ns") |
||||
udp_port_table:add(23000,gprs_ns_dis) |
||||
|
||||
-- we want to look here... |
||||
local llc_sapi_get = Field.new("llcgprs.sapib") |
||||
local llc_nu_get = Field.new("llcgprs.nu") |
||||
local bssgp_tlli_get = Field.new("bssgp.tlli") |
||||
|
||||
local tap = Listener.new("ip", "udp.port == 23000") |
||||
function tap.packet(pinfo,tvb,ip) |
||||
local llc_sapi = llc_sapi_get() |
||||
local llc_nu = llc_nu_get() |
||||
local bssgp_tlli = bssgp_tlli_get() |
||||
|
||||
if not llc_sapi or not llc_nu or not bssgp_tlli then |
||||
return |
||||
end |
||||
|
||||
local ip_src = tostring(ip.ip_src) |
||||
local bssgp_tlli = tostring(bssgp_tlli) |
||||
local llc_nu = tostring(llc_nu) |
||||
local llc_sapi = tostring(llc_sapi) |
||||
|
||||
local src_key = ip_src .. "-" .. bssgp_tlli .. "-" .. llc_sapi |
||||
local last_nu = nu_state_src[src_key] |
||||
if not last_nu then |
||||
-- print("Establishing mapping for " .. src_key) |
||||
nu_state_src[src_key] = llc_nu |
||||
return |
||||
end |
||||
|
||||
local function tohex(number) |
||||
return string.format("0x%x", tonumber(number)) |
||||
end |
||||
|
||||
nu_state_src[src_key] = llc_nu |
||||
if tonumber(last_nu) + 1 ~= tonumber(llc_nu) then |
||||
print("JUMP in N(U) on TLLI " .. tohex(bssgp_tlli) .. " and SAPI: " .. llc_sapi .. " src: " .. ip_src) |
||||
print("\t last: " .. last_nu .. " now: " .. llc_nu) |
||||
end |
||||
end |
||||
|
||||
function tap.draw() |
||||
end |
||||
|
||||
function tap.reset() |
||||
end |
||||
end |
||||
init_listener() |
||||
end |
||||
|
@ -1,18 +0,0 @@ |
||||
-- Remove old data from the database |
||||
DELETE FROM Subscriber |
||||
WHERE id != 1 AND datetime('now', '-10 days') > updated AND authorized != 1; |
||||
DELETE FROM Equipment |
||||
WHERE datetime('now', '-10 days') > updated; |
||||
DELETE FROM EquipmentWatch |
||||
WHERE datetime('now', '-10 days') > updated; |
||||
DELETE FROM SMS |
||||
WHERE datetime('now', '-10 days') > created; |
||||
DELETE FROM VLR |
||||
WHERE datetime('now', '-10 days') > updated; |
||||
DELETE FROM ApduBlobs |
||||
WHERE datetime('now', '-10 days') > created; |
||||
DELETE FROM Counters |
||||
WHERE datetime('now', '-10 days') > timestamp; |
||||
DELETE FROM RateCounters |
||||
WHERE datetime('now', '-10 days') > timestamp; |
||||
VACUUM; |
@ -1,125 +0,0 @@ |
||||
#!/usr/bin/python2.5 |
||||
|
||||
from __future__ import with_statement |
||||
|
||||
from pysqlite2 import dbapi2 as sqlite3 |
||||
import sys |
||||
|
||||
hlr = sqlite3.connect(sys.argv[1]) |
||||
web = sqlite3.connect(sys.argv[2]) |
||||
|
||||
# switch to autocommit |
||||
hlr.isolation_level = None |
||||
web.isolation_level = None |
||||
|
||||
hlr.row_factory = sqlite3.Row |
||||
web.row_factory = sqlite3.Row |
||||
|
||||
with hlr: |
||||
hlr_subscrs = hlr.execute(""" |
||||
SELECT * FROM Subscriber |
||||
""").fetchall() |
||||
hlr_tokens = hlr.execute(""" |
||||
SELECT * FROM AuthToken |
||||
""").fetchall() |
||||
|
||||
with web: |
||||
web_tokens = web.execute(""" |
||||
SELECT * FROM reg_tokens |
||||
""").fetchall() |
||||
web_sms = web.execute(""" |
||||
SELECT * FROM sms_queue |
||||
""").fetchall() |
||||
|
||||
# index by subscr id |
||||
hlr_subscrs_by_id = {} |
||||
hlr_subscrs_by_ext = {} |
||||
hlr_tokens_by_subscr_id = {} |
||||
for x in hlr_subscrs: |
||||
hlr_subscrs_by_id[x['id']] = x |
||||
hlr_subscrs_by_ext[x['extension']] = x |
||||
del hlr_subscrs |
||||
for x in hlr_tokens: |
||||
hlr_tokens_by_subscr_id[x['subscriber_id']] = x |
||||
del hlr_tokens |
||||
|
||||
web_tokens_by_subscr_id = {} |
||||
for x in web_tokens: |
||||
web_tokens_by_subscr_id[x['subscriber_id']] = x |
||||
del web_tokens |
||||
|
||||
# remove leftover web_tokens and correct inconsistent fields |
||||
with web: |
||||
for x in web_tokens_by_subscr_id.values(): |
||||
subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None) |
||||
if subscr is None: |
||||
web.execute(""" |
||||
DELETE FROM reg_tokens WHERE subscriber_id = ? |
||||
""", (x['subscriber_id'],)) |
||||
del web_tokens_by_subscr_id[x['subscriber_id']] |
||||
continue |
||||
if str(x['imsi']) != str(subscr['imsi']) or \ |
||||
x['extension'] != subscr['extension'] or \ |
||||
x['tmsi'] != subscr['tmsi'] or \ |
||||
x['lac'] != subscr['lac']: |
||||
web.execute(""" |
||||
UPDATE reg_tokens |
||||
SET imsi = ?, extension = ?, tmsi = ?, lac = ? |
||||
WHERE subscriber_id = ? |
||||
""", (str(subscr['imsi']), subscr['extension'], |
||||
subscr['tmsi'], subscr['lac'], x['subscriber_id'])) |
||||
|
||||
# add missing web_tokens |
||||
with web: |
||||
for x in hlr_tokens_by_subscr_id.values(): |
||||
subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None) |
||||
if subscr is None: |
||||
hlr.execute(""" |
||||
DELETE FROM AuthToken WHERE subscriber_id = ? |
||||
""", (x['subscriber_id'],)) |
||||
del hlr_tokens_by_subscr_id[x['subscriber_id']] |
||||
continue |
||||
webtoken = web_tokens_by_subscr_id.get(x['subscriber_id'], None) |
||||
if webtoken is None: |
||||
web.execute(""" |
||||
INSERT INTO reg_tokens |
||||
(subscriber_id, extension, reg_completed, name, email, lac, imsi, token, tmsi) |
||||
VALUES |
||||
(?, ?, 0, ?, '', ?, ?, ?, ?) |
||||
""", (x['subscriber_id'], subscr['extension'], subscr['name'], |
||||
subscr['lac'], str(subscr['imsi']), x['token'], subscr['tmsi'])) |
||||
|
||||
# authorize subscribers |
||||
with hlr: |
||||
for x in web_tokens_by_subscr_id.values(): |
||||
subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None) |
||||
if x['reg_completed'] and not subscr['authorized']: |
||||
hlr.execute(""" |
||||
UPDATE Subscriber |
||||
SET authorized = 1 |
||||
WHERE id = ? |
||||
""", (x['subscriber_id'],)) |
||||
|
||||
# Sync SMS from web to hlr |
||||
with hlr: |
||||
for sms in web_sms: |
||||
subscr = hlr_subscrs_by_ext.get(sms['receiver_ext']) |
||||
if subscr is None: |
||||
print '%s not found' % sms['receiver_ext'] |
||||
continue |
||||
hlr.execute(""" |
||||
INSERT INTO SMS |
||||
(created, sender_id, receiver_id, reply_path_req, status_rep_req, protocol_id, data_coding_scheme, ud_hdr_ind, text) |
||||
VALUES |
||||
(?, 1, ?, 0, 0, 0, 0, 0, ?) |
||||
""", (sms['created'], subscr['id'], sms['text'])) |
||||
with web: |
||||
for sms in web_sms: |
||||
web.execute(""" |
||||
DELETE FROM sms_queue WHERE id = ? |
||||
""", (sms['id'],)) |
||||
|
||||
|
||||
hlr.close() |
||||
web.close() |
||||
|
@ -1,60 +0,0 @@ |
||||
#!/usr/bin/env python |
||||
# Simple server for mgcp... send audit, receive response.. |
||||
|
||||
import socket, time |
||||
|
||||
MGCP_GATEWAY_PORT = 2427 |
||||
MGCP_CALLAGENT_PORT = 2727 |
||||
|
||||
rsip_resp = """200 321321332\r\n""" |
||||
audit_packet = """AUEP %d 13@mgw MGCP 1.0\r\n""" |
||||
crcx_packet = """CRCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n""" |
||||
dlcx_packet = """DLCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\n""" |
||||
mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 6666 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n""" |
||||
|
||||
def hexdump(src, length=8): |
||||
"""Recipe is from http://code.activestate.com/recipes/142812/""" |
||||
result = [] |
||||
digits = 4 if isinstance(src, unicode) else 2 |
||||
for i in xrange(0, len(src), length): |
||||
s = src[i:i+length] |
||||
hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s]) |
||||
text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s]) |
||||
result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) ) |
||||
return b'\n'.join(result) |
||||
|
||||
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
||||
server_socket.bind(("127.0.0.1", MGCP_CALLAGENT_PORT)) |
||||
server_socket.setblocking(1) |
||||
|
||||
last_ci = 1 |
||||
def send_and_receive(packet): |
||||
global last_ci |
||||
server_socket.sendto(packet, ("127.0.0.1", MGCP_GATEWAY_PORT)) |
||||
try: |
||||
data, addr = server_socket.recvfrom(4096) |
||||
|
||||
# attempt to store the CI of the response |
||||
list = data.split("\n") |
||||
for item in list: |
||||
if item.startswith("I: "): |
||||
last_ci = int(item[3:]) |
||||
|
||||
print hexdump(data), addr |
||||
except socket.error, e: |
||||
print e |
||||
pass |
||||
|
||||
def generate_tid(): |
||||
import random |
||||
return random.randint(0, 65123) |
||||
|
||||
|
||||
|
||||
while True: |
||||
send_and_receive(audit_packet % generate_tid()) |
||||
send_and_receive(crcx_packet % generate_tid() ) |
||||
send_and_receive(mdcx_packet % (generate_tid(), last_ci)) |
||||
send_and_receive(dlcx_packet % (generate_tid(), last_ci)) |
||||
|
||||
time.sleep(3) |
@ -1,30 +0,0 @@ |
||||
/* make test_regexp */ |
||||
#include <sys/types.h> |
||||
#include <regex.h> |
||||
#include <stdio.h> |
||||
|
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
regex_t reg; |
||||
regmatch_t matches[2]; |
||||
|
||||
if (argc != 4) { |
||||
printf("Invoke with: test_regexp REGEXP REPLACE NR\n"); |
||||
return -1; |
||||
} |
||||
|
||||
if (regcomp(®, argv[1], REG_EXTENDED) != 0) { |
||||
fprintf(stderr, "Regexp '%s' is not valid.\n", argv[1]); |
||||
return -1; |
||||
} |
||||
|
||||
if (regexec(®, argv[3], 2, matches, 0) == 0 && matches[1].rm_eo != -1) |
||||
printf("New Number: %s%s\n", argv[2], &argv[3][matches[1].rm_so]); |
||||
else |
||||
printf("No match.\n"); |
||||
|
||||
regfree(®); |
||||
|
||||
return 0; |
||||
} |
@ -1,65 +0,0 @@ |
||||
#!/usr/bin/env python2.7 |
||||
|
||||
""" |
||||
AGPLv3+ 2016 Copyright Holger Hans Peter Freyther |
||||
|
||||
Example of how to connect to the USSD side-channel and how to respond |
||||
with a fixed message. |
||||
""" |
||||
|
||||
import socket |
||||
import struct |
||||
|
||||
ussdSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
ussdSocket.connect(('127.0.0.1', 5001)) |
||||
|
||||
def send_dt1(dstref, data): |
||||
dlen = struct.pack('B', len(data)).encode('hex') |
||||
hex = '06' + dstref.encode('hex') + '00' + '01' + dlen + data.encode('hex') |
||||
pdata = hex.decode('hex') |
||||
out = struct.pack('>HB', len(pdata), 0xfd) + pdata |
||||
ussdSocket.send(out) |
||||
|
||||
def send_rel(srcref, dstref): |
||||
hex = '04' + dstref.encode('hex') + srcref.encode('hex') + '000100' |
||||
pdata = hex.decode('hex') |
||||
out = struct.pack('>HB', len(pdata), 0xfd) + pdata |
||||
ussdSocket.send(out) |
||||
|
||||
def recv_one(): |
||||
plen = ussdSocket.recv(3) |
||||
(plen,ptype) = struct.unpack(">HB", plen) |
||||
data = ussdSocket.recv(plen) |
||||
|
||||
return ptype, data |
||||
|
||||
# Assume this is the ID request |
||||
data = ussdSocket.recv(4) |
||||
ussdSocket.send("\x00\x08\xfe\x05\x00" + "\x05\x01" + "ussd") |
||||
# ^len ^len of tag ... and ignore |
||||
|
||||
# Expect a fake message. see struct ipac_msgt_sccp_state |
||||
ptype, data = recv_one() |
||||
print("%d %s" % (ptype, data.encode('hex'))) |
||||
(srcref, dstref, transid, invokeid) = struct.unpack("<3s3sBB", data[1:9]) |
||||
print("New transID %d invoke %d" % (transid, invokeid)) |
||||
|
||||
# Expect a the invocation.. todo.. extract invoke id |
||||
ptype, data = recv_one() |
||||
print("%d %s" % (ptype, data.encode('hex'))) |
||||
|
||||
# Reply with BSSAP + GSM 04.08 + MAP portion |
||||
# 00 == invoke id 0f == DCS |
||||
res = "01002a9b2a0802e1901c22a220020100301b02013b301604010f041155e7d2f9bc3a41412894991c06a9c9a713" |
||||
send_dt1(dstref, res.decode('hex')) |
||||
|
||||
clear = "000420040109" |
||||
send_dt1(dstref, clear.decode('hex')) |
||||
|
||||
# should be the clear complete |
||||
send_rel(srcref, dstref) |
||||
|
||||
# Give it some time to handle connection shutdown properly |
||||
print("Gracefully sleeping") |
||||
import time |
||||
time.sleep(3) |
@ -1,420 +0,0 @@ |
||||
#!/usr/bin/env escript |
||||
%% -*- erlang -*- |
||||
%%! -smp disable |
||||
-module(gen_rtp_header). |
||||
|
||||
% -mode(compile). |
||||
|
||||
-define(VERSION, "0.1"). |
||||
|
||||
-export([main/1]). |
||||
|
||||
-record(rtp_packet, |
||||
{ |
||||
version = 2, |
||||
padding = 0, |
||||
marker = 0, |
||||
payload_type = 0, |
||||
seqno = 0, |
||||
timestamp = 0, |
||||
ssrc = 0, |
||||
csrcs = [], |
||||
extension = <<>>, |
||||
payload = <<>>, |
||||
realtime |
||||
}). |
||||
|
||||
|
||||
main(Args) -> |
||||
DefaultOpts = [{format, state}, |
||||
{ssrc, 16#11223344}, |
||||
{rate, 8000}, |
||||
{pt, 98}], |
||||
{PosArgs, Opts} = getopts_checked(Args, DefaultOpts), |
||||
log(debug, fun (Dev) -> |
||||
io:format(Dev, "Initial options:~n", []), |
||||
dump_opts(Dev, Opts), |
||||
io:format(Dev, "~s: ~p~n", ["Args", PosArgs]) |
||||
end, [], Opts), |
||||
main(PosArgs, Opts). |
||||
|
||||
main([First | RemArgs], Opts) -> |
||||
try |
||||
F = list_to_integer(First), |
||||
Format = proplists:get_value(format, Opts, state), |
||||
PayloadData = proplists:get_value(payload, Opts, undef), |
||||
InFile = proplists:get_value(file, Opts, undef), |
||||
|
||||
Payload = case {PayloadData, InFile} of |
||||
{undef, undef} -> |
||||
% use default value |
||||
#rtp_packet{}#rtp_packet.payload; |
||||
{P, undef} -> P; |
||||
{_, File} -> |
||||
log(info, "Loading file '~s'~n", [File], Opts), |
||||
{ok, InDev} = file:open(File, [read]), |
||||
DS = [ Pl#rtp_packet.payload || {_T, Pl} <- read_packets(InDev, Opts)], |
||||
file:close(InDev), |
||||
log(debug, "File '~s' closed, ~w packets read.~n", [File, length(DS)], Opts), |
||||
DS |
||||
end, |
||||
Dev = standard_io, |
||||
write_packet_pre(Dev, Format), |
||||
do_groups(Dev, Payload, F, RemArgs, Opts), |
||||
write_packet_post(Dev, Format), |
||||
0 |
||||
catch |
||||
_:_ -> |
||||
log(debug, "~p~n", [hd(erlang:get_stacktrace())], Opts), |
||||
usage(), |
||||
halt(1) |
||||
end |
||||
; |
||||
|
||||
main(_, _Opts) -> |
||||
usage(), |
||||
halt(1). |
||||
|
||||
%%% group (count + offset) handling %%% |
||||
|
||||
do_groups(_Dev, _Pl, _F, [], _Opts) -> |
||||
ok; |
||||
|
||||
do_groups(Dev, Pl, F, [L], Opts) -> |
||||
do_groups(Dev, Pl, F, [L, 0], Opts); |
||||
|
||||
do_groups(Dev, Pl, First, [L, O | Args], Opts) -> |
||||
Ssrc = proplists:get_value(ssrc, Opts, #rtp_packet.ssrc), |
||||
PT = proplists:get_value(pt, Opts, #rtp_packet.payload_type), |
||||
Len = list_to_num(L), |
||||
Offs = list_to_num(O), |