Exemplo n.º 1
0
 def waitForCstaData(self, timeout=None):
     self.wait_lock.acquire()
     bkp = self.socket.gettimeout()
     if timeout: self.socket.settimeout(timeout)
     try:
         # header = ""
         # while not header:
         header = self.socket.recv(4)
         if not header:
             # disconnected socket
             return None
         datalength = int(''.join(["%02X" % x
                                   for x in header]), base=16) - 4
         data = b''
         while len(data) < datalength:
             data += self.socket.recv(datalength - len(data))
         # print('message:\n{}\nsize{}\n'.format(data,datalength))
         debug("Received on port {} message of length {}:\n\n".format(
             self.port, datalength) +
               (header + data
                ).decode("utf8", "backslashreplace").replace("\r\n", "\n"))
     finally:
         self.socket.settimeout(bkp)
     self.wait_lock.release()
     return header + data
Exemplo n.º 2
0
 def service_connection(self, key, mask):
     sock = key.fileobj
     data = key.data
     address = "{}:{}".format(*data.addr)
     if mask & selectors.EVENT_READ:
         try:
             link = self.get_address_link(address)
             inbytes = self.sip_endpoint.link.waitForSipData(timeout=5.0,
                                                             client=link)
             if inbytes is None:
                 self.sip_endpoint.link.socket.close()
                 self.sel.unregister(self.sip_endpoint.link.socket)
                 return
             inmessage = parseSip(inbytes)
             in_dialog = inmessage.get_dialog()
             if not in_dialog["to_tag"] and {
                     "Call-ID": in_dialog["Call-ID"],
                     "from_tag": in_dialog["from_tag"]
             } in self.sip_endpoint.dialogs:
                 self.sip_endpoint.dialogs.append(in_dialog)
             self.links.append((in_dialog, link))
             if inmessage.get_status_or_method() in self.handlers:
                 self.events[inmessage.get_status_or_method()].set()
                 self.buffers[inmessage.get_status_or_method()].append(
                     inmessage)
             else:
                 self.sip_endpoint.message_buffer.append(inmessage)
         except UnicodeDecodeError:
             debug("Ignoring malformed data")
Exemplo n.º 3
0
def setup(A,
          B,
          secondaryNumbers,
          user_address_pool,
          call_taker_address_pool,
          registration_expiration=360):
    B.connect(next(call_taker_address_pool),
              (params2["psap_thig_ip"], params2["psap_thig_port"]),
              params2["transport"])

    # Semi-Ugly way to handle OPTIONS messages from OSV when we don't shut down correctly :TODO
    B.link.register_for_event(("OPTIONS", {}, message["200_OK_1"]))

    try:
        register_primary(B,
                         secondaryNumbers,
                         expiration_in_seconds=registration_expiration)
    except:
        B.registered = False
        #debug(traceback.format_exc())
        traceback.print_exc()

    A.connect(next(user_address_pool),
              (params1["orig_osv_sipsm_ip"], params1["orig_osv_sipsm_port"]),
              params1["transport"])
    A.link.register_for_event(("OPTIONS", {}, message["200_OK_1"]))

    try:
        A.register(expiration_in_seconds=registration_expiration,
                   re_register_time=registration_expiration / 2)
    except:
        A.registered = False
        debug(traceback.format_exc())
Exemplo n.º 4
0
    def consume_sip_data(self):
        try:
            #debug("reading for sip data")
            content_length = -1
            data = b""
            data += self.sockfile.readline()

            while True:
                line = self.sockfile.readline()
                data += line
                if not line.strip():
                    break
                header, value = [x.strip() for x in line.split(b":", 1)]
                if header == b"Content-Length":
                    content_length = int(value)

            if content_length > 0:
                data += self.sockfile.read(content_length)

            if content_length == -1:
                #debug(data.decode())
                #raise Exception TODO
                print("No content length in message")
        except ValueError:
            debug(data.decode())
            debug(line.decode())
            print_exc()
            #raise
        except socket.timeout:
            #debug('Data received before timeout: "{}"'.format(data.decode()))
            print_exc()
            #raise
        self.handle_sip_message(data)
Exemplo n.º 5
0
 def get_address_link(self, address):
     for known_dialog, link in self.links:
         if "{}:{}".format(link.rip, link.rport) == address:
             return link
     debug(
         "No link found for address {}.\nAvailable dialogs and corresponding links:\n{}"
         .format(address, self.links))
Exemplo n.º 6
0
def flow(users, call_taker_pool, call_takers, secondary_numbers):

    A = next(users)
    B = next(call_taker_pool)
    line_appearance_index = next(secondary_numbers)
    C = B.secondary_lines[line_appearance_index]
    all_device_appearances = [
        device.secondary_lines[line_appearance_index] for device in call_takers
    ]
    appearance_invite_dialogs = {}

    print("{} will dial {} and device {} will pickup".format(
        A.number, C.number, B.number))

    A.send_new(C, message["Invite_SDP_1"])
    invite = C.waitForMessage("INVITE")
    assert "sip:" + C.number + "@" in invite["To"]
    C.reply(message["Trying_1"])
    C.reply(message["Ringing_1"])

    invited_lines = []

    for appearance in all_device_appearances:
        if appearance is not C:
            try:
                dialog = appearance.waitForMessage("INVITE",
                                                   timeout=0.1).get_dialog()
                appearance.reply(message["Trying_1"])
                appearance.reply(message["Ringing_1"])
                invited_lines.append((appearance, dialog))
            except TimeoutError:
                pass

    A.waitForMessage("180 Ringing", ignore_messages="100 Trying")
    C.reply(message["200_OK_SDP_1"])

    A.waitForMessage("200 OK")
    A.send(message["Ack_1"])

    C.waitForMessage("ACK")

    for appearance, dialog in invited_lines:
        try:
            appearance.set_dialog(dialog)
            appearance.waitForMessage("CANCEL")
            appearance.reply(message["200_OK_1"])
            appearance.send(message["487_Request_terminated"], dialog=dialog)
            appearance.waitForMessage("ACK")
        except TimeoutError:
            # Is it OK if some lines that got invite don't get CANCEL? Maybe if they get busy meanwhile.
            pass

    sleep(params1["call_duration"])

    A.send(message["Bye_1"], expected_response="200 OK")

    C.waitForMessage("BYE")
    C.reply(message["200_OK_1"])
    debug("SUCCESSFUL CALL: {} dial {} device {} pickup".format(
        A.number, C.number, B.number))
Exemplo n.º 7
0
 def get_dialog_link(self, dialog):
     for known_dialog, link in self.links:
         if known_dialog and (known_dialog == dialog or self.sip_endpoint.
                              get_complete_dialog(known_dialog) == dialog):
             return link
     debug(
         "No link found for dialog {}.\nAvailable dialogs and corresponding links:\n{}"
         .format(dialog, self.links))
Exemplo n.º 8
0
 def waitForData(self, timeout=None, buffer=4096):
     debug("Waiting on port {}".format(self.port))
     bkp = self.socket.gettimeout()
     if timeout: self.socket.settimeout(timeout)
     try:
         data = self.socket.recv(buffer)
     finally:
         self.socket.settimeout(bkp)
     debug("Received on port {}:\n\n".format(self.port) +
           data.decode("utf8", "backslashreplace").replace("\r\n", "\n"))
     return data
Exemplo n.º 9
0
 def send(self, data, encoding="utf8"):
     # self.socket.sendall(binascii.hexlify(bytes(data,"utf8")))
     if type(data) == type(b''):
         self.socket.sendall(data)
         debug(
             "Sent from port {}:\n\n".format(self.port) +
             data.decode("utf8", "backslashreplace").replace("\r\n", "\n"))
     else:
         self.socket.sendall(bytes(data, encoding))
         debug("Sent from port {}:\n\n".format(self.port) +
               data.replace("\r\n", "\n"))
Exemplo n.º 10
0
 def waitForCstaData(self):
     header = self.socket.recv(4)
     datalength = int(''.join(["%02X" % x for x in header]), base=16) - 4
     data = b''
     while len(data) < datalength:
         data += self.socket.recv(datalength - len(data))
     # print('message:\n{}\nsize{}\n'.format(data,datalength))
     debug("Received on port {}:\n\n".format(self.port) +
           (header +
            data).decode("utf8", "backslashreplace").replace("\r\n", "\n"))
     return header + data
Exemplo n.º 11
0
 def snapshot_device(csta_server, snapshot_device_message):
     user = snapshot_device_message["snapshotObject"]
     csta_server.csta_endpoint.get_user(user).update_incoming_transactions(
         snapshot_device_message)
     if not user:
         debug(
             "Invalid snapshot device user '{}'. Empty snapshotObject tag.".
             format(user))
         return
     csta_server.send("SnapshotDeviceResponse", to_user=user)
     csta_server.csta_endpoint.get_user(user).update_outgoing_transactions(
         snapshot_device_message)
Exemplo n.º 12
0
def register_secondary(primary, line, expiration_in_seconds=360):
    line.parameters["expires"] = expiration_in_seconds
    line.parameters["primary"] = primary.number
    line.parameters["primary_port"] = primary.port
    retry_count = 10
    for _ in range(retry_count):
        try:
            line.send_new(message_string=message["Register_secondary"],
                          expected_response="200 OK")
            debug("Registered " + line.number + " on " + primary.number)
            break
        except AssertionError:
            sleep(2)
Exemplo n.º 13
0
 def send(self, data, encoding="utf8"):
     # try:
     #     data = self.out_queue.get_nowait()
     # except Empty:
     #     return
     if type(data) == type(b''):
         debug(
             "Sending from port {}:\n\n".format(self.port) +
             data.decode("utf8", "backslashreplace").replace("\r\n", "\n"))
         self.internal_client.sendall(data)
     else:
         debug("Sending from port {}:\n\n".format(self.port) +
               data.replace("\r\n", "\n"))
         self.internal_client.sendall(bytes(data, encoding))
Exemplo n.º 14
0
def register_primary(sip_ep, secondary_numbers, expiration_in_seconds=360):
    sip_ep.re_register_timer = Timer(
        expiration_in_seconds / 2, register_primary,
        (sip_ep, secondary_numbers, expiration_in_seconds))
    sip_ep.re_register_timer.start()
    sip_ep.parameters["expires"] = expiration_in_seconds
    sip_ep.parameters["primary"] = sip_ep.number
    sip_ep.parameters["primary_port"] = sip_ep.port
    if not sip_ep.parameters["epid"]:
        sip_ep.parameters["epid"] = "SC" + util.randStr(6)
    debug("Sent register from " + sip_ep.number)
    sip_ep.send_new(message_string=message["Register_primary"],
                    expected_response="200 OK")
    debug("Got 200OK to register from " + sip_ep.number)
    if not sip_ep.secondary_lines:
        # first registration
        for n in secondary_numbers:
            line = SipEndpoint(n)
            line.use_link(sip_ep.link)
            sip_ep.secondary_lines.append(line)

    for line in sip_ep.secondary_lines:
        sleep(0.1)
        register_secondary(sip_ep, line)

    subscribe_primary(sip_ep)
    for line in sip_ep.secondary_lines:
        try:
            subscribe_secondary(line)
            line.registered = True
        except:
            debug(traceback.format_exc())
            raise
        debug("Subscribed " + line.number + " on " + sip_ep.number)
    sip_ep.registered = True
Exemplo n.º 15
0
 def monitor_user(csta_server, monitor_message):
     user = monitor_message["deviceObject"]
     if not user:
         debug(
             "Invalid monitor user '{}'. Empty deviceID tag.".format(user))
         return
     csta_server.csta_endpoint.new_user(user).parameters = {
         "monitorCrossRefID": csta_server.refid,
         "deviceID": user,
         "CSTA_CREATE_MONITOR_CROSS_REF_ID": csta_server.refid,
         "CSTA_USE_MONITOR_CROSS_REF_ID": csta_server.refid
     }
     csta_server.refid += 1
     csta_server.csta_endpoint.get_user(user).update_incoming_transactions(
         monitor_message)
     csta_server.send("MonitorStartResponse", to_user=user)
     csta_server.csta_endpoint.get_user(user).update_outgoing_transactions(
         monitor_message)
Exemplo n.º 16
0
 def service_connection(self, key, mask):
     # sock = key.fileobj
     # data = key.data
     if mask & selectors.EVENT_READ:
         try:
             inbytes = self.csta_endpoint.link.waitForCstaData(timeout=5.0)
             if inbytes is None:
                 self.csta_endpoint.link.socket.close()
                 self.sel.unregister(self.csta_endpoint.link.socket)
                 return
             inmessage = parseBytes(inbytes)
             if inmessage.event in self.handlers:
                 self.events[inmessage.event].set()
                 self.buffers[inmessage.event].append(inmessage)
             elif inmessage.event == "SystemStatusResponse":
                 # TODO: Ignoring incoming SystemStatusResponse for now
                 return
             else:
                 self.csta_endpoint.message_buffer.append(inmessage)
         except UnicodeDecodeError:
             debug("Ignoring malformed data")
Exemplo n.º 17
0
    def serve_forever(self):
        self.socket.bind((self.ip, self.port))
        if not self.protocol.upper() == "UDP":
            self.socket.listen()
        else:
            self.make_client(self.socket, (self.ip, self.port))
        self.port = self.socket.getsockname()[1]
        print("listening on", (self.ip, self.port))
        self.socket.setblocking(False)
        self.sel.register(self.socket, selectors.EVENT_READ, data=None)
        self.continue_serving = True
        while self.continue_serving:
            try:
                events = self.sel.select(timeout=60)
                for key, mask in events:
                    if key.data is None and self.protocol.upper() != "UDP":
                        self.accept_wrapper(key.fileobj)
                    else:
                        self.service_connection(key, mask)
            except socket.timeout:
                print("timeout")
                traceback.print_exc()
                continue
            except (IOError, socket.error):
                print("Disconnected. Waiting to reconnect")
                # self.sel.unregister(self.csta_endpoint.link.socket)
                continue
            except KeyboardInterrupt:
                self.shutdown()
            except:
                debug(traceback.format_exc())
                self.remove_address_link(key.fileobj)
                self.sel.unregister(key.fileobj)

        self.sel.unregister(self.socket)
        # self.socket.shutdown(socket.SHUT_RDWR)
        self.socket.close()
        self.sel.close()
        self.shutdown()
Exemplo n.º 18
0
def wait_for_call(B, c_index):
    C = B.secondary_lines[c_index]
    C.link.register_for_event(("BYE", {}, message["200_OK_1"]))
    debug(C.number + " waiting for calls from device " + B.number)
    while not B.shutdown:
        try:
            invite = C.waitForMessage("INVITE")
        except TimeoutError:
            continue

        try:
            C.set_dialog(invite.get_dialog())
            C.reply(message["Trying_1"])
            C.reply(message["Ringing_1"])

            other_lines = []
            assert "sip:" + C.number + "@" in invite["To"]

            C.reply(message["200_OK_SDP_1"])

            for line in B.secondary_lines:
                if line is not C:
                    try:
                        line.waitForMessage("INVITE", timeout=0.1)
                        line.reply(message["Trying_1"])
                        line.reply(message["Ringing_1"])
                        other_lines.append(line)
                    except TimeoutError:
                        pass

            C.waitForMessage("ACK")

            for line in other_lines:
                try:
                    line.waitForMessage("CANCEL", timeout=2)
                    line.reply(message["200_OK_1"])
                    line.send(message["487_Request_terminated"], dialog=invite.get_dialog())
                    line.waitForMessage("ACK")
                except TimeoutError:
                    # Is it OK if some lines that got invite don't get CANCEL? Maybe if they get busy meanwhile.
                    pass

            # C.waitForMessage("BYE")
            # C.reply(message["200_OK_1"])
        except:
            debug("FAILED CALL on B side: device "+B.number)
            debug(traceback.format_exc())
            continue
    debug(B.number + " exited")
Exemplo n.º 19
0
def flow(users, secondary_numbers):
    A = next(users)
    dial_number = next(secondary_numbers)
    try:

        print("{} will dial {}".format(A.number, dial_number))
        debug(A.number + "Sends invite to " + dial_number)
        A.send_new(dial_number, message["Invite_SDP_1"])
        debug(A.number + "Waiting 200 OK to INVITE from " + dial_number)
        A.waitForMessage("200 OK",
                         ignore_messages=["100 Trying", "180 Ringing"])
        A.send(message["Ack_1"])

        sleep(params1["call_duration"])

        A.send(message["Bye_1"], expected_response="200 OK")

        debug("SUCCESSFUL CALL: {} to {} ".format(A.number, dial_number))
    except KeyboardInterrupt:
        print("Stopping test")
        raise
    except:
        debug("FAILED CALL on A side: {} to {} ".format(A.number, dial_number))
        debug(traceback.format_exc())
Exemplo n.º 20
0
 def wait_for_data(self, timeout=None):
     debug("Waiting on address {}:{}".format(self.ip, self.port))
     try:
         data = self.in_queue.get(timeout=timeout)
         if data == "Stop":
             raise KeyboardInterrupt
     except Empty:
         debug("No message received after timeout")
         raise
     if isinstance(data, tuple):
         dbg = data[0]
     else:
         dbg = data
     debug("Received on address {}:{}:\n\n".format(self.ip, self.port) +
           dbg.decode("utf8").replace("\r\n", "\n"))
     return data
Exemplo n.º 21
0
 def waitForSipData(self, timeout=None, client=None):
     if not client:
         client = self
     client.wait_lock.acquire()
     debug("Waiting on port {}".format(client.port))
     bkp = client.socket.gettimeout()
     data = b""
     if timeout:
         client.socket.settimeout(timeout)
     try:
         data = wait_for_sip_data(client.sockfile)
     except ValueError:
         debug(data.decode())
         # debug(line.decode())
         raise
     except socket.timeout:
         debug('Data received before timeout: "{}"'.format(data.decode()))
         raise
     finally:
         client.socket.settimeout(bkp)
     debug("Received on port {}:\n\n".format(client.port) +
           data.decode("utf8").replace("\r\n", "\n"))
     client.wait_lock.release()
     return data
Exemplo n.º 22
0
    def waitForSipData(self, timeout=None):
        debug("Waiting on port {}".format(self.port))
        bkp = self.socket.gettimeout()
        if timeout: self.socket.settimeout(timeout)
        try:
            content_length = -1
            data = b""
            data += self.sockfile.readline()

            while True:
                line = self.sockfile.readline()
                data += line
                if not line.strip():
                    break
                header, value = [x.strip() for x in line.split(b":", 1)]
                if header == b"Content-Length":
                    content_length = int(value)

            if content_length > 0:
                data += self.sockfile.read(content_length)

            if content_length == -1:
                debug(data.decode())
                raise Exception("No content length in message")
        except ValueError:
            debug(data.decode())
            debug(line.decode())
            raise
        except socket.timeout:
            debug('Data received before timeout: "{}"'.format(data.decode()))
            raise
        finally:
            self.socket.settimeout(bkp)
        debug("Received on port {}:\n\n".format(self.port) +
              data.decode("utf8").replace("\r\n", "\n"))
        return data
Exemplo n.º 23
0
    def wait_for_csta_message(self,
                              for_user,
                              message,
                              ignore_messages=(),
                              timeout=5.0):
        """
        Wait for CSTA message
        :param for_user: The message intended recipient
        :param message: The message to wait for
        :param ignore_messages: Messages to ignore
        :param timeout: Defined timeout in seconds.
        :return: the CstaMessage received
        """
        inmessage = None
        user = self.users[for_user]
        other_users = [usr for usr in self.users if usr != user]

        while not inmessage:

            if self.message_buffer:
                # first get a message from the buffer
                inmessage = self.get_buffered_message(for_user)

            sleep(0.1)

            if self.server:
                continue

            if not inmessage:
                # no (more) buffered messages. try the network
                try:
                    # print("Waiting for", message)
                    # inbytes = self.link.waitForCstaData(timeout=0.2)
                    inbytes = self.link.waitForCstaData(timeout=timeout)
                    inmessage = parseBytes(inbytes)
                # except sock_timeout:
                #     inmessage = None
                #     timeout -= 0.2
                #     if timeout <= 0:
                #         raise
                #     else:
                #         continue
                except UnicodeDecodeError:
                    debug("Ignoring malformed data")
                    inmessage = None
                    continue
                except sock_timeout:
                    exception(for_user + " No" + message + " " +
                              str(self.message_buffer))

            inmessage_type = inmessage.event
            if inmessage_type in ignore_messages:
                inmessage = None
                continue

            if message and \
                    ((isinstance(message, str) and message != inmessage_type) or
                     (type(message) in (list, tuple) and not any([m == inmessage_type for m in message])) or
                     (inmessage["monitorCrossRefID"] and "monitorCrossRefID" in user.parameters and
                      inmessage["monitorCrossRefID"] != user.parameters["monitorCrossRefID"] and
                      inmessage_type != "MonitorStartResponse") or
                     inmessage.is_response() and inmessage.eventid not in user.out_transactions):

                # we have received an unexpected message.
                if inmessage["deviceID"] and any(usr in inmessage["deviceID"]
                                                 for usr in other_users):
                    # TODO apply here the deviceID fix as well
                    self.message_buffer.append(inmessage)
                    inmessage = None
                else:
                    raise AssertionError(
                        '{}: Got "{}" with callID {} and xrefid {} while expecting "{}" with '
                        'callID {} and xrefid {}.\n{} '.format(
                            for_user, inmessage_type, inmessage["callID"],
                            inmessage["monitorCrossRefID"], message,
                            user.parameters.get("callID", None),
                            user.parameters.get("monitorCrossRefID",
                                                None), inmessage))

        # Evaluate the invoke id
        user.update_incoming_transactions(inmessage)
        return inmessage
Exemplo n.º 24
0
def wait_for_call(B, c_index):
    C = B.secondary_lines[c_index]
    debug(C.number + " waiting for calls from device " + B.number)
    invite_dialogs = {}
    while not B.shutdown:
        try:
            # wait for any of the following messages
            inmessage = B.wait_for_message([
                "INVITE", "ACK", "CANCEL", "BYE", "NOTIFY", "SUBSCRIBE",
                "200 OK"
            ])

            inmessage_type = inmessage.get_status_or_method()
            to_number = inmessage["To"].split("@")[0].split(":")[1]
            line = [
                a for a in [B] + B.secondary_lines if a.number == to_number
            ][0]
            line.set_dialog(inmessage.get_dialog())
            line.set_transaction(inmessage.get_transaction())
            line.save_message(inmessage)

            if inmessage_type == "INVITE":
                line.reply(message["Trying_1"])
                line.reply(message["Ringing_1"])
                if line is C:
                    if not C.registered:
                        warning("Line {}@{}:{} is not registered".format(
                            C.number, C.ip, C.port))
                    line.reply(message["200_OK_SDP_1"])
                    print(C.number, "on", B.number, "picked up call from",
                          inmessage["From"].split("<")[0])
                else:
                    invite_dialogs[line.number] = inmessage.get_dialog()

            elif inmessage_type in ("ACK", "200 OK"):
                # Should we make sure all expected ACK have been received?
                continue

            elif inmessage_type == "CANCEL":
                line.reply(message["200_OK_1"])
                line.send(message["487_Request_Terminated"],
                          dialog=invite_dialogs[line.number])
                invite_dialogs.pop(line.number)

            elif inmessage_type in ("BYE", "NOTIFY"):
                line.reply(message["200_OK_1"])

            elif inmessage_type == "SUBSCRIBE":
                notify_after_subscribe(line, inmessage.get_dialog())
                # line.reply(message["200_OK_1"])
                # line.send(message_string=message["Notify_terminated_1"])

            else:
                raise Exception("Unexpected message received: " +
                                inmessage_type)

        except TimeoutError:
            continue

        except:
            debug("ERROR on B side: device " + B.number)
            debug(traceback.format_exc())
            continue

    debug(B.number + " exited")