blob: 1e266682c8e6c132fa13102c0aa6a70af0ebe9f5 [file] [log] [blame]
package org.eclipse.titan.user_provided;
//CoAP__Types.CoAP__Message
import org.eclipse.titan.generated.CoAP__Types.BlockOption;
import org.eclipse.titan.generated.CoAP__Types.CoAP__Message;
import org.eclipse.titan.generated.CoAP__Types.CoAP__Options;
import org.eclipse.titan.runtime.core.Base_Template.template_sel;
import org.eclipse.titan.runtime.core.TTCN_Buffer;
import org.eclipse.titan.runtime.core.TTCN_Logger;
import org.eclipse.titan.runtime.core.TTCN_Logger.Severity;
import org.eclipse.titan.runtime.core.TitanCharString.CharCoding;
import org.eclipse.titan.runtime.core.TitanOctetString;
import org.eclipse.titan.runtime.core.TtcnError;
public class CoAP__Types_externalfunctions {
public static int f__CoAP__enc(CoAP__Message msg, TitanOctetString v__encoded) {
if(TTCN_Logger.log_this_event(Severity.DEBUG_ENCDEC)){
TTCN_Logger.begin_event(Severity.DEBUG_ENCDEC);
TTCN_Logger.log_event("Encoding CoAP message: ");
msg.log();
TTCN_Logger.end_event();
}
TTCN_Buffer stream = new TTCN_Buffer();
int chr = 0;
switch(msg.get_selection()){
case ALT_raw__message:
stream.put_os(msg.get_field_raw__message());
stream.get_string(v__encoded);
return 0;
case ALT_msg:
default:
break;
}
//HEADER
//version
if(msg.get_field_msg().get_field_header().get_field_version().isGreaterThanOrEqual(0) && msg.get_field_msg().get_field_header().get_field_version().isLessThanOrEqual(3)){
chr = msg.get_field_msg().get_field_header().get_field_version().getInt() << 6;
}else{
return 1;
}
//message type
chr += msg.get_field_msg().get_field_header().get_field_msg__type().asInt() << 4;
//token length
if(msg.get_field_msg().get_field_token().lengthof().isGreaterThanOrEqual(0) && msg.get_field_msg().get_field_token().lengthof().isLessThanOrEqual(8)){
chr += msg.get_field_msg().get_field_token().lengthof().getInt();
}else{
return 1;
}
stream.put_c(Character.toChars(chr)[0]);
//code
if(msg.get_field_msg().get_field_header().get_field_code().get_field_class_().isGreaterThanOrEqual(0) && msg.get_field_msg().get_field_header().get_field_code().get_field_class_().isLessThanOrEqual(7)){
chr = msg.get_field_msg().get_field_header().get_field_code().get_field_class_().getInt() << 5;
}else{
return 1;
}
if(msg.get_field_msg().get_field_header().get_field_code().get_field_detail().isGreaterThanOrEqual(0) && msg.get_field_msg().get_field_header().get_field_code().get_field_detail().isLessThanOrEqual(31)){
chr += msg.get_field_msg().get_field_header().get_field_code().get_field_detail().getInt();
}else{
return 1;
}
stream.put_c(Character.toChars(chr)[0]);
//message ID
if(msg.get_field_msg().get_field_header().get_field_message__id().isGreaterThanOrEqual(0) && msg.get_field_msg().get_field_header().get_field_message__id().isLessThanOrEqual(65535)){
encodeInteger(stream, msg.get_field_msg().get_field_header().get_field_message__id().getInt(), 2);
}else{
return 1;
}
//TOKEN
stream.put_os(msg.get_field_msg().get_field_token());
//OPTIONS
if(msg.get_field_msg().get_field_options().ispresent() && msg.get_field_msg().get_field_options().get().size_of().isGreaterThan(0)){
int[] optionOrder = new int[msg.get_field_msg().get_field_options().get().size_of().getInt()];
int temp;
for(int i = 0; i < msg.get_field_msg().get_field_options().get().size_of().getInt(); i++){
optionOrder[i] = i;
}
//determine the order of options
for(int j = 0; j < msg.get_field_msg().get_field_options().get().size_of().getInt() - 1; j++){
int minOptionCode = getOptionCode(msg.get_field_msg().get_field_options().get().get_at(optionOrder[j]));
int minOptionIndex = j;
for(int i = j+1; i < msg.get_field_msg().get_field_options().get().size_of().getInt(); i++){
if(getOptionCode(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i])) < minOptionCode){
minOptionCode = getOptionCode(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]));
minOptionIndex = i;
}
}
temp = optionOrder[minOptionIndex];
optionOrder[minOptionIndex] = optionOrder[j];
optionOrder[j] = temp;
}
//encode options
int previousOptionCode = 0;
for(int i = 0; i < msg.get_field_msg().get_field_options().get().size_of().getInt(); i++){
int delta = getOptionCode(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i])) - previousOptionCode;
int length = getOptionLength(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]));
previousOptionCode += delta;
//first byte
if(delta >= 0 && delta <= 12){
chr = delta << 4;
}else if(delta >= 13 && delta <= 268){
chr = 13 << 4;
}else if(delta >= 269 && delta <= 65535){
chr = 14 << 4;
}else{
return 1;
}
if(length >= 0 && length <= 12){
chr += length;
}else if(length >= 13 && length <= 268){
chr += 13;
}else if(length >= 269 && length <= 65535){
chr += 14;
}else{
return 1;
}
stream.put_c(Character.toChars(chr)[0]);
//optional delta
if(delta >= 13 && delta <= 268){
chr = delta - 13;
stream.put_c(Character.toChars(chr)[0]);
}else if(delta >= 269 && delta <= 65535){
chr = (delta - 269) >> 8;
stream.put_c(Character.toChars(chr)[0]);
chr = (delta - 269) & 255;
stream.put_c(Character.toChars(chr)[0]);
}
//optional length
if(length >= 13 && length <= 268){
chr = length - 13;
stream.put_c(Character.toChars(chr)[0]);
}else if(length >= 269 && length <= 65535){
chr = (length - 269) >> 8;
stream.put_c(Character.toChars(chr)[0]);
chr = (length - 269) & 255;
stream.put_c(Character.toChars(chr)[0]);
}
//option value
if(length > 0){
switch(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_selection()){
case ALT_if__match:
stream.put_os(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_if__match());
break;
case ALT_uri__host:
msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_uri__host().encode_utf8(stream, false);
break;
case ALT_etag:
stream.put_os(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_etag());
break;
case ALT_if__none__match:
stream.put_os(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_if__none__match());
break;
case ALT_observe:
encodeInteger(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_observe().getInt(), length);
break;
case ALT_uri__port:
encodeInteger(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_uri__port().getInt(), length);
break;
case ALT_location__path:
msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_location__path().encode_utf8(stream, false);
break;
case ALT_uri__path:
msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_uri__path().encode_utf8(stream, false);
break;
case ALT_content__format:
encodeInteger(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_content__format().getInt(), length);
break;
case ALT_max__age:
encodeInteger(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_max__age().getInt(), length);
break;
case ALT_uri__query:
msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_uri__query().encode_utf8(stream, false);
break;
case ALT_accept:
encodeInteger(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_accept().getInt(), length);
break;
case ALT_location__query:
msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_location__query().encode_utf8(stream, false);
break;
case ALT_block1:
encodeBlock(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_block1(), length);
break;
case ALT_block2:
encodeBlock(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_block2(), length);
break;
case ALT_proxy__uri:
msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_proxy__uri().encode_utf8(stream, false);
break;
case ALT_proxy__scheme:
msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_proxy__scheme().encode_utf8(stream, false);
break;
case ALT_size1:
encodeInteger(stream, msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_size1().getInt(), length);
break;
case ALT_unknown__option:
stream.put_os(msg.get_field_msg().get_field_options().get().get_at(optionOrder[i]).get_field_unknown__option().get_field_option__value());
break;
case UNBOUND_VALUE:
default:
return 8;
}
}
}
}
//PAYLOAD
if(msg.get_field_msg().get_field_payload().ispresent()){
stream.put_c((char)255); //payload marker
stream.put_os(msg.get_field_msg().get_field_payload().get());
}
TTCN_Logger.begin_event(Severity.DEBUG_ENCDEC);
TTCN_Logger.log_event("Encoded CoAP message: ");
stream.log();
TTCN_Logger.end_event();
v__encoded.operator_assign(new TitanOctetString(stream.get_data()));
return 0;
}
public static int f__CoAP__dec(TitanOctetString v__enc, CoAP__Message v__dec) {
if(TTCN_Logger.log_this_event(Severity.DEBUG_ENCDEC)){
TTCN_Logger.begin_event(Severity.DEBUG_ENCDEC);
TTCN_Logger.log_event("Decoding CoAP message: ");
v__enc.log();
TTCN_Logger.end_event();
}
if(v__enc.lengthof().isGreaterThanOrEqual(4)){
int chr;
int position = 0;
int token_length = 0;
int actual_option_code = 0;
int count_of_options = 0;
boolean payload_marker = false;
//version, message type and token length
chr = v__enc.getValue()[0];
v__dec.get_field_msg().get_field_header().get_field_version().operator_assign(chr >> 6);
v__dec.get_field_msg().get_field_header().get_field_msg__type().operator_assign((chr >> 4) & 3);
token_length = chr & 15;
//code
chr = v__enc.getValue()[1];
v__dec.get_field_msg().get_field_header().get_field_code().get_field_class_().operator_assign((chr >> 5) & 7);
v__dec.get_field_msg().get_field_header().get_field_code().get_field_detail().operator_assign(chr & 31);
//message ID
v__dec.get_field_msg().get_field_header().get_field_message__id().operator_assign(v__enc.getValue()[2] * 256 + v__enc.getValue()[3]);
if(v__enc.lengthof().isGreaterThan(4) && v__dec.get_field_msg().get_field_header().get_field_code().get_field_class_().operator_equals(0) && v__dec.get_field_msg().get_field_header().get_field_code().get_field_detail().operator_equals(0)) {
v__dec.get_field_raw__message().operator_assign(v__enc);
return 1;
}
position = 4;
//token
if(token_length > 0){
if(v__enc.lengthof().isGreaterThanOrEqual(position + token_length)) {
v__dec.get_field_msg().get_field_token().operator_assign(new TitanOctetString(v__enc.getValue()[position]));
position += token_length;
}else{
v__dec.get_field_raw__message().operator_assign(v__enc);
return 1;
}
}else{
v__dec.get_field_msg().get_field_token().operator_assign(new TitanOctetString(""));
}
//options
v__dec.get_field_msg().get_field_options().operator_assign(template_sel.OMIT_VALUE);
if(v__enc.lengthof().isGreaterThan(4)) {
while(!payload_marker && v__enc.lengthof().isGreaterThan(position)) {
int delta = v__enc.get_nibble(position) >> 4;
int length = v__enc.get_nibble(position) & 15;
if(delta == 15 && length != 15){
v__dec.get_field_raw__message().operator_assign(v__enc);
return 1;
}
position++;
if(delta == 15 && length == 15){
payload_marker = true;
}else{
//optional delta
if(delta == 13){
delta = v__enc.get_nibble(position) + 13;
position++;
}else if(delta == 14){
delta = (v__enc.get_nibble(position) << 8) + v__enc.get_nibble(position+1) + 269;
position += 2;
}
//optional length
if(length == 13){
length = v__enc.get_nibble(position) + 13;
position++;
}else if(length == 14){
length = (v__enc.get_nibble(position) << 8) + v__enc.get_nibble(position + 1) + 269;
position += 2;
}else if(length == 15){
v__dec.get_field_raw__message().operator_assign(v__enc);
return 1; //void function cannot return
}
//value
actual_option_code += delta;
switch(actual_option_code){
case 1:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_if__match().operator_assign(new TitanOctetString(v__enc.get_nibble(position)));
break;
case 3:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_uri__host().decode_utf8(new char[] {v__enc.get_nibble(position)}, CharCoding.UTF_8, false);
break;
case 4:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_etag().operator_assign(new TitanOctetString(v__enc.get_nibble(position)));
break;
case 5:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_if__none__match().operator_assign(new TitanOctetString(""));
break;
case 6:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_observe().operator_assign(decodeInteger(v__enc, position, length));
break;
case 7:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_uri__port().operator_assign(decodeInteger(v__enc, position, length));
break;
case 8:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_location__path().decode_utf8(new char[] {v__enc.get_nibble(position)}, CharCoding.UTF_8, false);
break;
case 11:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_uri__path().decode_utf8(new char[] {v__enc.get_nibble(position)}, CharCoding.UTF_8, false);
break;
case 12:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_content__format().operator_assign(decodeInteger(v__enc, position, length));
break;
case 14:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_max__age().operator_assign(decodeInteger(v__enc, position, length));
break;
case 15:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_uri__query().decode_utf8(new char[] {v__enc.get_nibble(position)}, CharCoding.UTF_8, false);
break;
case 17:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_accept().operator_assign(decodeInteger(v__enc, position, length));
break;
case 20:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_location__query().decode_utf8(new char[] {v__enc.get_nibble(position)}, CharCoding.UTF_8, false);
break;
case 23: // Block2 RFC 7959
decodeBlock(v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_block2(), v__enc, position, length);
break;
case 27: // Block1 RFC 7959
decodeBlock(v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_block1(), v__enc, position, length);
break;
case 35:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_proxy__uri().decode_utf8(new char[] {v__enc.get_nibble(position)}, CharCoding.UTF_8, false);
break;
case 39:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_proxy__scheme().decode_utf8(new char[] {v__enc.get_nibble(position)}, CharCoding.UTF_8, false);
break;
case 60:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_size1().operator_assign(decodeInteger(v__enc, position, length));
break;
default:
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_unknown__option().get_field_option__code().operator_assign(actual_option_code);
v__dec.get_field_msg().get_field_options().get().get_at(count_of_options).get_field_unknown__option().get_field_option__value().operator_assign(new TitanOctetString(v__enc.get_nibble(position)));
break;
}
position += length;
count_of_options++;
}
}
}
//payload
if(v__enc.lengthof().isGreaterThan(position)) {
v__dec.get_field_msg().get_field_payload().operator_assign(new TitanOctetString(v__enc.get_nibble(position)));
if(v__dec.get_field_msg().get_field_payload().get().lengthof().operator_equals(0)) {
v__dec.get_field_raw__message().operator_assign(v__enc);
return 1;
}
} else {
if(payload_marker){
v__dec.get_field_raw__message().operator_assign(v__enc);
return 1;
}else{
v__dec.get_field_msg().get_field_payload().operator_assign(template_sel.OMIT_VALUE);
}
}
} else{
v__dec.get_field_raw__message().operator_assign(v__enc);
return 1;
}
if(TTCN_Logger.log_this_event(Severity.DEBUG_ENCDEC)){
TTCN_Logger.begin_event(Severity.DEBUG_ENCDEC);
TTCN_Logger.log_event("Decoded CoAP message: ");
v__enc.log();
TTCN_Logger.end_event();
}
return 0;
}
private static int decodeInteger(TitanOctetString str, int position, int length) {
int value = 0;
for(int i = 0; i < length; i++) {
value += (str.get_nibble(position + i) << (8 * (length-i-1)));
}
return value;
}
private static void decodeBlock(BlockOption block, TitanOctetString str, int position, int length) {
int num = 0;
for(int i = 0; i < length-1; i++) {
num += (str.get_nibble(position + i) << (8 * (length-i-1) - 4));
}
num += (str.get_nibble(position + length-1) >> 4) & 0x0f;
int szx = 0;
szx = str.get_nibble(position + length - 1) & 0x07;
int m = 0;
m = str.get_nibble(position+length - 1) & 0x08;
block.get_field_num().operator_assign(num);
block.get_field_szx().operator_assign(szx);
block.get_field_m().operator_assign(intToBoolean(m));
}
private static boolean intToBoolean(int value) {
return value > 0 ? true : false;
}
private static void encodeInteger(TTCN_Buffer stream, final int option, final int length){
int chr;
for(int i = length-1; i > 0; i--){
chr = (option >> (8 * i)) & 255;
stream.put_c(Character.toChars(chr)[0]);
}
chr = option & 255;
stream.put_c(Character.toChars(chr)[0]);
}
private static int getOptionCode(CoAP__Options option){
switch(option.get_selection()){
case ALT_if__match:
return 1;
case ALT_uri__host:
return 3;
case ALT_etag:
return 4;
case ALT_if__none__match:
return 5;
case ALT_observe:
return 6;
case ALT_uri__port:
return 7;
case ALT_location__path:
return 8;
case ALT_uri__path:
return 11;
case ALT_content__format:
return 12;
case ALT_max__age:
return 14;
case ALT_uri__query:
return 15;
case ALT_accept:
return 17;
case ALT_location__query:
return 20;
case ALT_block1: // RFC 7959
return 27;
case ALT_block2: // RFC 7959
return 23;
case ALT_proxy__uri:
return 35;
case ALT_proxy__scheme:
return 39;
case ALT_size1:
return 60;
case ALT_unknown__option:
return option.get_field_unknown__option().get_field_option__code().getInt();
case UNBOUND_VALUE:
default:
throw new TtcnError("CoAP: Error at getOptionCode!");
}
}
private static int getOptionLength(CoAP__Options option){
switch(option.get_selection()){
case ALT_if__match:
return option.get_field_if__match().lengthof().getInt();
case ALT_uri__host:
return option.get_field_uri__host().lengthof().getInt();
case ALT_etag:
return option.get_field_etag().lengthof().getInt();
case ALT_if__none__match:
return option.get_field_if__none__match().lengthof().getInt();
case ALT_observe:
return getIntegerLength(option.get_field_observe().getLong(), 3);
case ALT_uri__port:
return getIntegerLength(option.get_field_uri__port().getLong(), 2);
case ALT_location__path:
return option.get_field_location__path().lengthof().getInt();
case ALT_uri__path:
return option.get_field_uri__path().lengthof().getInt();
case ALT_content__format:
return getIntegerLength(option.get_field_content__format().getLong(), 2);
case ALT_max__age:
return getIntegerLength(option.get_field_max__age().getLong(), 4);
case ALT_uri__query:
return option.get_field_uri__query().lengthof().getInt();
case ALT_accept:
return getIntegerLength(option.get_field_accept().getLong(), 2);
case ALT_location__query:
return option.get_field_location__query().lengthof().getInt();
case ALT_block1:
return getBlockLengthForNum(option.get_field_block1().get_field_num().getLong());
case ALT_block2:
return getBlockLengthForNum(option.get_field_block2().get_field_num().getLong());
case ALT_proxy__uri:
return option.get_field_proxy__uri().lengthof().getInt();
case ALT_proxy__scheme:
return option.get_field_proxy__scheme().lengthof().getInt();
case ALT_size1:
return getIntegerLength(option.get_field_size1().getLong(), 4);
case ALT_unknown__option:
return option.get_field_unknown__option().get_field_option__value().lengthof().getInt();
case UNBOUND_VALUE:
default:
throw new TtcnError("CoAP: Error at getOptionLength!");
}
}
private static int getIntegerLength(final long value, int mode){
if(value == 0){
return 0;
}else if(value / 269.0 == 0){
return 1;
}else if(value / 65805.0 == 0){
return 2;
}else if(mode == 4 && value / 16777485.0 == 0){
return 3;
}else if(mode == 4 && value / 4294967296L == 0){
return 4;
}else{
throw new TtcnError("CoAP: Error at getIntegerLength!");
}
}
// RFC 7959
private static int getBlockLengthForNum(final long num) {
if (num < 0 || num > 1048575)
throw new TtcnError("CoAP: Error at getBlockLengthForNum: num must larger than 0 and smaller than 1048576!");
if (num <= 15) { // 2^4-1
return 1;
}
else if (num <= 1023) { // 2^10-1
return 2;
}
else if (num <= 1048575) { // 2^20-1
return 3;
}
return 0;
}
// RFC 7959
private static void encodeBlock(TTCN_Buffer stream, final BlockOption option, final int length) {
int chr;
int num_val = option.get_field_num().getInt();
int szx;
szx = option.get_field_szx().getInt() & 0x07; // szx_val & 00000111b
char m;
if (option.get_field_m().getValue())
m = 0x08; // 00001000b
else
m = 0x00; // 00000000b
int num;
for(int i = length-1; i > 0; i--){
num = (num_val >> (8 * i - 4)) & 0xff;
stream.put_c(Character.toChars(num)[0]);
}
num = (num_val << 4) & 0xf0; // num_val & 11110000b
chr = num | m | szx;
stream.put_c(Character.toChars(chr)[0]);
}
}