blob: 591f6c42ee21fe0dd5a386d7bdcff9ed874fbbea [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2020 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
///////////////////////////////////////////////////////////////////////////////
// File: IFW_CoAP_Peer_Functions.ttcn
// Description:
// Rev: <RnXnn>
// Prodnr: CNL 113 910
// Updated: 2020-02-06
// Contact: http://ttcn.ericsson.se
///////////////////////////////////////////////////////////////////////////////
module IFW_CoAP_Peer_Functions
{
import from IFW_CoAP_Peer_Definitions all;
import from CoAP_Types all;
import from IPL4asp_Types all;
import from IPL4asp_PortType all;
import from IFW_Common all;
///////////////////////////////////////////////////////////
// Module parameter: tsp_CoapPeer_maxResponseTime
//
// Purpose:
// Time the peer is waiting for a response message (0.0->not set)
//
// Type:
// *float*
//
// Default value:
// *0.0*
///////////////////////////////////////////////////////////
modulepar float tsp_CoapPeer_maxResponseTime := 0.0;
///////////////////////////////////////////////////////////
// Module parameter: tsp_cherryPickOptionCheck
//
// Purpose:
//
//
// Type:
// *boolean*
//
// Default value:
// *true*
///////////////////////////////////////////////////////////
modulepar boolean tsp_cherryPickOptionCheck := true;
function f_CoAP_Peer_init() runs on IFW_COAP_CT
{
log(%definitionId, " started");
var Result vl_result;
log("Mapping started");
map(self:IPL4_PCO,system:IPL4_PCO);
if (ctx.localHost != "" and ctx.localPort != -1)
{
log("Setting up the listening socket");
vl_result := f_IPL4_listen(
IPL4_PCO,
ctx.localHost, ctx.localPort, ctx.listeningProtocol, ctx.listeningOptions
);
f_checkResult(vl_result);
var f_IPL4_getMsgLen vl_f := refers(f_COAP_getMsgLength);
f_IPL4_setGetMsgLen(IPL4_PCO, vl_result.connId, vl_f, {});
ctx.connId_listen := vl_result.connId;
}
/*
log("Connecting the socket to the remote");
vl_result := f_IPL4_connect(
IPL4_PCO,
ctx.remoteHost, ctx.remotePort, ctx.localHost, ctx.localPort, -1, ctx.connectProtocol, ctx.connectOptions
);
f_checkResult(vl_result);
*/
if (isbound(vl_result.connId))
{
ctx.connId := vl_result.connId;
}
ctx.cherryPickOptionsCheck := tsp_cherryPickOptionCheck;
log(%definitionId, " finished");
}
function f_CoAP_Peer_listen() runs on IFW_COAP_CT
{
log("Setting up the listening socket");
var Result vl_result := f_IPL4_listen(
IPL4_PCO,
ctx.localHost, ctx.localPort, ctx.listeningProtocol, ctx.listeningOptions
);
f_checkResult(vl_result);
var f_IPL4_getMsgLen vl_f := refers(f_COAP_getMsgLength);
f_IPL4_setGetMsgLen(IPL4_PCO, vl_result.connId, vl_f, {});
ctx.connId_listen := vl_result.connId;
ctx.connId := vl_result.connId;
}
function f_CoAP_Peer_connect() runs on IFW_COAP_CT
{
log("Connecting the socket to the remote");
var Result vl_result;
vl_result := f_IPL4_connect(
IPL4_PCO,
ctx.remoteHost, ctx.remotePort, ctx.localHost, ctx.localPort, -1, ctx.connectProtocol, ctx.connectOptions
);
f_checkResult(vl_result);
if (ispresent(vl_result.errorCode) and vl_result.errorCode == ERROR_TEMPORARILY_UNAVAILABLE)
{
ctx.temporarilyUnavailable := true;
}
var f_IPL4_getMsgLen vl_f := refers(f_COAP_getMsgLength);
f_IPL4_setGetMsgLen(IPL4_PCO, vl_result.connId, vl_f, {});
ctx.connId := vl_result.connId;
}
function f_CoAP_Peer_getContext() runs on IFW_COAP_CT
return CoapContext
{
return ctx;
}
function f_CoAP_Peer_setContext(in CoapContext p_ctx) runs on IFW_COAP_CT
{
ctx := p_ctx;
}
function f_CoAP_Peer_setMessageToSend(in CoAP_ReqResp p_msg, in MID_Generation p_genMid, in Token_Generation p_genToken) runs on IFW_COAP_CT
{
msgToSend := p_msg;
if (p_genMid == GENERATE_NEW_MID)
{
msgToSend.header.message_id := float2int(int2float(65000)*rnd());
}
else if (p_genMid == USE_LAST_RECEIVED_MID) {
if (lastReceived != c_CoAP_ReqResp_empty) {
msgToSend.header.message_id := lastReceived.header.message_id;
}
}
if (p_genToken == GENERATE_NEW_TOKEN)
{
msgToSend.token := int2oct(float2int(int2float(65000)*rnd()),4);
}
if (p_genToken == USE_LAST_RECEIVED_TOKEN) {
if (lastReceived != c_CoAP_ReqResp_empty) {
msgToSend.token := lastReceived.token;
}
}
}
function f_CoAP_Peer_send() runs on IFW_COAP_CT
{
var octetstring v_encoded;
f_CoAP_enc(CoAP_Message: {msg := msgToSend}, v_encoded);
var ASP_SendTo vl_send;
vl_send.connId := ctx.connId;
vl_send.remName := ctx.remoteHost;
vl_send.remPort := ctx.remotePort;
vl_send.proto := ctx.connectProtocol
vl_send.msg := v_encoded;
if (not ctx.temporarilyUnavailable)
{
action("Sending: COAP PDU: ", msgToSend);
IPL4_PCO.send(vl_send);
}
else
{
action("Buffering: COAP PDU: ", msgToSend);
buffer[sizeof(buffer)] := vl_send;
}
}
function f_CoAP_Peer_receive() runs on IFW_COAP_CT
{
// Activate default
timer t_Timeout := tsp_CoapPeer_maxResponseTime;
if (tsp_CoapPeer_maxResponseTime > 0.0) { t_Timeout.start; }
var ASP_RecvFrom v_ipl4Recv;
var ASP_Event v_ipl4Event;
alt
{
[] IPL4_PCO.receive(ASP_RecvFrom:?) -> value v_ipl4Recv
{
log("Received: ", v_ipl4Recv);
var CoAP_Message v_coapMsg;
f_CoAP_dec(v_ipl4Recv.msg, v_coapMsg);
if (ischosen(v_coapMsg.msg))
{
lastReceived := v_coapMsg.msg;
action("Received: COAP PDU: ", lastReceived);
}
}
[] IPL4_PCO.receive(ASP_Event:?) -> value v_ipl4Event
{
log("Received: ", v_ipl4Event);
if (ischosen(v_ipl4Event.result))
{
if (ctx.temporarilyUnavailable and
ispresent(v_ipl4Event.result.errorCode) and
v_ipl4Event.result.errorCode == ERROR_AVAILABLE
)
{
if (sizeof(buffer)>0)
{
for (var integer i:=0; i<sizeof(buffer); i:=i+1)
{
action("Sending from buffer: ", buffer[i]);
IPL4_PCO.send(buffer[i]);
}
}
ctx.temporarilyUnavailable := false;
}
}
else if (ischosen(v_ipl4Event.connClosed))
{
action("Remote closed the connection");
}
repeat;
}
[] t_Timeout.timeout
{
lastReceived := c_CoAP_ReqResp_empty;
}
// Deactivate default
}
}
function f_CoAP_Peer_check(in template CoAP_ReqResp p_expected, in MID_Check p_checkMid := CHECK_MID) runs on IFW_COAP_CT
return ReturnBoolean
{
// TODO: checks
if (not f_COAP_isRequest(lastReceived) and lastReceived.header.msg_type == CONFIRMABLE and p_checkMid == CHECK_MID) {
// Check if the mid is the same in the req and in the rsp
if (not msgToSend.header.message_id == lastReceived.header.message_id) {
log("CHECK: header.message_id mismatch in request and response");
return false;
}
}
if (ctx.cherryPickOptionsCheck) {
var template CoAP_ReqResp v_expected_withoutOptions := p_expected;
v_expected_withoutOptions.options := *;
if (not match(lastReceived, v_expected_withoutOptions)) {
log("CHECK: last received is not matching with expected template");
return false;
}
// Check options 1-by-1
if (ispresent(p_expected.options) and sizeof(p_expected.options)>0)
{
if (not ispresent(lastReceived.options)) {
log("CHECK: Options are epxected but last received messages have them omitted");
return false;
}
var boolean optionsCheck := true;
for (var integer i:=0; i<sizeof(p_expected.options); i:=i+1) {
var template CoAP_Options v_currentExpectedOption := p_expected.options[i];
var boolean optionCheck := false;
for (var integer j:=0; j<sizeof(lastReceived.options); j:=j+1) {
var CoAP_Options v_currentReceivedOption := lastReceived.options[j];
if (match(v_currentReceivedOption, v_currentExpectedOption)) {
optionCheck := true;
}
}
if (not optionCheck) {
log("CHECK: Option mismatch!");
log("EXPECTED: ",v_currentExpectedOption);
log("RECEIVED: ",lastReceived.options);
optionsCheck := false;
}
}
if (not optionsCheck) {
return false;
}
}
}
else {
if (not match(lastReceived, p_expected)) {
log("CHECK: last received is not matching with expected template");
return false;
}
}
log("CHECK: return true");
return true;
}
function f_CoAP_Peer_saveLocationPath()
runs on IFW_COAP_CT
{
ctx.locationPath := {};
for (var integer i:=0; i<sizeof(lastReceived.options); i:=i+1)
{
if (ischosen(lastReceived.options[i].location_path))
{
ctx.locationPath[sizeof(ctx.locationPath)] := lastReceived.options[i].location_path;
}
}
}
function f_CoAP_Peer_addUriPath()
runs on IFW_COAP_CT
{
for (var integer i:=0; i<sizeof(ctx.locationPath); i:=i+1)
{
msgToSend.options[sizeof(msgToSend.options)] :=
{
uri_path := ctx.locationPath[i]
}
}
}
function f_COAP_getMsgLength(in octetstring stream, inout ro_integer args)
return integer
{
return lengthof(stream);
// Only for UDP
// For TCP other frameing is needed (see IETF: COAP mapping to TCP);
}
function f_COAP_isRequest(in CoAP_ReqResp p_msg)
return boolean
{
if (p_msg.header.code.class == 0) {
return true;
}
else {
return false;
}
}
}