Asterisk - The Open Source Telephony Project  GIT-master-1b41629
sip_to_pjsip.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 from __future__ import print_function
4 
5 import sys
6 import optparse
7 import socket
8 try:
9  from urllib.parse import urlparse
10 except ImportError:
11  from urlparse import urlparse # Python 2.7 required for Literal IPv6 Addresses
12 import astdicts
13 import astconfigparser
14 
15 PREFIX = 'pjsip_'
16 QUIET = False
17 
18 ###############################################################################
19 ### some utility functions
20 ###############################################################################
21 
22 
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."""
28 
29  def found(d):
30  return key in d and val in d[key]
31 
32  try:
33  return [d for d in mdicts if found(d)][0]
34  except IndexError:
35  raise LookupError("Dictionary not located for key = %s, value = %s"
36  % (key, val))
37 
38  try:
39  return __find_dict(pjsip.section(section), 'type', type)
40  except LookupError:
41  # section for type doesn't exist, so add
42  sect = pjsip.add_section(section)
43  sect['type'] = type
44  return sect
45 
46 
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"""
50 
51 
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)
57 
58  # if no value or section return the set_value
59  # function with the enclosed key and type
60  if not val and not section:
61  return _set_value
62 
63  # otherwise try to set the value
64  section_by_type(section, pjsip, type)[key] = \
65  val[0] if isinstance(val, list) else val
66 
67 
68 def merge_value(key=None, val=None, section=None, pjsip=None,
69  nmapped=None, type='endpoint', section_to=None,
70  key_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)
74 
75  # if no value or section return the merge_value
76  # function with the enclosed key and type
77  if not val and not section:
78  return _merge_value
79 
80  # should return a single value section list
81  try:
82  sect = sip.section(section)[0]
83  except LookupError:
84  sect = sip.default(section)[0]
85  # for each merged value add it to pjsip.conf
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,
89  pjsip, nmapped, type)
90 
91 def merge_codec_value(key=None, val=None, section=None, pjsip=None,
92  nmapped=None, type='endpoint', section_to=None,
93  key_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)
97 
98  # if no value or section return the merge_codec_value
99  # function with the enclosed key and type
100  if not val and not section:
101  return _merge_codec_value
102 
103  if key == 'allow':
104  try:
105  disallow = sip.get(section, 'disallow')[0]
106  if disallow == 'all':
107  #don't inherit
108  for i in sip.get(section, 'allow'):
109  set_value(key, i, section, pjsip, nmapped, type)
110  else:
111  merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
112  except LookupError:
113  print("lookup error", file=sys.stderr)
114  merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
115  return
116  elif key == 'disallow':
117  try:
118  allow = sip.get(section, 'allow')[0]
119  if allow == 'all':
120  #don't inherit
121  for i in sip.get(section, 'disallow'):
122  set_value(key, i, section, pjsip, nmapped, type)
123  else:
124  merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
125  except LookupError:
126  merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
127  return
128  else:
129  merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
130 
131 
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:
137  nmapped[section] = astconfigparser.Section()
138  if isinstance(val, list):
139  for v in val:
140  # since coming from sip.conf we can assume
141  # single section lists
142  nmapped[section][0][key] = v
143  else:
144  nmapped[section][0][key] = val
145  return _non_mapped
146 
147 ###############################################################################
148 ### mapping functions -
149 ### define f(key, val, section) where key/val are the key/value pair to
150 ### write to given section in pjsip.conf
151 ###############################################################################
152 
153 
154 def set_dtmfmode(key, val, section, pjsip, nmapped):
155  """
156  Sets the dtmfmode value. If value matches allowable option in pjsip
157  then map it, otherwise set it to none.
158  """
159  key = 'dtmf_mode'
160  # available pjsip.conf values: rfc4733, inband, info, none
161  if val == 'inband' or val == 'info':
162  set_value(key, val, section, pjsip, nmapped)
163  elif val == 'rfc2833':
164  set_value(key, 'rfc4733', section, pjsip, nmapped)
165  else:
166  nmapped(section, key, val + " ; did not fully map - set to none")
167  set_value(key, 'none', section, pjsip, nmapped)
168 
169 
170 def setup_udptl(section, pjsip, nmapped):
171  """Sets values from udptl into the appropriate pjsip.conf options."""
172  try:
173  val = sip.get(section, 't38pt_udptl')[0]
174  except LookupError:
175  try:
176  val = sip.get('general', 't38pt_udptl')[0]
177  except LookupError:
178  return
179 
180  ec = 'none'
181  if 'yes' in val:
182  set_value('t38_udptl', 'yes', section, pjsip, nmapped)
183  if 'no' in val:
184  set_value('t38_udptl', 'no', section, pjsip, nmapped)
185  if 'redundancy' in val:
186  ec = 'redundancy'
187  if 'fec' in val:
188  ec = 'fec'
189  set_value('t38_udptl_ec', ec, section, pjsip, nmapped)
190 
191 def from_nat(key, val, section, pjsip, nmapped):
192  """Sets values from nat into the appropriate pjsip.conf options."""
193  # nat from sip.conf can be comma separated list of values:
194  # yes/no, [auto_]force_rport, [auto_]comedia
195  if 'yes' in val:
196  set_value('rtp_symmetric', 'yes', section, pjsip, nmapped)
197  set_value('rewrite_contact', 'yes', section, pjsip, nmapped)
198  if 'comedia' in val:
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)
203 
204 
205 def set_timers(key, val, section, pjsip, nmapped):
206  """
207  Sets the timers in pjsip.conf from the session-timers option
208  found in sip.conf.
209  """
210  # pjsip.conf values can be yes/no, required, always
211  # 'required' is a new feature of chan_pjsip, which rejects
212  # all SIP clients not supporting Session Timers
213  # 'Accept' is the default value of chan_sip and maps to 'yes'
214  # chan_sip ignores the case, for example 'session-timers=Refuse'
215  val = val.lower()
216  if val == 'originate':
217  set_value('timers', 'always', section, pjsip, nmapped)
218  elif val == 'refuse':
219  set_value('timers', 'no', section, pjsip, nmapped)
220  else:
221  set_value('timers', 'yes', section, pjsip, nmapped)
222 
223 
224 def set_direct_media(key, val, section, pjsip, nmapped):
225  """
226  Maps values from the sip.conf comma separated direct_media option
227  into pjsip.conf direct_media options.
228  """
229  if 'yes' in val:
230  set_value('direct_media', 'yes', section, pjsip, nmapped)
231  if 'update' in val:
232  set_value('direct_media_method', 'update', section, pjsip, nmapped)
233  if 'outgoing' in val:
234  set_value('directed_media_glare_mitigation', 'outgoing', section,
235  pjsip, nmapped)
236  if 'nonat' in val:
237  set_value('disable_directed_media_on_nat', 'yes', section, pjsip,
238  nmapped)
239  if 'no' in val:
240  set_value('direct_media', 'no', section, pjsip, nmapped)
241 
242 
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)
247  elif val == 'pai':
248  set_value('send_pai', 'yes', section, pjsip, nmapped)
249 
250 
251 def set_media_encryption(key, val, section, pjsip, nmapped):
252  """Sets the media_encryption value in pjsip.conf"""
253  try:
254  dtls = sip.get(section, 'dtlsenable')[0]
255  if dtls == 'yes':
256  # If DTLS is enabled, then that overrides SDES encryption.
257  return
258  except LookupError:
259  pass
260 
261  if val == 'yes':
262  set_value('media_encryption', 'sdes', section, pjsip, nmapped)
263 
264 
265 def from_recordfeature(key, val, section, pjsip, nmapped):
266  """
267  If record on/off feature is set to automixmon then set
268  one_touch_recording, otherwise it can't be mapped.
269  """
270  set_value('one_touch_recording', 'yes', section, pjsip, nmapped)
271  set_value(key, val, section, pjsip, nmapped)
272 
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)
276 
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)
280 
281 def from_progressinband(key, val, section, pjsip, nmapped):
282  """Sets the inband_progress value in pjsip.conf"""
283  # progressinband can = yes/no/never
284  if val == 'never':
285  val = 'no'
286  set_value('inband_progress', val, section, pjsip, nmapped)
287 
288 
289 def build_host(config, host, section='general', port_key=None):
290  """
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.
294  """
295  try:
296  socket.inet_pton(socket.AF_INET6, host)
297  if not host.startswith('['):
298  # SIP URI will need brackets.
299  host = '[' + host + ']'
300  except socket.error:
301  pass
302 
303  # Literal IPv6 (like [::]), IPv4, or hostname
304  # does not work for IPv6 without brackets; case catched above
305  url = urlparse('sip://' + host)
306 
307  if port_key:
308  try:
309  port = config.get(section, port_key)[0]
310  host = url.hostname # no port, but perhaps no brackets
311  try:
312  socket.inet_pton(socket.AF_INET6, host)
313  if not host.startswith('['):
314  # SIP URI will need brackets.
315  host = '[' + host + ']'
316  except socket.error:
317  pass
318  return host + ':' + port
319  except LookupError:
320  pass
321 
322  # Returns host:port, in brackets if required
323  # TODO Does not compress IPv6, for example 0:0:0:0:0:0:0:0 should get [::]
324  return url.netloc
325 
326 
327 def from_host(key, val, section, pjsip, nmapped):
328  """
329  Sets contact info in an AOR section in pjsip.conf using 'host'
330  and 'port' data from sip.conf
331  """
332  # all aors have the same name as the endpoint so makes
333  # it easy to set endpoint's 'aors' value
334  set_value('aors', section, section, pjsip, nmapped)
335  if val == 'dynamic':
336  # Easy case. Just set the max_contacts on the aor and we're done
337  set_value('max_contacts', 1, section, pjsip, nmapped, 'aor')
338  return
339 
340  result = 'sip:'
341 
342  # More difficult case. The host will be either a hostname or
343  # IP address and may or may not have a port specified. pjsip.conf
344  # expects the contact to be a SIP URI.
345 
346  user = None
347 
348  try:
349  user = sip.multi_get(section, ['defaultuser', 'username'])[0]
350  result += user + '@'
351  except LookupError:
352  # It's fine if there's no user name
353  pass
354 
355  result += build_host(sip, val, section, 'port')
356 
357  set_value('contact', result, section, pjsip, nmapped, 'aor')
358 
359 
360 def from_mailbox(key, val, section, pjsip, nmapped):
361  """
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
365  endpoint.
366  """
367 
368  try:
369  subscribemwi = sip.get(section, 'subscribemwi')[0]
370  except LookupError:
371  # No subscribemwi option means default it to 'no'
372  subscribemwi = 'no'
373 
374  set_value('mailboxes', val, section, pjsip, nmapped, 'aor'
375  if subscribemwi == 'yes' else 'endpoint')
376 
377 
378 def setup_auth(key, val, section, pjsip, nmapped):
379  """
380  Sets up authentication information for a specific endpoint based on the
381  'secret' setting on a peer in sip.conf
382  """
383  set_value('username', section, section, pjsip, nmapped, 'auth')
384  # In chan_sip, if a secret and an md5secret are both specified on a peer,
385  # then in practice, only the md5secret is used. If both are encountered
386  # then we build an auth section that has both an md5_cred and password.
387  # However, the auth_type will indicate to authenticators to use the
388  # md5_cred, so like with sip.conf, the password will be there but have
389  # no purpose.
390  if key == 'secret':
391  set_value('password', val, section, pjsip, nmapped, 'auth')
392  else:
393  set_value('md5_cred', val, section, pjsip, nmapped, 'auth')
394  set_value('auth_type', 'md5', section, pjsip, nmapped, 'auth')
395 
396  realms = [section]
397  try:
398  auths = sip.get('authentication', 'auth')
399  for i in auths:
400  user, at, realm = i.partition('@')
401  realms.append(realm)
402  except LookupError:
403  pass
404 
405  realm_str = ','.join(realms)
406 
407  set_value('auth', section, section, pjsip, nmapped)
408  set_value('outbound_auth', realm_str, section, pjsip, nmapped)
409 
410 
411 def setup_ident(key, val, section, pjsip, nmapped):
412  """
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.
416  """
417  if val != 'peer' and val != 'friend':
418  return
419 
420  try:
421  ip = sip.get(section, 'host')[0]
422  except LookupError:
423  return
424 
425  if ip == 'dynamic':
426  try:
427  ip = sip.get(section, 'defaultip')[0]
428  except LookupError:
429  return
430 
431  set_value('endpoint', section, section, pjsip, nmapped, 'identify')
432  set_value('match', ip, section, pjsip, nmapped, 'identify')
433 
434 
435 def from_encryption_taglen(key, val, section, pjsip, nmapped):
436  """Sets the srtp_tag32 option based on sip.conf encryption_taglen"""
437  if val == '32':
438  set_value('srtp_tag_32', 'yes', section, pjsip, nmapped)
439 
440 
441 def from_dtlsenable(key, val, section, pjsip, nmapped):
442  """Optionally sets media_encryption=dtls based on sip.conf dtlsenable"""
443  if val == 'yes':
444  set_value('media_encryption', 'dtls', section, pjsip, nmapped)
445 
446 ###############################################################################
447 
448 # options in pjsip.conf on an endpoint that have no sip.conf equivalent:
449 # type, 100rel, trust_id_outbound, aggregate_mwi, connected_line_method
450 
451 # known sip.conf peer keys that can be mapped to a pjsip.conf section/key
452 peer_map = [
453  # sip.conf option mapping function pjsip.conf option(s)
454  ###########################################################################
455  ['context', set_value],
456  ['dtmfmode', set_dtmfmode],
457  ['disallow', merge_codec_value],
458  ['allow', merge_codec_value],
459  ['nat', from_nat], # rtp_symmetric, force_rport,
460  # rewrite_contact
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], # timers
467  ['session-minse', set_value('timers_min_se')],
468  ['session-expires', set_value('timers_sess_expires')],
469  # identify_by ?
470  ['canreinvite', set_direct_media], # direct_media alias
471  ['directmedia', set_direct_media], # direct_media
472  # direct_media_method
473  # directed_media_glare_mitigation
474  # disable_directed_media_on_nat
475  ['callerid', set_value], # callerid
476  ['callingpres', set_value('callerid_privacy')],
477  ['cid_tag', set_value('callerid_tag')],
478  ['trustrpid', set_value('trust_id_inbound')],
479  ['sendrpid', from_sendrpid], # send_pai, send_rpid
480  ['send_diversion', set_value],
481  ['encryption', set_media_encryption],
482  ['avpf', set_value('use_avpf')],
483  ['recordonfeature', set_record_on_feature], # automixon
484  ['recordofffeature', set_record_off_feature], # automixon
485  ['progressinband', from_progressinband], # in_band_progress
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  ['subminexpiry', set_value('sub_min_expiry')],
504  ['rtp_engine', set_value],
505  ['mailbox', from_mailbox],
506  ['busylevel', set_value('device_state_busy_at')],
507  ['secret', setup_auth],
508  ['md5secret', setup_auth],
509  ['type', setup_ident],
510  ['dtlsenable', from_dtlsenable],
511  ['dtlsverify', set_value('dtls_verify')],
512  ['dtlsrekey', set_value('dtls_rekey')],
513  ['dtlscertfile', set_value('dtls_cert_file')],
514  ['dtlsprivatekey', set_value('dtls_private_key')],
515  ['dtlscipher', set_value('dtls_cipher')],
516  ['dtlscafile', set_value('dtls_ca_file')],
517  ['dtlscapath', set_value('dtls_ca_path')],
518  ['dtlssetup', set_value('dtls_setup')],
519  ['encryption_taglen', from_encryption_taglen],
520  ['setvar', ignore],
521 
522 ############################ maps to an aor ###################################
523 
524  ['host', from_host], # contact, max_contacts
525  ['qualifyfreq', set_value('qualify_frequency', type='aor')],
526  ['maxexpiry', set_value('maximum_expiration', type='aor')],
527  ['minexpiry', set_value('minimum_expiration', type='aor')],
528  ['defaultexpiry', set_value('default_expiration', type='aor')],
529 
530 ############################# maps to auth#####################################
531 # type = auth
532 # username
533 # password
534 # md5_cred
535 # realm
536 # nonce_lifetime
537 # auth_type
538 ######################### maps to acl/security ################################
539 
540  ['permit', merge_value(type='acl', section_to='acl')],
541  ['deny', merge_value(type='acl', section_to='acl')],
542  ['acl', merge_value(type='acl', section_to='acl')],
543  ['contactpermit', merge_value(type='acl', section_to='acl', key_to='contact_permit')],
544  ['contactdeny', merge_value(type='acl', section_to='acl', key_to='contact_deny')],
545  ['contactacl', merge_value(type='acl', section_to='acl', key_to='contact_acl')],
546 
547 ########################### maps to transport #################################
548 # type = transport
549 # protocol
550 # bind
551 # async_operations
552 # ca_list_file
553 # ca_list_path
554 # cert_file
555 # privkey_file
556 # password
557 # external_signaling_address - externip & externhost
558 # external_signaling_port
559 # external_media_address
560 # domain
561 # verify_server
562 # verify_client
563 # require_client_cert
564 # method
565 # cipher
566 # localnet
567 ######################### maps to domain_alias ################################
568 # type = domain_alias
569 # domain
570 ######################### maps to registration ################################
571 # type = registration
572 # server_uri
573 # client_uri
574 # contact_user
575 # transport
576 # outbound_proxy
577 # expiration
578 # retry_interval
579 # max_retries
580 # auth_rejection_permanent
581 # outbound_auth
582 ########################### maps to identify ##################################
583 # type = identify
584 # endpoint
585 # match
586 ]
587 
588 
589 def split_hostport(addr):
590  """
591  Given an address in the form 'host:port' separate the host and port
592  components.
593  Returns a two-tuple of strings, (host, port). If no port is present in the
594  string, then the port section of the tuple is None.
595  """
596  try:
597  socket.inet_pton(socket.AF_INET6, addr)
598  if not addr.startswith('['):
599  return (addr, None)
600  except socket.error:
601  pass
602 
603  # Literal IPv6 (like [::]), IPv4, or hostname
604  # does not work for IPv6 without brackets; case catched above
605  url = urlparse('sip://' + addr)
606  # TODO Does not compress IPv6, for example 0:0:0:0:0:0:0:0 should get [::]
607  return (url.hostname, url.port)
608 
609 
610 def set_transport_common(section, sip, pjsip, protocol, nmapped):
611  """
612  sip.conf has several global settings that in pjsip.conf apply to individual
613  transports. This function adds these global settings to each individual
614  transport.
615 
616  The settings included are:
617  externaddr (or externip)
618  externhost
619  externtcpport for TCP
620  externtlsport for TLS
621  localnet
622  tos_sip
623  cos_sip
624  """
625  try:
626  extern_addr = sip.multi_get('general', ['externaddr', 'externip',
627  'externhost'])[0]
628  host, port = split_hostport(extern_addr)
629  try:
630  port = sip.get('general', 'extern' + protocol + 'port')[0]
631  except LookupError:
632  pass
633  set_value('external_media_address', host, section, pjsip,
634  nmapped, 'transport')
635  set_value('external_signaling_address', host, section, pjsip,
636  nmapped, 'transport')
637  if port:
638  set_value('external_signaling_port', port, section, pjsip,
639  nmapped, 'transport')
640  except LookupError:
641  pass
642 
643  try:
644  merge_value('localnet', sip.get('general', 'localnet')[0], 'general',
645  pjsip, nmapped, 'transport', section, "local_net")
646  except LookupError:
647  # No localnet options configured. Move on.
648  pass
649 
650  try:
651  set_value('tos', sip.get('general', 'tos_sip')[0], section, pjsip,
652  nmapped, 'transport')
653  except LookupError:
654  pass
655 
656  try:
657  set_value('cos', sip.get('general', 'cos_sip')[0], section, pjsip,
658  nmapped, 'transport')
659  except LookupError:
660  pass
661 
662 
663 def get_bind(sip, pjsip, protocol):
664  """
665  Given the protocol (udp, tcp, or tls), return
666  - the bind address, like [::] or 0.0.0.0
667  - name of the section to be created
668  """
669  section = 'transport-' + protocol
670 
671  # UDP cannot be disabled in chan_sip
672  if protocol != 'udp':
673  try:
674  enabled = sip.get('general', protocol + 'enable')[0]
675  except LookupError:
676  # No value means disabled by default. Don't create this transport
677  return (None, section)
678  if enabled != 'yes':
679  return (None, section)
680 
681  try:
682  bind = pjsip.get(section, 'bind')[0]
683  # The first run created an transport already but this
684  # server was not configured for IPv4/IPv6 Dual Stack
685  return (None, section)
686  except LookupError:
687  pass
688 
689  try:
690  bind = pjsip.get(section + '6', 'bind')[0]
691  # The first run created an IPv6 transport, because
692  # the server was configured with :: as bindaddr.
693  # Now, re-use its port and create the IPv4 transport
694  host, port = split_hostport(bind)
695  bind = '0.0.0.0'
696  if port:
697  bind += ':' + str(port)
698  except LookupError:
699  # This is the first run, no transport in pjsip exists.
700  try:
701  bind = sip.get('general', protocol + 'bindaddr')[0]
702  except LookupError:
703  if protocol == 'udp':
704  try:
705  bind = sip.get('general', 'bindaddr')[0]
706  except LookupError:
707  bind = '0.0.0.0'
708  else:
709  try:
710  bind = pjsip.get('transport-udp6', 'bind')[0]
711  except LookupError:
712  bind = pjsip.get('transport-udp', 'bind')[0]
713  # Only TCP reuses host:port of UDP, others reuse just host
714  if protocol == 'tls':
715  bind, port = split_hostport(bind)
716  host, port = split_hostport(bind)
717  if host == '::':
718  section += '6'
719 
720  if protocol == 'udp':
721  host = build_host(sip, bind, 'general', 'bindport')
722  else:
723  host = build_host(sip, bind)
724 
725  return (host, section)
726 
727 
728 def create_udp(sip, pjsip, nmapped):
729  """
730  Creates a 'transport-udp' section in the pjsip.conf file based
731  on the following settings from sip.conf:
732 
733  bindaddr (or udpbindaddr)
734  bindport
735  """
736  protocol = 'udp'
737  bind, section = get_bind(sip, pjsip, protocol)
738 
739  set_value('protocol', protocol, section, pjsip, nmapped, 'transport')
740  set_value('bind', bind, section, pjsip, nmapped, 'transport')
741  set_transport_common(section, sip, pjsip, protocol, nmapped)
742 
743 
744 def create_tcp(sip, pjsip, nmapped):
745  """
746  Creates a 'transport-tcp' section in the pjsip.conf file based
747  on the following settings from sip.conf:
748 
749  tcpenable
750  tcpbindaddr (or bindaddr)
751  """
752  protocol = 'tcp'
753  bind, section = get_bind(sip, pjsip, protocol)
754  if not bind:
755  return
756 
757  set_value('protocol', protocol, section, pjsip, nmapped, 'transport')
758  set_value('bind', bind, section, pjsip, nmapped, 'transport')
759  set_transport_common(section, sip, pjsip, protocol, nmapped)
760 
761 
762 def set_tls_cert_file(val, pjsip, section, nmapped):
763  """Sets cert_file based on sip.conf tlscertfile"""
764  set_value('cert_file', val, section, pjsip, nmapped,
765  'transport')
766 
767 
768 def set_tls_private_key(val, pjsip, section, nmapped):
769  """Sets privkey_file based on sip.conf tlsprivatekey or sslprivatekey"""
770  set_value('priv_key_file', val, section, pjsip, nmapped,
771  'transport')
772 
773 
774 def set_tls_cipher(val, pjsip, section, nmapped):
775  """Sets cipher based on sip.conf tlscipher or sslcipher"""
776  set_value('cipher', val, section, pjsip, nmapped, 'transport')
777 
778 
779 def set_tls_cafile(val, pjsip, section, nmapped):
780  """Sets ca_list_file based on sip.conf tlscafile"""
781  set_value('ca_list_file', val, section, pjsip, nmapped,
782  'transport')
783 
784 
785 def set_tls_capath(val, pjsip, section, nmapped):
786  """Sets ca_list_path based on sip.conf tlscapath"""
787  set_value('ca_list_path', val, section, pjsip, nmapped,
788  'transport')
789 
790 
791 def set_tls_verifyclient(val, pjsip, section, nmapped):
792  """Sets verify_client based on sip.conf tlsverifyclient"""
793  set_value('verify_client', val, section, pjsip, nmapped,
794  'transport')
795 
796 
797 def set_tls_verifyserver(val, pjsip, section, nmapped):
798  """Sets verify_server based on sip.conf tlsdontverifyserver"""
799 
800  if val == 'no':
801  set_value('verify_server', 'yes', section, pjsip, nmapped,
802  'transport')
803  else:
804  set_value('verify_server', 'no', section, pjsip, nmapped,
805  'transport')
806 
807 
808 def create_tls(sip, pjsip, nmapped):
809  """
810  Creates a 'transport-tls' section in pjsip.conf based on the following
811  settings from sip.conf:
812 
813  tlsenable (or sslenable)
814  tlsbindaddr (or sslbindaddr or bindaddr)
815  tlsprivatekey (or sslprivatekey)
816  tlscipher (or sslcipher)
817  tlscafile
818  tlscapath (or tlscadir)
819  tlscertfile (or sslcert or tlscert)
820  tlsverifyclient
821  tlsdontverifyserver
822  tlsclientmethod (or sslclientmethod)
823  """
824  protocol = 'tls'
825  bind, section = get_bind(sip, pjsip, protocol)
826  if not bind:
827  return
828 
829  set_value('protocol', protocol, section, pjsip, nmapped, 'transport')
830  set_value('bind', bind, section, pjsip, nmapped, 'transport')
831  set_transport_common(section, sip, pjsip, protocol, nmapped)
832 
833  tls_map = [
834  (['tlscertfile', 'sslcert', 'tlscert'], set_tls_cert_file),
835  (['tlsprivatekey', 'sslprivatekey'], set_tls_private_key),
836  (['tlscipher', 'sslcipher'], set_tls_cipher),
837  (['tlscafile'], set_tls_cafile),
838  (['tlscapath', 'tlscadir'], set_tls_capath),
839  (['tlsverifyclient'], set_tls_verifyclient),
840  (['tlsdontverifyserver'], set_tls_verifyserver)
841  ]
842 
843  for i in tls_map:
844  try:
845  i[1](sip.multi_get('general', i[0])[0], pjsip, section, nmapped)
846  except LookupError:
847  pass
848 
849  try:
850  method = sip.multi_get('general', ['tlsclientmethod',
851  'sslclientmethod'])[0]
852  if section != 'transport-' + protocol + '6': # print only once
853  print('In chan_sip, you specified the TLS version. With chan_sip,' \
854  ' this was just for outbound client connections. In' \
855  ' chan_pjsip, this value is for client and server. Instead,' \
856  ' consider not to specify \'tlsclientmethod\' for chan_sip' \
857  ' and \'method = sslv23\' for chan_pjsip.', file=sys.stderr)
858  except LookupError:
859  """
860  OpenSSL emerged during the 90s. SSLv2 and SSLv3 were the only
861  existing methods at that time. The OpenSSL project continued. And as
862  of today (OpenSSL 1.0.2) this does not start SSLv2 and SSLv3 anymore
863  but TLSv1.0 and v1.2. Or stated differently: This method should
864  have been called 'method = secure' or 'method = automatic' back in
865  the 90s. The PJProject did not realize this and uses 'tlsv1' as
866  default when unspecified, which disables TLSv1.2. chan_sip used
867  'sslv23' as default when unspecified, which gives TLSv1.0 and v1.2.
868  """
869  method = 'sslv23'
870  set_value('method', method, section, pjsip, nmapped, 'transport')
871 
872 
873 def map_transports(sip, pjsip, nmapped):
874  """
875  Finds options in sip.conf general section pertaining to
876  transport configuration and creates appropriate transport
877  configuration sections in pjsip.conf.
878 
879  sip.conf only allows a single UDP transport, TCP transport,
880  and TLS transport for each IP version. As such, the mapping
881  into PJSIP can be made consistent by defining six sections:
882 
883  transport-udp6
884  transport-udp
885  transport-tcp6
886  transport-tcp
887  transport-tls6
888  transport-tls
889 
890  To accommodate the default behaviors in sip.conf, we'll need to
891  create the UDP transports first, followed by the TCP and TLS transports.
892  """
893 
894  # First create a UDP transport. Even if no bind parameters were provided
895  # in sip.conf, chan_sip would always bind to UDP 0.0.0.0:5060
896  create_udp(sip, pjsip, nmapped)
897  create_udp(sip, pjsip, nmapped)
898 
899  # TCP settings may be dependent on UDP settings, so do it second.
900  create_tcp(sip, pjsip, nmapped)
901  create_tcp(sip, pjsip, nmapped)
902  create_tls(sip, pjsip, nmapped)
903  create_tls(sip, pjsip, nmapped)
904 
905 
906 def map_auth(sip, pjsip, nmapped):
907  """
908  Creates auth sections based on entries in the authentication section of
909  sip.conf. pjsip.conf section names consist of "auth_" followed by the name
910  of the realm.
911  """
912  try:
913  auths = sip.get('authentication', 'auth')
914  except LookupError:
915  return
916 
917  for i in auths:
918  creds, at, realm = i.partition('@')
919  if not at and not realm:
920  # Invalid. Move on
921  continue
922  user, colon, secret = creds.partition(':')
923  if not secret:
924  user, sharp, md5 = creds.partition('#')
925  if not md5:
926  #Invalid. move on
927  continue
928  section = "auth_" + realm
929 
930  set_value('realm', realm, section, pjsip, nmapped, 'auth')
931  set_value('username', user, section, pjsip, nmapped, 'auth')
932  if secret:
933  set_value('password', secret, section, pjsip, nmapped, 'auth')
934  else:
935  set_value('md5_cred', md5, section, pjsip, nmapped, 'auth')
936  set_value('auth_type', 'md5', section, pjsip, nmapped, 'auth')
937 
938 
940  """
941  Class for parsing and storing information in a register line in sip.conf.
942  """
943  def __init__(self, line, retry_interval, max_attempts, outbound_proxy):
944  self.retry_interval = retry_interval
945  self.max_attempts = max_attempts
946  self.outbound_proxy = outbound_proxy
947  self.parse(line)
948 
949  def parse(self, line):
950  """
951  Initial parsing routine for register lines in sip.conf.
952 
953  This splits the line into the part before the host, and the part
954  after the '@' symbol. These two parts are then passed to their
955  own parsing routines
956  """
957 
958  # register =>
959  # [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
960 
961  prehost, at, host_part = line.rpartition('@')
962  if not prehost:
963  raise
964 
965  self.parse_host_part(host_part)
966  self.parse_user_part(prehost)
967 
968  def parse_host_part(self, host_part):
969  """
970  Parsing routine for the part after the final '@' in a register line.
971  The strategy is to use partition calls to peel away the data starting
972  from the right and working to the left.
973  """
974  pre_expiry, sep, expiry = host_part.partition('~')
975  pre_extension, sep, self.extension = pre_expiry.partition('/')
976  self.host, sep, self.port = pre_extension.partition(':')
977 
978  self.expiry = expiry if expiry else '120'
979 
980  def parse_user_part(self, user_part):
981  """
982  Parsing routine for the part before the final '@' in a register line.
983  The only mandatory part of this line is the user portion. The strategy
984  here is to start by using partition calls to remove everything to
985  the right of the user, then finish by using rpartition calls to remove
986  everything to the left of the user.
987  """
988  self.peer = ''
989  self.protocol = 'udp'
990  protocols = ['udp', 'tcp', 'tls']
991  for protocol in protocols:
992  position = user_part.find(protocol + '://')
993  if -1 < position:
994  post_transport = user_part[position + 6:]
995  self.peer, sep, self.protocol = user_part[:position + 3].rpartition('?')
996  user_part = post_transport
997  break
998 
999  colons = user_part.count(':')
1000  if (colons == 3):
1001  # :domainport:secret:authuser
1002  pre_auth, sep, port_auth = user_part.partition(':')
1003  self.domainport, sep, auth = port_auth.partition(':')
1004  self.secret, sep, self.authuser = auth.partition(':')
1005  elif (colons == 2):
1006  # :secret:authuser
1007  pre_auth, sep, auth = user_part.partition(':')
1008  self.secret, sep, self.authuser = auth.partition(':')
1009  elif (colons == 1):
1010  # :secret
1011  pre_auth, sep, self.secret = user_part.partition(':')
1012  elif (colons == 0):
1013  # No port, secret, or authuser
1014  pre_auth = user_part
1015  else:
1016  # Invalid setting
1017  raise
1018 
1019  self.user, sep, self.domain = pre_auth.partition('@')
1020 
1021  def write(self, pjsip, nmapped):
1022  """
1023  Write parsed registration data into a section in pjsip.conf
1024 
1025  Most of the data in self will get written to a registration section.
1026  However, there will also need to be an auth section created if a
1027  secret or authuser is present.
1028 
1029  General mapping of values:
1030  A combination of self.host and self.port is server_uri
1031  A combination of self.user, self.domain, and self.domainport is
1032  client_uri
1033  self.expiry is expiration
1034  self.extension is contact_user
1035  self.protocol will map to one of the mapped transports
1036  self.secret and self.authuser will result in a new auth section, and
1037  outbound_auth will point to that section.
1038  XXX self.peer really doesn't map to anything :(
1039  """
1040 
1041  section = 'reg_' + self.host
1042 
1043  set_value('retry_interval', self.retry_interval, section, pjsip,
1044  nmapped, 'registration')
1045  set_value('max_retries', self.max_attempts, section, pjsip, nmapped,
1046  'registration')
1047  if self.extension:
1048  set_value('contact_user', self.extension, section, pjsip, nmapped,
1049  'registration')
1050 
1051  set_value('expiration', self.expiry, section, pjsip, nmapped,
1052  'registration')
1053 
1054  if self.protocol == 'udp':
1055  set_value('transport', 'transport-udp', section, pjsip, nmapped,
1056  'registration')
1057  elif self.protocol == 'tcp':
1058  set_value('transport', 'transport-tcp', section, pjsip, nmapped,
1059  'registration')
1060  elif self.protocol == 'tls':
1061  set_value('transport', 'transport-tls', section, pjsip, nmapped,
1062  'registration')
1063 
1064  auth_section = 'auth_reg_' + self.host
1065 
1066  if hasattr(self, 'secret') and self.secret:
1067  set_value('password', self.secret, auth_section, pjsip, nmapped,
1068  'auth')
1069  set_value('username', self.authuser if hasattr(self, 'authuser')
1070  else self.user, auth_section, pjsip, nmapped, 'auth')
1071  set_value('outbound_auth', auth_section, section, pjsip, nmapped,
1072  'registration')
1073 
1074  client_uri = "sip:%s@" % self.user
1075  if self.domain:
1076  client_uri += self.domain
1077  else:
1078  client_uri += self.host
1079 
1080  if hasattr(self, 'domainport') and self.domainport:
1081  client_uri += ":" + self.domainport
1082  elif self.port:
1083  client_uri += ":" + self.port
1084 
1085  set_value('client_uri', client_uri, section, pjsip, nmapped,
1086  'registration')
1087 
1088  server_uri = "sip:%s" % self.host
1089  if self.port:
1090  server_uri += ":" + self.port
1091 
1092  set_value('server_uri', server_uri, section, pjsip, nmapped,
1093  'registration')
1094 
1095  if self.outbound_proxy:
1096  set_value('outboundproxy', self.outbound_proxy, section, pjsip,
1097  nmapped, 'registration')
1098 
1099 
1100 def map_registrations(sip, pjsip, nmapped):
1101  """
1102  Gathers all necessary outbound registration data in sip.conf and creates
1103  corresponding registration sections in pjsip.conf
1104  """
1105  try:
1106  regs = sip.get('general', 'register')
1107  except LookupError:
1108  return
1109 
1110  try:
1111  retry_interval = sip.get('general', 'registertimeout')[0]
1112  except LookupError:
1113  retry_interval = '20'
1114 
1115  try:
1116  max_attempts = sip.get('general', 'registerattempts')[0]
1117  except LookupError:
1118  max_attempts = '10'
1119 
1120  try:
1121  outbound_proxy = sip.get('general', 'outboundproxy')[0]
1122  except LookupError:
1123  outbound_proxy = ''
1124 
1125  for i in regs:
1126  reg = Registration(i, retry_interval, max_attempts, outbound_proxy)
1127  reg.write(pjsip, nmapped)
1128 
1129 
1130 def map_setvars(sip, section, pjsip, nmapped):
1131  """
1132  Map all setvar in peer section to the appropriate endpoint set_var
1133  """
1134  try:
1135  setvars = sip.section(section)[0].get('setvar')
1136  except LookupError:
1137  return
1138 
1139  for setvar in setvars:
1140  set_value('set_var', setvar, section, pjsip, nmapped)
1141 
1142 
1143 def map_peer(sip, section, pjsip, nmapped):
1144  """
1145  Map the options from a peer section in sip.conf into the appropriate
1146  sections in pjsip.conf
1147  """
1148  for i in peer_map:
1149  try:
1150  # coming from sip.conf the values should mostly be a list with a
1151  # single value. In the few cases that they are not a specialized
1152  # function (see merge_value) is used to retrieve the values.
1153  i[1](i[0], sip.get(section, i[0])[0], section, pjsip, nmapped)
1154  except LookupError:
1155  pass # key not found in sip.conf
1156 
1157  setup_udptl(section, pjsip, nmapped)
1158 
1159 def find_non_mapped(sections, nmapped):
1160  """
1161  Determine sip.conf options that were not properly mapped to pjsip.conf
1162  options.
1163  """
1164  for section, sect in sections.iteritems():
1165  try:
1166  # since we are pulling from sip.conf this should always
1167  # be a single value list
1168  sect = sect[0]
1169  # loop through the section and store any values that were not
1170  # mapped
1171  for key in sect.keys(True):
1172  for i in peer_map:
1173  if i[0] == key:
1174  break
1175  else:
1176  nmapped(section, key, sect[key])
1177  except LookupError:
1178  pass
1179 
1180 
1181 def map_system(sip, pjsip, nmapped):
1182  section = 'system' # Just a label; you as user can change that
1183  type = 'system' # Not a label, therefore not the same as section
1184 
1185  try:
1186  user_agent = sip.get('general', 'useragent')[0]
1187  set_value('user_agent', user_agent, 'global', pjsip, nmapped, 'global')
1188  except LookupError:
1189  pass
1190 
1191 
1192  try:
1193  sipdebug = sip.get('general', 'sipdebug')[0]
1194  set_value('debug', sipdebug, 'global', pjsip, nmapped, 'global')
1195  except LookupError:
1196  pass
1197 
1198  try:
1199  useroption_parsing = sip.get('general', 'legacy_useroption_parsing')[0]
1200  set_value('ignore_uri_user_options', useroption_parsing, 'global', pjsip, nmapped, 'global')
1201  except LookupError:
1202  pass
1203 
1204  try:
1205  timer_t1 = sip.get('general', 'timert1')[0]
1206  set_value('timer_t1', timer_t1, section, pjsip, nmapped, type)
1207  except LookupError:
1208  pass
1209 
1210  try:
1211  timer_b = sip.get('general', 'timerb')[0]
1212  set_value('timer_b', timer_b, section, pjsip, nmapped, type)
1213  except LookupError:
1214  pass
1215 
1216  try:
1217  compact_headers = sip.get('general', 'compactheaders')[0]
1218  set_value('compact_headers', compact_headers, section, pjsip, nmapped, type)
1219  except LookupError:
1220  pass
1221 
1222 
1223 def convert(sip, filename, non_mappings, include):
1224  """
1225  Entry point for configuration file conversion. This
1226  function will create a pjsip.conf object and begin to
1227  map specific sections from sip.conf into it.
1228  Returns the new pjsip.conf object once completed
1229  """
1230  pjsip = sip.__class__()
1231  non_mappings[filename] = astdicts.MultiOrderedDict()
1232  nmapped = non_mapped(non_mappings[filename])
1233  if not include:
1234  # Don't duplicate transport and registration configs
1235  map_system(sip, pjsip, nmapped)
1236  map_transports(sip, pjsip, nmapped)
1237  map_registrations(sip, pjsip, nmapped)
1238  map_auth(sip, pjsip, nmapped)
1239  for section in sip.sections():
1240  if section == 'authentication':
1241  pass
1242  else:
1243  map_peer(sip, section, pjsip, nmapped)
1244  map_setvars(sip, section, pjsip, nmapped)
1245 
1246  find_non_mapped(sip.defaults(), nmapped)
1247  find_non_mapped(sip.sections(), nmapped)
1248 
1249  for key, val in sip.includes().iteritems():
1250  pjsip.add_include(PREFIX + key, convert(val, PREFIX + key,
1251  non_mappings, True)[0])
1252  return pjsip, non_mappings
1253 
1254 
1255 def write_pjsip(filename, pjsip, non_mappings):
1256  """
1257  Write pjsip.conf file to disk
1258  """
1259  try:
1260  with open(filename, 'wt') as fp:
1261  fp.write(';--\n')
1262  fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
1263  fp.write('Non mapped elements start\n')
1264  fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n')
1265  astconfigparser.write_dicts(fp, non_mappings[filename])
1266  fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
1267  fp.write('Non mapped elements end\n')
1268  fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
1269  fp.write('--;\n\n')
1270  # write out include file(s)
1271  pjsip.write(fp)
1272 
1273  except IOError:
1274  print("Could not open file " + filename + " for writing", file=sys.stderr)
1275 
1276 ###############################################################################
1277 
1278 
1280  """
1281  Parse command line options and apply them. If invalid input is given,
1282  print usage information
1283  """
1284  global PREFIX
1285  global QUIET
1286  usage = "usage: %prog [options] [input-file [output-file]]\n\n" \
1287  "Converts the chan_sip configuration input-file to the chan_pjsip output-file.\n" \
1288  "The input-file defaults to 'sip.conf'.\n" \
1289  "The output-file defaults to 'pjsip.conf'."
1290  parser = optparse.OptionParser(usage=usage)
1291  parser.add_option('-p', '--prefix', dest='prefix', default=PREFIX,
1292  help='output prefix for include files')
1293  parser.add_option('-q', '--quiet', dest='quiet', default=False, action='store_true',
1294  help="don't print messages to stdout")
1295 
1296  options, args = parser.parse_args()
1297  PREFIX = options.prefix
1298  if options.quiet:
1299  QUIET = True
1300 
1301  sip_filename = args[0] if len(args) else 'sip.conf'
1302  pjsip_filename = args[1] if len(args) == 2 else 'pjsip.conf'
1303 
1304  return sip_filename, pjsip_filename
1305 
1306 
1307 def info(msg):
1308  if QUIET:
1309  return
1310  print(msg)
1311 
1312 
1313 if __name__ == "__main__":
1314  sip_filename, pjsip_filename = cli_options()
1315  # configuration parser for sip.conf
1317  info('Please, report any issue at:')
1318  info(' https://issues.asterisk.org/')
1319  info('Reading ' + sip_filename)
1320  sip.read(sip_filename)
1321  info('Converting to PJSIP...')
1322  pjsip, non_mappings = convert(sip, pjsip_filename, dict(), False)
1323  info('Writing ' + pjsip_filename)
1324  write_pjsip(pjsip_filename, pjsip, non_mappings)
def __init__(self, line, retry_interval, max_attempts, outbound_proxy)
def set_dtmfmode(key, val, section, pjsip, nmapped)
mapping functions - define f(key, val, section) where key/val are the key/value pair to write to give...
def set_tls_cipher(val, pjsip, section, nmapped)
def section_by_type(section, pjsip, type)
some utility functions
Definition: sip_to_pjsip.py:23
def from_progressinband(key, val, section, pjsip, nmapped)
def from_recordfeature(key, val, section, pjsip, nmapped)
def set_tls_private_key(val, pjsip, section, nmapped)
def set_value(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
Definition: sip_to_pjsip.py:53
def set_tls_capath(val, pjsip, section, nmapped)
def split_hostport(addr)
def from_sendrpid(key, val, section, pjsip, nmapped)
def parse_host_part(self, host_part)
def set_timers(key, val, section, pjsip, nmapped)
const char * str
Definition: app_jack.c:147
def set_record_off_feature(key, val, section, pjsip, nmapped)
def create_tls(sip, pjsip, nmapped)
def map_peer(sip, section, pjsip, nmapped)
def from_mailbox(key, val, section, pjsip, nmapped)
def write(self, pjsip, nmapped)
def map_auth(sip, pjsip, nmapped)
def convert(sip, filename, non_mappings, include)
def map_system(sip, pjsip, nmapped)
def set_tls_cert_file(val, pjsip, section, nmapped)
def map_transports(sip, pjsip, nmapped)
def merge_value(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint', section_to=None, key_to=None)
Definition: sip_to_pjsip.py:70
def parse_user_part(self, user_part)
def write_pjsip(filename, pjsip, non_mappings)
def setup_auth(key, val, section, pjsip, nmapped)
def set_media_encryption(key, val, section, pjsip, nmapped)
def merge_codec_value(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint', section_to=None, key_to=None)
Definition: sip_to_pjsip.py:93
def info(msg)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
def find_non_mapped(sections, nmapped)
def ignore(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
Definition: sip_to_pjsip.py:48
def map_setvars(sip, section, pjsip, nmapped)
def create_udp(sip, pjsip, nmapped)
def build_host(config, host, section='general', port_key=None)
def from_host(key, val, section, pjsip, nmapped)
def non_mapped(nmapped)
def from_encryption_taglen(key, val, section, pjsip, nmapped)
def from_dtlsenable(key, val, section, pjsip, nmapped)
def set_direct_media(key, val, section, pjsip, nmapped)
def set_record_on_feature(key, val, section, pjsip, nmapped)
def map_registrations(sip, pjsip, nmapped)
def write_dicts(config_file, mdicts)
def setup_ident(key, val, section, pjsip, nmapped)
def set_tls_cafile(val, pjsip, section, nmapped)
def from_nat(key, val, section, pjsip, nmapped)
def set_tls_verifyclient(val, pjsip, section, nmapped)
def set_transport_common(section, sip, pjsip, protocol, nmapped)
def set_tls_verifyserver(val, pjsip, section, nmapped)
def setup_udptl(section, pjsip, nmapped)
def get_bind(sip, pjsip, protocol)
def create_tcp(sip, pjsip, nmapped)