3 from __future__
import print_function
9 from urllib.parse
import urlparse
11 from urlparse
import urlparse
13 import astconfigparser
23 def section_by_type(section, pjsip, type):
24 """Finds a section based upon the given type, adding it if not found."""
25 def __find_dict(mdicts, key, val):
26 """Given a list of multi-dicts, return the multi-dict that contains
27 the given key/value pair."""
30 return key
in d
and val
in d[key]
33 return [d
for d
in mdicts
if found(d)][0]
35 raise LookupError(
"Dictionary not located for key = %s, value = %s"
39 return __find_dict(pjsip.section(section),
'type', type)
42 sect = pjsip.add_section(section)
47 def ignore(key=None, val=None, section=None, pjsip=None,
48 nmapped=
None, type=
'endpoint'):
49 """Ignore a key and mark it as mapped"""
52 def set_value(key=None, val=None, section=None, pjsip=None,
53 nmapped=
None, type=
'endpoint'):
54 """Sets the key to the value within the section in pjsip.conf"""
55 def _set_value(k, v, s, r, n):
56 set_value(key
if key
else k, v, s, r, n, type)
60 if not val
and not section:
64 section_by_type(section, pjsip, type)[key] = \
65 val[0]
if isinstance(val, list)
else val
68 def merge_value(key=None, val=None, section=None, pjsip=None,
69 nmapped=
None, type=
'endpoint', section_to=
None,
71 """Merge values from the given section with those from the default."""
72 def _merge_value(k, v, s, r, n):
73 merge_value(key
if key
else k, v, s, r, n, type, section_to, key_to)
77 if not val
and not section:
82 sect = sip.section(section)[0]
84 sect = sip.default(section)[0]
86 for i
in sect.get_merged(key):
87 set_value(key_to
if key_to
else key, i,
88 section_to
if section_to
else section,
91 def merge_codec_value(key=None, val=None, section=None, pjsip=None,
92 nmapped=
None, type=
'endpoint', section_to=
None,
94 """Merge values from allow/deny with those from the default. Special treatment for all"""
95 def _merge_codec_value(k, v, s, r, n):
96 merge_codec_value(key
if key
else k, v, s, r, n, type, section_to, key_to)
100 if not val
and not section:
101 return _merge_codec_value
105 disallow = sip.get(section,
'disallow')[0]
106 if disallow ==
'all':
108 for i
in sip.get(section,
'allow'):
109 set_value(key, i, section, pjsip, nmapped, type)
111 merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
113 print(
"lookup error", file=sys.stderr)
114 merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
116 elif key ==
'disallow':
118 allow = sip.get(section,
'allow')[0]
121 for i
in sip.get(section,
'disallow'):
122 set_value(key, i, section, pjsip, nmapped, type)
124 merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
126 merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
129 merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
132 def non_mapped(nmapped):
133 """Write non-mapped sip.conf values to the non-mapped object"""
134 def _non_mapped(section, key, val):
135 """Writes a non-mapped value from sip.conf to the non-mapped object."""
136 if section
not in nmapped:
138 if isinstance(val, list):
142 nmapped[section][0][key] = v
144 nmapped[section][0][key] = val
154 def set_dtmfmode(key, val, section, pjsip, nmapped):
156 Sets the dtmfmode value. If value matches allowable option in pjsip
157 then map it, otherwise set it to none.
161 if val ==
'inband' or val ==
'info' or val ==
'auto':
162 set_value(key, val, section, pjsip, nmapped)
163 elif val ==
'rfc2833':
164 set_value(key,
'rfc4733', section, pjsip, nmapped)
166 nmapped(section, key, val +
" ; did not fully map - set to none")
167 set_value(key,
'none', section, pjsip, nmapped)
170 def setup_udptl(section, pjsip, nmapped):
171 """Sets values from udptl into the appropriate pjsip.conf options."""
173 val = sip.get(section,
't38pt_udptl')[0]
176 val = sip.get(
'general',
't38pt_udptl')[0]
182 set_value(
't38_udptl',
'yes', section, pjsip, nmapped)
184 set_value(
't38_udptl',
'no', section, pjsip, nmapped)
185 if 'redundancy' in val:
189 set_value(
't38_udptl_ec', ec, section, pjsip, nmapped)
191 def from_nat(key, val, section, pjsip, nmapped):
192 """Sets values from nat into the appropriate pjsip.conf options."""
196 set_value(
'rtp_symmetric',
'yes', section, pjsip, nmapped)
197 set_value(
'rewrite_contact',
'yes', section, pjsip, nmapped)
199 set_value(
'rtp_symmetric',
'yes', section, pjsip, nmapped)
200 if 'force_rport' in val:
201 set_value(
'force_rport',
'yes', section, pjsip, nmapped)
202 set_value(
'rewrite_contact',
'yes', section, pjsip, nmapped)
205 def set_timers(key, val, section, pjsip, nmapped):
207 Sets the timers in pjsip.conf from the session-timers option
216 if val ==
'originate':
217 set_value(
'timers',
'always', section, pjsip, nmapped)
218 elif val ==
'refuse':
219 set_value(
'timers',
'no', section, pjsip, nmapped)
221 set_value(
'timers',
'yes', section, pjsip, nmapped)
224 def set_direct_media(key, val, section, pjsip, nmapped):
226 Maps values from the sip.conf comma separated direct_media option
227 into pjsip.conf direct_media options.
230 set_value(
'direct_media',
'yes', section, pjsip, nmapped)
232 set_value(
'direct_media_method',
'update', section, pjsip, nmapped)
233 if 'outgoing' in val:
234 set_value(
'directed_media_glare_mitigation',
'outgoing', section,
237 set_value(
'disable_directed_media_on_nat',
'yes', section, pjsip,
240 set_value(
'direct_media',
'no', section, pjsip, nmapped)
243 def from_sendrpid(key, val, section, pjsip, nmapped):
244 """Sets the send_rpid/pai values in pjsip.conf."""
245 if val ==
'yes' or val ==
'rpid':
246 set_value(
'send_rpid',
'yes', section, pjsip, nmapped)
248 set_value(
'send_pai',
'yes', section, pjsip, nmapped)
251 def set_media_encryption(key, val, section, pjsip, nmapped):
252 """Sets the media_encryption value in pjsip.conf"""
254 dtls = sip.get(section,
'dtlsenable')[0]
262 set_value(
'media_encryption',
'sdes', section, pjsip, nmapped)
265 def from_recordfeature(key, val, section, pjsip, nmapped):
267 If record on/off feature is set to automixmon then set
268 one_touch_recording, otherwise it can't be mapped.
270 set_value(
'one_touch_recording',
'yes', section, pjsip, nmapped)
271 set_value(key, val, section, pjsip, nmapped)
273 def set_record_on_feature(key, val, section, pjsip, nmapped):
274 """Sets the record_on_feature in pjsip.conf"""
275 from_recordfeature(
'record_on_feature', val, section, pjsip, nmapped)
277 def set_record_off_feature(key, val, section, pjsip, nmapped):
278 """Sets the record_off_feature in pjsip.conf"""
279 from_recordfeature(
'record_off_feature', val, section, pjsip, nmapped)
281 def from_progressinband(key, val, section, pjsip, nmapped):
282 """Sets the inband_progress value in pjsip.conf"""
286 set_value(
'inband_progress', val, section, pjsip, nmapped)
289 def build_host(config, host, section='general', port_key=None):
291 Returns a string composed of a host:port. This assumes that the host
292 may have a port as part of the initial value. The port_key overrides
293 a port in host, see parameter 'bindport' in chan_sip.
296 socket.inet_pton(socket.AF_INET6, host)
297 if not host.startswith(
'['):
299 host =
'[' + host +
']'
305 url = urlparse(
'sip://' + host)
309 port = config.get(section, port_key)[0]
312 socket.inet_pton(socket.AF_INET6, host)
313 if not host.startswith(
'['):
315 host =
'[' + host +
']'
318 return host +
':' + port
327 def from_host(key, val, section, pjsip, nmapped):
329 Sets contact info in an AOR section in pjsip.conf using 'host'
330 and 'port' data from sip.conf
334 set_value(
'aors', section, section, pjsip, nmapped)
337 set_value(
'max_contacts', 1, section, pjsip, nmapped,
'aor')
349 user = sip.multi_get(section, [
'defaultuser',
'username'])[0]
355 result += build_host(sip, val, section,
'port')
357 set_value(
'contact', result, section, pjsip, nmapped,
'aor')
360 def from_mailbox(key, val, section, pjsip, nmapped):
362 Determines whether a mailbox configured in sip.conf should map to
363 an endpoint or aor in pjsip.conf. If subscribemwi is true, then the
364 mailboxes are set on an aor. Otherwise the mailboxes are set on the
369 subscribemwi = sip.get(section,
'subscribemwi')[0]
374 set_value(
'mailboxes', val, section, pjsip, nmapped,
'aor'
375 if subscribemwi ==
'yes' else 'endpoint')
378 def setup_auth(key, val, section, pjsip, nmapped):
380 Sets up authentication information for a specific endpoint based on the
381 'secret' setting on a peer in sip.conf
383 set_value(
'username', section, section, pjsip, nmapped,
'auth')
391 set_value(
'password', val, section, pjsip, nmapped,
'auth')
393 set_value(
'md5_cred', val, section, pjsip, nmapped,
'auth')
394 set_value(
'auth_type',
'md5', section, pjsip, nmapped,
'auth')
398 auths = sip.get(
'authentication',
'auth')
400 user, at, realm = i.partition(
'@')
405 realm_str =
','.join(realms)
407 set_value(
'auth', section, section, pjsip, nmapped)
408 set_value(
'outbound_auth', realm_str, section, pjsip, nmapped)
411 def setup_ident(key, val, section, pjsip, nmapped):
413 Examines the 'type' field for a sip.conf peer and creates an identify
414 section if the type is either 'peer' or 'friend'. The identify section uses
415 either the host or defaultip field of the sip.conf peer.
417 if val !=
'peer' and val !=
'friend':
421 ip = sip.get(section,
'host')[0]
427 ip = sip.get(section,
'defaultip')[0]
431 set_value(
'endpoint', section, section, pjsip, nmapped,
'identify')
432 set_value(
'match', ip, section, pjsip, nmapped,
'identify')
435 def from_encryption_taglen(key, val, section, pjsip, nmapped):
436 """Sets the srtp_tag32 option based on sip.conf encryption_taglen"""
438 set_value(
'srtp_tag_32',
'yes', section, pjsip, nmapped)
441 def from_dtlsenable(key, val, section, pjsip, nmapped):
442 """Optionally sets media_encryption=dtls based on sip.conf dtlsenable"""
444 set_value(
'media_encryption',
'dtls', section, pjsip, nmapped)
455 [
'context', set_value],
456 [
'dtmfmode', set_dtmfmode],
457 [
'disallow', merge_codec_value],
458 [
'allow', merge_codec_value],
461 [
'rtptimeout', set_value(
'rtp_timeout')],
462 [
'icesupport', set_value(
'ice_support')],
463 [
'autoframing', set_value(
'use_ptime')],
464 [
'outboundproxy', set_value(
'outbound_proxy')],
465 [
'mohsuggest', set_value(
'moh_suggest')],
466 [
'session-timers', set_timers],
467 [
'session-minse', set_value(
'timers_min_se')],
468 [
'session-expires', set_value(
'timers_sess_expires')],
470 [
'canreinvite', set_direct_media],
471 [
'directmedia', set_direct_media],
475 [
'callerid', set_value],
476 [
'callingpres', set_value(
'callerid_privacy')],
477 [
'cid_tag', set_value(
'callerid_tag')],
478 [
'trustrpid', set_value(
'trust_id_inbound')],
479 [
'sendrpid', from_sendrpid],
480 [
'send_diversion', set_value],
481 [
'encryption', set_media_encryption],
482 [
'avpf', set_value(
'use_avpf')],
483 [
'recordonfeature', set_record_on_feature],
484 [
'recordofffeature', set_record_off_feature],
485 [
'progressinband', from_progressinband],
486 [
'callgroup', set_value(
'call_group')],
487 [
'pickupgroup', set_value(
'pickup_group')],
488 [
'namedcallgroup', set_value(
'named_call_group')],
489 [
'namedpickupgroup', set_value(
'named_pickup_group')],
490 [
'allowtransfer', set_value(
'allow_transfer')],
491 [
'fromuser', set_value(
'from_user')],
492 [
'fromdomain', set_value(
'from_domain')],
493 [
'mwifrom', set_value(
'mwi_from_user')],
494 [
'tos_audio', set_value],
495 [
'tos_video', set_value],
496 [
'cos_audio', set_value],
497 [
'cos_video', set_value],
498 [
'sdpowner', set_value(
'sdp_owner')],
499 [
'sdpsession', set_value(
'sdp_session')],
500 [
'tonezone', set_value(
'tone_zone')],
501 [
'language', set_value],
502 [
'allowsubscribe', set_value(
'allow_subscribe')],
503 [
'subscribecontext', set_value(
'subscribe_context')],
504 [
'subminexpiry', set_value(
'sub_min_expiry')],
505 [
'rtp_engine', set_value],
506 [
'mailbox', from_mailbox],
507 [
'busylevel', set_value(
'device_state_busy_at')],
508 [
'secret', setup_auth],
509 [
'md5secret', setup_auth],
510 [
'type', setup_ident],
511 [
'dtlsenable', from_dtlsenable],
512 [
'dtlsverify', set_value(
'dtls_verify')],
513 [
'dtlsrekey', set_value(
'dtls_rekey')],
514 [
'dtlscertfile', set_value(
'dtls_cert_file')],
515 [
'dtlsprivatekey', set_value(
'dtls_private_key')],
516 [
'dtlscipher', set_value(
'dtls_cipher')],
517 [
'dtlscafile', set_value(
'dtls_ca_file')],
518 [
'dtlscapath', set_value(
'dtls_ca_path')],
519 [
'dtlssetup', set_value(
'dtls_setup')],
520 [
'encryption_taglen', from_encryption_taglen],
526 [
'qualifyfreq', set_value(
'qualify_frequency', type=
'aor')],
527 [
'maxexpiry', set_value(
'maximum_expiration', type=
'aor')],
528 [
'minexpiry', set_value(
'minimum_expiration', type=
'aor')],
529 [
'defaultexpiry', set_value(
'default_expiration', type=
'aor')],
541 [
'permit', merge_value(type=
'acl', section_to=
'acl')],
542 [
'deny', merge_value(type=
'acl', section_to=
'acl')],
543 [
'acl', merge_value(type=
'acl', section_to=
'acl')],
544 [
'contactpermit', merge_value(type=
'acl', section_to=
'acl', key_to=
'contact_permit')],
545 [
'contactdeny', merge_value(type=
'acl', section_to=
'acl', key_to=
'contact_deny')],
546 [
'contactacl', merge_value(type=
'acl', section_to=
'acl', key_to=
'contact_acl')],
590 def split_hostport(addr):
592 Given an address in the form 'host:port' separate the host and port
594 Returns a two-tuple of strings, (host, port). If no port is present in the
595 string, then the port section of the tuple is None.
598 socket.inet_pton(socket.AF_INET6, addr)
599 if not addr.startswith(
'['):
606 url = urlparse(
'sip://' + addr)
608 return (url.hostname, url.port)
611 def set_transport_common(section, sip, pjsip, protocol, nmapped):
613 sip.conf has several global settings that in pjsip.conf apply to individual
614 transports. This function adds these global settings to each individual
617 The settings included are:
618 externaddr (or externip)
620 externtcpport for TCP
621 externtlsport for TLS
627 extern_addr = sip.multi_get(
'general', [
'externaddr',
'externip',
629 host, port = split_hostport(extern_addr)
631 port = sip.get(
'general',
'extern' + protocol +
'port')[0]
634 set_value(
'external_media_address', host, section, pjsip,
635 nmapped,
'transport')
636 set_value(
'external_signaling_address', host, section, pjsip,
637 nmapped,
'transport')
639 set_value(
'external_signaling_port', port, section, pjsip,
640 nmapped,
'transport')
645 merge_value(
'localnet', sip.get(
'general',
'localnet')[0],
'general',
646 pjsip, nmapped,
'transport', section,
"local_net")
652 set_value(
'tos', sip.get(
'general',
'tos_sip')[0], section, pjsip,
653 nmapped,
'transport')
658 set_value(
'cos', sip.get(
'general',
'cos_sip')[0], section, pjsip,
659 nmapped,
'transport')
664 def get_bind(sip, pjsip, protocol):
666 Given the protocol (udp, tcp, or tls), return
667 - the bind address, like [::] or 0.0.0.0
668 - name of the section to be created
670 section =
'transport-' + protocol
673 if protocol !=
'udp':
675 enabled = sip.get(
'general', protocol +
'enable')[0]
678 return (
None, section)
680 return (
None, section)
683 bind = pjsip.get(section,
'bind')[0]
686 return (
None, section)
691 bind = pjsip.get(section +
'6',
'bind')[0]
695 host, port = split_hostport(bind)
698 bind +=
':' + str(port)
702 bind = sip.get(
'general', protocol +
'bindaddr')[0]
704 if protocol ==
'udp':
706 bind = sip.get(
'general',
'bindaddr')[0]
711 bind = pjsip.get(
'transport-udp6',
'bind')[0]
713 bind = pjsip.get(
'transport-udp',
'bind')[0]
715 if protocol ==
'tls':
716 bind, port = split_hostport(bind)
717 host, port = split_hostport(bind)
721 if protocol ==
'udp':
722 host = build_host(sip, bind,
'general',
'bindport')
724 host = build_host(sip, bind)
726 return (host, section)
729 def create_udp(sip, pjsip, nmapped):
731 Creates a 'transport-udp' section in the pjsip.conf file based
732 on the following settings from sip.conf:
734 bindaddr (or udpbindaddr)
738 bind, section = get_bind(sip, pjsip, protocol)
740 set_value(
'protocol', protocol, section, pjsip, nmapped,
'transport')
741 set_value(
'bind', bind, section, pjsip, nmapped,
'transport')
742 set_transport_common(section, sip, pjsip, protocol, nmapped)
745 def create_tcp(sip, pjsip, nmapped):
747 Creates a 'transport-tcp' section in the pjsip.conf file based
748 on the following settings from sip.conf:
751 tcpbindaddr (or bindaddr)
754 bind, section = get_bind(sip, pjsip, protocol)
758 set_value(
'protocol', protocol, section, pjsip, nmapped,
'transport')
759 set_value(
'bind', bind, section, pjsip, nmapped,
'transport')
760 set_transport_common(section, sip, pjsip, protocol, nmapped)
763 def set_tls_cert_file(val, pjsip, section, nmapped):
764 """Sets cert_file based on sip.conf tlscertfile"""
765 set_value(
'cert_file', val, section, pjsip, nmapped,
769 def set_tls_private_key(val, pjsip, section, nmapped):
770 """Sets privkey_file based on sip.conf tlsprivatekey or sslprivatekey"""
771 set_value(
'priv_key_file', val, section, pjsip, nmapped,
775 def set_tls_cipher(val, pjsip, section, nmapped):
776 """Sets cipher based on sip.conf tlscipher or sslcipher"""
779 print(
'chan_sip ciphers do not match 1:1 with PJSIP ciphers.' \
780 ' You should manually review and adjust this.', file=sys.stderr)
782 set_value(
'cipher', val, section, pjsip, nmapped,
'transport')
785 def set_tls_cafile(val, pjsip, section, nmapped):
786 """Sets ca_list_file based on sip.conf tlscafile"""
787 set_value(
'ca_list_file', val, section, pjsip, nmapped,
791 def set_tls_capath(val, pjsip, section, nmapped):
792 """Sets ca_list_path based on sip.conf tlscapath"""
793 set_value(
'ca_list_path', val, section, pjsip, nmapped,
797 def set_tls_verifyclient(val, pjsip, section, nmapped):
798 """Sets verify_client based on sip.conf tlsverifyclient"""
799 set_value(
'verify_client', val, section, pjsip, nmapped,
803 def set_tls_verifyserver(val, pjsip, section, nmapped):
804 """Sets verify_server based on sip.conf tlsdontverifyserver"""
807 set_value(
'verify_server',
'yes', section, pjsip, nmapped,
810 set_value(
'verify_server',
'no', section, pjsip, nmapped,
814 def create_tls(sip, pjsip, nmapped):
816 Creates a 'transport-tls' section in pjsip.conf based on the following
817 settings from sip.conf:
819 tlsenable (or sslenable)
820 tlsbindaddr (or sslbindaddr or bindaddr)
821 tlsprivatekey (or sslprivatekey)
822 tlscipher (or sslcipher)
824 tlscapath (or tlscadir)
825 tlscertfile (or sslcert or tlscert)
828 tlsclientmethod (or sslclientmethod)
831 bind, section = get_bind(sip, pjsip, protocol)
835 set_value(
'protocol', protocol, section, pjsip, nmapped,
'transport')
836 set_value(
'bind', bind, section, pjsip, nmapped,
'transport')
837 set_transport_common(section, sip, pjsip, protocol, nmapped)
840 ([
'tlscertfile',
'sslcert',
'tlscert'], set_tls_cert_file),
841 ([
'tlsprivatekey',
'sslprivatekey'], set_tls_private_key),
842 ([
'tlscipher',
'sslcipher'], set_tls_cipher),
843 ([
'tlscafile'], set_tls_cafile),
844 ([
'tlscapath',
'tlscadir'], set_tls_capath),
845 ([
'tlsverifyclient'], set_tls_verifyclient),
846 ([
'tlsdontverifyserver'], set_tls_verifyserver)
851 i[1](sip.multi_get(
'general', i[0])[0], pjsip, section, nmapped)
856 method = sip.multi_get(
'general', [
'tlsclientmethod',
857 'sslclientmethod'])[0]
858 if section !=
'transport-' + protocol +
'6':
859 print(
'In chan_sip, you specified the TLS version. With chan_sip,' \
860 ' this was just for outbound client connections. In' \
861 ' chan_pjsip, this value is for client and server. Instead,' \
862 ' consider not to specify \'tlsclientmethod\' for chan_sip' \
863 ' and \'method = sslv23\' for chan_pjsip.', file=sys.stderr)
866 OpenSSL emerged during the 90s. SSLv2 and SSLv3 were the only
867 existing methods at that time. The OpenSSL project continued. And as
868 of today (OpenSSL 1.0.2) this does not start SSLv2 and SSLv3 anymore
869 but TLSv1.0 and v1.2. Or stated differently: This method should
870 have been called 'method = secure' or 'method = automatic' back in
871 the 90s. The PJProject did not realize this and uses 'tlsv1' as
872 default when unspecified, which disables TLSv1.2. chan_sip used
873 'sslv23' as default when unspecified, which gives TLSv1.0 and v1.2.
876 set_value(
'method', method, section, pjsip, nmapped,
'transport')
879 def map_transports(sip, pjsip, nmapped):
881 Finds options in sip.conf general section pertaining to
882 transport configuration and creates appropriate transport
883 configuration sections in pjsip.conf.
885 sip.conf only allows a single UDP transport, TCP transport,
886 and TLS transport for each IP version. As such, the mapping
887 into PJSIP can be made consistent by defining six sections:
896 To accommodate the default behaviors in sip.conf, we'll need to
897 create the UDP transports first, followed by the TCP and TLS transports.
902 create_udp(sip, pjsip, nmapped)
903 create_udp(sip, pjsip, nmapped)
906 create_tcp(sip, pjsip, nmapped)
907 create_tcp(sip, pjsip, nmapped)
908 create_tls(sip, pjsip, nmapped)
909 create_tls(sip, pjsip, nmapped)
912 def map_auth(sip, pjsip, nmapped):
914 Creates auth sections based on entries in the authentication section of
915 sip.conf. pjsip.conf section names consist of "auth_" followed by the name
919 auths = sip.get(
'authentication',
'auth')
924 creds, at, realm = i.partition(
'@')
925 if not at
and not realm:
928 user, colon, secret = creds.partition(
':')
930 user, sharp, md5 = creds.partition(
'#')
934 section =
"auth_" + realm
936 set_value(
'realm', realm, section, pjsip, nmapped,
'auth')
937 set_value(
'username', user, section, pjsip, nmapped,
'auth')
939 set_value(
'password', secret, section, pjsip, nmapped,
'auth')
941 set_value(
'md5_cred', md5, section, pjsip, nmapped,
'auth')
942 set_value(
'auth_type',
'md5', section, pjsip, nmapped,
'auth')
947 Class for parsing and storing information in a register line in sip.conf.
949 def __init__(self, line, retry_interval, max_attempts, outbound_proxy):
957 Initial parsing routine for register lines in sip.conf.
959 This splits the line into the part before the host, and the part
960 after the '@' symbol. These two parts are then passed to their
967 prehost, at, host_part = line.rpartition(
'@')
976 Parsing routine for the part after the final '@' in a register line.
977 The strategy is to use partition calls to peel away the data starting
978 from the right and working to the left.
980 pre_expiry, sep, expiry = host_part.partition(
'~')
981 pre_extension, sep, self.
extension = pre_expiry.partition(
'/')
982 self.host, sep, self.
port = pre_extension.partition(
':')
984 self.
expiry = expiry
if expiry
else '120'
988 Parsing routine for the part before the final '@' in a register line.
989 The only mandatory part of this line is the user portion. The strategy
990 here is to start by using partition calls to remove everything to
991 the right of the user, then finish by using rpartition calls to remove
992 everything to the left of the user.
996 protocols = [
'udp',
'tcp',
'tls']
997 for protocol
in protocols:
998 position = user_part.find(protocol +
'://')
1000 post_transport = user_part[position + 6:]
1001 self.
peer, sep, self.
protocol = user_part[:position + 3].rpartition(
'?')
1002 user_part = post_transport
1005 colons = user_part.count(
':')
1008 pre_auth, sep, port_auth = user_part.partition(
':')
1009 self.domainport, sep, auth = port_auth.partition(
':')
1013 pre_auth, sep, auth = user_part.partition(
':')
1017 pre_auth, sep, self.
secret = user_part.partition(
':')
1020 pre_auth = user_part
1025 self.user, sep, self.
domain = pre_auth.partition(
'@')
1029 Write parsed registration data into a section in pjsip.conf
1031 Most of the data in self will get written to a registration section.
1032 However, there will also need to be an auth section created if a
1033 secret or authuser is present.
1035 General mapping of values:
1036 A combination of self.host and self.port is server_uri
1037 A combination of self.user, self.domain, and self.domainport is
1039 self.expiry is expiration
1040 self.extension is contact_user
1041 self.protocol will map to one of the mapped transports
1042 self.secret and self.authuser will result in a new auth section, and
1043 outbound_auth will point to that section.
1044 XXX self.peer really doesn't map to anything :(
1047 section =
'reg_' + self.host
1050 nmapped,
'registration')
1051 set_value(
'max_retries', self.
max_attempts, section, pjsip, nmapped,
1054 set_value(
'contact_user', self.
extension, section, pjsip, nmapped,
1057 set_value(
'expiration', self.
expiry, section, pjsip, nmapped,
1061 set_value(
'transport',
'transport-udp', section, pjsip, nmapped,
1064 set_value(
'transport',
'transport-tcp', section, pjsip, nmapped,
1067 set_value(
'transport',
'transport-tls', section, pjsip, nmapped,
1070 auth_section =
'auth_reg_' + self.host
1072 if hasattr(self,
'secret')
and self.
secret:
1073 set_value(
'password', self.
secret, auth_section, pjsip, nmapped,
1075 set_value(
'username', self.
authuser if hasattr(self,
'authuser')
1076 else self.user, auth_section, pjsip, nmapped,
'auth')
1077 set_value(
'outbound_auth', auth_section, section, pjsip, nmapped,
1080 client_uri =
"sip:%s@" % self.user
1082 client_uri += self.
domain
1084 client_uri += self.host
1086 if hasattr(self,
'domainport')
and self.domainport:
1087 client_uri +=
":" + self.domainport
1089 client_uri +=
":" + self.
port
1091 set_value(
'client_uri', client_uri, section, pjsip, nmapped,
1094 server_uri =
"sip:%s" % self.host
1096 server_uri +=
":" + self.
port
1098 set_value(
'server_uri', server_uri, section, pjsip, nmapped,
1103 nmapped,
'registration')
1106 def map_registrations(sip, pjsip, nmapped):
1108 Gathers all necessary outbound registration data in sip.conf and creates
1109 corresponding registration sections in pjsip.conf
1112 regs = sip.get(
'general',
'register')
1117 retry_interval = sip.get(
'general',
'registertimeout')[0]
1119 retry_interval =
'20'
1122 max_attempts = sip.get(
'general',
'registerattempts')[0]
1127 outbound_proxy = sip.get(
'general',
'outboundproxy')[0]
1132 reg =
Registration(i, retry_interval, max_attempts, outbound_proxy)
1133 reg.write(pjsip, nmapped)
1136 def map_setvars(sip, section, pjsip, nmapped):
1138 Map all setvar in peer section to the appropriate endpoint set_var
1141 setvars = sip.section(section)[0].get(
'setvar')
1145 for setvar
in setvars:
1146 set_value(
'set_var', setvar, section, pjsip, nmapped)
1149 def map_peer(sip, section, pjsip, nmapped):
1151 Map the options from a peer section in sip.conf into the appropriate
1152 sections in pjsip.conf
1159 i[1](i[0], sip.get(section, i[0])[0], section, pjsip, nmapped)
1163 setup_udptl(section, pjsip, nmapped)
1165 def find_non_mapped(sections, nmapped):
1167 Determine sip.conf options that were not properly mapped to pjsip.conf
1170 for section, sect
in sections.iteritems():
1177 for key
in sect.keys(
True):
1182 nmapped(section, key, sect[key])
1187 def map_system(sip, pjsip, nmapped):
1192 user_agent = sip.get(
'general',
'useragent')[0]
1193 set_value(
'user_agent', user_agent,
'global', pjsip, nmapped,
'global')
1199 sipdebug = sip.get(
'general',
'sipdebug')[0]
1200 set_value(
'debug', sipdebug,
'global', pjsip, nmapped,
'global')
1205 useroption_parsing = sip.get(
'general',
'legacy_useroption_parsing')[0]
1206 set_value(
'ignore_uri_user_options', useroption_parsing,
'global', pjsip, nmapped,
'global')
1211 timer_t1 = sip.get(
'general',
'timert1')[0]
1212 set_value(
'timer_t1', timer_t1, section, pjsip, nmapped, type)
1217 timer_b = sip.get(
'general',
'timerb')[0]
1218 set_value(
'timer_b', timer_b, section, pjsip, nmapped, type)
1223 compact_headers = sip.get(
'general',
'compactheaders')[0]
1224 set_value(
'compact_headers', compact_headers, section, pjsip, nmapped, type)
1229 def convert(sip, filename, non_mappings, include):
1231 Entry point for configuration file conversion. This
1232 function will create a pjsip.conf object and begin to
1233 map specific sections from sip.conf into it.
1234 Returns the new pjsip.conf object once completed
1236 pjsip = sip.__class__()
1238 nmapped = non_mapped(non_mappings[filename])
1241 map_system(sip, pjsip, nmapped)
1242 map_transports(sip, pjsip, nmapped)
1243 map_registrations(sip, pjsip, nmapped)
1244 map_auth(sip, pjsip, nmapped)
1245 for section
in sip.sections():
1246 if section ==
'authentication':
1249 map_peer(sip, section, pjsip, nmapped)
1250 map_setvars(sip, section, pjsip, nmapped)
1252 find_non_mapped(sip.defaults(), nmapped)
1253 find_non_mapped(sip.sections(), nmapped)
1255 for key, val
in sip.includes().iteritems():
1256 pjsip.add_include(PREFIX + key, convert(val, PREFIX + key,
1257 non_mappings,
True)[0])
1258 return pjsip, non_mappings
1261 def write_pjsip(filename, pjsip, non_mappings):
1263 Write pjsip.conf file to disk
1266 with open(filename,
'wt')
as fp:
1268 fp.write(
';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
1269 fp.write(
'Non mapped elements start\n')
1270 fp.write(
';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n')
1272 fp.write(
';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
1273 fp.write(
'Non mapped elements end\n')
1274 fp.write(
';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
1280 print(
"Could not open file " + filename +
" for writing", file=sys.stderr)
1287 Parse command line options and apply them. If invalid input is given,
1288 print usage information
1292 usage =
"usage: %prog [options] [input-file [output-file]]\n\n" \
1293 "Converts the chan_sip configuration input-file to the chan_pjsip output-file.\n" \
1294 "The input-file defaults to 'sip.conf'.\n" \
1295 "The output-file defaults to 'pjsip.conf'."
1296 parser = optparse.OptionParser(usage=usage)
1297 parser.add_option(
'-p',
'--prefix', dest=
'prefix', default=PREFIX,
1298 help=
'output prefix for include files')
1299 parser.add_option(
'-q',
'--quiet', dest=
'quiet', default=
False, action=
'store_true',
1300 help=
"don't print messages to stdout")
1302 options, args = parser.parse_args()
1303 PREFIX = options.prefix
1307 sip_filename = args[0]
if len(args)
else 'sip.conf'
1308 pjsip_filename = args[1]
if len(args) == 2
else 'pjsip.conf'
1310 return sip_filename, pjsip_filename
1319 if __name__ ==
"__main__":
1320 sip_filename, pjsip_filename = cli_options()
1323 info(
'Please, report any issue at:')
1324 info(
' https://github.com/asterisk/asterisk/issues/')
1325 info(
'Reading ' + sip_filename)
1326 sip.read(sip_filename)
1327 info(
'Converting to PJSIP...')
1328 pjsip, non_mappings = convert(sip, pjsip_filename, dict(),
False)
1329 info(
'Writing ' + pjsip_filename)
1330 write_pjsip(pjsip_filename, pjsip, non_mappings)
def parse_host_part(self, host_part)
def write(self, pjsip, nmapped)
def parse_user_part(self, user_part)
def write_dicts(config_file, mdicts)