[SIPForum-discussion] PNP Server
Ed Lentz
elentz at gmail.com
Wed Aug 10 13:45:15 UTC 2016
Hello All,
I am new to the group but not so much to the SIP world. I am in need of
some assistance. We are importing phones from China and they can use a Sip
Subscribe message to get the provisioning server address. This does away
with Option66 and manually entering the provisioning IP into the phone. I
found a python script that is used for Snom phones. I know enough about
Snom phones to know I don't know them at all. Anyway, I have found little
info on this. Here is the code, if there is anyone that cah help me change
this code to work with any phone I would greatly appreciate it.
#! /usr/bin/python
#
# snom multicast telephone discovery
#
#
# Author: Filip Polsakiewicz <filip.polsakiewicz at snom.de>
#
# 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, see <http://www.gnu.org/licenses/>.
import socket
import struct
import sys
import re
from optparse import OptionParser
class snom_phone(object):
"""Basic representation of a snom phone."""
def __init__(self, mac=None, ip=None, mod=None, fw=None, subs=None):
"""Default constructor."""
self.mac_addr = mac
self.ip_addr = ip
self.sip_port = 5060
self.model = mod
self.fw_version = fw
self.subscribe = subs
def __repr__(self):
"""Gets a string representation of the phone"""
return "%s (MAC: %s) running Firmware %s found at IP %s" %
(self.model, self.__macrepr(self.mac_addr), self.fw_version, self.ip_addr)
def __macrepr(self, m):
""" Normalize a MAC address to lower case unix style """
m = re.sub("[.:-]", "", m)
m = m.lower()
n = "%s:%s:%s:%s:%s:%s" % (m[0:2], m[2:4], m[4:6], m[6:8],
m[8:10], m[10:])
return n
def parse(text):
"""Parses the incoming SUBSCRIBE."""
try:
lines = text.split('\r\n')
# Line 1 conatains the SUBSCRIBE and our MAC
new_phone = snom_phone(subs=text)
new_phone.mac_addr = lines[0][20:32]
# We can read the IP address from line 2
new_phone.ip_addr = lines[1][17:].split(';')[0].split(':')[0]
new_phone.sip_port = lines[1][17:].split(';')[0].split(':')[1]
# The other interesting information can be found in line 7
model_info = lines[6]
l_model_info = model_info.split(';')
new_phone.model = l_model_info[3].split('=')[1][1:-1]
new_phone.fw_version = l_model_info[4].split('=')[1][1:-1]
print new_phone
return new_phone
except:
# Parsing failed. Probably not a SUBSCRIBE
return None
def get_sip_info(text):
"""Get some relevant SIP information which we need in order to generate
the responses."""
lines = text.split('\r\n')
# Some SIP info we need
call_id = lines[4][9:]
cseq = lines[5][6]
via_header = lines[1]
from_header = lines[2]
to_header = lines[3]
if options.verbose: print "CallId: " + call_id + "; CSeq: " + cseq +
"\r\n";
return (call_id, cseq, via_header, from_header, to_header)
def get_ip_address():
# This is a simple hack to find our IP address
# AFAIK this is the only platform-independent way to obtain the
address
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('snom.com', 0))
return s.getsockname()[0]
prov_uri = None
parser = OptionParser()
parser.add_option('-u', '--url', action="store", dest="prov_uri", help="URI
of the provisioning server")
parser.add_option('-l', '--local-ip', action="store", dest="local_ip",
help="Local IP address")
parser.add_option("-v", "--verbose",
action="store_true", dest="verbose", default=False,
help="make lots of noise")
(options, args) = parser.parse_args()
print """
.ijjt; ..... :tjt: LLLi ..... .ijt, :tjt:
.LLLLLLLLL, LLLLtLLLLLLL ,ft LLLLL. LLLLLjLLLLLL .LLLLLLL
LLLLLLLLLLLt LLLLLLLLLLLL; :LLLj LLLLLL fLLLLLLLLLLLLLLLLLLLLt
tLLLf,,iLLLt LLLLLLfLLLLLf. :LLLLf :LLLLj fLLLLLffLLLLLLLfLLLLLL
LLLL :t LLLLL jLLLf. LLLLL: :LLLL fLLLL. :LLLLL jLLLL
LLLLL;. LLLLt ,LLLf.;LLLL LLLL.fLLLL LLLLj :LLLL
jLLLLLLLLf, LLLLt ,LLLf.fLLL; LLLL:fLLLL LLLLj .LLLL
LLLLLLLLLLL LLLLt ,LLLf.LLLL: fLLL:fLLLL LLLLj .LLLL
,fLLLLLLLLt LLLLt ,LLLf.LLLL. LLLL.fLLLL LLLLj .LLLL
:iLLLLL LLLLt ,LLLf.LLLL, .LLLL fLLLL LLLLj .LLLL
L; LLLL LLLLt ,LLLf.jLLLj .LLLLf fLLLL LLLLj .LLLL
iLL: .LLLL LLLLt ,LLLf.iLLLL ;fLLLL; fLLLL LLLLj .LLLL
tLLLLLjjfLLLL; LLLLt ,LLLf. LLLLf. fLLLLf fLLLL LLLLj .LLLL
fLLLLLLLLLLf LLLLt ,LLLf. ;LLLLL jLLLt fLLLL LLLLj .LLLL
,LLLLLLLLi LLLLt ,LLLf. iLLLL tf; LLLLL LLLLj .LLLL
:,,:. .jLL
"""
print "\nsnom multicast PnP Provisioning Server (mcserv)\n"
print "(c) 2008-2009 snom technology AG\n"
print "=" * 80
print "Provisioning URI is %s\n" % options.prov_uri
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('224.0.1.75', 5060))
mreq = struct.pack('4sl', socket.inet_aton('224.0.1.75'), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
if not options.local_ip:
ip_adr = get_ip_address()
else:
ip_adr = options.local_ip
print "Local IP Address is :: %s" % ip_adr
print "=" * 80
while True:
subs = sock.recv(10240)
if options.verbose: print subs
phone = parse(subs)
(call_id, cseq, via_header, from_header, to_header) = get_sip_info(subs)
if phone:
# Create a socket to send data
sendsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
socket.IPPROTO_UDP)
sendsock.bind(('%s' % ip_adr, 1036))
# If a phone has been recognized first send 200 OK
ok_response = "SIP/2.0 200 OK\r\n"
ok_response += via_header + "\r\n"
ok_response += "Contact: <sip:" + phone.ip_addr + ":" +
phone.sip_port + ";transport=tcp;handler=dum>\r\n"
ok_response += to_header + "\r\n"
ok_response += from_header + "\r\n"
ok_response += "Call-ID: %s\r\n" % call_id
ok_response += "CSeq: %s SUBSCRIBE\r\nExpires: 0\r\nContent-Length:
0\r\n" % cseq
sendsock.sendto(ok_response, ("%s" % phone.ip_addr,
int(phone.sip_port)))
# Now send a NOTIFY with the configuration URL
if not options.prov_uri:
prov_uri = "http://provisioning.snom.com/%s/%s.php?mac={mac}" %
(phone.model, phone.model)
else:
prov_uri = options.prov_uri
prov_uri = "%s/%s.htm" % (prov_uri,phone.model)
notify = "NOTIFY sip:%s:%s SIP/2.0\r\n" % (phone.ip_addr,
phone.sip_port)
notify += via_header + "\r\n"
notify += "Max-Forwards: 20\r\n"
notify += "Contact: <sip:%s:1036;transport=TCP;handler=dum>\r\n" %
ip_adr
notify += to_header + "\r\n"
notify += from_header + "\r\n"
notify += "Call-ID: %s\r\n" % call_id
notify += "CSeq: 3 NOTIFY\r\n"
notify += "Content-Type: application/url\r\n"
notify += "Subscription-State: terminated;reason=timeout\r\n"
notify += "Event:
ua-profile;profile-type=\"device\";vendor=\"OEM\";model=\"OEM\";version=\"7.1.19\"\r\n"
notify += "Content-Length: %i\r\n" % (len(prov_uri))
notify += "\r\n%s" % prov_uri
print "Sending NOTIFY with URI :: %s\n" % prov_uri
if options.verbose: print notify
sendsock.sendto(notify, ("%s" % phone.ip_addr, int(phone.sip_port)))
Thanks for any ideas, comments
--
Ed
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sipforum.org/pipermail/discussion/attachments/20160810/ae6d1613/attachment-0002.html>
More information about the discussion
mailing list