Page MenuHomePhabricator

No OneTemporary

diff --git a/sipsimple/core/_core.request.pxi b/sipsimple/core/_core.request.pxi
index 67246c7a..4820d02b 100644
--- a/sipsimple/core/_core.request.pxi
+++ b/sipsimple/core/_core.request.pxi
@@ -1,506 +1,505 @@
from datetime import datetime, timedelta
cdef class EndpointAddress:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.ip, self.port)
def __str__(self):
return "%s:%d" % (self.ip, self.port)
cdef class Request:
expire_warning_time = 30
# properties
property method:
def __get__(self):
return self._method.str
property call_id:
def __get__(self):
return self._call_id.str
property content_type:
def __get__(self):
if self._content_type is None:
return None
else:
return "/".join([self._content_type.str, self._content_subtype.str])
property body:
def __get__(self):
if self._body is None:
return None
else:
return self._body.str
property expires_in:
def __get__(self):
cdef object dt
self._get_ua()
if self.state != "EXPIRING" or self._expire_time is None:
return 0
else:
dt = self._expire_time - datetime.now()
return max(0, dt.seconds)
# public methods
def __cinit__(self, *args, **kwargs):
self.state = "INIT"
self.peer_address = None
pj_timer_entry_init(&self._timer, 0, <void *> self, _Request_cb_timer)
self._timer_active = 0
def __init__(self, method, SIPURI request_uri not None, FromHeader from_header not None, ToHeader to_header not None,
RouteHeader route_header not None, Credentials credentials=None, ContactHeader contact_header=None, call_id=None, cseq=None,
object extra_headers=None, content_type=None, body=None):
cdef pjsip_method method_pj
cdef PJSTR from_header_str
cdef PJSTR to_header_str
cdef PJSTR request_uri_str
cdef PJSTR contact_header_str
cdef pj_str_t *contact_header_pj = NULL
cdef pj_str_t *call_id_pj = NULL
cdef object content_type_spl
cdef pjsip_hdr *hdr
cdef pjsip_contact_hdr *contact_hdr
cdef pjsip_cid_hdr *cid_hdr
cdef pjsip_cseq_hdr *cseq_hdr
cdef int status
cdef dict event_dict
cdef PJSIPUA ua = _get_ua()
if self._tsx != NULL or self.state != "INIT":
raise SIPCoreError("Request.__init__() was already called")
if cseq is not None and cseq < 0:
raise ValueError("cseq argument cannot be negative")
if extra_headers is not None:
header_names = set([header.name for header in extra_headers])
if "Route" in header_names:
raise ValueError("Route should be specified with route_header argument, not extra_headers")
if "Content-Type" in header_names:
raise ValueError("Content-Type should be specified with content_type argument, not extra_headers")
else:
header_names = ()
if content_type is not None and body is None:
raise ValueError("Cannot specify a content_type without a body")
if content_type is None and body is not None:
raise ValueError("Cannot specify a body without a content_type")
self._method = PJSTR(method.encode())
pjsip_method_init_np(&method_pj, &self._method.pj_str)
if credentials is not None:
self.credentials = FrozenCredentials.new(credentials)
from_header_str = PJSTR(from_header.body.encode())
self.to_header = FrozenToHeader.new(to_header)
to_header_str = PJSTR(to_header.body.encode())
struri = str(request_uri)
self.request_uri = FrozenSIPURI.new(request_uri)
request_uri_str = PJSTR(struri.encode())
self.route_header = FrozenRouteHeader.new(route_header)
- #self.route_header = FrozenRouteHeader(FrozenSIPURI(host=route_header.uri.host))
self.route_header.uri.parameters.dict["lr"] = None # always send lr parameter in Route header
- self.route_header.uri.parameters.dict["hide"] = None # always hide Route header
+ #self.route_header.uri.parameters.dict["hide"] = None # always hide Route header
if contact_header is not None:
self.contact_header = FrozenContactHeader.new(contact_header)
contact_parameters = contact_header.parameters.copy()
contact_parameters.pop("q", None)
contact_parameters.pop("expires", None)
contact_header.parameters = {}
contact_header_str = PJSTR(contact_header.body.encode())
contact_header_pj = &contact_header_str.pj_str
if call_id is not None:
self._call_id = PJSTR(call_id.encode())
call_id_pj = &self._call_id.pj_str
if cseq is None:
self.cseq = -1
else:
self.cseq = cseq
if extra_headers is None:
self.extra_headers = frozenlist()
else:
self.extra_headers = frozenlist([header.frozen_type.new(header) for header in extra_headers])
if body is not None:
content_type_spl = content_type.split("/", 1)
self._content_type = PJSTR(content_type_spl[0].encode())
self._content_subtype = PJSTR(content_type_spl[1].encode())
self._body = PJSTR(body)
status = pjsip_endpt_create_request(ua._pjsip_endpoint._obj, &method_pj, &request_uri_str.pj_str,
&from_header_str.pj_str, &to_header_str.pj_str, contact_header_pj,
call_id_pj, self.cseq, NULL, &self._tdata)
if status != 0:
raise PJSIPError("Could not create request", status)
if body is not None:
self._tdata.msg.body = pjsip_msg_body_create(self._tdata.pool, &self._content_type.pj_str,
&self._content_subtype.pj_str, &self._body.pj_str)
status = _BaseRouteHeader_to_pjsip_route_hdr(self.route_header, &self._route_header, self._tdata.pool)
pjsip_msg_add_hdr(self._tdata.msg, <pjsip_hdr *> &self._route_header)
hdr = <pjsip_hdr *> (<pj_list *> &self._tdata.msg.hdr).next
while hdr != &self._tdata.msg.hdr:
hdr_name = _pj_str_to_str(hdr.name)
if hdr_name in header_names:
raise ValueError("Cannot override %s header value in extra_headers" % _pj_str_to_bytes(hdr.name))
if hdr.type == PJSIP_H_CONTACT:
contact_hdr = <pjsip_contact_hdr *> hdr
_dict_to_pjsip_param(contact_parameters, &contact_hdr.other_param, self._tdata.pool)
elif hdr.type == PJSIP_H_CALL_ID:
cid_hdr = <pjsip_cid_hdr *> hdr
self._call_id = PJSTR(_pj_str_to_bytes(cid_hdr.id))
elif hdr.type == PJSIP_H_CSEQ:
cseq_hdr = <pjsip_cseq_hdr *> hdr
self.cseq = cseq_hdr.cseq
elif hdr.type == PJSIP_H_FROM:
self.from_header = FrozenFromHeader_create(<pjsip_fromto_hdr*> hdr)
else:
pass
hdr = <pjsip_hdr *> (<pj_list *> hdr).next
_add_headers_to_tdata(self._tdata, self.extra_headers)
event_dict = dict(obj=self)
_pjsip_msg_to_dict(self._tdata.msg, event_dict)
print('Request dict %s' % event_dict)
if self.credentials is not None:
status = pjsip_auth_clt_init(&self._auth, ua._pjsip_endpoint._obj, self._tdata.pool, 0)
if status != 0:
raise PJSIPError("Could not init authentication credentials", status)
status = pjsip_auth_clt_set_credentials(&self._auth, 1, self.credentials.get_cred_info())
if status != 0:
raise PJSIPError("Could not set authentication credentials", status)
self._need_auth = 1
else:
self._need_auth = 0
status = pjsip_tsx_create_uac(&ua._module, self._tdata, &self._tsx)
if status != 0:
raise PJSIPError("Could not create transaction for request", status)
self._tsx.mod_data[ua._module.id] = <void *> self
def __dealloc__(self):
cdef PJSIPUA ua = self._get_ua()
if self._tsx != NULL:
self._tsx.mod_data[ua._module.id] = NULL
if self._tsx.state < PJSIP_TSX_STATE_COMPLETED:
pjsip_tsx_terminate(self._tsx, 500)
self._tsx = NULL
if self._tdata != NULL:
pjsip_tx_data_dec_ref(self._tdata)
self._tdata = NULL
if self._timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
def send(self, timeout=None):
cdef pj_time_val timeout_pj
cdef int status
cdef PJSIPUA ua = self._get_ua()
if self.state != "INIT":
raise SIPCoreError('This method may only be called in the "INIT" state, current state is "%s"' % self.state)
if timeout is not None:
if timeout <= 0:
raise ValueError("Timeout value cannot be negative")
timeout_pj.sec = int(timeout)
timeout_pj.msec = (timeout * 1000) % 1000
self._timeout = timeout
status = pjsip_tsx_send_msg(self._tsx, self._tdata)
if status != 0:
raise PJSIPError("Could not send request", status)
pjsip_tx_data_add_ref(self._tdata)
if timeout:
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &timeout_pj)
if status == 0:
self._timer_active = 1
self.state = "IN_PROGRESS"
def end(self):
cdef PJSIPUA ua = self._get_ua()
if self.state == "IN_PROGRESS":
pjsip_tsx_terminate(self._tsx, 408)
elif self.state == "EXPIRING":
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
# private methods
cdef PJSIPUA _get_ua(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
self._tsx = NULL
self._tdata = NULL
self._timer_active = 0
self.state = "TERMINATED"
return None
else:
return ua
cdef int _cb_tsx_state(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
cdef pjsip_tx_data *tdata_auth
cdef pjsip_transaction *tsx_auth
cdef pjsip_cseq_hdr *cseq
cdef dict event_dict
cdef int expires = -1
cdef SIPURI contact_uri
cdef dict contact_params
cdef pj_time_val timeout_pj
cdef int status
if rdata != NULL:
self.to_header = FrozenToHeader_create(rdata.msg_info.to_hdr)
if self.peer_address is None:
self.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
else:
self.peer_address.ip = rdata.pkt_info.src_name
self.peer_address.port = rdata.pkt_info.src_port
if self._tsx.state == PJSIP_TSX_STATE_PROCEEDING:
if rdata == NULL:
return 0
event_dict = dict(obj=self)
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
_add_event("SIPRequestGotProvisionalResponse", event_dict)
elif self._tsx.state == PJSIP_TSX_STATE_COMPLETED:
if self._timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
if self._need_auth and self._tsx.status_code in [401, 407]:
self._need_auth = 0
status = pjsip_auth_clt_reinit_req(&self._auth, rdata, self._tdata, &tdata_auth)
if status != 0:
_add_event("SIPRequestDidFail",
dict(obj=self, code=0,
reason="Could not add auth data to request %s" % _pj_status_to_str(status)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
cseq = <pjsip_cseq_hdr *> pjsip_msg_find_hdr(tdata_auth.msg, PJSIP_H_CSEQ, NULL)
if cseq != NULL:
cseq.cseq += 1
self.cseq = cseq.cseq
status = pjsip_tsx_create_uac(&ua._module, tdata_auth, &tsx_auth)
if status != 0:
pjsip_tx_data_dec_ref(tdata_auth)
_add_event("SIPRequestDidFail",
dict(obj=self, code=0,
reason="Could not create transaction for request with auth %s" %
_pj_status_to_str(status)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
self._tsx.mod_data[ua._module.id] = NULL
self._tsx = tsx_auth
self._tsx.mod_data[ua._module.id] = <void *> self
status = pjsip_tsx_send_msg(self._tsx, tdata_auth)
if status != 0:
pjsip_tx_data_dec_ref(tdata_auth)
_add_event("SIPRequestDidFail",
dict(obj=self, code=0,
reason="Could not send request with auth %s" % _pj_status_to_str(status)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
elif self._timeout is not None:
timeout_pj.sec = int(self._timeout)
timeout_pj.msec = (self._timeout * 1000) % 1000
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &timeout_pj)
if status == 0:
self._timer_active = 1
else:
event_dict = dict(obj=self)
if rdata != NULL:
# This shouldn't happen, but safety fist!
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
if self._tsx.status_code / 100 == 2:
if rdata != NULL:
if "Expires" in event_dict["headers"]:
expires = event_dict["headers"]["Expires"]
elif self.contact_header is not None:
for contact_header in event_dict["headers"].get("Contact", []):
if contact_header.uri == self.contact_header.uri and contact_header.expires is not None:
expires = contact_header.expires
if expires == -1:
expires = 0
for header in self.extra_headers:
if header.name == "Expires":
try:
expires = int(header.body)
except ValueError:
pass
break
event_dict["expires"] = expires
self._expire_time = datetime.now() + timedelta(seconds=expires)
_add_event("SIPRequestDidSucceed", event_dict)
else:
expires = 0
_add_event("SIPRequestDidFail", event_dict)
if expires == 0:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
else:
timeout_pj.sec = max(1, expires - self.expire_warning_time, expires/2)
timeout_pj.msec = 0
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &timeout_pj)
if status == 0:
self._timer_active = 1
self.state = "EXPIRING"
self._expire_rest = max(1, expires - timeout_pj.sec)
else:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
elif self._tsx.state == PJSIP_TSX_STATE_TERMINATED:
if self.state == "IN_PROGRESS":
if self._timer_active:
pjsip_endpt_cancel_timer(ua._pjsip_endpoint._obj, &self._timer)
self._timer_active = 0
_add_event("SIPRequestDidFail", dict(obj=self, code=self._tsx.status_code,
reason=_pj_str_to_bytes(self._tsx.status_text)))
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
self._tsx.mod_data[ua._module.id] = NULL
self._tsx = NULL
else:
pass
cdef int _cb_timer(self, PJSIPUA ua) except -1:
cdef pj_time_val expires
cdef int status
if self.state == "IN_PROGRESS":
pjsip_tsx_terminate(self._tsx, 408)
elif self.state == "EXPIRING":
if self._expire_rest > 0:
_add_event("SIPRequestWillExpire", dict(obj=self, expires=self._expire_rest))
expires.sec = self._expire_rest
expires.msec = 0
self._expire_rest = 0
status = pjsip_endpt_schedule_timer(ua._pjsip_endpoint._obj, &self._timer, &expires)
if status == 0:
self._timer_active = 1
else:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
else:
self.state = "TERMINATED"
_add_event("SIPRequestDidEnd", dict(obj=self))
return 0
cdef class IncomingRequest:
def __cinit__(self, *args, **kwargs):
self.peer_address = None
def __dealloc__(self):
cdef PJSIPUA ua
try:
ua = _get_ua()
except SIPCoreError:
return
if self._tsx != NULL:
pjsip_tsx_terminate(self._tsx, 500)
self._tsx = NULL
if self._tdata != NULL:
pjsip_tx_data_dec_ref(self._tdata)
self._tdata = NULL
def answer(self, int code, str reason=None, object extra_headers=None):
cdef bytes reason_bytes
cdef dict event_dict
cdef int status
cdef PJSIPUA ua = _get_ua()
if self.state != "incoming":
raise SIPCoreInvalidStateError('Can only answer an incoming request in the "incoming" state, '
'object is currently in the "%s" state' % self.state)
if code < 200 or code >= 700:
raise ValueError("Invalid SIP final response code: %d" % code)
self._tdata.msg.line.status.code = code
if reason is None:
self._tdata.msg.line.status.reason = pjsip_get_status_text(code)[0]
else:
pj_strdup2_with_null(self._tdata.pool, &self._tdata.msg.line.status.reason, reason.encode())
if extra_headers is not None:
_add_headers_to_tdata(self._tdata, extra_headers)
event_dict = dict(obj=self)
_pjsip_msg_to_dict(self._tdata.msg, event_dict)
status = pjsip_tsx_send_msg(self._tsx, self._tdata)
if status != 0:
raise PJSIPError("Could not send response", status)
self.state = "answered"
self._tdata = NULL
self._tsx = NULL
_add_event("SIPIncomingRequestSentResponse", event_dict)
cdef int init(self, PJSIPUA ua, pjsip_rx_data *rdata) except -1:
cdef dict event_dict
cdef int status
status = pjsip_endpt_create_response(ua._pjsip_endpoint._obj, rdata, 500, NULL, &self._tdata)
if status != 0:
raise PJSIPError("Could not create response", status)
status = pjsip_tsx_create_uas(&ua._module, rdata, &self._tsx)
if status != 0:
pjsip_tx_data_dec_ref(self._tdata)
self._tdata = NULL
raise PJSIPError("Could not create transaction for incoming request", status)
pjsip_tsx_recv_msg(self._tsx, rdata)
self.state = "incoming"
self.peer_address = EndpointAddress(rdata.pkt_info.src_name, rdata.pkt_info.src_port)
event_dict = dict(obj=self)
_pjsip_msg_to_dict(rdata.msg_info.msg, event_dict)
_add_event("SIPIncomingRequestGotRequest", event_dict)
# callback functions
cdef void _Request_cb_tsx_state(pjsip_transaction *tsx, pjsip_event *event) with gil:
cdef PJSIPUA ua
cdef void *req_ptr
cdef Request req
cdef pjsip_rx_data *rdata = NULL
try:
ua = _get_ua()
except:
return
try:
req_ptr = tsx.mod_data[ua._module.id]
if req_ptr != NULL:
req = <object> req_ptr
if event.type == PJSIP_EVENT_RX_MSG:
rdata = event.body.rx_msg.rdata
elif event.type == PJSIP_EVENT_TSX_STATE and event.body.tsx_state.type == PJSIP_EVENT_RX_MSG:
rdata = event.body.tsx_state.src.rdata
req._cb_tsx_state(ua, rdata)
except:
ua._handle_exception(1)
cdef void _Request_cb_timer(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) with gil:
cdef PJSIPUA ua
cdef Request req
try:
ua = _get_ua()
except:
return
try:
if entry.user_data != NULL:
req = <object> entry.user_data
req._timer_active = 0
req._cb_timer(ua)
except:
ua._handle_exception(1)
diff --git a/sipsimple/core/_core.util.pxi b/sipsimple/core/_core.util.pxi
index acc65db4..91f55df7 100644
--- a/sipsimple/core/_core.util.pxi
+++ b/sipsimple/core/_core.util.pxi
@@ -1,435 +1,425 @@
import platform
import re
import sys
from application.version import Version
cdef class PJSTR:
def __cinit__(self, str):
self.str = str
_str_to_pj_str(str, &self.pj_str)
def __str__(self):
return self.str
cdef class SIPStatusMessages:
cdef object _default_status
def __cinit__(self, *args, **kwargs):
self._default_status = _pj_str_to_str(pjsip_get_status_text(0)[0])
def __getitem__(self, int val):
cdef object _status
_status = _pj_str_to_str(pjsip_get_status_text(val)[0])
if _status == self._default_status:
raise IndexError("Unknown SIP response code: %d" % val)
return _status
cdef class frozenlist:
def __cinit__(self, *args, **kw):
self.list = list()
self.initialized = 0
self.hash = 0
def __init__(self, *args, **kw):
if not self.initialized:
self.list = list(*args, **kw)
self.initialized = 1
self.hash = hash(tuple(self.list))
def __reduce__(self):
return (self.__class__, (self.list,), None)
def __repr__(self):
return "frozenlist(%r)" % self.list
def __len__(self):
return self.list.__len__()
def __hash__(self):
return self.hash
def __iter__(self):
return self.list.__iter__()
def __cmp__(self, frozenlist other):
return self.list.__cmp__(other.list)
def __richcmp__(frozenlist self, other, op):
if isinstance(other, frozenlist):
other = (<frozenlist>other).list
if op == 0:
return self.list.__cmp__(other) < 0
elif op == 1:
return self.list.__cmp__(other) <= 0
elif op == 2:
return self.list.__eq__(other)
elif op == 3:
return self.list.__ne__(other)
elif op == 4:
return self.list.__cmp__(other) > 0
elif op == 5:
return self.list.__cmp__(other) >= 0
else:
return NotImplemented
def __contains__(self, item):
return self.list.__contains__(item)
def __getitem__(self, key):
return self.list.__getitem__(key)
def __add__(first, second):
if isinstance(first, frozenlist):
first = (<frozenlist>first).list
if isinstance(second, frozenlist):
second = (<frozenlist>second).list
return frozenlist(first+second)
def __mul__(first, second):
if isinstance(first, frozenlist):
first = (<frozenlist>first).list
if isinstance(second, frozenlist):
second = (<frozenlist>second).list
return frozenlist(first*second)
def __reversed__(self):
return self.list.__reversed__()
def count(self, elem):
return self.list.count(elem)
def index(self, elem):
return self.list.index(elem)
cdef class frozendict:
def __cinit__(self, *args, **kw):
self.dict = dict()
self.initialized = 0
def __init__(self, *args, **kw):
if not self.initialized:
self.dict = dict(*args, **kw)
self.initialized = 1
self.hash = hash(tuple(self.dict.iteritems()))
def __reduce__(self):
return (self.__class__, (self.dict,), None)
def __repr__(self):
return "frozendict(%r)" % self.dict
def __len__(self):
return self.dict.__len__()
def __hash__(self):
return self.hash
def __iter__(self):
return self.dict.__iter__()
def __cmp__(self, frozendict other):
return self.dict.__cmp__(other.dict)
def __richcmp__(frozendict self, other, op):
if isinstance(other, frozendict):
other = (<frozendict>other).dict
if op == 0:
return self.dict.__cmp__(other) < 0
elif op == 1:
return self.dict.__cmp__(other) <= 0
elif op == 2:
return self.dict.__eq__(other)
elif op == 3:
return self.dict.__ne__(other)
elif op == 4:
return self.dict.__cmp__(other) > 0
elif op == 5:
return self.dict.__cmp__(other) >= 0
else:
return NotImplemented
def __contains__(self, item):
return self.dict.__contains__(item)
def __getitem__(self, key):
return self.dict.__getitem__(key)
def copy(self):
return self
def get(self, *args):
return self.dict.get(*args)
def has_key(self, key):
return self.dict.has_key(key)
def items(self):
return list(self.dict.items())
def iteritems(self):
return list(self.dict.items())
def iterkeys(self):
return list(self.dict.keys())
def itervalues(self):
return list(self.dict.values())
def keys(self):
return list(self.dict.keys())
def values(self):
return list(self.dict.values())
# functions
cdef int _str_to_pj_str(object string, pj_str_t *pj_str) except -1:
- #print('Convert %s (%s)' % (string, type(string)))
- if isinstance(string, str):
- string = string.encode()
-
+ print('Convert %s (%s)' % (string, type(string)))
pj_str.ptr = PyBytes_AsString(string)
pj_str.slen = len(string)
cdef object _pj_str_to_bytes(pj_str_t pj_str):
return PyBytes_FromStringAndSize(pj_str.ptr, pj_str.slen)
cdef object _pj_str_to_str(pj_str_t pj_str):
return PyBytes_FromStringAndSize(pj_str.ptr, pj_str.slen).decode()
cdef object _pj_buf_len_to_str(object buf, int buf_len):
return PyBytes_FromStringAndSize(buf, buf_len)
cdef object _buf_to_str(object buf):
return PyBytes_FromString(buf).decode()
cdef object _str_as_str(object string):
return PyBytes_AsString(string)
cdef object _str_as_size(object string):
return PyBytes_Size(string)
cdef object _pj_status_to_str(int status):
cdef char buf[PJ_ERR_MSG_SIZE]
return _pj_str_to_str(pj_strerror(status, buf, PJ_ERR_MSG_SIZE))
cdef object _pj_status_to_def(int status):
return _re_pj_status_str_def.match(_pj_status_to_str(status)).group(1)
cdef dict _pjsip_param_to_dict(pjsip_param *param_list):
cdef pjsip_param *param
cdef dict retval = dict()
param = <pjsip_param *> (<pj_list *> param_list).next
while param != param_list:
if param.value.slen == 0:
retval[_pj_str_to_str(param.name)] = None
else:
retval[_pj_str_to_str(param.name)] = _pj_str_to_str(param.value)
param = <pjsip_param *> (<pj_list *> param).next
return retval
cdef int _dict_to_pjsip_param(object params, pjsip_param *param_list, pj_pool_t *pool):
cdef pjsip_param *param = NULL
for name, value in params.iteritems():
param = <pjsip_param *> pj_pool_alloc(pool, sizeof(pjsip_param))
if param == NULL:
return -1
_str_to_pj_str(name, &param.name)
if value is None:
param.value.slen = 0
else:
_str_to_pj_str(value, &param.value)
pj_list_insert_after(<pj_list *> param_list, <pj_list *> param)
return 0
cdef int _pjsip_msg_to_dict(pjsip_msg *msg, dict info_dict) except -1:
cdef pjsip_msg_body *body
cdef pjsip_hdr *header
cdef pjsip_generic_array_hdr *array_header
cdef pjsip_ctype_hdr *ctype_header
cdef pjsip_cseq_hdr *cseq_header
cdef char *buf
cdef int buf_len, i, status
headers = {}
header = <pjsip_hdr *> (<pj_list *> &msg.hdr).next
while header != &msg.hdr:
header_name = _pj_str_to_str(header.name)
header_data = None
multi_header = False
if header_name in ("Accept", "Allow", "Require", "Supported", "Unsupported", "Allow-Events"):
array_header = <pjsip_generic_array_hdr *> header
header_data = []
for i from 0 <= i < array_header.count:
pass
# TODO crash here
#header_data.append(_pj_str_to_str(array_header.values[i]))
elif header_name == "Contact":
multi_header = True
header_data = FrozenContactHeader_create(<pjsip_contact_hdr *> header)
elif header_name == "Content-Length":
header_data = (<pjsip_clen_hdr *> header).len
elif header_name == "Content-Type":
header_data = FrozenContentTypeHeader_create(<pjsip_ctype_hdr *> header)
elif header_name == "CSeq":
cseq_header = <pjsip_cseq_hdr *> header
hvalue = _pj_str_to_str(cseq_header.method.name)
header_data = (cseq_header.cseq, hvalue)
elif header_name in ("Expires", "Max-Forwards", "Min-Expires"):
header_data = (<pjsip_generic_int_hdr *> header).ivalue
elif header_name == "From":
header_data = FrozenFromHeader_create(<pjsip_fromto_hdr *> header)
elif header_name == "To":
header_data = FrozenToHeader_create(<pjsip_fromto_hdr *> header)
elif header_name == "Route":
multi_header = True
header_data = FrozenRouteHeader_create(<pjsip_routing_hdr *> header)
elif header_name == "Reason":
value = _pj_str_to_str((<pjsip_generic_string_hdr *>header).hvalue)
protocol, sep, params_str = value.partition(';')
params = frozendict([(name, value or None) for name, sep, value in [param.partition('=') for param in params_str.split(';')]])
header_data = FrozenReasonHeader(protocol, params)
elif header_name == "Record-Route":
multi_header = True
header_data = FrozenRecordRouteHeader_create(<pjsip_routing_hdr *> header)
elif header_name == "Retry-After":
header_data = FrozenRetryAfterHeader_create(<pjsip_retry_after_hdr *> header)
elif header_name == "Via":
multi_header = True
header_data = FrozenViaHeader_create(<pjsip_via_hdr *> header)
elif header_name == "Warning":
match = _re_warning_hdr.match(_pj_str_to_str((<pjsip_generic_string_hdr *>header).hvalue))
if match is not None:
warning_params = match.groupdict()
warning_params['code'] = int(warning_params['code'])
header_data = FrozenWarningHeader(**warning_params)
elif header_name == "Event":
header_data = FrozenEventHeader_create(<pjsip_event_hdr *> header)
elif header_name == "Subscription-State":
header_data = FrozenSubscriptionStateHeader_create(<pjsip_sub_state_hdr *> header)
elif header_name == "Refer-To":
header_data = FrozenReferToHeader_create(<pjsip_generic_string_hdr *> header)
elif header_name == "Subject":
header_data = FrozenSubjectHeader_create(<pjsip_generic_string_hdr *> header)
elif header_name == "Replaces":
header_data = FrozenReplacesHeader_create(<pjsip_replaces_hdr *> header)
# skip the following headers:
elif header_name not in ("Authorization", "Proxy-Authenticate", "Proxy-Authorization", "WWW-Authenticate"):
hvalue = (<pjsip_generic_string_hdr *> header).hvalue
header_value = _pj_str_to_str(hvalue)
header_data = FrozenHeader(header_name, header_value)
if header_data is not None:
if multi_header:
headers.setdefault(header_name, []).append(header_data)
else:
if header_name not in headers:
headers[header_name] = header_data
header = <pjsip_hdr *> (<pj_list *> header).next
info_dict["headers"] = headers
body = msg.body
if body == NULL:
info_dict["body"] = None
else:
status = pjsip_print_body(body, &buf, &buf_len)
if status != 0:
info_dict["body"] = None
else:
info_dict["body"] = _pj_buf_len_to_str(buf, buf_len).decode()
if msg.type == PJSIP_REQUEST_MSG:
info_dict["method"] = _pj_str_to_str(msg.line.req.method.name)
# You need to call pjsip_uri_get_uri on the request URI if the message is for transmitting,
# but it isn't required if message is one received. Otherwise, a seg fault occurs. Don't ask.
info_dict["request_uri"] = FrozenSIPURI_create(<pjsip_sip_uri*>pjsip_uri_get_uri(msg.line.req.uri))
else:
info_dict["code"] = msg.line.status.code
info_dict["reason"] = _pj_str_to_str(msg.line.status.reason)
return 0
cdef int _is_valid_ip(int af, object ip) except -1:
cdef char buf[16]
cdef pj_str_t src
cdef int status
_str_to_pj_str(ip, &src)
status = pj_inet_pton(af, &src, buf)
if status == 0:
return 1
else:
return 0
cdef int _get_ip_version(object ip) except -1:
if _is_valid_ip(pj_AF_INET(), ip):
return pj_AF_INET()
elif _is_valid_ip(pj_AF_INET6(), ip):
return pj_AF_INET()
else:
return 0
cdef int _add_headers_to_tdata(pjsip_tx_data *tdata, object headers) except -1:
cdef pj_str_t name_pj, value_pj
cdef pjsip_hdr *hdr
for header in headers:
hb = header.name.encode()
bb = header.body.encode()
_str_to_pj_str(hb, &name_pj)
_str_to_pj_str(bb, &value_pj)
hdr = <pjsip_hdr *> pjsip_generic_string_hdr_create(tdata.pool, &name_pj, &value_pj)
pjsip_msg_add_hdr(tdata.msg, hdr)
cdef int _remove_headers_from_tdata(pjsip_tx_data *tdata, object headers) except -1:
cdef pj_str_t header_name_pj
cdef pjsip_hdr *hdr
for header in headers:
_str_to_pj_str(header, &header_name_pj)
hdr = <pjsip_hdr *> pjsip_msg_find_remove_hdr_by_name(tdata.msg, &header_name_pj, NULL)
cdef int _BaseRouteHeader_to_pjsip_route_hdr(BaseIdentityHeader header, pjsip_route_hdr *pj_header, pj_pool_t *pool) except -1:
cdef pjsip_param *param
cdef pjsip_sip_uri *sip_uri
pjsip_route_hdr_init(NULL, <void *> pj_header)
sip_uri = <pjsip_sip_uri *> pj_pool_alloc(pool, sizeof(pjsip_sip_uri))
_BaseSIPURI_to_pjsip_sip_uri(header.uri, sip_uri, pool)
pj_header.name_addr.uri = <pjsip_uri *> sip_uri
if header.display_name:
_str_to_pj_str(header.display_name, &pj_header.name_addr.display)
_dict_to_pjsip_param(header.parameters, &pj_header.other_param, pool)
return 0
cdef int _BaseSIPURI_to_pjsip_sip_uri(BaseSIPURI uri, pjsip_sip_uri *pj_uri, pj_pool_t *pool) except -1:
cdef pjsip_param *param
pjsip_sip_uri_init(pj_uri, uri.secure)
if uri.user:
_str_to_pj_str(uri.user, &pj_uri.user)
if uri.password:
_str_to_pj_str(uri.password, &pj_uri.passwd)
if uri.host:
_str_to_pj_str(uri.host, &pj_uri.host)
if uri.port:
pj_uri.port = uri.port
for name, value in uri.parameters.iteritems():
- if value is not None:
- try:
- int(value)
- except ValueError:
- value = value.encode()
-
- name = name.encode()
-
+ print('Adding parameter for host %s: %s=%s' % (uri.host, name, value))
if name == "lr":
pj_uri.lr_param = 1
elif name == "maddr":
_str_to_pj_str(value, &pj_uri.maddr_param)
elif name == "method":
_str_to_pj_str(value, &pj_uri.method_param)
elif name == "transport":
_str_to_pj_str(value, &pj_uri.transport_param)
elif name == "ttl":
pj_uri.ttl_param = int(value)
elif name == "user":
_str_to_pj_str(value, &pj_uri.user_param)
else:
param = <pjsip_param *> pj_pool_alloc(pool, sizeof(pjsip_param))
_str_to_pj_str(name, &param.name)
if value is None:
param.value.slen = 0
else:
_str_to_pj_str(value, &param.value)
pj_list_insert_after(<pj_list *> &pj_uri.other_param, <pj_list *> param)
_dict_to_pjsip_param(uri.headers, &pj_uri.header_param, pool)
return 0
def _get_device_name_encoding():
if sys.platform == 'win32':
encoding = 'mbcs'
elif sys.platform.startswith('linux2') and Version.parse(platform.release()) < Version(2,6,31):
encoding = 'latin1'
else:
encoding = 'utf-8'
return encoding
_device_name_encoding = _get_device_name_encoding()
def decode_device_name(device_name):
# ignore decoding errors, some systems (I'm looking at you, OSX), seem to misbehave
return device_name.decode(_device_name_encoding, 'ignore')
# globals
cdef object _re_pj_status_str_def = re.compile("^.*\((.*)\)$")
cdef object _re_warning_hdr = re.compile('(?P<code>[0-9]{3}) (?P<agent>.*?) "(?P<text>.*?)"')
sip_status_messages = SIPStatusMessages()
diff --git a/sipsimple/core/_helpers.py b/sipsimple/core/_helpers.py
index d999edef..0475f734 100644
--- a/sipsimple/core/_helpers.py
+++ b/sipsimple/core/_helpers.py
@@ -1,129 +1,129 @@
"""Miscellaneous SIP related helpers"""
import random
import socket
import string
from application.python.types import MarkerType
from application.system import host
from sipsimple.core._core import SIPURI
from sipsimple.core._engine import Engine
__all__ = ['Route', 'ContactURIFactory', 'NoGRUU', 'PublicGRUU', 'TemporaryGRUU', 'PublicGRUUIfAvailable', 'TemporaryGRUUIfAvailable']
class Route(object):
_default_ports = dict(udp=5060, tcp=5060, tls=5061)
def __init__(self, address, port=None, transport='udp'):
self.address = address
self.port = port
self.transport = transport
@property
def address(self):
return self._address
@address.setter
def address(self, address):
try:
socket.inet_aton(address)
except:
raise ValueError('illegal address: %s' % address)
self._address = address
@property
def port(self):
if self._port is None:
return 5061 if self.transport == 'tls' else 5060
else:
return self._port
@port.setter
def port(self, port):
port = int(port) if port is not None else None
if port is not None and not (0 < port < 65536):
raise ValueError('illegal port value: %d' % port)
self._port = port
@property
def transport(self):
return self._transport
@transport.setter
def transport(self, transport):
if transport not in ('udp', 'tcp', 'tls'):
raise ValueError('illegal transport value: %s' % transport)
self._transport = transport
@property
def uri(self):
port = None if self._default_ports[self.transport] == self.port else self.port
- parameters = {} if self.transport == 'udp' else {'transport': self.transport}
+ parameters = {} if self.transport == 'udp' else {'transport': self.transport.encode()}
return SIPURI(host=self.address, port=port, parameters=parameters)
def __repr__(self):
return '{0.__class__.__name__}({0.address!r}, port={0.port!r}, transport={0.transport!r})'.format(self)
def __str__(self):
return str(self.uri)
class ContactURIType(MarkerType): pass
class NoGRUU(metaclass=ContactURIType): pass
class PublicGRUU(metaclass=ContactURIType): pass
class TemporaryGRUU(metaclass=ContactURIType): pass
class PublicGRUUIfAvailable(metaclass=ContactURIType): pass
class TemporaryGRUUIfAvailable(metaclass=ContactURIType): pass
class ContactURIFactory(object):
def __init__(self, username=None):
self.username = username or ''.join(random.sample(string.digits, 8))
self.public_gruu = None
self.temporary_gruu = None
def __repr__(self):
return '{0.__class__.__name__}(username={0.username!r})'.format(self)
def __getitem__(self, key):
if isinstance(key, tuple):
contact_type, key = key
if not isinstance(contact_type, ContactURIType):
raise KeyError("unsupported contact type: %r" % contact_type)
else:
contact_type = NoGRUU
if not isinstance(key, (str, Route)):
raise KeyError("key must be a transport name or Route instance")
transport = key if isinstance(key, str) else key.transport
parameters = {} if transport == 'udp' else {'transport': transport}
if contact_type is PublicGRUU:
if self.public_gruu is None:
raise KeyError("could not get Public GRUU")
uri = SIPURI.new(self.public_gruu)
elif contact_type is TemporaryGRUU:
if self.temporary_gruu is None:
raise KeyError("could not get Temporary GRUU")
uri = SIPURI.new(self.temporary_gruu)
elif contact_type is PublicGRUUIfAvailable and self.public_gruu is not None:
uri = SIPURI.new(self.public_gruu)
elif contact_type is TemporaryGRUUIfAvailable and self.temporary_gruu is not None:
uri = SIPURI.new(self.temporary_gruu)
else:
ip = host.default_ip if isinstance(key, str) else host.outgoing_ip_for(key.address)
if ip is None:
raise KeyError("could not get outgoing IP address")
port = getattr(Engine(), '%s_port' % transport, None)
if port is None:
raise KeyError("unsupported transport: %s" % transport)
uri = SIPURI(user=self.username, host=ip, port=port)
uri.parameters.update(parameters)
return uri

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 23, 3:17 AM (13 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3408651
Default Alt Text
(43 KB)

Event Timeline