Skip to content

Commit

Permalink
fix: update Route header handling in established dialogs
Browse files Browse the repository at this point in the history
  • Loading branch information
moha-abdi committed Nov 29, 2024
1 parent 439cab1 commit 7195ef7
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 34 deletions.
17 changes: 11 additions & 6 deletions PySIP/sip_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,15 +457,16 @@ def construct_invite_message(
def ack_generator(self, transaction):
_, port = self.sip_core.get_extra_info("sockname")
ip = self.my_public_ip
request_uri = self.dialogue.remote_contact_uri or f"sip:{self.callee}@{self.server}:{self.port};transport={self.CTS}"

msg = f"ACK sip:{self.callee}@{self.server}:{self.port};transport={self.CTS} SIP/2.0\r\n"
msg = f"ACK {request_uri} SIP/2.0\r\n"
msg += f"Via: SIP/2.0/{self.CTS} {ip}:{port};rport;branch={transaction.branch_id};alias\r\n"
msg += "Max-Forwards: 70\r\n"
msg += f"From: sip:{self.caller_id}@{self.server};tag={self.dialogue.local_tag}\r\n"
msg += f"To: sip:{self.callee}@{self.server};tag={self.dialogue.remote_tag}\r\n"
msg += f"Call-ID: {self.call_id}\r\n"
msg += f"CSeq: {transaction.cseq} ACK\r\n"
msg += f"Route: <sip:{self.server}:{self.port};transport={self.CTS};lr>\r\n"
msg += f"Route: <{request_uri};lr>\r\n"
msg += "Content-Length: 0\r\n\r\n"

return msg
Expand All @@ -476,18 +477,20 @@ def bye_generator(self):

branch_id = self.sip_core.gen_branch()
transaction = self.dialogue.add_transaction(branch_id, "BYE")
request_uri = self.dialogue.remote_contact_uri or f"sip:{self.callee}@{peer_ip}:{peer_port};transport={self.CTS}"

msg = f"BYE sip:{self.callee}@{peer_ip}:{peer_port};transport={self.CTS} SIP/2.0\r\n"
msg = f"BYE {request_uri} SIP/2.0\r\n"
msg += (
f"Via: SIP/2.0/{self.CTS} {self.my_public_ip}:{port};rport;"
+ f"branch={branch_id};alias\r\n"
)
msg += 'Reason: Q.850;cause=16;text="normal call clearing"'
msg += 'Reason: Q.850;cause=16;text="normal call clearing"\r\n'
msg += "Max-Forwards: 70\r\n"
msg += f"From: sip:{self.caller_id}@{self.server};tag={self.dialogue.local_tag}\r\n"
msg += f"To: sip:{self.callee}@{self.server};tag={self.dialogue.remote_tag}\r\n"
msg += f"Call-ID: {self.call_id}\r\n"
msg += f"CSeq: {transaction.cseq} BYE\r\n"
msg += f"Route: <{request_uri};lr>\r\n"
msg += "Content-Length: 0\r\n\r\n"

return msg
Expand All @@ -500,8 +503,9 @@ def refer_generator(self, refer_to_callee):
transaction = self.dialogue.add_transaction(branch_id, "REFER")
refer_to = f"sip:{refer_to_callee}@{self.server};transport={self.CTS}"
referred_by = f"sip:{self.caller_id}@{self.server}"
request_uri= self.dialogue.remote_contact_uri or f"sip:{self.callee}@{self.server}:{self.port};transport={self.CTS}"

msg = f"REFER sip:{self.callee}@{self.server}:{self.port};transport={self.CTS} sip/2.0\r\n"
msg = f"REFER {request_uri} sip/2.0\r\n"
msg += f"Via: sip/2.0/{self.CTS} {ip}:{port};rport;branch={branch_id};alias\r\n"
msg += "Max-Forwards: 70\r\n"
msg += f"From: sip:{self.caller_id}@{self.server};tag={self.dialogue.local_tag}\r\n"
Expand All @@ -511,6 +515,7 @@ def refer_generator(self, refer_to_callee):
msg += f"Refer-To: {refer_to}\r\n"
msg += f"Referred-By: {referred_by}\r\n"
msg += f"Contact: <sip:{self.username}@{ip}:{port};transport={self.CTS}>\r\n"
msg += f"Route: <{request_uri};lr>\r\n"
msg += "Content-Length: 0\r\n\r\n"

return msg
Expand Down Expand Up @@ -668,10 +673,10 @@ async def message_handler(self, msg: SipMessage):
transaction = self.dialogue.add_transaction(
self.sip_core.gen_branch(), "ACK"
)
self.dialogue.update_state(msg)
ack_message = self.ack_generator(transaction)
self.dialogue.auth_retry_count = 0 # reset the auth counter
await self.sip_core.send(ack_message)
self.dialogue.update_state(msg)
await self.update_call_state(CallState.ANSWERED)
return

Expand Down
40 changes: 12 additions & 28 deletions PySIP/sip_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class DTMFMode(Enum):
ConnectionType.UDP: 5060,
ConnectionType.TCP: 5060,
ConnectionType.TLS: 5061,
ConnectionType.TLSv1: 5061,
ConnectionType.TLSv1: 5061
}

SAVE_TLS_KEYLOG = False
Expand Down Expand Up @@ -143,22 +143,16 @@ def gen_urn_uuid(self) -> str:
def gen_branch(self):
return f"z9hG4bK-{str(uuid.uuid4())}"

def generate_response(
self, method, nonce, realm, uri, qop=None, nc=None, cnonce=None
):
def generate_response(self, method, nonce, realm, uri):
A1_string = self.username + ":" + realm + ":" + self.password
A1_hash = hashlib.md5(A1_string.encode()).hexdigest()

A2_string = (method + ":" + uri).encode()
A2_hash = hashlib.md5(A2_string).hexdigest()

if qop == "auth":
response_string = (
f"{A1_hash}:{nonce}:{nc}:{cnonce}:{qop}:{A2_hash}"
).encode()
else:
response_string = (A1_hash + ":" + nonce + ":" + A2_hash).encode()

response_string = (A1_hash + ":" + nonce + ":" + A2_hash).encode()
response_hash = hashlib.md5(response_string).hexdigest()

return response_hash

@staticmethod
Expand All @@ -182,7 +176,7 @@ def generate_checksum(self, method: str, username: str):
message_hash = hmac.new(salt, message, hashlib.sha512).digest()
hashb64 = base64.b64encode(message_hash).decode()

return Checksum(hashb64, timestamp)
return Checksum(hashb64, timestamp)

async def connect(self):
self.is_running = asyncio.Event()
Expand Down Expand Up @@ -410,9 +404,9 @@ def __init__(self, call_id, local_tag, remote_tag) -> None:
self.call_id = call_id
self.local_tag = local_tag # The tag of the party who initiated the dialogue
self.remote_tag = remote_tag # The tag of the other party
self.transactions: List[SipTransaction] = (
[]
) # List to store transactions related to this dialogue
self.transactions: List[
SipTransaction
] = [] # List to store transactions related to this dialogue
self.cseq = Counter(random.randint(1, 2000))
self.state = DialogState.PREDIALOG # Start with the PREDIALOG state
self.events = {state: asyncio.Event() for state in DialogState}
Expand Down Expand Up @@ -481,7 +475,7 @@ def update_state(self, message):
self.events[self.state].set()

if self.state != self.previous_state:
logger.log(logging.DEBUG, f"Dialog state changed to -> {self.state}")
logger.log(logging.DEBUG, f"Dialog state changed to -> {self.state}")

@property
def local_session_info(self):
Expand Down Expand Up @@ -520,7 +514,6 @@ def __init__(self, message: str = "") -> None:
self._rport = None
self._branch = None
self._did = None
self._qop = None

@property
def type(self):
Expand Down Expand Up @@ -634,14 +627,6 @@ def realm(self):
def realm(self, value):
self._realm = value

@property
def qop(self):
return self._qop

@qop.setter
def qop(self, value):
self._qop = value

def parse(self):
data = self.data.split("\r\n\r\n")
self.headers_data = data[0]
Expand Down Expand Up @@ -721,7 +706,6 @@ def set_properties(self):
if auth_header:
self.nonce = auth_header.split('nonce="')[1].split('"')[0]
self.realm = auth_header.split('realm="')[1].split('"')[0]
self.qop = auth_header.split("qop=")[1].split('"')[1]
# dialog_id
contact_header = self.get_header("Contact")
if contact_header:
Expand Down Expand Up @@ -758,8 +742,8 @@ def generate_sdp(cls, ip, port, ssrc, supported_codecs):

sdp = "v=0\r\n"
sdp += f"o=- {random.randint(100000000, 999999999)} {random.randint(100000000, 999999999)} IN IP4 {ip}\r\n"
sdp += "s=PySIP Call\r\n"
sdp += "b=AS:84\r\n"
sdp += "s=PySIP Call\r\n"
sdp += "b=AS:84\r\n"
sdp += "t=0 0\r\n"
sdp += f"m=audio {port} RTP/AVP {' '.join([str(int(i)) for i in supported_codecs])}\r\n"
sdp += f"c=IN IP4 {ip}\r\n"
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pydub>=0.25.1
requests>=2.25.1
edge-tts>=5.0.0
python-dotenv>=0.19.0
scipy

0 comments on commit 7195ef7

Please sign in to comment.