Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pain in spain falls mainly on the number 4 toll crossbar #1178

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions WorkInProgress/francinum/cphones_new/_defines.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#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"
// ----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

Check failure on line 45 in WorkInProgress/francinum/cphones_new/_defines.dm

View workflow job for this annotation

GitHub Actions / Run Linters

#error HEY DIPSHIT TEAR OUT A LOT OF YOUR SHIT AND IMPLIMENT STATUS CODES INSTEAD OF SHITTING YOURSELF LIKE A MONKEY
64 changes: 64 additions & 0 deletions WorkInProgress/francinum/cphones_new/exchange.dm
Original file line number Diff line number Diff line change
@@ -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)
. = ..()
67 changes: 67 additions & 0 deletions WorkInProgress/francinum/cphones_new/extensions_info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//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

// 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",
"verb":"register",
"user":"$EXTNUM",
"auth":"$SECRET",
}
exchange reply:
{
"proto":"sip",
"verb":"ack",
"user":"$EXTNUM",
"auth_token":"$token",
}


//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",
}
30 changes: 30 additions & 0 deletions WorkInProgress/francinum/cphones_new/phone/_packet_handler.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/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.
*
* 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
102 changes: 102 additions & 0 deletions WorkInProgress/francinum/cphones_new/phone/phone.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#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 = ""

/// 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(src, /*speaker*/)

/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 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()

/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/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
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};
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
73 changes: 73 additions & 0 deletions WorkInProgress/francinum/cphones_new/phone/sip_call.dm
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading