From 3f21f30ecb78cc60b33aa468130ad9a83a8f9914 Mon Sep 17 00:00:00 2001 From: Francinum <5572280+francinum@users.noreply.github.com> Date: Mon, 30 Dec 2024 02:10:52 -0500 Subject: [PATCH 1/3] NetworkInitialize support --- code/controllers/subsystem/packetnets.dm | 23 +++++++++++++++++++++++ code/game/atoms.dm | 12 ++++++++++++ 2 files changed, 35 insertions(+) diff --git a/code/controllers/subsystem/packetnets.dm b/code/controllers/subsystem/packetnets.dm index e30bee6fa002..50dee0ca369f 100644 --- a/code/controllers/subsystem/packetnets.dm +++ b/code/controllers/subsystem/packetnets.dm @@ -54,6 +54,10 @@ SUBSYSTEM_DEF(packets) /// @everyone broadcast key var/gprs_broadcast_packet + /// NetworkInitialize requesters + /// For objects that need the full network ready. You probably don't need this. + VAR_PRIVATE/list/atom/network_initializers + /// Generates a unique (at time of read) ID for an atom, It just plays silly with the ref. /// Pass the target atom in as arg[1] /datum/controller/subsystem/packets/proc/generate_net_id(invoker) @@ -78,12 +82,23 @@ SUBSYSTEM_DEF(packets) return ..() /datum/controller/subsystem/packets/Initialize(start_timeofday) + + //Calculate the stupid magic bullshit detomatix_magic_packet = random_string(rand(16,32), GLOB.hex_characters) clownvirus_magic_packet = random_string(rand(16,32), GLOB.hex_characters) mimevirus_magic_packet = random_string(rand(16,32), GLOB.hex_characters) framevirus_magic_packet = random_string(rand(16,32), GLOB.hex_characters) gprs_broadcast_packet = random_string(rand(16,32), GLOB.hex_characters) pda_exploitable_register = pick_list(PACKET_STRING_FILE, "packet_field_names") + + // We're late enough in init order that all network devices have late initialized, + // so the network *should* be stable, we can now safely re-wake anything that has requested network readiness. + if(network_initializers) //...If there are any, of course + for(var/atom/initializer in network_initializers) + initializer.NetworkInitialize() + CHECK_TICK + network_initializers.Cut() //Drop the refs. + . = ..() /datum/controller/subsystem/packets/Recover() @@ -504,3 +519,11 @@ SUBSYSTEM_DEF(packets) ASSOC_UNSETEMPTY(recursive_contents, RECURSIVE_CONTENTS_RADIO_NONATMOS) UNSETEMPTY(location.important_recursive_contents) +/datum/controller/subsystem/packets/proc/request_network_initialize(atom/initializer) + if(initialized) + //Hi. If you're here, you might have tried to load a device that requests this as part of a + //post-roundstart map load. I apologize that the idea of touching the code required to support that + //at the current time of 02:09:24 EST is... Not on the table. Suck my dick. + CRASH("Attempted to request NetworkInitialize() after SSpackets has initialized!") + + LAZYADD(network_initializers, initializer) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 925df00ded57..492e360b0be3 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -293,6 +293,18 @@ /atom/proc/LateInitialize() set waitfor = FALSE +/** + * 'Network' Intialization, for code that should run after the packet network has stabilized. + * + * To have your NetworkInitialize proc be called, you must call SSpackets.request_network_initialize(src) + * in your Initialize() or LateInitialize() procs. + * + * This has limited usefulness for most atoms, Mostly used for direct-access based autoconfiguration of + * major network equipment, such as telephone exchanges or packet routing equipment (some day, I promise) + */ +/atom/proc/NetworkInitialize() + set waitfor = FALSE + /** * Top level of the destroy chain for most atoms * From badf077b17a07672d71be2ee6975d4eb4831ca30 Mon Sep 17 00:00:00 2001 From: Francinum <5572280+francinum@users.noreply.github.com> Date: Tue, 31 Dec 2024 03:12:42 -0500 Subject: [PATCH 2/3] pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain pain --- .../francinum/cphones_new/_defines.dm | 15 ++ .../francinum/cphones_new/exchange.dm | 64 +++++++ .../francinum/cphones_new/extensions_info.txt | 40 +++++ .../cphones_new/phone/_packet_handler.dm | 11 ++ .../francinum/cphones_new/phone/phone.dm | 88 ++++++++++ .../cphones_new/phone/sip_handler.dm | 50 ++++++ .../cphones_new/phone/voice_data_handler.dm | 160 ++++++++++++++++++ .../francinum/cphones_new/reg_info.dm | 12 ++ code/game/communications.dm | 12 ++ code/game/machinery/_machinery.dm | 2 +- code/game/machinery/datanet/_networked.dm | 20 ++- .../modular_computers/hardware/gprs_card.dm | 2 +- code/modules/power/data_terminal.dm | 7 +- daedalus.dme | 7 + 14 files changed, 483 insertions(+), 7 deletions(-) create mode 100644 WorkInProgress/francinum/cphones_new/_defines.dm create mode 100644 WorkInProgress/francinum/cphones_new/exchange.dm create mode 100644 WorkInProgress/francinum/cphones_new/extensions_info.txt create mode 100644 WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm create mode 100644 WorkInProgress/francinum/cphones_new/phone/phone.dm create mode 100644 WorkInProgress/francinum/cphones_new/phone/sip_handler.dm create mode 100644 WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm create mode 100644 WorkInProgress/francinum/cphones_new/reg_info.dm diff --git a/WorkInProgress/francinum/cphones_new/_defines.dm b/WorkInProgress/francinum/cphones_new/_defines.dm new file mode 100644 index 000000000000..af62e7b65569 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/_defines.dm @@ -0,0 +1,15 @@ +#define NETCLASS_EXCHANGE "PNET_TELEX" +#define NETCLASS_SIPPHONE "PNET_TELSUB" + +/// Ping Reply staple for telephone office identification +#define PACKET_FIELD_OFFICE_CODE "office_code" + +/// data[command] 2.0 +#define PACKET_FIELD_VERB "verb" + +/// A high level 'group' of verbs +#define PACKET_FIELD_PROTOCOL "proto" + #define PACKET_PROTOCOL_SIP "sip" + #define PACKET_SIP_VERB_REGISTER "register" + #define PACKET_SIP_VERB_ACKNOWLEDGE "ack" + #define PACKET_PROTOCOL_RTP "rtp" diff --git a/WorkInProgress/francinum/cphones_new/exchange.dm b/WorkInProgress/francinum/cphones_new/exchange.dm new file mode 100644 index 000000000000..df92e2cb6547 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/exchange.dm @@ -0,0 +1,64 @@ +/obj/machinery/telephony/exchange + name = "Telephone Exchange" + icon_state = "blackbox_b" + network_flags = NETWORK_FLAGS_STANDARD_CONNECTION + net_class = NETCLASS_EXCHANGE + + // This is... A complicated datastructure + // see extensions_info.txt in this folder for the layout. + var/list/datum/tel_extension/extensions + + /// Defaults to 000, Used to select an exchange to register to in 'complex environments' + var/office_number = "000" + +/obj/machinery/telephony/exchange/Initialize(mapload) + . = ..() + // Request NetInit for autodiscovery. + SSpackets.request_network_initialize(src) + extensions = list() + + +/obj/machinery/telephony/exchange/NetworkInitialize() + . = ..() + // Load ping_additional with the office code, so pinging devices can find us. + ping_addition = list("office_code" = office_number) + // The network is ready, we can now use it to resolve networked phones. + if(!netjack) + return //Or we can just go fuck ourselves that works too. + + //Determine all phones on our network. + for(var/obj/machinery/power/data_terminal/possible_jack as anything in netjack.powernet.data_nodes) + var/obj/machinery/telephony/telephone/registrant = possible_jack.connected_machine + if(!istype(registrant) || (registrant.init_office_code && (registrant.init_office_code != office_number))) + continue //Not you. + + var/datum/tel_extension/ext_record = assert_extension(registrant.init_extension) + + registrant.autoconf_secret = ext_record.auth_secret + //Program the office number so it knows who to care about. + registrant.init_office_code = office_number + if(!registrant.init_cnam) + continue // Not setting or writing a CNAM. + if(ext_record.cnam && (ext_record.cnam != registrant.init_cnam)) + stack_trace("Init phone CNAM conflict for extension [registrant.init_extension].") + ext_record.cnam = registrant.init_cnam + + +/// Creates a new extension. Returns the generated tel_extension record. +/// If the extension already exists, Return the existing record. +/obj/machinery/telephony/exchange/proc/assert_extension(new_ext) as /datum/tel_extension + RETURN_TYPE(/datum/tel_extension) + // Secrets must be numeric so they can be entered via config mode. + if(extensions[new_ext]) + return extensions[new_ext] + var/datum/tel_extension/record = new() + + record.name = new_ext + record.auth_secret = random_string(8, GLOB.numerals) + + extensions[new_ext] = record + + return record + +/obj/machinery/telephony/exchange/receive_signal(datum/signal/signal) + . = ..() diff --git a/WorkInProgress/francinum/cphones_new/extensions_info.txt b/WorkInProgress/francinum/cphones_new/extensions_info.txt new file mode 100644 index 000000000000..e7ea9141fe36 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/extensions_info.txt @@ -0,0 +1,40 @@ +//Var +list( + //Extension + "0003" = list( + //Authentication secret. + "secret" = "auth_secret", + //Caller Name. Replacement for p2p_phone friendly_name. Optional, Uses the extension number otherwise. + "cnam" = "Bar", + //Registered phones. + "reg" = list( + "net_addr_here" = bool:busy + ) + ) +) + + +// signal protocol + +user send: +{ + "proto":"sip", + "verb":"register", + "user":"$EXTNUM", + "auth":"$SECRET", +} +exchange reply: +{ + "proto":"sip", + "verb":"ack", + "user":"$EXTNUM", + "reg_token":"$token", +} + + +//keepalive, Intentionally doesn't include password. +{ + "proto":"sip", + "verb":"reauth", + "user":"$EXTNUM", +} diff --git a/WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm b/WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm new file mode 100644 index 000000000000..e4f93df29a02 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm @@ -0,0 +1,11 @@ +/datum/packet_handler + /// Who owns us? + var/obj/machinery/master + +/* + * Handlers are passed signals via receive_signal. + * If false, the packet is unhandled and should be passed to the next handler. + * + * We're just gonna trust this is only ever being called by the master, + * if it's not, go fuck yourself. seriously. + */ diff --git a/WorkInProgress/francinum/cphones_new/phone/phone.dm b/WorkInProgress/francinum/cphones_new/phone/phone.dm new file mode 100644 index 000000000000..db1339f398f7 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/phone/phone.dm @@ -0,0 +1,88 @@ +#define PACKET_HANDLER_SIGNALLING "sip" +#define PACKET_HANDLER_VOICE_DATA "rtp" + +/obj/machinery/telephony/telephone + + icon = 'goon/icons/obj/phones.dmi' + icon_state = "phone" + + // Mapload/setup/autodiscovery vars. These are only used to configure the signalling datum during "bootup" + // At all other times, all signalling state is stored on the signalling datum. + + /// The phone's assigned number, Used for mapload discovery + var/init_extension = "0000" + /// The phone's initial Caller NAMe. Used to give a name to the voice on the other side. + /// This is only used to configure the CNAM on the exchange. + /// If unset, will not attempt to change an existing CNAM, or if none is ever registered + /// for an extension, will display the calling phone number instead. + var/init_cnam + /// Used to select which exchange to register to. if unset, first come first serve. + /// Defaults to `"NEVER"`, which will not autoconfigure at all. + var/init_office_code = "NEVER" + /// Used to authenticate with the exchange. + var/tmp/autoconf_secret = "" + + /// Set to TRUE once the SIP core has fully booted. + var/tmp/net_booted = FALSE + + /// Is our write-protect screw installed? If not, Allow entering configuration mode. + var/config_screwed = TRUE + /// Are we currently in the config handler? If so, what state are we in. + var/tmp/configuring = FALSE + + // Queue of packets, We drain this on process. Only broadcast or packets meant for us get queued. + var/tmp/list/datum/signal/packet_queue + + // Our packet handlers, We use these to compartmentalize behaviour so I don't go fucking insane. + var/tmp/list/datum/packet_handler/packet_handlers + + var/tmp/obj/item/food/grown/banana/handset + +/obj/machinery/telephony/telephone/LateInitialize() + . = ..() + packet_queue = list() + packet_handlers = list() + //Init our various handlers. + packet_handlers[PACKET_HANDLER_VOICE_DATA] = new /datum/packet_handler/voice_data() + +/obj/machinery/telephony/telephone/Destroy() + . = ..() + QDEL_LIST_ASSOC(packet_handlers) + +/obj/machinery/telephony/telephone/examine(mob/user) + . = ..() + if(config_screwed) + . += span_info("Odd. One of the screws is [span_alert("red")].") + else + . += span_info("One of the screws is very loose. It's [span_alert("red")], unlike the rest.") + + + +/obj/machinery/telephony/telephone/process() + // We have not 'booted' + if(packet_handlers[PACKET_HANDLER_SIGNALLING]) + packet_handlers[PACKET_HANDLER_SIGNALLING] = new /datum/packet_handler/sip_registration( + init_extension, + init_office_code, + autoconf_secret + ) + if(length(packet_queue)) + handle_packet_queue() + +/obj/machinery/telephony/telephone/receive_signal(datum/signal/signal) + if(..() == RECEIVE_SIGNAL_FINISHED)//Handled by default. + return + var/datum/signal/storable = signal.Copy() + packet_queue += storable + +/obj/machinery/telephony/telephone + +/obj/machinery/telephony/telephone/proc/handle_packet_queue() + for(var/datum/signal/packet as anything in packet_queue) + var/list/data = packet.data + switch(data[PACKET_FIELD_PROTOCOL]) + if(PACKET_PROTOCOL_SIP) + packet_handlers[PACKET_HANDLER_SIGNALLING]?.receive_signal(packet) + if(PACKET_PROTOCOL_RTP) + packet_handlers[PACKET_HANDLER_VOICE_DATA].receive_signal(packet) + //else {drop_packet}; diff --git a/WorkInProgress/francinum/cphones_new/phone/sip_handler.dm b/WorkInProgress/francinum/cphones_new/phone/sip_handler.dm new file mode 100644 index 000000000000..9aa8fc5a69a3 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/phone/sip_handler.dm @@ -0,0 +1,50 @@ +/datum/packet_handler/sip_registration + /// Cooldown for sending the next keepalive/heartbeat to the exchange to keep registered. + COOLDOWN_DECLARE(keepalive_timeout) + /// Cooldown for registration. We will always attempt to re-register if we go off-hook. + COOLDOWN_DECLARE(registration_timeout) + + VAR_PRIVATE/office_code + VAR_PRIVATE/auth_name + VAR_PRIVATE/auth_secret + + /// Our authentication refresh token, think of it as a second, temporary password. + /// if null, we are not registered at all. Start trying to register again with slowly increasing backoff. + VAR_PRIVATE/auth_refresh_token + /// Exponential backoff factor. + VAR_PRIVATE/backoff_factor = 0 + + + /// Address of our server. + VAR_PRIVATE/server_address + VAR_PRIVATE/master_netid + + /* Master Interface: + * + * output: receive_sip_packet(datum/signal/varname) + * > Receives a data-complete SIP signalling packet. + * d_addr is already set, so it should mostly be sent + * straight out of post_signal. + * + * control: + * New(extension, officecode, auth_secret) + * > Load map-varedit and autoconf information. + * The phone still has to 'boot' and register itself. + * This just provides it the correct information to start with. + * + */ + + +/datum/packet_handler/sip_registration/New(_ext, _office, _auth) + . = ..() + auth_name = _ext + auth_secret = _auth + office_code = _office + +/datum/packet_handler/sip_registration/process(delta_time) + if(COOLDOWN_FINISHED()) + +/datum/packet_handler/sip_registration/receive_signal(datum/signal/signal) + + + diff --git a/WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm b/WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm new file mode 100644 index 000000000000..575a4d0ab3cf --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm @@ -0,0 +1,160 @@ +/datum/packet_handler/voice_data + /// What atom do we make speak? Think: Phone Handset. + VAR_PRIVATE/atom/movable/speaker + /// Are we active and doing things, pretty much noops every function if false. + VAR_PRIVATE/active = FALSE + /// Are we mute? We'll still hear packets coming in, we just can't send. + VAR_PRIVATE/mute = FALSE + /// Are we *allowed* to mute, useful for + VAR_PRIVATE/allow_mute = TRUE + //Visual Configuration, used to pretend to be a radio. + VAR_PRIVATE/vis_span = "radio" + VAR_PRIVATE/vis_name = "UNSET_NAME" + + // How far should we listen or broadcast heard messages. + VAR_PRIVATE/hear_range = 1 + VAR_PRIVATE/broadcast_range = 2 + + /* Master Interface: + * + * output: receive_voice_packet(datum/signal/varname) + * > Receives a data-complete voice packet, the master is + * expected to make any modifications they need (addressing, etc) + * before sending it out via the usual means. + * + * control: + * New(speaker,allow_mute, hear_range, broadcast_range) + * > Provide a speaker atom for this handler to parasitize. + * > allow_mute allows you to enable or disable use-inhand mute. + * > It is not required to mute via proccall. (Think: PA speakers.) + * > You can also control the range the speaker can hear/broadcast relayed speech. + * handler.activate(vis_name) + * > Begin + * + */ + + +/datum/packet_handler/voice_data/New(_speaker, _allow_mute) + . = ..() + allow_mute = _allow_mute + set_speaker(_speaker) + +/datum/packet_handler/voice_data/Destroy(force, ...) + release_speaker() + master = null + return ..() + +/datum/packet_handler/voice_data/proc/set_visuals(_span, _name) + vis_span = _span || vis_span + vis_name = _name || vis_name + +/datum/packet_handler/voice_data/proc/set_speaker(atom/movable/new_speaker) + // Do we already have a speaker? + if(!new_speaker || (speaker && speaker != new_speaker)) + //Release the old one. + release_speaker() + + speaker = new_speaker + speaker.become_hearing_sensitive(ref(src)) + RegisterSignal(speaker, COMSIG_MOVABLE_HEAR, PROC_REF(handle_speaker_hearing)) + if(allow_mute) + RegisterSignal(speaker, COMSIG_ITEM_ATTACK_SELF, PROC_REF(handle_attack_self)) + +//Release a speaker +/datum/packet_handler/voice_data/proc/release_speaker() + UnregisterSignal(speaker, list(COMSIG_MOVABLE_HEAR,COMSIG_ITEM_ATTACK_SELF)) + speaker.lose_hearing_sensitivity(ref(src)) + +/datum/packet_handler/voice_data/proc/handle_attack_self(mob/user) + SIGNAL_HANDLER + if(mute) + to_chat(user, span_notice("You mute the [speaker].")) + else + to_chat(user, span_notice("You unmute the [speaker].")) + set_mute(!mute) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/datum/packet_handler/voice_data/proc/handle_speaker_hearing(datum/source, list/hearing_args) + SIGNAL_HANDLER + if(mute) + return + + // Unpack the vars we need. + var/atom/movable/heard_speaker = hearing_args[HEARING_SPEAKER] + var/sound_loc = hearing_args[HEARING_SOUND_LOC] + var/list/message_mods = hearing_args[HEARING_MESSAGE_MODE] + + var/atom/movable/checked_thing = sound_loc || heard_speaker //If we have a location, we care about that, otherwise we're speaking directly from something. + if(!IN_GIVEN_RANGE(get_turf(speaker), get_turf(checked_thing), hear_range)) + return + + //START SHAMELESS RADIO CARGOCULTING + var/filtered_mods = list() + if (message_mods[MODE_CUSTOM_SAY_EMOTE]) + filtered_mods[MODE_CUSTOM_SAY_EMOTE] = message_mods[MODE_CUSTOM_SAY_EMOTE] + filtered_mods[MODE_CUSTOM_SAY_ERASE_INPUT] = message_mods[MODE_CUSTOM_SAY_ERASE_INPUT] + + encode_voice(heard_speaker, hearing_args[HEARING_RAW_MESSAGE], , hearing_args[HEARING_SPANS], language=hearing_args[HEARING_LANGUAGE], message_mods=filtered_mods) + //END SHAMELESS RADIO CARGOCULTING + +/datum/packet_handler/voice_data/proc/encode_voice(atom/movable/talking_movable, message, channel, list/spans, datum/language/language, list/message_mods) + if(mute || !active || !talking_movable || !message || !talking_movable.IsVocal()) + return + + //The third var is the 'radio'. It's null. Go fuck yourself. + var/atom/movable/virtualspeaker/v_speaker = new(null, talking_movable, null) + if(isliving(talking_movable)) + var/mob/living/libbing = v_speaker + v_speaker.voice_type = libbing.voice_type + + + +/datum/packet_handler/voice_data/proc/set_mute(new_mute) + if(mute == new_mute) + return + + if(mute) + mute = FALSE + else + mute = TRUE + +/// Enable the voice relay behaviour. Will always unmute. +/datum/packet_handler/voice_data/proc/activate(voice_name = null) + set_visuals(_name = voice_name) + set_mute(FALSE) + active = TRUE + +/datum/packet_handler/voice_data/proc/deactivate() + active = FALSE + +/datum/packet_handler/voice_data/receive_signal(datum/signal/signal) + if(!active) + return TRUE + if(!speaker) + CRASH("No speaker. Fix your bullshit.") + + var/list/data = signal.data + + var/list/radio_bullshit_override = list("span"=vis_span, "name"=vis_name) + + var/atom/movable/virtualspeaker/admission_of_defeat = data["virtualspeaker"] + var/sound/funnysound + if(admission_of_defeat.voice_type) + var/funnysound_index = copytext_char(data["message"], -1) + switch(funnysound_index) + if("?") + funnysound = voice_type2sound[admission_of_defeat.voice_type]["?"] + if("!") + funnysound = voice_type2sound[admission_of_defeat.voice_type]["!"] + else + funnysound = voice_type2sound[admission_of_defeat.voice_type][admission_of_defeat.voice_type] + + + playsound(speaker, funnysound || 'modular_pariah/modules/radiosound/sound/radio/syndie.ogg', funnysound ? 300 : 30, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, falloff_exponent = 0) + var/rendered = speaker.compose_message(data["virtualspeaker"], data["language"], data["message"], radio_bullshit_override, data["spans"], data["message_mods"]) + for(var/atom/movable/hearing_movable as anything in get_hearers_in_view(2, speaker)-speaker) + if(!hearing_movable)//theoretically this should use as anything because it shouldnt be able to get nulls but there are reports that it does. + stack_trace("somehow theres a null returned from get_hearers_in_view() in send_speech!") + continue + + hearing_movable.Hear(rendered, data["virtualspeaker"], data["language"], data["message"], radio_bullshit_override, data["spans"], data["message_mods"], speaker.speaker_location(), message_range = INFINITY) diff --git a/WorkInProgress/francinum/cphones_new/reg_info.dm b/WorkInProgress/francinum/cphones_new/reg_info.dm new file mode 100644 index 000000000000..a0a9054c90d3 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/reg_info.dm @@ -0,0 +1,12 @@ +/datum/tel_extension + /// 'name' - the extension number. Used mostly for VV. Canon extension is this thing's key in an exchanges' extensions list. + var/name + /// Auth secret. Required to act as this extension. + var/auth_secret + /// Caller Name. Replacement for p2p_phone friendly_name. Optional, Uses the extension number otherwise. + var/cnam + /// Registered phones, k,v netaddr=exp_time, Registration will expire if not renewed every minute. + var/list/registered = list() + /// Registration tokens, k,v netaddr=token. Used for keepalive. + var/list/reg_tokens = list() + diff --git a/code/game/communications.dm b/code/game/communications.dm index 23e953b6b8c6..8a0c4e4b3000 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -226,3 +226,15 @@ GLOBAL_LIST_INIT(freq2icon, list( src.data = data || list() src.transmission_method = transmission_method src.logging_data = logging_data + +/// Create a duplicate of the signal that's safe for store-and-forward situations. +/// No assurance is made that the *data* can survive this, of course. +/datum/signal/proc/Copy() + var/datum/signal/duplicate = new(null, data.Copy(), transmission_method, logging_data) + // Now for the vars new doesn't do for us. + duplicate.author = author + duplicate.frequency_datum = frequency_datum + duplicate.frequency = frequency + duplicate.range = range + duplicate.filter_list = filter_list + duplicate.has_magic_data = has_magic_data diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index e0f163acde1a..23aef6438471 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -171,7 +171,7 @@ /// A short string shown to players fingerprinting the device type as part of `command:ping` var/net_class = "PNET_CALL_A_PRIEST" /// Additional data stapled to pings, reduces network usage for some machines. - var/ping_addition = null + var/list/ping_addition = null ///Used by SSairmachines for optimizing scrubbers and vent pumps. COOLDOWN_DECLARE(hibernating) diff --git a/code/game/machinery/datanet/_networked.dm b/code/game/machinery/datanet/_networked.dm index f46bc7aaf335..6cef38e848d3 100644 --- a/code/game/machinery/datanet/_networked.dm +++ b/code/game/machinery/datanet/_networked.dm @@ -29,7 +29,9 @@ SHOULD_CALL_PARENT(TRUE) . = ..() //Should the subtype *probably* stop caring about this packet? if(isnull(signal)) - return + return RECEIVE_SIGNAL_FINISHED + if(machine_stat & (BROKEN|NOPOWER)) + return RECEIVE_SIGNAL_FINISHED var/sigdat = signal.data //cache for sanic speed this joke is getting old. if(sigdat[PACKET_DESTINATION_ADDRESS] != src.net_id)//This packet doesn't belong to us directly if(sigdat[PACKET_DESTINATION_ADDRESS] == NET_ADDRESS_PING)// But it could be a ping, if so, reply @@ -37,7 +39,16 @@ if(!isnull(tmp_filter) && tmp_filter != net_class) return RECEIVE_SIGNAL_FINISHED //Blame kapu for how stupid this looks :3 - post_signal(create_signal(sigdat[PACKET_SOURCE_ADDRESS], list("command"=NET_COMMAND_PING_REPLY,"netclass"=src.net_class,"netaddr"=src.net_id)+src.ping_addition)) + post_signal( + create_signal( + sigdat[PACKET_SOURCE_ADDRESS], + list( + "command"=NET_COMMAND_PING_REPLY, + "netclass"=src.net_class, + "netaddr"=src.net_id + )+src.ping_addition + ) + ) return RECEIVE_SIGNAL_FINISHED//regardless, return 1 so that machines don't process packets not intended for them. return RECEIVE_SIGNAL_CONTINUE // We are the designated recipient of this packet, we need to handle it. @@ -66,3 +77,8 @@ if(!netjack) return netjack.disconnect_machine(src) + +/// Called just before the network jack is removed. +/// Cannot be used to abort disconnection. +/obj/machinery/proc/netjack_disconnected(var/obj/machinery/power/data_terminal/disconnecting) + return diff --git a/code/modules/modular_computers/hardware/gprs_card.dm b/code/modules/modular_computers/hardware/gprs_card.dm index 4b5ad47f60b7..8291a843f531 100644 --- a/code/modules/modular_computers/hardware/gprs_card.dm +++ b/code/modules/modular_computers/hardware/gprs_card.dm @@ -121,7 +121,7 @@ return //We can't hold volatile signals. if(length(packet_queue) == queue_max) pop_signal() //Discard the first signal in the queue - packet_queue += signal + packet_queue += signal.Copy() return /// Get the length of the packet queue diff --git a/code/modules/power/data_terminal.dm b/code/modules/power/data_terminal.dm index 6ff2efee2c38..7fe7ce6e02da 100644 --- a/code/modules/power/data_terminal.dm +++ b/code/modules/power/data_terminal.dm @@ -13,9 +13,9 @@ AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) /obj/machinery/power/data_terminal/Destroy() - . = ..() // Disconnect from the seizing machine. disconnect_machine(connected_machine) + return ..() /obj/machinery/power/data_terminal/should_have_node() return TRUE @@ -80,10 +80,11 @@ /// Attempt to disconnect from a data terminal. /obj/machinery/power/data_terminal/proc/disconnect_machine(obj/machinery/leaving_machine) - if(!leaving_machine && !connected_machine) // No connected machine in the first place + if(!leaving_machine || !connected_machine) // One of these is null, beating you with a hammer. return if(leaving_machine != connected_machine)//Let's just be sure. CRASH("[leaving_machine] [REF(leaving_machine)] attempted to disconnect despite not owning the data terminal (owned by [connected_machine] [REF(connected_machine)])!") + leaving_machine.netjack_disconnected(src) UnregisterSignal(leaving_machine, COMSIG_MOVABLE_MOVED) leaving_machine.netjack = null connected_machine = null @@ -126,7 +127,7 @@ "You start screwing [src] into \the [T]", "You hear quiet metal scraping.") tool.play_tool_sound(src, 50) - if(!do_after(user, src, 10 SECONDS, DO_PUBLIC)) + if(!do_after(user, src, 5 SECONDS, DO_PUBLIC)) to_chat(user, span_warning("You need to stand still to install [src]!")) return TOOL_ACT_TOOLTYPE_SUCCESS diff --git a/daedalus.dme b/daedalus.dme index 00701db4e464..ed9a2cb4e974 100644 --- a/daedalus.dme +++ b/daedalus.dme @@ -4790,4 +4790,11 @@ #include "modular_pariah\modules\indicators\code\typing_indicator.dm" #include "modular_pariah\modules\pixel_shift\code\pixel_shift.dm" #include "modular_pariah\modules\radiosound\code\headset.dm" +#include "WorkInProgress\francinum\cphones_new\_defines.dm" +#include "WorkInProgress\francinum\cphones_new\exchange.dm" +#include "WorkInProgress\francinum\cphones_new\reg_info.dm" +#include "WorkInProgress\francinum\cphones_new\phone\_packet_handler.dm" +#include "WorkInProgress\francinum\cphones_new\phone\phone.dm" +#include "WorkInProgress\francinum\cphones_new\phone\sip_handler.dm" +#include "WorkInProgress\francinum\cphones_new\phone\voice_data_handler.dm" // END_INCLUDE From 501631c7e4328a9b6152bbcd431a3f36be123ad8 Mon Sep 17 00:00:00 2001 From: Francinum <5572280+francinum@users.noreply.github.com> Date: Sun, 5 Jan 2025 04:04:38 -0500 Subject: [PATCH 3/3] you are in a maze of twisty little menus, all alike. --- .../francinum/cphones_new/_defines.dm | 30 ++++ .../francinum/cphones_new/extensions_info.txt | 31 +++- .../cphones_new/phone/_packet_handler.dm | 19 +++ .../francinum/cphones_new/phone/phone.dm | 30 +++- .../francinum/cphones_new/phone/sip_call.dm | 73 ++++++++ .../cphones_new/phone/sip_handler.dm | 158 +++++++++++++++++- .../cphones_new/phone/voice_data_handler.dm | 5 +- daedalus.dme | 1 + 8 files changed, 330 insertions(+), 17 deletions(-) create mode 100644 WorkInProgress/francinum/cphones_new/phone/sip_call.dm diff --git a/WorkInProgress/francinum/cphones_new/_defines.dm b/WorkInProgress/francinum/cphones_new/_defines.dm index af62e7b65569..bd621c168f1b 100644 --- a/WorkInProgress/francinum/cphones_new/_defines.dm +++ b/WorkInProgress/francinum/cphones_new/_defines.dm @@ -10,6 +10,36 @@ /// A high level 'group' of verbs #define PACKET_FIELD_PROTOCOL "proto" #define PACKET_PROTOCOL_SIP "sip" + // ----REGISTRATION---- #define PACKET_SIP_VERB_REGISTER "register" + #define PACKET_SIP_FIELD_USER "user" + #define PACKET_SIP_FIELD_REGISTER_SECRET "auth" + #define PACKET_SIP_VERB_REAUTH "reauth" + #define PACKET_SIP_FIELD_AUTH_TOKEN "auth_token" #define PACKET_SIP_VERB_ACKNOWLEDGE "ack" + //shares PACKET_SIP_FIELD_AUTH_TOKEN + #define PACKET_SIP_VERB_NEGATIVE_ACKNOWLEDGE "nack" + #define PACKET_SIP_FIELD_NACK_CAUSE "cause" + #define PACKET_SIP_NACK_CAUSE_BAD_SECRET "badsecret" + + // ----CALL CONTROL---- + #define PACKET_SIP_FIELD_CALLID "call-id" + #define PACKET_SIP_VERB_INVITE "invite" + /// Sender + #define PACKET_SIP_INVITE_FIELD_FROM "from" + /// Invite recipient number. + #define PACKET_SIP_INVITE_FIELD_TO "to" + #define PACKET_SIP_VERB_SESSION "session" + #define PACKET_SIP_SESSION_ #define PACKET_PROTOCOL_RTP "rtp" + + +// SIP State values +#define SIP_STATE_CODE 1 //List Index + #define SIP_STATE_CODE_START_RINGING 1 //No data + #define SIP_STATE_CODE_STOP_RINGING 2 //No data + #define SIP_STATE_TERMINATE 3 // data: Cause Code + #define SIP_STATE_REG_FAILURE 4 //No data +#define SIP_STATE_DATA 2 //List Index + +#error HEY DIPSHIT TEAR OUT A LOT OF YOUR SHIT AND IMPLIMENT STATUS CODES INSTEAD OF SHITTING YOURSELF LIKE A MONKEY diff --git a/WorkInProgress/francinum/cphones_new/extensions_info.txt b/WorkInProgress/francinum/cphones_new/extensions_info.txt index e7ea9141fe36..50ea1ac39ab9 100644 --- a/WorkInProgress/francinum/cphones_new/extensions_info.txt +++ b/WorkInProgress/francinum/cphones_new/extensions_info.txt @@ -16,6 +16,24 @@ list( // signal protocol +// Skeleton: +{ + "proto":"sip", + "verb": VERB, + "seq": $RAND_SEQ // Used to associate ACKs with various flows. - NOT ANYMORE THIS IS ANNOYING +} + +//Verbs: +/* + * REGISTER: Grants a reauth token upon login, allows placing calls via INVITE + * REAUTH: like register, returns a new auth token (via ACK) upon successful reauth, else NACK + * INVITE: Request to start a call with another extension. + * RINGING: Informs the station that the far side is now ringing. + * CANCEL: Sent by the requesting client. Cancel the call, free all equipment. + * + */ + +// Registration user send: { "proto":"sip", @@ -28,13 +46,22 @@ exchange reply: "proto":"sip", "verb":"ack", "user":"$EXTNUM", - "reg_token":"$token", + "auth_token":"$token", } -//keepalive, Intentionally doesn't include password. +//keepalive, Use the auth token instead. { "proto":"sip", "verb":"reauth", "user":"$EXTNUM", + "auth_token":"$REAUTHTOKEN", +} + +// Start Call +{ + "proto":"sip", + "verb": "invite", + "to" : "$EXT", + "auth_token":"$token", } diff --git a/WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm b/WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm index e4f93df29a02..a72fb1c00a15 100644 --- a/WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm +++ b/WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm @@ -8,4 +8,23 @@ * * We're just gonna trust this is only ever being called by the master, * if it's not, go fuck yourself. seriously. + * + * Standard packet output function: + * receive_handler_packet(datum/packet_handler/sender, datum/signal/signal) + * + * Other handlers may define more required functions. */ + +/obj/machinery/proc/receive_handler_packet(datum/packet_handler/sender, /datum/signal/signal, ...) + return + +/datum/packet_handler/New(_master) + . = ..() + master = _master + +/datum/packet_handler/Destroy(force, ...) + master = null + return ..() + +/datum/packet_handler/process(delta_time) + return diff --git a/WorkInProgress/francinum/cphones_new/phone/phone.dm b/WorkInProgress/francinum/cphones_new/phone/phone.dm index db1339f398f7..55d5d1e7c5f8 100644 --- a/WorkInProgress/francinum/cphones_new/phone/phone.dm +++ b/WorkInProgress/francinum/cphones_new/phone/phone.dm @@ -22,9 +22,6 @@ /// Used to authenticate with the exchange. var/tmp/autoconf_secret = "" - /// Set to TRUE once the SIP core has fully booted. - var/tmp/net_booted = FALSE - /// Is our write-protect screw installed? If not, Allow entering configuration mode. var/config_screwed = TRUE /// Are we currently in the config handler? If so, what state are we in. @@ -43,7 +40,7 @@ packet_queue = list() packet_handlers = list() //Init our various handlers. - packet_handlers[PACKET_HANDLER_VOICE_DATA] = new /datum/packet_handler/voice_data() + packet_handlers[PACKET_HANDLER_VOICE_DATA] = new /datum/packet_handler/voice_data(src, /*speaker*/) /obj/machinery/telephony/telephone/Destroy() . = ..() @@ -59,13 +56,16 @@ /obj/machinery/telephony/telephone/process() - // We have not 'booted' - if(packet_handlers[PACKET_HANDLER_SIGNALLING]) + // We intentionally delay this until game start. + if(!packet_handlers[PACKET_HANDLER_SIGNALLING]) packet_handlers[PACKET_HANDLER_SIGNALLING] = new /datum/packet_handler/sip_registration( + src, init_extension, init_office_code, autoconf_secret ) + else + packet_handlers[PACKET_HANDLER_SIGNALLING].process() if(length(packet_queue)) handle_packet_queue() @@ -75,8 +75,17 @@ var/datum/signal/storable = signal.Copy() packet_queue += storable -/obj/machinery/telephony/telephone - +/obj/machinery/telephony/telephone/receive_handler_packet(datum/packet_handler/sender, datum/signal/signal, list/sip_state) + switch(sender.type) + if(/datum/packet_handler/sip_registration) + //SIP data handler can also send control information instead, it'll only send one or the other. + if(sip_state) + switch(sip_state[SIP_STATE_CODE]) + if(SIP_STATE_CODE_START_RINGING) + else + if(/datum/packet_handler/voice_data) + +// time to play dress-up as a subsystem /obj/machinery/telephony/telephone/proc/handle_packet_queue() for(var/datum/signal/packet as anything in packet_queue) var/list/data = packet.data @@ -86,3 +95,8 @@ if(PACKET_PROTOCOL_RTP) packet_handlers[PACKET_HANDLER_VOICE_DATA].receive_signal(packet) //else {drop_packet}; + if(data[PACKET_CMD] == NET_COMMAND_PING_REPLY) //If this is a ping reply, it also goes to the SIP handler. + packet_handlers[PACKET_HANDLER_SIGNALLING]?.receive_signal(packet) + packet_queue -= packet + if(TICK_CHECK) + return diff --git a/WorkInProgress/francinum/cphones_new/phone/sip_call.dm b/WorkInProgress/francinum/cphones_new/phone/sip_call.dm new file mode 100644 index 000000000000..5cf3e7978ce3 --- /dev/null +++ b/WorkInProgress/francinum/cphones_new/phone/sip_call.dm @@ -0,0 +1,73 @@ +// Holds state about an individual SIP call. + +/datum/sip_call + + /// The controlling SIP handler. + var/datum/sip_handler/owner + + /// Are we originating this call? + /// Behaviour basically flips if this is false. + var/originating = TRUE + + /// Randomly generated call ID. Used for tracing and for identification. md5(world.time+ref(src)) + var/call_id + + /// ORIGINATE: The number we are calling. + /// ANSWER: The number calling us. + var/calling_number + + var/our_number + + /// Server address + var/target_addr + + /* Call Setup */ + /// ORIGINATE: Call is being set up, Play no comfort noises. If timeout, cancel and terminate self. + #define CALLSTATE_SETUP 0 + /// ORIGINATE: Far side is ringing, play ringback. + /// ANSWER: We are ringing, Instruct the phone to start ringing. + #define CALLSTATE_RINGING 1 + + + /// We are talking, Stop noises, instruct the SIP handler to get everything ready for audio. + #define CALLSTATE_TALKING 2 + + /* Call Teardown/Error */ + /// The connection was closed, check cause_code and go from there. + #define CALLSTATE_TERMINATE 3 + + /// Current call state. + var/state = 0 + + /// Q.850 Cause Code (Beats coming up with my own system) for which our call was terminated. + var/cause_code + +/datum/sip_call/New(_master, _our_number, _calling_number, _target_addr, _call_id) + . = ..() + call_id = _call_id || md5("[world.time][ref(src)]") + our_number = _our_number + calling_number = _calling_number + target_addr = _target_addr + if(_call_id) + // Being supplied a call ID means we are NOT originating. + originating = FALSE + +/datum/sip_call/receive_signal(datum/signal/signal) + . = ..() + +// +/datum/sip_call/proc/place_call(destination = calling_number) + if(!calling_number) + calling_number = destination + var/datum/signal/invite = new( + null, + list( + PACKET_DESTINATION_ADDRESS = target_addr, + PACKET_FIELD_PROTOCOL = PACKET_PROTOCOL_SIP, + PACKET_FIELD_VERB = PACKET_SIP_VERB_INVITE, + PACKET_SIP_INVITE_FIELD_FROM = our_number, + PACKET_SIP_INVITE_FIELD_TO = calling_number, + PACKET_SIP_FIELD_CALLID = call_id + ) + ) + return invite diff --git a/WorkInProgress/francinum/cphones_new/phone/sip_handler.dm b/WorkInProgress/francinum/cphones_new/phone/sip_handler.dm index 9aa8fc5a69a3..03e642c4bc03 100644 --- a/WorkInProgress/francinum/cphones_new/phone/sip_handler.dm +++ b/WorkInProgress/francinum/cphones_new/phone/sip_handler.dm @@ -4,8 +4,11 @@ /// Cooldown for registration. We will always attempt to re-register if we go off-hook. COOLDOWN_DECLARE(registration_timeout) + /// Office number to look for. VAR_PRIVATE/office_code + /// Our extension number. VAR_PRIVATE/auth_name + /// Our login secret. VAR_PRIVATE/auth_secret /// Our authentication refresh token, think of it as a second, temporary password. @@ -13,38 +16,185 @@ VAR_PRIVATE/auth_refresh_token /// Exponential backoff factor. VAR_PRIVATE/backoff_factor = 0 - + /// Secondary backoff factor for waiting for a ping. This curve starts shallow before getting very strong. + VAR_PRIVATE/ping_backoff_factor = 0 + /// Reauth count, after some amount, just give up and assume de-registration. + VAR_PRIVATE/reauth_attempts = 0 /// Address of our server. VAR_PRIVATE/server_address + /// Owner device address. VAR_PRIVATE/master_netid + VAR_PRIVATE/datum/sip_call/current_call + /* Master Interface: * - * output: receive_sip_packet(datum/signal/varname) + * output: + * receive_handler_update(datum/packet_handler/sender, datum/signal/signal, sip_state) * > Receives a data-complete SIP signalling packet. * d_addr is already set, so it should mostly be sent * straight out of post_signal. * + * > Can also send control state information via 'sip_state' + * as a list of 2 values, a code, and free additional data. + * list(SIP_STATE_CODE = $NUM, SIP_STATE_DATA = $WHATEVER) + * + * * control: * New(extension, officecode, auth_secret) * > Load map-varedit and autoconf information. * The phone still has to 'boot' and register itself. * This just provides it the correct information to start with. * + * + * */ -/datum/packet_handler/sip_registration/New(_ext, _office, _auth) +/datum/packet_handler/sip_registration/New(_master, _ext, _office, _auth) . = ..() auth_name = _ext auth_secret = _auth office_code = _office + // Give us a random cooldown between 1 and 5 seconds in half-second increments. Just to spread out when these things fully wake up. + COOLDOWN_START(src, registration_timeout, (rand(2,10)/2) SECONDS) /datum/packet_handler/sip_registration/process(delta_time) - if(COOLDOWN_FINISHED()) + // If we aren't registered and we're off cooldown for attempting to. + if(!auth_refresh_token && COOLDOWN_FINISHED(src, registration_timeout)) + // Do we know which server to try to register to? + if(!server_address) + locate_server() + return + // If we do, try and connect to it. + attempt_registration() + return + + //We either have a token or the cooldown hasn't finished yet, if we do have one and the keepalive timeout is finished... + else if(auth_refresh_token && COOLDOWN_FINISHED(src, keepalive_timeout)) + // If we've not tried this enough + if(reauth_attempts < 10) + do_keepalive() + else + // Give up. + clear_registration() + +// Send out a ping +/datum/packet_handler/sip_registration/proc/locate_server() + +/datum/packet_handler/sip_registration/proc/attempt_registration() + var/datum/signal/reg_packet = new( + null, + list( + PACKET_DESTINATION_ADDRESS = master_netid, + PACKET_FIELD_PROTOCOL = PACKET_PROTOCOL_SIP, + PACKET_FIELD_VERB = PACKET_SIP_VERB_REGISTER, + PACKET_SIP_FIELD_USER = auth_name, + PACKET_SIP_FIELD_REGISTER_SECRET = auth_secret + ) + ) + master.receive_handler_packet(reg_packet) + ping_backoff_factor++ + /* This factor will, after a few attmps, drastically slow down attempts to contact the exchange. + * https://www.desmos.com/calculator/hmctyrgrux + * For cases where the phone is physically disconnected from the exchange. + * These numbers were chosen through the advanced process of ass.pull() + */ + COOLDOWN_START(src, registration_timeout, (floor(0.5*(2.1**backoff_factor))) SECONDS) + +/// Reset all state, start over. +/datum/packet_handler/sip_registration/proc/clear_registration() + // Clear the registration. + auth_refresh_token = null + // Forget about our server. + server_address = null + // Reset our timeouts and scaling factors. + ping_backoff_factor = 0 + backoff_factor = 0 + reauth_attempts = 0 + COOLDOWN_RESET(src, keepalive_timeout) + COOLDOWN_RESET(src, registration_timeout) + + + +/datum/packet_handler/sip_registration/proc/do_keepalive() + var/datum/signal/reg_packet = new( + null, + list( + PACKET_DESTINATION_ADDRESS = master_netid, + PACKET_FIELD_PROTOCOL = PACKET_PROTOCOL_SIP, + PACKET_FIELD_VERB = PACKET_SIP_VERB_REAUTH, + PACKET_SIP_FIELD_USER = auth_name, + PACKET_SIP_FIELD_AUTH_TOKEN = auth_refresh_token + ) + ) + master.receive_handler_packet(reg_packet) + // This does NOT get a backoff period, we re-attempt every 2 seconds for 20 seconds, and then give up, assuming de-registration. + COOLDOWN_START(src, keepalive_timeout, 2 SECONDS) + /datum/packet_handler/sip_registration/receive_signal(datum/signal/signal) + var/list/data = signal.data + //Are you our SIP server? + if(data[PACKET_SOURCE_ADDRESS] == server_address) + // Do you have a token for us? + if((data[PACKET_FIELD_VERB] == PACKET_SIP_VERB_ACKNOWLEDGE) && (data[PACKET_SIP_FIELD_AUTH_TOKEN])) + // Our registered server is issuing us an auth token, sweet. + refresh_auth(data[PACKET_SIP_FIELD_AUTH_TOKEN]) + return + + // Do we have a token? + if(!auth_refresh_token) + //NACK from server before full auth? We probably did something wrong, Lock up and pass the cause up to the master to alert. + if((data[PACKET_FIELD_VERB] == PACKET_SIP_VERB_NEGATIVE_ACKNOWLEDGE) && (data[PACKET_SIP_FIELD_NACK_CAUSE])) + COOLDOWN_START(src, registration_timeout, INFINITY) + master.receive_handler_packet(src, null, list(SIP_STATE_REG_FAILURE, data[PACKET_SIP_FIELD_NACK_CAUSE])) + return + return + + // We have a registration, and the server isn't here to renew one. Do we have an active call? If so, pass the packet to it. + if(current_call) + current_call.receive_signal(signal) + return + // No current call, are they trying to place one? + if((data[PACKET_FIELD_VERB] == PACKET_SIP_VERB_INVITE)) + incoming_call(signal) + + //Is this an *INCOMING* invite? + if(data[PACKET_FIELD_VERB] == PACKET_SIP_VERB_ACKNOWLEDGE) + else + // No? Who cares. + return + +/// Fully refresh the keepalive timeout, usually as part of initial registration or during a timeout. +/datum/packet_handler/sip_registration/proc/refresh_auth(new_token) + auth_refresh_token = new_token + ping_backoff_factor = 0 + backoff_factor = 0 + reauth_attempts = 0 + COOLDOWN_START(src, keepalive_timeout, (2 MINUTES)+(rand(0,60) SECONDS)) + +/// Place a call to a designated extension, Sets the active call, and sends an INVITE packet out the master. +/datum/packet_handler/sip_registration/proc/place_call(destination) + current_call = new( + src, + auth_name, + destination, + server_address, + ) + // Ask the call datum to 'place' the call, and give us the invite packet to send off. + var/datum/signal/invite = current_call.place_call() + master.receive_handler_packet(src, invite) +/datum/packet_handler/sip_registration/proc/incoming_call(datum/signal/signal) + current_call = new( + src, + auth_name, + signal[PACKET_SIP_INVITE_FIELD_FROM], + server_address, //You think I'm gonna bother with direct media? You're high as fuck. + signal[PACKET_SIP_FIELD_CALLID] + ) + master.receive_handler_packet(src, invite) diff --git a/WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm b/WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm index 575a4d0ab3cf..2af6a7d09ece 100644 --- a/WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm +++ b/WorkInProgress/francinum/cphones_new/phone/voice_data_handler.dm @@ -17,7 +17,7 @@ /* Master Interface: * - * output: receive_voice_packet(datum/signal/varname) + * output: receive_handler_packet(datum/packet_handler/sender, datum/signal/signal) * > Receives a data-complete voice packet, the master is * expected to make any modifications they need (addressing, etc) * before sending it out via the usual means. @@ -34,14 +34,13 @@ */ -/datum/packet_handler/voice_data/New(_speaker, _allow_mute) +/datum/packet_handler/voice_data/New(_master, _speaker, _allow_mute) . = ..() allow_mute = _allow_mute set_speaker(_speaker) /datum/packet_handler/voice_data/Destroy(force, ...) release_speaker() - master = null return ..() /datum/packet_handler/voice_data/proc/set_visuals(_span, _name) diff --git a/daedalus.dme b/daedalus.dme index ed9a2cb4e974..2ca987695b6c 100644 --- a/daedalus.dme +++ b/daedalus.dme @@ -4795,6 +4795,7 @@ #include "WorkInProgress\francinum\cphones_new\reg_info.dm" #include "WorkInProgress\francinum\cphones_new\phone\_packet_handler.dm" #include "WorkInProgress\francinum\cphones_new\phone\phone.dm" +#include "WorkInProgress\francinum\cphones_new\phone\sip_call.dm" #include "WorkInProgress\francinum\cphones_new\phone\sip_handler.dm" #include "WorkInProgress\francinum\cphones_new\phone\voice_data_handler.dm" // END_INCLUDE