/****************************************************************************** * Copyright (c) 2000-2019 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Gabor Szalai - initial implementation and initial documentation ******************************************************************************/ module DIAMETER_Mapping { //========================================================================= // Import Part //========================================================================= import from DIAMETER_Types all; import from TCPasp_Types all; import from TCPasp_PortType all; import from SCTPasp_Types all; import from SCTPasp_PortType all; //========================================================================= // Module Parameters //========================================================================= modulepar { // hostname and portnumber are mandatory parameters. They specify either // Destination host and portnumber in client mode, or // Listening interface and portnumber in server mode charstring tsp_hostname := ""; integer tsp_portnumber := -1; // In client mode, this parameter enables reconnecting if the // channel was closed by the other peer. boolean tsp_reconnect := true; // Timeouts: float tsp_reconnect_timeout := 2.0; float tsp_connect_timeout := 5.0; }; //========================================================================= // Data Types //========================================================================= // PDU Type for server mode, where the client_id is included // with the diameter PDU type record PDU_DIAMETER_Server { PDU_DIAMETER data, integer client_id } // ASP for Notifying users type record ASP_DIA_Mapping_Notification { NotificationEnum notification, PDU_DIAMETER pdu optional, integer client_id optional } // ASP for registering users for notifications type enumerated ASP_DIA_Mapping_Registration { REGISTER, REGISTER_ACK, DEREGISTER, DEREGISTER_ACK } // Incoming SCTP events are stored in this type: type union SCTPPortMessage { ASP_SCTP_ASSOC_CHANGE f_AssocChange, ASP_SCTP_PEER_ADDR_CHANGE f_PeerAddrChange, ASP_SCTP_SEND_FAILED f_SendFailed, ASP_SCTP_REMOTE_ERROR f_RemoteError, ASP_SCTP_SHUTDOWN_EVENT f_ShutdownEvent, ASP_SCTP_PARTIAL_DELIVERY_EVENT f_PartialDeliveryEvent, ASP_SCTP_ADAPTION_INDICATION f_AdaptionIndication, ASP_SCTP_SENDMSG_ERROR f_SendMsgError, ASP_SCTP_RESULT f_Result } // Incoming TCP events are stored in this type: type union TCPPortMessage { ASP_TCP_Connected f_Connected, ASP_TCP_Close f_Close, ASP_TCP_Listen_result f_ListenResult, ASP_TCP_Connect_result f_ConnectResult } // Available notifications: type enumerated NotificationEnum { CONNECTION_IS_UP, CONNECTION_IS_DOWN, SEND_FAILED, TRANSMISSION_FAILED } type record RoutingTableElementType { octetstring hop_by_hop_id, octetstring end_to_end_id, DIAMETER_CT ptcId } type record of RoutingTableElementType RoutingTableType; type record of DIAMETER_CT MappingUserTableType; //========================================================================= // Port Types //========================================================================= // The port type that conveys DIAMETER messages and ASP of the mapping CT type port DIAMETERmsg_PT message { inout PDU_DIAMETER; inout PDU_DIAMETER_Server; inout ASP_DIA_Mapping_Notification; inout ASP_DIA_Mapping_Registration; } with {extension "internal"} //========================================================================= // Component Types //========================================================================= // Component type for DIAMETER_Mapping users: type component DIAMETER_CT { port DIAMETERmsg_PT DIA_PCO; } // The mapping component type component DIAMETER_Mapping_CT { port DIAMETERmsg_PT DIA_PCO; port TCPasp_PT TCP_PCO; port SCTPasp_PT SCTP_PCO; // In client mode, the routing table keeps track of the sent diameter // messages in order that the mapping component can route back the // corresponding answers to the users properly. var RoutingTableType v_RoutingTable := {}; // In client mode, this table stores the user components that subscribed // to notifications var MappingUserTableType v_MappingUserTable := {}; var TCPPortMessage v_TCPPortMsg; //TCP Events are stored here var SCTPPortMessage v_SCTPPortMsg; //SCTP Events are stored here var boolean v_State := false; //Connection state // Timers for reconnection mode: timer Ttimeout; timer Treconnect; } //========================================================================= // Constants //========================================================================= // This constant specifyes the upper layer protocol ID that will be // embedded in the SCTP messages. Since IANA hasn't assigned a value // for Diameter yet, 20 was chosen as an arbitrary number const integer c_DIAMETER_ppid := 20; //========================================================================= // Templates //========================================================================= template ASP_SCTP_Connect t_ASP_SCTP_Connect ( template charstring p_host, template integer p_portnum) := { peer_hostname := p_host, peer_portnumber := p_portnum }; template ASP_TCP_Connect t_ASP_TCP_Connect ( template charstring p_host, template integer p_portnum) := { hostname := p_host, portnumber := p_portnum, local_hostname := omit, local_portnumber := omit }; template ASP_TCP_Listen t_ASP_TCP_Listen ( template charstring p_host, template integer p_port) := { portnumber := p_port, local_hostname := p_host }; template ASP_SCTP_ASSOC_CHANGE t_ASP_SCTP_AssocChange ( template integer p_cid, template SAC_STATE p_state) := { client_id := p_cid, sac_state := p_state }; template ASP_DIA_Mapping_Notification t_notification ( template NotificationEnum p_notification, template PDU_DIAMETER p_pdu, template integer p_cid) := { notification := p_notification, pdu := p_pdu, client_id := p_cid }; //========================================================================= // Altsteps //========================================================================= // Altstep for handling SCTP events in server mode altstep as_SCTPEventHandling_Server() runs on DIAMETER_Mapping_CT { [] SCTP_PCO.receive(ASP_SCTP_ASSOC_CHANGE:?) -> value v_SCTPPortMsg.f_AssocChange { if (v_SCTPPortMsg.f_AssocChange.sac_state == SCTP_COMM_LOST) { DIA_PCO.send(t_notification( CONNECTION_IS_DOWN, omit, v_SCTPPortMsg.f_AssocChange.client_id) ); } else if (v_SCTPPortMsg.f_AssocChange.sac_state == SCTP_COMM_UP) { DIA_PCO.send(t_notification( CONNECTION_IS_UP, omit, v_SCTPPortMsg.f_AssocChange.client_id) ); } repeat; } [] SCTP_PCO.receive(ASP_SCTP_SHUTDOWN_EVENT:?) -> value v_SCTPPortMsg.f_ShutdownEvent { //There is nothing to do, an ASSOC_CHANGE must arrive before log("This message is currently ignored: ", v_SCTPPortMsg.f_ShutdownEvent); repeat; } [] SCTP_PCO.receive(ASP_SCTP_RESULT:?) -> value v_SCTPPortMsg.f_Result { // There is nothing to do: an ASSOC_CHANGE(SCTP_COMM_UP) must arrive. log("This message is currently ignored: ", v_SCTPPortMsg.f_Result); repeat; } [] SCTP_PCO.receive(ASP_SCTP_SENDMSG_ERROR:?) -> value v_SCTPPortMsg.f_SendMsgError { DIA_PCO.send(t_notification( TRANSMISSION_FAILED, f_DIAMETER_Dec(v_SCTPPortMsg.f_SendMsgError.data), v_SCTPPortMsg.f_SendMsgError.client_id)); repeat; } [] SCTP_PCO.receive(ASP_SCTP_SEND_FAILED:?) -> value v_SCTPPortMsg.f_SendFailed { DIA_PCO.send(t_notification( SEND_FAILED, omit, v_SCTPPortMsg.f_SendFailed.client_id) ); repeat; } [] SCTP_PCO.receive(ASP_SCTP_PEER_ADDR_CHANGE:?) -> value v_SCTPPortMsg.f_PeerAddrChange { log("This message is currently ignored: ", v_SCTPPortMsg.f_PeerAddrChange); repeat; } [] SCTP_PCO.receive(ASP_SCTP_REMOTE_ERROR:?) -> value v_SCTPPortMsg.f_RemoteError { log("This message is currently ignored: ", v_SCTPPortMsg.f_RemoteError); repeat; } [] SCTP_PCO.receive(ASP_SCTP_PARTIAL_DELIVERY_EVENT:?) -> value v_SCTPPortMsg.f_PartialDeliveryEvent { log("This message is currently ignored: ", v_SCTPPortMsg.f_PartialDeliveryEvent); repeat; } [] SCTP_PCO.receive(ASP_SCTP_ADAPTION_INDICATION:?) -> value v_SCTPPortMsg.f_AdaptionIndication { log("This message is currently ignored: ", v_SCTPPortMsg.f_AdaptionIndication); repeat; } } // Altstep for handling SCTP events in client mode altstep as_SCTPEventHandling_Client() runs on DIAMETER_Mapping_CT { var DIAMETER_CT vl_dia_comp; var PDU_DIAMETER vl_dia_pdu; [] SCTP_PCO.receive(ASP_SCTP_ASSOC_CHANGE:?) -> value v_SCTPPortMsg.f_AssocChange { if (v_SCTPPortMsg.f_AssocChange.sac_state == SCTP_COMM_LOST) { v_State := false; if (tsp_reconnect) { Treconnect.start(tsp_reconnect_timeout); } else { log("Warning: SCTP connection is lost."& "Reconnect mode is not set. Exiting."); stop; } if (Ttimeout.running) { Ttimeout.stop; } f_sendNotificationToUsers(t_notification(CONNECTION_IS_DOWN, omit, omit)); } else if (v_SCTPPortMsg.f_AssocChange.sac_state == SCTP_COMM_UP) { v_State := true; if (Treconnect.running) { Treconnect.stop;} if (Ttimeout.running) { Ttimeout.stop; } f_sendNotificationToUsers(t_notification(CONNECTION_IS_UP, omit, omit)); } repeat; } [] SCTP_PCO.receive(ASP_SCTP_SHUTDOWN_EVENT:?) -> value v_SCTPPortMsg.f_ShutdownEvent { v_State := false; repeat; } [] SCTP_PCO.receive(ASP_SCTP_RESULT:?) -> value v_SCTPPortMsg.f_Result { if (Treconnect.running) { Treconnect.stop; } if (Ttimeout.running) { Ttimeout.stop; } if (v_SCTPPortMsg.f_Result.error_status == false) { log("SCTP connection was succesful: ", v_SCTPPortMsg.f_Result); // There is nothing to do: an ASSOC_CHANGE(SCTP_COMM_UP) must arrive. } else { log("SCTP connection was not established, error message: ", v_SCTPPortMsg.f_Result.error_message); // We don't have to wait for Ttimeout // initiating reconnection timer: v_State := false; if (tsp_reconnect) { Treconnect.start(tsp_reconnect_timeout); } else { log("Warning: SCTP connection was not established."& "Reconnect mode is not set. Exiting."); stop; } } repeat; } [] SCTP_PCO.receive(ASP_SCTP_SENDMSG_ERROR:?) -> value v_SCTPPortMsg.f_SendMsgError { vl_dia_pdu := f_DIAMETER_Dec(v_SCTPPortMsg.f_SendMsgError.data); vl_dia_comp := f_findInRT( v_RoutingTable, vl_dia_pdu.hop_by_hop_id, vl_dia_pdu.end_to_end_id ); if (vl_dia_comp != null) { DIA_PCO.send(t_notification( TRANSMISSION_FAILED, vl_dia_pdu, omit) ) to vl_dia_comp; f_delFromRT( v_RoutingTable, vl_dia_pdu.hop_by_hop_id, vl_dia_pdu.end_to_end_id ); } else { log("Diameter couldn't be sent with unknown "& "hop_by_hop_id and end_to_end_id:" & "Dropping at SCTP SENDMSG ERROR"); } repeat; } [] SCTP_PCO.receive(ASP_SCTP_SEND_FAILED:?) -> value v_SCTPPortMsg.f_SendFailed { f_sendNotificationToUsers(t_notification(SEND_FAILED, omit, omit)); repeat; } [] SCTP_PCO.receive(ASP_SCTP_PEER_ADDR_CHANGE:?) -> value v_SCTPPortMsg.f_PeerAddrChange { log("This message is currently ignored: ", v_SCTPPortMsg.f_PeerAddrChange); repeat; } [] SCTP_PCO.receive(ASP_SCTP_REMOTE_ERROR:?) -> value v_SCTPPortMsg.f_RemoteError { log("This message is currently ignored: ", v_SCTPPortMsg.f_RemoteError); repeat; } [] SCTP_PCO.receive(ASP_SCTP_PARTIAL_DELIVERY_EVENT:?) -> value v_SCTPPortMsg.f_PartialDeliveryEvent { log("This message is currently ignored: ", v_SCTPPortMsg.f_PartialDeliveryEvent); repeat; } [] SCTP_PCO.receive(ASP_SCTP_ADAPTION_INDICATION:?) -> value v_SCTPPortMsg.f_AdaptionIndication { log("This message is currently ignored: ", v_SCTPPortMsg.f_AdaptionIndication); repeat; } } // Altstep for handling TCP events in server mode altstep as_TCPEventHandling_Server() runs on DIAMETER_Mapping_CT { [] TCP_PCO.receive(ASP_TCP_Connected:?) -> value v_TCPPortMsg.f_Connected { DIA_PCO.send(t_notification( CONNECTION_IS_UP, omit, v_TCPPortMsg.f_Connected.client_id) ); repeat; } [] TCP_PCO.receive(ASP_TCP_Close:?) -> value v_TCPPortMsg.f_Close { DIA_PCO.send(t_notification( CONNECTION_IS_DOWN, omit, v_TCPPortMsg.f_Close.client_id) ); repeat; } } // Altstep for handling TCP events in client mode altstep as_TCPEventHandling_Client() runs on DIAMETER_Mapping_CT { [] TCP_PCO.receive(ASP_TCP_Connect_result:?) -> value v_TCPPortMsg.f_ConnectResult { if (Treconnect.running) { Treconnect.stop; } if (Ttimeout.running) { Ttimeout.stop; } if (v_TCPPortMsg.f_ConnectResult.client_id == -1) { v_State := false; if (tsp_reconnect) { Treconnect.start(tsp_reconnect_timeout); } else { log("Warning: TCP connection was not established."& " Reconnect mode is not set. Exiting."); stop; } } else { v_State := true; if (Treconnect.running) { Treconnect.stop;} if (Ttimeout.running) { Ttimeout.stop; } f_sendNotificationToUsers(t_notification(CONNECTION_IS_UP, omit, omit)); } repeat; } [] TCP_PCO.receive(ASP_TCP_Close:?) -> value v_TCPPortMsg.f_Close { v_State := false; if (tsp_reconnect) { Treconnect.start(tsp_reconnect_timeout); } else { log("Warning: TCP connection is lost."& " Reconnect mode is not set. Exiting."); stop; } if (Ttimeout.running) { Ttimeout.stop; } f_sendNotificationToUsers(t_notification(CONNECTION_IS_DOWN, omit, omit)); repeat; } } // Altstep for reconnection and no response timeouts altstep as_handleSCTPTimeouts() runs on DIAMETER_Mapping_CT { [] Treconnect.timeout { log("SCTP reconnection is starting"); SCTP_PCO.send(t_ASP_SCTP_Connect(tsp_hostname, tsp_portnumber)); Ttimeout.start(tsp_connect_timeout); repeat; } [] Ttimeout.timeout { log("SCTP connection establishment failed: no response, but trying again"); SCTP_PCO.send(t_ASP_SCTP_Connect(tsp_hostname, tsp_portnumber)); Ttimeout.start(tsp_connect_timeout); repeat; } } // Altstep for reconnection and no response timeouts altstep as_handleTCPTimeouts() runs on DIAMETER_Mapping_CT { [] Treconnect.timeout { log("TCP reconnection is starting"); TCP_PCO.send(t_ASP_TCP_Connect(tsp_hostname, tsp_portnumber)); Ttimeout.start(tsp_connect_timeout); repeat; } [] Ttimeout.timeout { log("TCP connection establishment failed: no response, but trying again"); TCP_PCO.send(t_ASP_TCP_Connect(tsp_hostname, tsp_portnumber)); Ttimeout.start(tsp_connect_timeout); repeat; } } // Altstep for handling mapping client database altstep as_handleMappingUserMessages() runs on DIAMETER_Mapping_CT { var DIAMETER_CT vl_dia_ct; [] DIA_PCO.receive(ASP_DIA_Mapping_Registration:REGISTER) -> sender vl_dia_ct { f_putInUserTable(v_MappingUserTable, vl_dia_ct); DIA_PCO.send(ASP_DIA_Mapping_Registration:REGISTER_ACK) to vl_dia_ct; if (v_State == true) { DIA_PCO.send(t_notification(CONNECTION_IS_UP, omit, omit)) to vl_dia_ct; } else { DIA_PCO.send(t_notification(CONNECTION_IS_DOWN, omit, omit)) to vl_dia_ct; } log("Mapping client has been registered"); repeat; } [] DIA_PCO.receive(ASP_DIA_Mapping_Registration:DEREGISTER) -> sender vl_dia_ct { f_delFromUserTable(v_MappingUserTable, vl_dia_ct); DIA_PCO.send(ASP_DIA_Mapping_Registration:DEREGISTER_ACK) to vl_dia_ct; log("Mapping client has been deregistered"); repeat; } } //========================================================================= // Functions //========================================================================= // Main mapping function for client mode, over TCP function f_DIA_TCP_Mapping_Client() runs on DIAMETER_Mapping_CT { var ASP_TCP vl_TCP_msg; var PDU_DIAMETER vl_DIA_msg; var DIAMETER_CT vl_DIA_comp; const octetstring cl_zero := '00000000'O; f_initTCPConnection(); alt { [] as_TCPEventHandling_Client(); [] TCP_PCO.receive(ASP_TCP:?) -> value vl_TCP_msg { log("TCP Packet received"); vl_DIA_msg := f_DIAMETER_Dec(vl_TCP_msg.data); vl_DIA_comp := f_findInRT( v_RoutingTable, vl_DIA_msg.hop_by_hop_id, vl_DIA_msg.end_to_end_id ); if (vl_DIA_comp != null) { DIA_PCO.send(vl_DIA_msg) to vl_DIA_comp; f_delFromRT( v_RoutingTable, vl_DIA_msg.hop_by_hop_id, vl_DIA_msg.end_to_end_id ); log("Diameter message sent to the corresponding component"); } else { log("Diameter message arrived with unknown"& " hop_by_hop_id and end_to_end_id: dropping: ", vl_DIA_msg); } repeat; } [] as_handleTCPTimeouts() [] DIA_PCO.receive(PDU_DIAMETER:?) -> value vl_DIA_msg sender vl_DIA_comp { log("DIA message received") if (v_State == true) { if (vl_DIA_msg.hop_by_hop_id == cl_zero and vl_DIA_msg.end_to_end_id == cl_zero) { vl_DIA_msg.hop_by_hop_id := f_DIAMETER_genHopByHop(); vl_DIA_msg.end_to_end_id := f_DIAMETER_genEndToEnd(); } vl_TCP_msg.data := f_DIAMETER_Enc(vl_DIA_msg); vl_TCP_msg.client_id := omit; TCP_PCO.send(vl_TCP_msg); v_RoutingTable[sizeof(v_RoutingTable)] := { vl_DIA_msg.hop_by_hop_id, vl_DIA_msg.end_to_end_id, vl_DIA_comp } log("Message sent via TCP"); } else { DIA_PCO.send(t_notification(TRANSMISSION_FAILED, vl_DIA_msg, omit)) to vl_DIA_comp; log("Diameter message is not forwarded"& " since the TCP connection is down"); } repeat; } [] as_handleMappingUserMessages() [] DIA_PCO.receive { log("Unexpected DIAMETER message is dropped"& " at function f_DIA_TCP_Mapping_Client()"); } [] TCP_PCO.receive { log("Unexpected TCP message is dropped"& " at function f_DIA_TCP_Mapping_Client()"); } } } // Main mapping function for client mode, over SCTP function f_DIA_SCTP_Mapping_Client() runs on DIAMETER_Mapping_CT { var ASP_SCTP vl_SCTP_msg; var PDU_DIAMETER vl_DIA_msg; var DIAMETER_CT vl_DIA_comp; const octetstring cl_zero := '00000000'O; f_initSCTPConnection(); alt { [] as_SCTPEventHandling_Client() [] SCTP_PCO.receive(ASP_SCTP:?) -> value vl_SCTP_msg { log("SCTP packet received"); vl_DIA_msg := f_DIAMETER_Dec(vl_SCTP_msg.data); vl_DIA_comp := f_findInRT( v_RoutingTable, vl_DIA_msg.hop_by_hop_id, vl_DIA_msg.end_to_end_id ); if (vl_DIA_comp != null) { DIA_PCO.send(vl_DIA_msg) to vl_DIA_comp; f_delFromRT( v_RoutingTable, vl_DIA_msg.hop_by_hop_id, vl_DIA_msg.end_to_end_id ); log("Diameter message sent to the corresponding component"); } else { log("Diameter message arrived"& " with unknown hop_by_hop_id and end_to_end_id: dropping: ", vl_DIA_msg); } repeat; } [] as_handleSCTPTimeouts() [] DIA_PCO.receive(PDU_DIAMETER:?) -> value vl_DIA_msg sender vl_DIA_comp { log("Diameter message received"); if (v_State == true) { if (vl_DIA_msg.hop_by_hop_id == cl_zero and vl_DIA_msg.end_to_end_id == cl_zero) { vl_DIA_msg.hop_by_hop_id := f_DIAMETER_genHopByHop(); vl_DIA_msg.end_to_end_id := f_DIAMETER_genEndToEnd(); } vl_SCTP_msg.data := f_DIAMETER_Enc(vl_DIA_msg); vl_SCTP_msg.client_id := omit; vl_SCTP_msg.sinfo_stream := 0; vl_SCTP_msg.sinfo_ppid := c_DIAMETER_ppid; SCTP_PCO.send(vl_SCTP_msg); v_RoutingTable[sizeof(v_RoutingTable)] := { vl_DIA_msg.hop_by_hop_id, vl_DIA_msg.end_to_end_id, vl_DIA_comp } log("Diameter message sent via SCTP"); } else { DIA_PCO.send(t_notification(TRANSMISSION_FAILED, vl_DIA_msg, omit)) to vl_DIA_comp; log("Diameter message is not forwarded"& " since the SCTP connection is down"); } repeat; } [] as_handleMappingUserMessages() [] DIA_PCO.receive { log("Unexpected DIAMETER message is dropped"& " at function f_DIA_SCTP_Mapping_Client()"); } [] SCTP_PCO.receive { log("Unexpected SCTP message is dropped"& " at function f_DIA_SCTP_Mapping_Client()"); } } } // Main mapping function for server mode, over SCTP function f_DIA_SCTP_Mapping_Server() runs on DIAMETER_Mapping_CT { var ASP_SCTP vl_SCTP_msg; var PDU_DIAMETER_Server vl_DIA_msg; alt { [] as_SCTPEventHandling_Server() [] SCTP_PCO.receive(ASP_SCTP:?) -> value vl_SCTP_msg { log("SCTP packet received"); vl_DIA_msg.data := f_DIAMETER_Dec(vl_SCTP_msg.data); vl_DIA_msg.client_id := vl_SCTP_msg.client_id; DIA_PCO.send(vl_DIA_msg); log("Diameter message sent"); repeat; } [] DIA_PCO.receive(PDU_DIAMETER_Server:?) -> value vl_DIA_msg { log("Diameter message received"); vl_SCTP_msg.data := f_DIAMETER_Enc(vl_DIA_msg.data); vl_SCTP_msg.client_id := vl_DIA_msg.client_id; vl_SCTP_msg.sinfo_stream := 0; vl_SCTP_msg.sinfo_ppid := c_DIAMETER_ppid; SCTP_PCO.send(vl_SCTP_msg); log("Diameter message sent via SCTP"); repeat; } [] DIA_PCO.receive { log("Unexpected DIAMETER message is dropped"& " at function f_DIA_SCTP_Mapping_Server()"); } [] SCTP_PCO.receive { log("Unexpected SCTP message is dropped"& " at function f_DIA_SCTP_Mapping_Server()"); } } } // Main mapping function for server mode, over SCTP function f_DIA_TCP_Mapping_Server() runs on DIAMETER_Mapping_CT { var ASP_TCP vl_TCP_msg; var PDU_DIAMETER_Server vl_DIA_msg; f_initTCPListening(); alt { [] as_TCPEventHandling_Server(); [] TCP_PCO.receive(ASP_TCP:?) -> value vl_TCP_msg { log("TCP Packet received"); vl_DIA_msg.data := f_DIAMETER_Dec(vl_TCP_msg.data); vl_DIA_msg.client_id := vl_TCP_msg.client_id; DIA_PCO.send(vl_DIA_msg); log("Diameter message sent"); repeat; } [] DIA_PCO.receive(PDU_DIAMETER_Server:?) -> value vl_DIA_msg { log("Diameter message received") vl_TCP_msg.data := f_DIAMETER_Enc(vl_DIA_msg.data); vl_TCP_msg.client_id := vl_DIA_msg.client_id; TCP_PCO.send(vl_TCP_msg); log("Diameter message sent via TCP"); repeat; } [] DIA_PCO.receive { log("Unexpected DIAMETER message is dropped"& " at function f_DIA_TCP_Mapping_Server()"); } [] TCP_PCO.receive { log("Unexpected TCP message is dropped"& " at function f_DIA_TCP_Mapping_Server()"); } } } // The SCTP client port tries to connect to the configured server function f_initSCTPConnection() runs on DIAMETER_Mapping_CT { log("f_initSCTPConnection is starting."); SCTP_PCO.send(t_ASP_SCTP_Connect(tsp_hostname, tsp_portnumber)); Ttimeout.start(tsp_connect_timeout); } // The TCP client port tries to connect to the configured server function f_initTCPConnection() runs on DIAMETER_Mapping_CT { log("f_initTCPConnection is starting."); TCP_PCO.send(t_ASP_TCP_Connect(tsp_hostname, tsp_portnumber)); Ttimeout.start(tsp_connect_timeout); } // The TCP port starts listening on the port that was specified in mod. pars. function f_initTCPListening() runs on DIAMETER_Mapping_CT { log("f_initTCPListening is starting."); TCP_PCO.send(t_ASP_TCP_Listen(tsp_hostname, tsp_portnumber)); Ttimeout.start(tsp_connect_timeout); alt { [] TCP_PCO.receive(ASP_TCP_Listen_result:?) -> value v_TCPPortMsg.f_ListenResult { if (v_TCPPortMsg.f_ListenResult.portnumber != tsp_portnumber) { log("Warning: The acquired portnumber is not the requested"); } } [] Ttimeout.timeout { log("Error: Couldn't open listening TCP port"); setverdict(fail); stop; } [] TCP_PCO.receive { log("Warning: Ignored TCP message at f_initTCPListening"); repeat; } [] DIA_PCO.receive { log("Warning: Ignored DIA message at f_initTCPListening"); repeat; } } } // There is no ASP for start listening in the SCTP port. It must be configured // using test port parameter in the configuration file. // Looks up a mapping user component (DIAMETER_CT) in the routing table based // on the hop-by-hop and end-to-end id function f_findInRT( in RoutingTableType pl_table, in octetstring pl_hop_by_hop_id, in octetstring pl_end_to_end_id) return DIAMETER_CT { var integer i; for( i:=0; i < sizeof(pl_table); i:= i+1) { if( pl_table[i].hop_by_hop_id == pl_hop_by_hop_id and pl_table[i].end_to_end_id == pl_end_to_end_id) { return pl_table[i].ptcId; } } return null; } // Deletes a line from the routing table based // on the hop-by-hop and end-to-end id function f_delFromRT( inout RoutingTableType pl_table, in octetstring pl_hop_by_hop_id, in octetstring pl_end_to_end_id) { var integer i, j:=0; var RoutingTableType vl_table := {}; for( i:=0; i < sizeof(pl_table); i:= i+1) { if(pl_table[i].hop_by_hop_id == pl_hop_by_hop_id and pl_table[i].end_to_end_id == pl_end_to_end_id) { } else { vl_table[j] := pl_table[i]; j:=j+1; } } pl_table := vl_table; } // Inserts a line into user table that keeps track of the mapping users // who want to receive notifications about the state of the client connection function f_putInUserTable( inout MappingUserTableType p_table, in DIAMETER_CT pl_ptc) { p_table[sizeof(p_table)] := pl_ptc; } // Removes a line from the user table function f_delFromUserTable( inout MappingUserTableType p_table, in DIAMETER_CT pl_ptc) { var integer i, j:=0; var boolean vl_user_found := false; var MappingUserTableType vl_table := {}; for( i:=0; i < sizeof(p_table); i:= i+1) { if(p_table[i] == pl_ptc) { vl_user_found := true; } else { vl_table[j] := p_table[i]; j:=j+1; } } p_table := vl_table; if (not vl_user_found) { log("Warning: user was not in the MappingUserTable (f_delFromUserTable())"); } } // Sends the notification that was passed as a parameter to all users // who registered at the mapping component function f_sendNotificationToUsers( template ASP_DIA_Mapping_Notification pl_notification) runs on DIAMETER_Mapping_CT { var integer i; for (i:=0; i < sizeof(v_MappingUserTable); i:=i+1) { DIA_PCO.send(pl_notification) to v_MappingUserTable[i]; } } } // end module