Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F7159168
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
43 KB
Referenced Files
None
Subscribers
None
View Options
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, ¶m.name)
if value is None:
param.value.slen = 0
else:
_str_to_pj_str(value, ¶m.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, ¶m.name)
if value is None:
param.value.slen = 0
else:
_str_to_pj_str(value, ¶m.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
Details
Attached
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)
Attached To
Mode
rPYNSIPSIMPLE python3-sipsimple
Attached
Detach File
Event Timeline
Log In to Comment