From 992ee5a596531b123ecf155e6af67afb35dfafeb Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Tue, 8 May 2018 11:52:25 +0200
Subject: [PATCH] Implemented remote mapping in translation mode (bug 534266)

Change-Id: I8c4e454d8ba843b983388ec8beaa134c5c9eb8cc
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 compiler2/AST.cc                              | 30 ++++++-
 compiler2/Code.cc                             |  4 +
 compiler2/CodeGenHelper.cc                    |  1 +
 compiler2/CompType.cc                         | 31 +++++++
 compiler2/ttcn3/Statement.cc                  | 47 +---------
 compiler2/ttcn3/Statement.hh                  |  1 -
 compiler2/ttcn3/compiler.h                    |  1 +
 compiler2/ttcn3/port.c                        | 84 +++++++++++++-----
 core/Array.hh                                 |  8 ++
 core/Communication.cc                         | 30 ++++++-
 core/Module_list.cc                           | 22 +++++
 core/Module_list.hh                           |  6 ++
 core/Port.cc                                  | 45 ++++++++--
 core/Port.hh                                  |  7 ++
 core/Runtime.cc                               | 25 ++++++
 core/Runtime.hh                               |  6 ++
 mctr2/mctr/MainController.cc                  | 11 +--
 mctr2/mctr/MainController.h                   |  5 +-
 regression_test/portTranslation/Makefile      |  2 +-
 regression_test/portTranslation/P5.cc         | 81 +++++++++++++++++
 regression_test/portTranslation/P5.hh         | 52 +++++++++++
 regression_test/portTranslation/PT4.cc        | 80 +++++++++++++++++
 regression_test/portTranslation/PT4.hh        | 47 ++++++++++
 .../portTranslation/PortTranslation.ttcn      | 88 +++++++++++++++++++
 24 files changed, 625 insertions(+), 89 deletions(-)
 create mode 100644 regression_test/portTranslation/P5.cc
 create mode 100644 regression_test/portTranslation/P5.hh
 create mode 100644 regression_test/portTranslation/PT4.cc
 create mode 100644 regression_test/portTranslation/PT4.hh

diff --git a/compiler2/AST.cc b/compiler2/AST.cc
index 29acfbfa3..caa95f4bd 100644
--- a/compiler2/AST.cc
+++ b/compiler2/AST.cc
@@ -1064,6 +1064,29 @@ namespace Common {
       output->functions.init_comp = NULL;
       has_init_comp = true;
     } else has_init_comp = false;
+    // init system port function
+    bool has_init_system_port;
+    if (output->functions.init_system_port != NULL) {
+      output->source.static_function_prototypes =
+        mputprintf(output->source.static_function_prototypes,
+        "%sboolean init_system_port(const char* component_type, const char* port_name);\n",
+        split_to_slices ? "extern " : "static ");
+      output->source.static_function_bodies =
+        mputprintf(output->source.static_function_bodies,
+        "%sboolean init_system_port(const char* component_type, const char* port_name)\n"
+        "{\n", split_to_slices ? "" : "static ");
+      output->source.static_function_bodies =
+        mputstr(output->source.static_function_bodies, output->functions.init_system_port);
+      output->source.static_function_bodies =
+        mputstr(output->source.static_function_bodies, "return FALSE;\n"
+        "}\n\n");
+      Free(output->functions.init_system_port);
+      output->functions.init_system_port = NULL;
+      has_init_system_port = true;
+    }
+    else {
+      has_init_system_port = false;
+    }
     // start function
     bool has_start;
     if (output->functions.start) {
@@ -1187,15 +1210,16 @@ namespace Common {
       }
       string extra_str = extra ? ( string('"') + extra + string('"') ) : string("NULL");
       output->source.global_vars = mputprintf(output->source.global_vars,
-	", %uU, %uU, %uU, %uU, %s, %luLU, %s, %s, %s, %s, %s, %s, %s, %s",
+	", %uU, %uU, %uU, %uU, %s, %luLU, %s, %s, %s, %s, %s, %s, %s, %s, %s",
         suffix, release, patch, build, extra_str.c_str(),
         (unsigned long)num_xml_namespaces,
         ((num_xml_namespaces || (control_ns && control_ns_prefix)) ? "xml_namespaces" : "0"),
 	has_post_init ? "post_init_module" : "NULL",
 	has_set_param ? "set_module_param" : "NULL",
-  has_get_param ? "get_module_param" : "NULL",
+	has_get_param ? "get_module_param" : "NULL",
 	has_log_param ? "log_module_param" : "NULL",
 	has_init_comp ? "init_comp_type" : "NULL",
+	has_init_system_port ? "init_system_port" : "NULL",
 	has_start ? "start_ptc_function" : "NULL",
 	has_control ? "module_control_part" : "NULL");
     } else {
@@ -1210,6 +1234,8 @@ namespace Common {
 	FATAL_ERROR("Module::generate_functions(): log_param function in ASN.1 module");
       if (has_init_comp)
 	FATAL_ERROR("Module::generate_functions(): init_comp function in ASN.1 module");
+      if (has_init_system_port)
+	FATAL_ERROR("Module::generate_functions(): init_system_port function in ASN.1 module");
       if (has_start)
 	FATAL_ERROR("Module::generate_functions(): startable function in ASN.1 module");
       if (has_control)
diff --git a/compiler2/Code.cc b/compiler2/Code.cc
index 740605829..5df657a95 100644
--- a/compiler2/Code.cc
+++ b/compiler2/Code.cc
@@ -54,6 +54,7 @@ namespace Common {
     output->functions.get_param = NULL;
     output->functions.log_param = NULL;
     output->functions.init_comp = NULL;
+    output->functions.init_system_port = NULL;
     output->functions.start = NULL;
     output->functions.control = NULL;
     output->intervals.pre_things_size = 0;
@@ -136,6 +137,8 @@ namespace Common {
       mputstr(dest->functions.log_param, src->functions.log_param);
     dest->functions.init_comp =
       mputstr(dest->functions.init_comp, src->functions.init_comp);
+    dest->functions.init_system_port =
+      mputstr(dest->functions.init_system_port, src->functions.init_system_port);
     dest->functions.start =
       mputstr(dest->functions.start, src->functions.start);
     dest->functions.control =
@@ -167,6 +170,7 @@ namespace Common {
     Free(output->functions.get_param);
     Free(output->functions.log_param);
     Free(output->functions.init_comp);
+    Free(output->functions.init_system_port);
     Free(output->functions.start);
     Free(output->functions.control);
     Free(output->intervals.methods);
diff --git a/compiler2/CodeGenHelper.cc b/compiler2/CodeGenHelper.cc
index 31c722fb7..0d27d4521 100644
--- a/compiler2/CodeGenHelper.cc
+++ b/compiler2/CodeGenHelper.cc
@@ -373,6 +373,7 @@ void CodeGenHelper::finalize_generation(Type* type) {
   transfer_value(dst.functions.get_param, src.functions.get_param);
   transfer_value(dst.functions.log_param, src.functions.log_param);
   transfer_value(dst.functions.init_comp, src.functions.init_comp);
+  transfer_value(dst.functions.init_system_port, src.functions.init_system_port);
   transfer_value(dst.functions.start,     src.functions.start);
   transfer_value(dst.functions.control,   src.functions.control);
 }
diff --git a/compiler2/CompType.cc b/compiler2/CompType.cc
index 6d425044f..65c003766 100644
--- a/compiler2/CompType.cc
+++ b/compiler2/CompType.cc
@@ -546,6 +546,37 @@ void ComponentTypeBody::generate_code(output_struct* target)
   target->functions.init_comp = mputstr(target->functions.init_comp,
     "return TRUE;\n"
     "} else ");
+  
+  // system port initializer function
+  bool first_port_found = false;
+  nof_defs = all_defs_m.size();
+  for (size_t i = 0; i < nof_defs; i++) {
+    // go through all port definitions, including inherited ones
+    Ttcn::Definition* def = all_defs_m.get_nth_elem(i);
+    if (def->get_asstype() == Common::Assignment::A_PORT) {
+      if (!first_port_found) {
+        // only add a segment for this component if it has at least one port
+        first_port_found = true;
+        target->functions.init_system_port = mputprintf(
+          target->functions.init_system_port,
+          "%sif (!strcmp(component_type, \"%s\")) {\n",
+          target->functions.init_system_port == NULL ? "" : "else ",
+          comp_id->get_dispname().c_str());
+      }
+      target->functions.init_system_port = mputprintf(
+        target->functions.init_system_port,
+        "if (!strcmp(port_name, \"%s\")) {\n"
+        "%s.safe_start();\n"
+        "return TRUE;\n"
+        "}\n",
+        def->get_id().get_dispname().c_str(),
+        def->get_genname_from_scope(my_type->get_my_scope()).c_str());
+    }
+  }
+  if (first_port_found) {
+    target->functions.init_system_port = mputstr(
+      target->functions.init_system_port, "}\n");
+  }
 }
 
 char *ComponentTypeBody::generate_code_comptype_name(char *str)
diff --git a/compiler2/ttcn3/Statement.cc b/compiler2/ttcn3/Statement.cc
index 3cd3fdb50..cb87d8ee4 100644
--- a/compiler2/ttcn3/Statement.cc
+++ b/compiler2/ttcn3/Statement.cc
@@ -1414,7 +1414,6 @@ namespace Ttcn {
       config_op.compref2=p_compref2;
       config_op.portref2=p_portref2;
       config_op.translate=false;
-      config_op.first_is_system = false;
       break;
     default:
       FATAL_ERROR("Statement::Statement()");
@@ -4959,9 +4958,6 @@ error:
         warning("Port type `%s' cannot send or receive from system port type `%s'.",
           pt2->get_typename().c_str(), pt1->get_typename().c_str());
       }
-      if (config_op.translate) {
-        config_op.first_is_system = true;
-      }
     } else {
       // we have no idea which one is the system port
       bool first_is_mapped_to_second = !ptb1->is_legacy() && ptb1->is_translate(ptb2);
@@ -4971,9 +4967,6 @@ error:
         error("The mapping between port types `%s' and `%s' is not consistent",
                 pt1->get_typename().c_str(), pt2->get_typename().c_str());
       }
-      if (config_op.translate) {
-        config_op.first_is_system = second_is_mapped_to_first;
-      }
     }
     if (!config_op.translate) {
       if (ptb1->is_internal()) {
@@ -7624,10 +7617,8 @@ error:
   {
     expression_struct expr;
     Code::init_expr(&expr);
-    bool warning = false;
     if (config_op.translate == true) {
       if (!config_op.compref1->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE)) {
-        warning = true;
         if (strcmp(opname, "map") == 0) {
           config_op.compref1->warning(
             "Cannot determine the type of the component in the first parameter."
@@ -7635,24 +7626,12 @@ error:
         }
       }
       if (!config_op.compref2->get_expr_governor(Type::EXPECTED_DYNAMIC_VALUE)) {
-        warning = true;
         if (strcmp(opname, "map") == 0) {
           config_op.compref2->warning(
             "Cannot determine the type of the component in the second parameter."
             "The port translation will not work.");
         }
       }
-      if (warning == false) {
-        Reference* portref = config_op.first_is_system ?
-          config_op.portref1 : config_op.portref2;
-        expr.expr = mputstr(expr.expr, "if (!(");
-        portref->generate_code_portref(&expr, my_sb);
-        expr.expr = mputstr(expr.expr, ".port_is_started())) {\n");
-        portref->generate_code_portref(&expr, my_sb);
-        expr.expr = mputstr(expr.expr, ".activate_port(TRUE);\n");
-        portref->generate_code_portref(&expr, my_sb);
-        expr.expr = mputstr(expr.expr, ".start();\n}\n");
-      }
     }
     expr.expr = mputprintf(expr.expr, "TTCN_Runtime::%s_port(", opname);
     config_op.compref1->generate_code_expr(&expr);
@@ -7680,32 +7659,10 @@ error:
       // a simple string shall be formed from the port name and array indices
       generate_code_portref(&expr, config_op.portref2);
     }
-    if (config_op.translate == true && warning == false) {
-      expr.expr = mputstr(expr.expr, ", TRUE");
-      }
-    expr.expr = mputstr(expr.expr, ")");
     if (config_op.translate == true) {
-      string funcname;
-      if (strcmp(opname, "map") == 0) {
-        funcname = "add_port";
-      } else if (strcmp(opname, "unmap") == 0) {
-        funcname = "remove_port";
-      } else {
-        //connect, disconnect are not supported
-      }
-      if (!funcname.empty() && warning == false) {
-        expr.expr = mputstr(expr.expr, ";\n");
-        config_op.portref1->generate_code_portref(&expr, my_sb);
-        expr.expr = mputprintf(expr.expr, ".%s(&(", funcname.c_str());
-        config_op.portref2->generate_code_portref(&expr, my_sb);
-        expr.expr = mputstr(expr.expr, "));\n");
-
-        config_op.portref2->generate_code_portref(&expr, my_sb);
-        expr.expr = mputprintf(expr.expr, ".%s(&(", funcname.c_str());
-        config_op.portref1->generate_code_portref(&expr, my_sb);
-        expr.expr = mputstr(expr.expr, "))");
-      }
+      expr.expr = mputstr(expr.expr, ", TRUE");
     }
+    expr.expr = mputstr(expr.expr, ")");
     return Code::merge_free_expr(str, &expr);
   }
 
diff --git a/compiler2/ttcn3/Statement.hh b/compiler2/ttcn3/Statement.hh
index e79e9de0f..90a0ccec0 100644
--- a/compiler2/ttcn3/Statement.hh
+++ b/compiler2/ttcn3/Statement.hh
@@ -348,7 +348,6 @@ namespace Ttcn {
         Value *compref2;
         Reference *portref2;
         bool translate; // true if a map statement enables translation mode
-        bool first_is_system; // true if the first operand is the system component (only used in translation mode)
       } config_op; ///< used by S_CONNECT, S_MAP, S_DISCONNECT, S_UNMAP
 
       struct {
diff --git a/compiler2/ttcn3/compiler.h b/compiler2/ttcn3/compiler.h
index 576a0bdee..78ed60abc 100644
--- a/compiler2/ttcn3/compiler.h
+++ b/compiler2/ttcn3/compiler.h
@@ -63,6 +63,7 @@ extern "C" {
       char *get_param; /**< Code for get_module_param() */
       char *log_param; /**< Code for log_module_param() */
       char *init_comp; /**< Code for init_comp_type() */
+      char* init_system_port; /**< Code for init_system_port() */
       char *start;     /**< Code for start_ptc_function() */
       char *control;   /**< Code for module_control_part() */
     } functions;
diff --git a/compiler2/ttcn3/port.c b/compiler2/ttcn3/port.c
index 194584412..1d6b9c24c 100644
--- a/compiler2/ttcn3/port.c
+++ b/compiler2/ttcn3/port.c
@@ -2136,24 +2136,35 @@ void defPortClass(const port_def* pdef, output_struct* output)
     
   if (pdef->port_type == USER && !pdef->legacy) {
     // add_port and remove_port is called after the map and unmap statements.
+    def = mputstr(def, "void add_port(PORT* p);\n");
+    src = mputprintf(src, "void %s::add_port(PORT* p)\n{\n", class_name);
     for (i = 0; i < pdef->provider_msg_outlist.nElements; i++) {
-      def = mputprintf(def, "void add_port(%s* p);\n", pdef->provider_msg_outlist.elements[i].name);
       src = mputprintf(src,
-        "void %s::add_port(%s*p) {\n"
+        "%s* x_%i = dynamic_cast<%s*>(p);\n"
+        "if (x_%i != NULL) {\n"
         "n_%i++;\n"
         "p_%i = static_cast<%s**>(Realloc(p_%i, n_%i * sizeof(%s*)));\n"
-        "p_%i[n_%i-1] = p;\n"
-        "}\n\n",
-        class_name, pdef->provider_msg_outlist.elements[i].name, (int)i,
+        "p_%i[n_%i-1] = x_%i;\n"
+        "return;\n"
+        "}\n",
+        pdef->provider_msg_outlist.elements[i].name, (int)i,
+        pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i,
         (int)i, pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i,
-        pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i);
+        pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i, (int)i);
+    }
+    src = mputstr(src,
+      "TTCN_error(\"Internal error: Adding invalid port type.\");\n"
+      "}\n\n");
+    
+    def = mputstr(def, "void remove_port(PORT* p);\n");
+    src = mputprintf(src, "void %s::remove_port(PORT* p)\n{\n", class_name);
       
-      def = mputprintf(def, "void remove_port(%s* p);\n", pdef->provider_msg_outlist.elements[i].name);
+    for (i = 0; i < pdef->provider_msg_outlist.nElements; i++) {
       src = mputprintf(src,
-        "void %s::remove_port(%s* p) {\n"
+        "%s* x_%i = dynamic_cast<%s*>(p);\n"
+        "if (x_%i != NULL) {\n"
         "for (size_t i = 0; i < n_%i; i++) {\n"
-        "if (p_%i[i] == p) {\n"
-        "p_%i[i]->remove_port(static_cast<%s*>(this));\n"
+        "if (p_%i[i] == x_%i) {\n"
         "p_%i[i] = NULL;\n"
         "}\n"
         "}\n"
@@ -2169,12 +2180,19 @@ void defPortClass(const port_def* pdef, output_struct* output)
         "Free(p_%i);\n"
         "p_%i = port_list;\n"
         "n_%i = size;\n"
-        "}\n\n", class_name, pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i,
-        (int)i, pdef->name, (int)i, pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i,
+        "return;\n"
+        "}\n",
+        pdef->provider_msg_outlist.elements[i].name, (int)i,
+        pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i, (int)i,
+        (int)i, (int)i, pdef->provider_msg_outlist.elements[i].name, (int)i, (int)i,
         pdef->provider_msg_outlist.elements[i].name, pdef->provider_msg_outlist.elements[i].name,
         (int)i, (int)i, (int)i, (int)i);
     }
     
+    src = mputstr(src,
+      "TTCN_error(\"Internal error: Removing invalid port type.\");\n"
+      "}\n\n");
+    
     // in_translation_mode returns true if one of the port type variables are not null
     def = mputstr(def, "boolean in_translation_mode() const;\n");
     src = mputprintf(src, "boolean %s::in_translation_mode() const {\nreturn ", class_name);
@@ -2211,22 +2229,35 @@ void defPortClass(const port_def* pdef, output_struct* output)
   if (pdef->n_mapper_name > 0) {
     def = mputstr(def, "public:\n");
     // add_port and remove_port is called after the map and unmap statements.
+    def = mputstr(def, "void add_port(PORT* p);\n");
+    src = mputprintf(src, "void %s::add_port(PORT* p)\n{\n", class_name);
     for (i = 0; i < pdef->n_mapper_name; i++) {
-      def = mputprintf(def, "void add_port(%s* p);\n", pdef->mapper_name[i]);
       src = mputprintf(src,
-        "void %s::add_port(%s*p) {\n"
+        "%s* x_%i = dynamic_cast<%s*>(p);\n"
+        "if (x_%i != NULL) {\n"
         "n_%i++;\n"
         "p_%i = static_cast<%s**>(Realloc(p_%i, n_%i * sizeof(%s*)));\n"
-        "p_%i[n_%i-1] = p;\n"
-        "}\n\n", class_name, pdef->mapper_name[i], (int)i, (int)i,
-        pdef->mapper_name[i], (int)i, (int)i, pdef->mapper_name[i],
-        (int)i, (int)i);
+        "p_%i[n_%i-1] = x_%i;\n"
+        "return;\n"
+        "}\n",
+        pdef->mapper_name[i], (int)i,
+        pdef->mapper_name[i], (int)i, (int)i,
+        (int)i, pdef->mapper_name[i], (int)i, (int)i,
+        pdef->mapper_name[i], (int)i, (int)i, (int)i);
+    }
+    src = mputstr(src,
+      "TTCN_error(\"Internal error: Adding invalid port type.\");\n"
+      "}\n\n");
+    
+    def = mputstr(def, "void remove_port(PORT* p);\n");
+    src = mputprintf(src, "void %s::remove_port(PORT* p)\n{\n", class_name);
       
-      def = mputprintf(def, "void remove_port(%s*);\n", pdef->mapper_name[i]);
+    for (i = 0; i < pdef->n_mapper_name; i++) {
       src = mputprintf(src,
-        "void %s::remove_port(%s* p) {\n"
+        "%s* x_%i = dynamic_cast<%s*>(p);\n"
+        "if (x_%i != NULL) {\n"
         "for (size_t i = 0; i < n_%i; i++) {\n"
-        "if (p_%i[i] == p) {\n"
+        "if (p_%i[i] == x_%i) {\n"
         "p_%i[i] = NULL;\n"
         "}\n"
         "}\n"
@@ -2242,11 +2273,18 @@ void defPortClass(const port_def* pdef, output_struct* output)
         "Free(p_%i);\n"
         "p_%i = port_list;\n"
         "n_%i = size;\n"
-        "}\n\n", class_name, pdef->mapper_name[i], (int)i,
-        (int)i, (int)i, pdef->mapper_name[i], (int)i, (int)i,
+        "return;\n"
+        "}\n",
+        pdef->mapper_name[i], (int)i, pdef->mapper_name[i], (int)i,
+        (int)i, (int)i, (int)i, (int)i, pdef->mapper_name[i], (int)i, (int)i,
         pdef->mapper_name[i], pdef->mapper_name[i],
         (int)i, (int)i, (int)i, (int)i);
     }
+    
+    src = mputstr(src,
+      "TTCN_error(\"Internal error: Removing invalid port type.\");\n"
+      "}\n\n");
+    
     def = mputstr(def, "private:\n");
     // Resets all port type variables to NULL
     def = mputstr(def, "void reset_port_variables();\n");
diff --git a/core/Array.hh b/core/Array.hh
index 4554cfad7..3178d604d 100644
--- a/core/Array.hh
+++ b/core/Array.hh
@@ -204,6 +204,14 @@ public:
       array_elements[v_index].activate_port();
     }
   }
+  
+  // needed by the init_system_port function
+  void safe_start()
+  {
+    for (unsigned int v_index = 0; v_index < array_size; v_index++) {
+      array_elements[v_index].safe_start();
+    }
+  }
 
   void log() const
   {
diff --git a/core/Communication.cc b/core/Communication.cc
index b8110bcc2..548ee2d93 100644
--- a/core/Communication.cc
+++ b/core/Communication.cc
@@ -1357,15 +1357,20 @@ void TTCN_Communication::process_create_ptc()
       "component reference %d.", component_reference);
     return;
   }
-  qualified_name component_type;
+  qualified_name component_type, system_type;
   incoming_buf.pull_qualified_name(component_type);
+  incoming_buf.pull_qualified_name(system_type);
   if (component_type.module_name == NULL ||
-    component_type.definition_name == NULL) {
+      component_type.definition_name == NULL ||
+      system_type.module_name == NULL ||
+      system_type.definition_name == NULL) {
     incoming_buf.cut_message();
     delete [] component_type.module_name;
     delete [] component_type.definition_name;
+    delete [] system_type.module_name;
+    delete [] system_type.definition_name;
     send_error("Message CREATE_PTC with component reference %d contains "
-      "an invalid component type.", component_reference);
+      "an invalid component type or system type.", component_reference);
     return;
   }
   char *component_name = incoming_buf.pull_string();
@@ -1377,12 +1382,15 @@ void TTCN_Communication::process_create_ptc()
   try {
     TTCN_Runtime::process_create_ptc(component_reference,
       component_type.module_name, component_type.definition_name,
+      system_type.module_name, system_type.definition_name,
       component_name, is_alive, current_testcase.module_name,
       current_testcase.definition_name);
   } catch (...) {
     // to prevent from memory leaks
     delete [] component_type.module_name;
     delete [] component_type.definition_name;
+    delete [] system_type.module_name;
+    delete [] system_type.definition_name;
     delete [] component_name;
     delete [] current_testcase.module_name;
     delete [] current_testcase.definition_name;
@@ -1391,6 +1399,8 @@ void TTCN_Communication::process_create_ptc()
 
   delete [] component_type.module_name;
   delete [] component_type.definition_name;
+  delete [] system_type.module_name;
+  delete [] system_type.definition_name;
   delete [] component_name;
   delete [] current_testcase.module_name;
   delete [] current_testcase.definition_name;
@@ -1759,6 +1769,13 @@ void TTCN_Communication::process_map()
     if (translation == TRUE) {
       PORT::map_port(local_port, system_port, TRUE);
     }
+    if (!TTCN_Runtime::is_single()) {
+      if (translation == FALSE) {
+        send_mapped(local_port, system_port, translation);
+      } else {
+        send_mapped(system_port, local_port, translation);
+      }
+    }
   } catch (...) {
     delete [] local_port;
     delete [] system_port;
@@ -1798,6 +1815,13 @@ void TTCN_Communication::process_unmap()
     if (translation == TRUE) {
       PORT::unmap_port(local_port, system_port, TRUE);
     }
+    if (!TTCN_Runtime::is_single()) {
+      if (translation == FALSE) {
+        send_unmapped(local_port, system_port, translation);
+      } else {
+        send_unmapped(system_port, local_port, translation);
+      }
+    }
   } catch (...) {
     delete [] local_port;
     delete [] system_port;
diff --git a/core/Module_list.cc b/core/Module_list.cc
index c63f30373..a5b8483b9 100644
--- a/core/Module_list.cc
+++ b/core/Module_list.cc
@@ -155,6 +155,24 @@ void Module_List::initialize_component(const char *module_name,
       "module %s.", component_type, module_name);
 }
 
+void Module_List::initialize_system_port(const char* module_name,
+  const char* component_type, const char* port_name)
+{
+  TTCN_Module* system_module = Module_List::lookup_module(module_name);
+  if (system_module == NULL) {
+    TTCN_error("Internal error: Module %s does not exist.", module_name);
+  }
+  if (system_module->initialize_system_port_func == NULL) {
+    TTCN_error("Internal error: Module %s does not have a system port "
+      "initializer function.", module_name);
+  }
+  if (!system_module->initialize_system_port_func(component_type, port_name)) {
+    TTCN_error("Internal error: Cannot find port %s in component type %s, or "
+      "component type %s in module %s.", port_name, component_type,
+      component_type, module_name);
+  }
+}
+
 void Module_List::set_param(Module_Param& param)
 {
 #ifndef TITAN_RUNTIME_2
@@ -786,6 +804,7 @@ TTCN_Module::TTCN_Module(const char *par_module_name,
   get_param_func_t par_get_param_func,
   log_param_func_t par_log_param_func,
   initialize_component_func_t par_initialize_component_func,
+  initialize_system_port_func_t par_initialize_system_port_func,
   start_func_t par_start_func,
   control_func_t par_control_func)
 : list_prev(NULL), list_next(NULL)
@@ -810,6 +829,7 @@ TTCN_Module::TTCN_Module(const char *par_module_name,
 , get_param_func(par_get_param_func)
 , log_param_func(par_log_param_func)
 , initialize_component_func(par_initialize_component_func)
+, initialize_system_port_func(par_initialize_system_port_func)
 , start_func(par_start_func)
 , control_func(par_control_func)
 , function_head(NULL)
@@ -850,6 +870,7 @@ TTCN_Module::TTCN_Module(const char *par_module_name,
 , get_param_func(NULL)
 , log_param_func(NULL)
 , initialize_component_func(NULL)
+, initialize_system_port_func(NULL)
 , start_func(NULL)
 , control_func(NULL)
 , function_head(NULL)
@@ -888,6 +909,7 @@ TTCN_Module::TTCN_Module(const char *par_module_name,
 , set_param_func(NULL)
 , log_param_func(NULL)
 , initialize_component_func(NULL)
+, initialize_system_port_func(NULL)
 , start_func(NULL)
 , control_func(NULL)
 , function_head(NULL)
diff --git a/core/Module_list.hh b/core/Module_list.hh
index 27146f5eb..b2dfa4705 100644
--- a/core/Module_list.hh
+++ b/core/Module_list.hh
@@ -56,6 +56,8 @@ public:
 
   static void initialize_component(const char *module_name,
     const char *component_type, boolean init_base_comps);
+  static void initialize_system_port(const char* module_name,
+    const char* component_type, const char* port_name);
 
   static void set_param(Module_Param& param);
 #ifdef TITAN_RUNTIME_2
@@ -122,6 +124,8 @@ public:
   typedef void (*log_param_func_t)();
   typedef boolean (*initialize_component_func_t)(const char *component_type,
     boolean init_base_comps);
+  typedef boolean (*initialize_system_port_func_t)(const char* component_type,
+    const char* port_name);
   typedef boolean (*start_func_t)(const char *function_name,
     Text_Buf& function_arguments);
   typedef void (*control_func_t)();
@@ -152,6 +156,7 @@ private:
   get_param_func_t get_param_func;
   log_param_func_t log_param_func;
   initialize_component_func_t initialize_component_func;
+  initialize_system_port_func_t initialize_system_port_func;
   start_func_t start_func;
   control_func_t control_func;
   struct function_list_item;
@@ -184,6 +189,7 @@ public:
     get_param_func_t par_get_param_func,
     log_param_func_t par_log_param_func,
     initialize_component_func_t par_initialize_component_func,
+    initialize_system_port_func_t par_initialize_system_port_func,
     start_func_t par_start_func,
     control_func_t par_control_func);
   TTCN_Module(const char *par_module_name,
diff --git a/core/Port.cc b/core/Port.cc
index 8cdd77ab9..b1f0f7a5e 100644
--- a/core/Port.cc
+++ b/core/Port.cc
@@ -503,6 +503,24 @@ boolean PORT::port_is_started() {
   return is_started;
 }
 
+void PORT::safe_start()
+{
+  if (!is_started) {
+    activate_port(TRUE);
+    start();
+  }
+}
+
+void PORT::add_port(PORT* /*p*/)
+{
+  TTCN_error("Internal error: Calling PORT::add_port");
+}
+
+void PORT::remove_port(PORT* /*p*/)
+{
+  TTCN_error("Internal error: Calling PORT::remove_port");
+}
+
 PORT* PORT::get_provider_port() {
   return NULL;
 }
@@ -2493,6 +2511,9 @@ void PORT::terminate_local_connection(const char *src_port,
 
 void PORT::map_port(const char *component_port, const char *system_port, boolean translation)
 {
+  if (translation == TRUE) {
+    TTCN_Runtime::initialize_system_port(system_port);
+  }
   const char *port_name = translation == FALSE ? component_port : system_port;
   PORT *port_ptr = lookup_by_name(port_name, translation);
   if (port_ptr == NULL) TTCN_error("Map operation refers to "
@@ -2505,17 +2526,21 @@ void PORT::map_port(const char *component_port, const char *system_port, boolean
   } else {
     port_ptr->map(component_port, translation);
   }
-  if (!TTCN_Runtime::is_single()) {
-    if (translation == FALSE) {
-      TTCN_Communication::send_mapped(component_port, system_port, translation);
-    } else {
-      TTCN_Communication::send_mapped(system_port, component_port, translation);
+  if (translation == TRUE) {
+    PORT* other_port_ptr = lookup_by_name(component_port, FALSE);
+    if (other_port_ptr == NULL) {
+      TTCN_error("Map operation refers to non-existent port %s.", port_name);
     }
+    other_port_ptr->add_port(port_ptr);
+    port_ptr->add_port(other_port_ptr);
   }
 }
 
 void PORT::unmap_port(const char *component_port, const char *system_port, boolean translation)
 {
+  if (translation == TRUE) {
+    TTCN_Runtime::initialize_system_port(system_port);
+  }
   const char *port_name = translation == FALSE ? component_port : system_port;
   PORT *port_ptr = lookup_by_name(port_name, translation);
   if (port_ptr == NULL) TTCN_error("Unmap operation refers to "
@@ -2525,8 +2550,14 @@ void PORT::unmap_port(const char *component_port, const char *system_port, boole
   } else {
     port_ptr->unmap(component_port, translation);
   }
-  if (!TTCN_Runtime::is_single())
-    TTCN_Communication::send_unmapped(component_port, system_port, translation);
+  if (translation == TRUE) {
+    PORT* other_port_ptr = lookup_by_name(component_port, FALSE);
+    if (other_port_ptr == NULL) {
+      TTCN_error("Unmap operation refers to non-existent port %s.", port_name);
+    }
+    other_port_ptr->remove_port(port_ptr);
+    port_ptr->remove_port(other_port_ptr);
+  }
 }
 
 boolean PORT::check_port_state(const CHARSTRING& type) const
diff --git a/core/Port.hh b/core/Port.hh
index 0d0d6a132..08578a1cc 100644
--- a/core/Port.hh
+++ b/core/Port.hh
@@ -138,6 +138,13 @@ public:
   
   boolean port_is_started();
   
+  // activate and start a system port if it's not already started
+  // needed by the init_system_port function
+  void safe_start();
+  
+  virtual void add_port(PORT* p);
+  virtual void remove_port(PORT* p);
+  
   // Returns the outer message port it is mapped to 
   // when the port works in translation mode. 
   // In the case of dual faced ports it returns the port object
diff --git a/core/Runtime.cc b/core/Runtime.cc
index 4f2f64596..744135032 100644
--- a/core/Runtime.cc
+++ b/core/Runtime.cc
@@ -74,6 +74,7 @@ TTCN_Runtime::executor_state_enum
     TTCN_Runtime::executor_state = UNDEFINED_STATE;
 
 qualified_name TTCN_Runtime::component_type = { NULL, NULL };
+qualified_name TTCN_Runtime::system_type = { NULL, NULL };
 char *TTCN_Runtime::component_name = NULL;
 boolean TTCN_Runtime::is_alive = FALSE;
 
@@ -204,6 +205,7 @@ void TTCN_Runtime::clear_qualified_name(qualified_name& q_name)
 void TTCN_Runtime::clean_up()
 {
   clear_qualified_name(component_type);
+  clear_qualified_name(system_type);
   Free(component_name);
   component_name = NULL;
   control_module_name = NULL;
@@ -269,6 +271,20 @@ void TTCN_Runtime::set_component_type(const char *component_type_module,
   component_type.definition_name = mcopystr(component_type_name);
 }
 
+void TTCN_Runtime::set_system_type(const char* system_type_module,
+  const char* system_type_name)
+{
+  if (system_type_module == NULL || system_type_module[0] == '\0' ||
+      system_type_name == NULL || system_type_name[0] == '\0') {
+    TTCN_error("Internal error: TTCN_Runtime::set_system_type: "
+      "Trying to set an invalid system component type.");
+  }
+
+  clear_qualified_name(system_type);
+  system_type.module_name = mcopystr(system_type_module);
+  system_type.definition_name = mcopystr(system_type_name);
+}
+
 void TTCN_Runtime::set_component_name(const char *new_component_name)
 {
   Free(component_name);
@@ -626,6 +642,12 @@ int TTCN_Runtime::ptc_main()
   return ret_val;
 }
 
+void TTCN_Runtime::initialize_system_port(const char* port_name)
+{
+  Module_List::initialize_system_port(system_type.module_name,
+    system_type.definition_name, port_name);
+}
+
 component TTCN_Runtime::create_component(
   const char *created_component_type_module,
   const char *created_component_type_name, const char *created_component_name,
@@ -2042,6 +2064,7 @@ void TTCN_Runtime::begin_testcase(
   TIMER::save_control_timers();
   TTCN_Default::save_control_defaults();
   set_testcase_name(par_module_name, par_testcase_name);
+  set_system_type(system_comptype_module, system_comptype_name);
   char *command_arguments = mprintf("%s.%s", testcase_name.module_name,
     testcase_name.definition_name);
   execute_command(begin_testcase_command, command_arguments);
@@ -2422,6 +2445,7 @@ void TTCN_Runtime::process_create_mtc()
 
 void TTCN_Runtime::process_create_ptc(component component_reference,
   const char *component_type_module, const char *component_type_name,
+  const char *system_type_module, const char *system_type_name,
   const char *par_component_name, boolean par_is_alive,
   const char *current_testcase_module, const char *current_testcase_name)
 {
@@ -2468,6 +2492,7 @@ void TTCN_Runtime::process_create_ptc(component component_reference,
     TTCN_Communication::close_mc_connection();
     self = component_reference;
     set_component_type(component_type_module, component_type_name);
+    set_system_type(system_type_module, system_type_name);
     set_component_name(par_component_name);
     is_alive = par_is_alive;
     set_testcase_name(current_testcase_module, current_testcase_name);
diff --git a/core/Runtime.hh b/core/Runtime.hh
index 490d544a9..7173b8012 100644
--- a/core/Runtime.hh
+++ b/core/Runtime.hh
@@ -62,6 +62,7 @@ private:
   static executor_state_enum executor_state;
 
   static qualified_name component_type;
+  static qualified_name system_type;
   static char *component_name;
   static boolean is_alive;
 
@@ -153,6 +154,8 @@ public:
   static void clean_up();
   static void set_component_type(const char *component_type_module,
     const char *component_type_name);
+  static void set_system_type(const char* system_type_module,
+    const char* system_type_name);
   static void set_component_name(const char *new_component_name);
   inline static void set_alive_flag(boolean par_is_alive)
   { is_alive = par_is_alive; }
@@ -195,6 +198,8 @@ public:
     unsigned short MC_port);
   static int mtc_main();
   static int ptc_main();
+  
+  static void initialize_system_port(const char* port_name);
 
   static component create_component(const char *created_component_type_module,
     const char *created_component_type_name,
@@ -306,6 +311,7 @@ public:
   static void process_create_mtc();
   static void process_create_ptc(component component_reference,
     const char *component_type_module, const char *component_type_name,
+    const char *system_type_module, const char *system_type_name,
     const char *par_component_name, boolean par_is_alive,
     const char *current_testcase_module, const char *current_testcase_name);
 
diff --git a/mctr2/mctr/MainController.cc b/mctr2/mctr/MainController.cc
index a9c705610..3eaee3bdd 100644
--- a/mctr2/mctr/MainController.cc
+++ b/mctr2/mctr/MainController.cc
@@ -3232,13 +3232,14 @@ void MainController::send_create_mtc(host_struct *hc)
 
 void MainController::send_create_ptc(host_struct *hc,
   component component_reference, const qualified_name& component_type,
-  const char *component_name, boolean is_alive,
-  const qualified_name& current_testcase)
+  const qualified_name& system_type, const char *component_name,
+  boolean is_alive, const qualified_name& current_testcase)
 {
   Text_Buf text_buf;
   text_buf.push_int(MSG_CREATE_PTC);
   text_buf.push_int(component_reference);
   text_buf.push_qualified_name(component_type);
+  text_buf.push_qualified_name(system_type);
   text_buf.push_string(component_name);
   text_buf.push_int(is_alive ? 1 : 0);
   text_buf.push_qualified_name(current_testcase);
@@ -3997,7 +3998,7 @@ void MainController::process_create_nak(host_struct *hc)
       tc->initial.location_str);
     if (new_host != NULL) {
       send_create_ptc(new_host, component_reference, tc->comp_type,
-        tc->comp_name, tc->is_alive, mtc->tc_fn_name);
+        system->comp_type, tc->comp_name, tc->is_alive, mtc->tc_fn_name);
       notify("PTC with component reference %d was relocated from host "
         "%s to %s because of overload: %s.", component_reference,
         hc->hostname, new_host->hostname, reason);
@@ -4145,8 +4146,8 @@ void MainController::process_create_req(component_struct *tc)
   }
 
   component comp_ref = next_comp_ref++;
-  send_create_ptc(host, comp_ref, component_type, component_name, is_alive,
-    mtc->tc_fn_name);
+  send_create_ptc(host, comp_ref, component_type, system->comp_type,
+    component_name, is_alive, mtc->tc_fn_name);
 
   tc->tc_state = TC_CREATE;
 
diff --git a/mctr2/mctr/MainController.h b/mctr2/mctr/MainController.h
index 6d4384bb2..c67f13eec 100644
--- a/mctr2/mctr/MainController.h
+++ b/mctr2/mctr/MainController.h
@@ -491,8 +491,9 @@ private:
   static void send_exit_hc(host_struct *hc);
   static void send_create_mtc(host_struct *hc);
   static void send_create_ptc(host_struct *hc, component component_reference,
-    const qualified_name& component_type, const char *component_name,
-    boolean is_alive, const qualified_name& current_testcase);
+    const qualified_name& component_type, const qualified_name& system_type,
+    const char *component_name, boolean is_alive,
+    const qualified_name& current_testcase);
   static void send_kill_process(host_struct *hc,
     component component_reference);
 
diff --git a/regression_test/portTranslation/Makefile b/regression_test/portTranslation/Makefile
index f5dad0b4c..22e80bbcc 100644
--- a/regression_test/portTranslation/Makefile
+++ b/regression_test/portTranslation/Makefile
@@ -64,7 +64,7 @@ GENERATED_SOURCES += $(GENERATED_SOURCES2)
 endif
 # C/C++ Source & header files of Test Ports, external functions and
 # other modules:
-USER_SOURCES = PT2.cc PT3.cc P1.cc P2.cc P3.cc P4.cc VP1.cc NVP1.cc P1Internal.cc P2Internal.cc P3Internal.cc VP1Internal.cc
+USER_SOURCES = PT2.cc PT3.cc PT4.cc P1.cc P2.cc P3.cc P4.cc P5.cc VP1.cc NVP1.cc P1Internal.cc P2Internal.cc P3Internal.cc VP1Internal.cc
 USER_HEADERS = $(USER_SOURCES:.cc=.hh)
 
 # Object files of this project that are needed for the executable test suite:
diff --git a/regression_test/portTranslation/P5.cc b/regression_test/portTranslation/P5.cc
new file mode 100644
index 000000000..50f7e748a
--- /dev/null
+++ b/regression_test/portTranslation/P5.cc
@@ -0,0 +1,81 @@
+/******************************************************************************
+ * Copyright (c) 2000-2018 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Botond, Baranyi
+ *
+ ******************************************************************************/
+
+#include "P5.hh"
+#include "PortTranslation.hh"
+
+namespace PortTranslation {
+
+P5_PROVIDER::P5_PROVIDER(const char *par_port_name)
+	: PORT(par_port_name)
+{
+
+}
+
+P5_PROVIDER::~P5_PROVIDER()
+{
+
+}
+
+void P5_PROVIDER::set_parameter(const char * /*parameter_name*/,
+	const char * /*parameter_value*/)
+{
+
+}
+
+/*void P5_PROVIDER::Handle_Fd_Event(int fd, boolean is_readable,
+	boolean is_writable, boolean is_error) {}*/
+
+void P5_PROVIDER::Handle_Fd_Event_Error(int /*fd*/)
+{
+
+}
+
+void P5_PROVIDER::Handle_Fd_Event_Writable(int /*fd*/)
+{
+
+}
+
+void P5_PROVIDER::Handle_Fd_Event_Readable(int /*fd*/)
+{
+
+}
+
+/*void P5_PROVIDER::Handle_Timeout(double time_since_last_call) {}*/
+
+void P5_PROVIDER::user_map(const char * /*system_port*/)
+{
+
+}
+
+void P5_PROVIDER::user_unmap(const char * /*system_port*/)
+{
+
+}
+
+void P5_PROVIDER::user_start()
+{
+
+}
+
+void P5_PROVIDER::user_stop()
+{
+
+}
+
+void P5_PROVIDER::outgoing_send(const CHARSTRING& /*send_par*/)
+{
+  
+}
+
+} /* end of namespace */
+
diff --git a/regression_test/portTranslation/P5.hh b/regression_test/portTranslation/P5.hh
new file mode 100644
index 000000000..828a9048b
--- /dev/null
+++ b/regression_test/portTranslation/P5.hh
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * Copyright (c) 2000-2018 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Botond, Baranyi
+ *
+ ******************************************************************************/
+
+#ifndef P5_HH
+#define P5_HH
+
+#include <TTCN3.hh>
+
+// Note: Header file PortTranslation.hh must not be included into this file!
+// (because it includes this file)
+// Please add the declarations of message types manually.
+
+namespace PortTranslation {
+
+class P5_PROVIDER : public PORT {
+public:
+	P5_PROVIDER(const char *par_port_name);
+	~P5_PROVIDER();
+
+	void set_parameter(const char *parameter_name,
+		const char *parameter_value);
+
+private:
+	/* void Handle_Fd_Event(int fd, boolean is_readable,
+		boolean is_writable, boolean is_error); */
+	void Handle_Fd_Event_Error(int fd);
+	void Handle_Fd_Event_Writable(int fd);
+	void Handle_Fd_Event_Readable(int fd);
+	/* void Handle_Timeout(double time_since_last_call); */
+protected:
+	void user_map(const char *system_port);
+	void user_unmap(const char *system_port);
+
+	void user_start();
+	void user_stop();
+
+	void outgoing_send(const CHARSTRING& send_par);
+	virtual void incoming_message(const INTEGER& incoming_par) = 0;
+};
+
+} /* end of namespace */
+
+#endif
diff --git a/regression_test/portTranslation/PT4.cc b/regression_test/portTranslation/PT4.cc
new file mode 100644
index 000000000..556deab60
--- /dev/null
+++ b/regression_test/portTranslation/PT4.cc
@@ -0,0 +1,80 @@
+/******************************************************************************
+ * Copyright (c) 2000-2018 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Botond, Baranyi
+ *
+ ******************************************************************************/
+
+#include "PT4.hh"
+
+namespace PortTranslation {
+
+PT4::PT4(const char *par_port_name)
+	: PT4_BASE(par_port_name)
+{
+
+}
+
+PT4::~PT4()
+{
+
+}
+
+void PT4::set_parameter(const char * /*parameter_name*/,
+	const char * /*parameter_value*/)
+{
+
+}
+
+/*void PT4::Handle_Fd_Event(int fd, boolean is_readable,
+	boolean is_writable, boolean is_error) {}*/
+
+void PT4::Handle_Fd_Event_Error(int /*fd*/)
+{
+
+}
+
+void PT4::Handle_Fd_Event_Writable(int /*fd*/)
+{
+
+}
+
+void PT4::Handle_Fd_Event_Readable(int /*fd*/)
+{
+
+}
+
+/*void PT4::Handle_Timeout(double time_since_last_call) {}*/
+
+void PT4::user_map(const char * /*system_port*/)
+{
+
+}
+
+void PT4::user_unmap(const char * /*system_port*/)
+{
+
+}
+
+void PT4::user_start()
+{
+
+}
+
+void PT4::user_stop()
+{
+
+}
+
+void PT4::outgoing_send(const CHARSTRING& /*send_par*/)
+{
+  TTCN_Runtime::setverdict(FAIL, "The port mapping was not done in translation mode.");
+}
+
+} /* end of namespace */
+
diff --git a/regression_test/portTranslation/PT4.hh b/regression_test/portTranslation/PT4.hh
new file mode 100644
index 000000000..4b5a5d05c
--- /dev/null
+++ b/regression_test/portTranslation/PT4.hh
@@ -0,0 +1,47 @@
+/******************************************************************************
+ * Copyright (c) 2000-2018 Ericsson Telecom AB
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *   Botond, Baranyi
+ *
+ ******************************************************************************/
+
+#ifndef PT4_HH
+#define PT4_HH
+
+#include "PortTranslation.hh"
+
+namespace PortTranslation {
+
+class PT4 : public PT4_BASE {
+public:
+	PT4(const char *par_port_name = NULL);
+	~PT4();
+
+	void set_parameter(const char *parameter_name,
+		const char *parameter_value);
+
+private:
+	/* void Handle_Fd_Event(int fd, boolean is_readable,
+		boolean is_writable, boolean is_error); */
+	void Handle_Fd_Event_Error(int fd);
+	void Handle_Fd_Event_Writable(int fd);
+	void Handle_Fd_Event_Readable(int fd);
+	/* void Handle_Timeout(double time_since_last_call); */
+protected:
+	void user_map(const char *system_port);
+	void user_unmap(const char *system_port);
+
+	void user_start();
+	void user_stop();
+
+	void outgoing_send(const CHARSTRING& send_par);
+};
+
+} /* end of namespace */
+
+#endif
diff --git a/regression_test/portTranslation/PortTranslation.ttcn b/regression_test/portTranslation/PortTranslation.ttcn
index f08d14dee..c820043a3 100644
--- a/regression_test/portTranslation/PortTranslation.ttcn
+++ b/regression_test/portTranslation/PortTranslation.ttcn
@@ -231,6 +231,26 @@ module PortTranslation {
 	} with {
 		extension "prototype(fast)";
 	}
+	
+	function int_to_int(in integer i, out integer j) port PT4 {
+		j := i;
+		port.setstate(0);
+	} with {
+		extension "prototype(fast)";
+	}
+
+	function char_to_char2(in charstring i, out charstring j) port PT4 {
+		j := i;
+		if (i == "abc") {
+			setverdict(pass);
+		}
+		else {
+			setverdict(fail, "Sending invalid message: ", i);
+		}
+		port.setstate(0);
+	} with {
+		extension "prototype(fast)";
+	}
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -272,6 +292,13 @@ module PortTranslation {
 	} with {
 	  extension "provider"
 	}
+	
+	type port P5 message {
+		in integer
+		out charstring
+	} with {
+		extension "provider"
+	}
 
 	type port PT2 message map to P1, P2 {
 		in charstring from charstring with char_to_char()
@@ -294,23 +321,32 @@ module PortTranslation {
 	  out integer, charstring
 	  out boolean to boolean with bool_to_bool_discard()
 	}
+	
+	type port PT4 message map to P5 {
+		in integer from integer with int_to_int()
+		out charstring to charstring with char_to_char2()
+	}
 
 
 	type component MyComp {
 		port PT2 p;
 		port PT3 p3;
+		port PT4 p4;
 
 		// Extra port types to check if multiple map/unmaps does not make things go bad
 		port PT2 p11;
 		port PT2 p12;
 		port PT2 p13;
 	}
+	
+	type component MyComp2 {}
 
 	type component System {
 		port P1 p1
 		port P2 p2
 		port P3 p3
 		port P4 p4
+		port P5 p5
 
 		// Extra port types to check if multiple map/unmaps does not make things go bad
 		port P1 p11
@@ -831,6 +867,55 @@ module PortTranslation {
 		}
 		t.stop;
 	}
+	
+	// Test function for remote mappings (is executed on the same PTC where the mappings take place)
+	function f_behavior_mapping_test(boolean mapping_required) runs on MyComp system System {
+		var boolean is_mapped := p4.checkstate("Mapped");
+		if (is_mapped and mapping_required) {
+			// it's mapped and it should be
+			// the translation function will set the verdict
+			p4.send("abc");
+		}
+		else if (not is_mapped and not mapping_required) {
+			// it's correctly not mapped
+			setverdict(pass);
+		}
+		else {
+			var charstring mapped_state;
+			if (is_mapped) {
+				mapped_state := "mapped";
+			}
+			else {
+				mapped_state := "unmapped";
+			}
+			setverdict(fail, "Invalid port state (port is ", mapped_state, ").");
+		}
+	}
+
+	// Remote mapping function
+	// Maps and unmaps ports (in translation mode) on a different PTC, and runs the test function.
+	function f_behavior_map_and_unmap() runs on MyComp2 system System {
+		var MyComp ct := MyComp.create alive;
+		map(ct:p4, system:p5);
+		ct.start(f_behavior_mapping_test(true));
+		ct.done;
+		
+		unmap(ct:p4, system:p5);
+		ct.start(f_behavior_mapping_test(false));
+		ct.done;
+	}
+
+	// Tests remote mapping and unmapping (initiated from a PTC).
+	testcase tc_remote_mapping_from_ptc() runs on MyComp2 system System {
+		var MyComp2 ct := MyComp2.create;
+		ct.start(f_behavior_map_and_unmap());
+		ct.done;
+	}
+
+	// Tests remote mapping and unmapping (initiated from the MTC).
+	testcase tc_remote_mapping_from_mtc() runs on MyComp2 system System {
+		f_behavior_map_and_unmap();
+	}
 
 	control {
 		execute(tc_send())
@@ -850,6 +935,9 @@ module PortTranslation {
 		execute(tc_receive_fragmented());
 		
 		execute(tc_receive_discarded_plus_port_ref());
+		
+		execute(tc_remote_mapping_from_ptc());
+		execute(tc_remote_mapping_from_mtc());
 	}
 
 }
-- 
GitLab