1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
13 #include <sys/types.h>
14 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
20 #include "../common/platform.h"
22 #include "../common/memory.h"
23 #include "Component.hh"
26 #include "Event_Handler.hh"
27 #include "Fd_And_Timeout_User.hh"
28 #include "Snapshot.hh"
29 #include "Communication.hh"
31 #include "Octetstring.hh"
32 #include "TitanLoggerApi.hh"
34 // maximum number of iterations for binding the UNIX server socket
35 #define UNIX_BIND_MAX_ITER 100
37 #include "../common/dbgnew.hh"
39 PORT
*PORT::list_head
= NULL
, *PORT::list_tail
= NULL
;
41 void PORT::add_to_list()
43 // check for duplicate names
44 for (PORT
*p
= list_head
; p
!= NULL
; p
= p
->list_next
) {
45 // do nothing if this is already a member of the list
46 if (p
== this) return;
47 else if (!strcmp(p
->port_name
, port_name
))
48 TTCN_error("Internal error: There are more than one ports with "
49 "name %s.", port_name
);
51 // append this to the list
52 if (list_head
== NULL
) list_head
= this;
53 else if (list_tail
!= NULL
) list_tail
->list_next
= this;
54 list_prev
= list_tail
;
59 void PORT::remove_from_list()
61 if (list_prev
!= NULL
) list_prev
->list_next
= list_next
;
62 else if (list_head
== this) list_head
= list_next
;
63 if (list_next
!= NULL
) list_next
->list_prev
= list_prev
;
64 else if (list_tail
== this) list_tail
= list_prev
;
69 PORT
*PORT::lookup_by_name(const char *par_port_name
)
71 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
72 if (!strcmp(par_port_name
, port
->port_name
)) return port
;
76 struct PORT::port_parameter
{
77 component_id_t component_id
;
80 char *parameter_value
;
81 struct port_parameter
*next_par
;
82 } *PORT::parameter_head
= NULL
, *PORT::parameter_tail
= NULL
;
84 void PORT::apply_parameter(port_parameter
*par_ptr
)
86 if (par_ptr
->port_name
!= NULL
) {
87 // the parameter refers to a specific port
88 PORT
*port
= lookup_by_name(par_ptr
->port_name
);
89 if (port
!= NULL
) port
->set_parameter(par_ptr
->parameter_name
,
90 par_ptr
->parameter_value
);
92 // the parameter refers to all ports (*)
93 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
94 port
->set_parameter(par_ptr
->parameter_name
,
95 par_ptr
->parameter_value
);
99 void PORT::set_system_parameters(const char *system_port
)
101 for (port_parameter
*par
= parameter_head
; par
!= NULL
; par
= par
->next_par
)
102 if (par
->component_id
.id_selector
== COMPONENT_ID_SYSTEM
&&
103 (par
->port_name
== NULL
|| !strcmp(par
->port_name
, system_port
)))
104 set_parameter(par
->parameter_name
, par
->parameter_value
);
107 void PORT::add_parameter(const component_id_t
& component_id
,
108 const char *par_port_name
, const char *parameter_name
,
109 const char *parameter_value
)
111 port_parameter
*new_par
= new port_parameter
;
113 new_par
->component_id
.id_selector
= component_id
.id_selector
;
114 switch (component_id
.id_selector
) {
115 case COMPONENT_ID_NAME
:
116 new_par
->component_id
.id_name
= mcopystr(component_id
.id_name
);
118 case COMPONENT_ID_COMPREF
:
119 new_par
->component_id
.id_compref
= component_id
.id_compref
;
125 if (par_port_name
== NULL
) new_par
->port_name
= NULL
;
126 else new_par
->port_name
= mcopystr(par_port_name
);
127 new_par
->parameter_name
= mcopystr(parameter_name
);
128 new_par
->parameter_value
= mcopystr(parameter_value
);
130 new_par
->next_par
= NULL
;
131 if (parameter_head
== NULL
) parameter_head
= new_par
;
132 if (parameter_tail
!= NULL
) parameter_tail
->next_par
= new_par
;
133 parameter_tail
= new_par
;
136 void PORT::clear_parameters()
138 while (parameter_head
!= NULL
) {
139 port_parameter
*next_par
= parameter_head
->next_par
;
140 if (parameter_head
->component_id
.id_selector
== COMPONENT_ID_NAME
)
141 Free(parameter_head
->component_id
.id_name
);
142 Free(parameter_head
->port_name
);
143 Free(parameter_head
->parameter_name
);
144 Free(parameter_head
->parameter_value
);
145 delete parameter_head
;
146 parameter_head
= next_par
;
150 void PORT::set_parameters(component component_reference
,
151 const char *component_name
)
153 for (port_parameter
*par
= parameter_head
; par
!= NULL
; par
= par
->next_par
)
154 switch (par
->component_id
.id_selector
) {
155 case COMPONENT_ID_NAME
:
156 if (component_name
!= NULL
&&
157 !strcmp(par
->component_id
.id_name
, component_name
))
158 apply_parameter(par
);
160 case COMPONENT_ID_COMPREF
:
161 if (par
->component_id
.id_compref
== component_reference
)
162 apply_parameter(par
);
164 case COMPONENT_ID_ALL
:
165 apply_parameter(par
);
172 enum connection_data_type_enum
{
173 CONN_DATA_LAST
= 0, CONN_DATA_MESSAGE
= 1, CONN_DATA_CALL
= 2,
174 CONN_DATA_REPLY
= 3, CONN_DATA_EXCEPTION
= 4
177 enum connection_state_enum
{
178 CONN_IDLE
, CONN_LISTENING
, CONN_CONNECTED
, CONN_LAST_MSG_SENT
,
182 struct port_connection
: public Fd_Event_Handler
{
184 connection_state_enum connection_state
;
185 component remote_component
;
187 transport_type_enum transport_type
;
194 Text_Buf
*incoming_buf
;
197 struct port_connection
*list_prev
, *list_next
;
198 OCTETSTRING sliding_buffer
;
200 virtual void Handle_Fd_Event(int fd
,
201 boolean is_readable
, boolean is_writeable
, boolean is_error
);
202 virtual ~port_connection();
203 virtual void log() const;
206 void port_connection::Handle_Fd_Event(int,
207 boolean is_readable
, boolean
/*is_writeable*/, boolean
/*is_error*/)
209 // Note event for connection with TRANSPORT_LOCAL transport_type
211 if (transport_type
== TRANSPORT_INET_STREAM
212 || transport_type
== TRANSPORT_UNIX_STREAM
215 if (connection_state
== CONN_LISTENING
)
216 owner_port
->handle_incoming_connection(this);
217 else owner_port
->handle_incoming_data(this);
220 TTCN_error("Internal error: Invalid transport type (%d) in port "
221 "connection between %s and %d:%s.", transport_type
,
222 owner_port
->get_name(), remote_component
, remote_port
);
225 void port_connection::log() const
227 TTCN_Logger::log_event("port connection between ");
228 owner_port
->log(); TTCN_Logger::log_event(" and ");
229 TTCN_Logger::log_event(remote_component
); TTCN_Logger::log_event(":");
230 TTCN_Logger::log_event("%s", remote_port
);
233 port_connection::~port_connection()
235 if (transport_type
== TRANSPORT_INET_STREAM
236 || transport_type
== TRANSPORT_UNIX_STREAM
238 if (stream
.comm_fd
!= -1) {
239 TTCN_warning_begin("Internal Error: File descriptor %d not "
240 "closed/removed in ", stream
.comm_fd
); log();
244 sliding_buffer
.clean_up();
247 PORT::PORT(const char *par_port_name
)
249 port_name
= par_port_name
!= NULL
? par_port_name
: "<unknown>";
256 connection_list_head
= NULL
;
257 connection_list_tail
= NULL
;
258 n_system_mappings
= 0;
259 system_mappings
= NULL
;
264 if (is_active
) deactivate_port();
267 void PORT::set_name(const char * name
)
269 if (name
== NULL
) TTCN_error("Internal error: Setting an "
270 "invalid name for a single element of a port array.");
274 void PORT::log() const
276 TTCN_Logger::log_event("port %s", port_name
);
279 void PORT::activate_port()
291 void PORT::deactivate_port()
294 /* In order to proceed with the deactivation we must ignore the
296 * - errors in user code of Test Port (i.e. user_stop, user_unmap)
297 * - failures when sending messages to MC (the link may be down)
299 boolean is_parallel
= !TTCN_Runtime::is_single();
300 // terminate all connections
301 while (connection_list_head
!= NULL
) {
302 TTCN_Logger::log_port_misc(
303 TitanLoggerApi::Port__Misc_reason::removing__unterminated__connection
,
305 connection_list_head
->remote_component
, connection_list_head
->remote_port
);
308 TTCN_Communication::send_disconnected(port_name
,
309 connection_list_head
->remote_component
,
310 connection_list_head
->remote_port
);
311 } catch (const TC_Error
&) { }
313 remove_connection(connection_list_head
);
315 // terminate all mappings
316 while (n_system_mappings
> 0) {
317 // we must make a copy of the string because unmap() will destroy it
318 char *system_port
= mcopystr(system_mappings
[0]);
319 TTCN_Logger::log_port_misc(
320 TitanLoggerApi::Port__Misc_reason::removing__unterminated__mapping
,
321 port_name
, NULL_COMPREF
, system_port
);
324 } catch (const TC_Error
&) { }
327 TTCN_Communication::send_unmapped(port_name
, system_port
);
328 } catch (const TC_Error
&) { }
332 // the previous disconnect/unmap operations may generate incoming events
333 // so we should stop and clear the queue after them
334 if (is_started
|| is_halted
) {
337 } catch (const TC_Error
&) { }
340 // deactivate all event handlers
341 Fd_And_Timeout_User::remove_all_fds(this);
342 Fd_And_Timeout_User::set_timer(this, 0.0);
343 // File descriptor events of port connections are removed
344 // in remove_connection
350 void PORT::deactivate_all()
352 while (list_head
!= NULL
) list_head
->deactivate_port();
357 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
358 "be cleared.", port_name
);
359 if (!is_started
&& !is_halted
) {
360 TTCN_warning("Performing clear operation on port %s, which is "
361 "already stopped. The operation has no effect.", port_name
);
364 TTCN_Logger::log_port_misc(
365 TitanLoggerApi::Port__Misc_reason::port__was__cleared
, port_name
);
368 void PORT::all_clear()
370 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
376 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
377 "be started.", port_name
);
379 TTCN_warning("Performing start operation on port %s, which is "
380 "already started. The operation will clear the incoming queue.",
385 // the queue might contain old messages which has to be discarded
392 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::started
,
396 void PORT::all_start()
398 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
404 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
405 "be stopped.", port_name
);
410 // dropping all messages from the queue because they cannot be
411 // extracted by receiving operations anymore
413 } else if (is_halted
) {
417 TTCN_warning("Performing stop operation on port %s, which is "
418 "already stopped. The operation has no effect.", port_name
);
420 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::stopped
,
424 void PORT::all_stop()
426 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
432 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
433 "be halted.", port_name
);
438 // keep the messages in the queue
439 } else if (is_halted
) {
440 TTCN_warning("Performing halt operation on port %s, which is "
441 "already halted. The operation has no effect.", port_name
);
443 TTCN_warning("Performing halt operation on port %s, which is "
444 "already stopped. The operation has no effect.", port_name
);
446 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::halted
,
450 void PORT::all_halt()
452 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
456 alt_status
PORT::receive(const COMPONENT_template
&, COMPONENT
*)
458 TTCN_Logger::log_matching_problem(
459 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
460 TitanLoggerApi::MatchingProblemType_operation::receive__
,
461 false, false, port_name
);
465 alt_status
PORT::any_receive(const COMPONENT_template
& sender_template
,
466 COMPONENT
*sender_ptr
)
468 if (list_head
!= NULL
) {
469 alt_status ret_val
= ALT_NO
;
470 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
471 switch (port
->receive(sender_template
, sender_ptr
)) {
480 TTCN_error("Internal error: Receive operation returned "
481 "unexpected status code on port %s while evaluating "
482 "`any port.receive'.", port
->port_name
);
487 TTCN_Logger::log_matching_problem(
488 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
489 TitanLoggerApi::MatchingProblemType_operation::receive__
,
495 alt_status
PORT::check_receive(const COMPONENT_template
&, COMPONENT
*)
497 TTCN_Logger::log_matching_problem(
498 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
499 TitanLoggerApi::MatchingProblemType_operation::receive__
,
500 false, true, port_name
);
504 alt_status
PORT::any_check_receive(const COMPONENT_template
& sender_template
,
505 COMPONENT
*sender_ptr
)
507 if (list_head
!= NULL
) {
508 alt_status ret_val
= ALT_NO
;
509 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
510 switch (port
->check_receive(sender_template
, sender_ptr
)) {
519 TTCN_error("Internal error: Check-receive operation returned "
520 "unexpected status code on port %s while evaluating "
521 "`any port.check(receive)'.", port
->port_name
);
526 TTCN_Logger::log_matching_problem(
527 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
528 TitanLoggerApi::MatchingProblemType_operation::receive__
,
534 alt_status
PORT::trigger(const COMPONENT_template
&, COMPONENT
*)
536 TTCN_Logger::log_matching_problem(
537 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
538 TitanLoggerApi::MatchingProblemType_operation::trigger__
,
539 false, false, port_name
);
543 alt_status
PORT::any_trigger(const COMPONENT_template
& sender_template
,
544 COMPONENT
*sender_ptr
)
546 if (list_head
!= NULL
) {
547 alt_status ret_val
= ALT_NO
;
548 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
549 switch (port
->trigger(sender_template
, sender_ptr
)) {
560 TTCN_error("Internal error: Trigger operation returned "
561 "unexpected status code on port %s while evaluating "
562 "`any port.trigger'.", port
->port_name
);
567 TTCN_Logger::log_matching_problem(
568 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
569 TitanLoggerApi::MatchingProblemType_operation::trigger__
,
575 alt_status
PORT::getcall(const COMPONENT_template
&, COMPONENT
*)
577 // ToDo:Unnecessary log matching problem warning removed.
578 // Question: does it unnecessary?
579 // TTCN_Logger::log_matching_problem(
580 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
581 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
582 // false, false, port_name);
586 alt_status
PORT::any_getcall(const COMPONENT_template
& sender_template
,
587 COMPONENT
*sender_ptr
)
589 if (list_head
!= NULL
) {
590 alt_status ret_val
= ALT_NO
;
591 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
592 switch (port
->getcall(sender_template
, sender_ptr
)) {
601 TTCN_error("Internal error: Getcall operation returned "
602 "unexpected status code on port %s while evaluating "
603 "`any port.getcall'.", port
->port_name
);
608 TTCN_Logger::log_matching_problem(
609 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
610 TitanLoggerApi::MatchingProblemType_operation::getcall__
,
616 alt_status
PORT::check_getcall(const COMPONENT_template
&, COMPONENT
*)
618 // ToDo:Unnecessary log matching problem warning removed.
619 // Question: does it unnecessary
620 // TTCN_Logger::log_matching_problem(
621 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
622 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
623 // false, false, port_name);
627 alt_status
PORT::any_check_getcall(const COMPONENT_template
& sender_template
,
628 COMPONENT
*sender_ptr
)
630 if (list_head
!= NULL
) {
631 alt_status ret_val
= ALT_NO
;
632 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
633 switch (port
->check_getcall(sender_template
, sender_ptr
)) {
642 TTCN_error("Internal error: Check-getcall operation returned "
643 "unexpected status code on port %s while evaluating "
644 "`any port.check(getcall)'.", port
->port_name
);
649 TTCN_Logger::log_matching_problem(
650 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
651 TitanLoggerApi::MatchingProblemType_operation::getcall__
,
657 alt_status
PORT::getreply(const COMPONENT_template
&, COMPONENT
*)
659 // ToDo:Unnecessary log matching problem warning removed.
660 // Question: does it unnecessary
661 // TTCN_Logger::log_matching_problem(
662 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
663 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
664 // false, false, port_name);
668 alt_status
PORT::any_getreply(const COMPONENT_template
& sender_template
,
669 COMPONENT
*sender_ptr
)
671 if (list_head
!= NULL
) {
672 alt_status ret_val
= ALT_NO
;
673 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
674 switch (port
->getreply(sender_template
, sender_ptr
)) {
683 TTCN_error("Internal error: Getreply operation returned "
684 "unexpected status code on port %s while evaluating "
685 "`any port.getreply'.", port
->port_name
);
690 TTCN_Logger::log_matching_problem(
691 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
692 TitanLoggerApi::MatchingProblemType_operation::getreply__
,
698 alt_status
PORT::check_getreply(const COMPONENT_template
&, COMPONENT
*)
700 // ToDo:Unnecessary log matching problem warning removed.
701 // Question: does it unnecessary
702 // TTCN_Logger::log_matching_problem(
703 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
704 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
705 // false, true, port_name);
709 alt_status
PORT::any_check_getreply(const COMPONENT_template
& sender_template
,
710 COMPONENT
*sender_ptr
)
712 if (list_head
!= NULL
) {
713 alt_status ret_val
= ALT_NO
;
714 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
715 switch (port
->check_getreply(sender_template
, sender_ptr
)) {
724 TTCN_error("Internal error: Check-getreply operation returned "
725 "unexpected status code on port %s while evaluating "
726 "`any port.check(getreply)'.", port
->port_name
);
731 TTCN_Logger::log_matching_problem(
732 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
733 TitanLoggerApi::MatchingProblemType_operation::getreply__
,
739 alt_status
PORT::get_exception(const COMPONENT_template
&, COMPONENT
*)
741 // ToDo:Unnecessary log matching problem warning removed.
742 // Question: does it unnecessary
743 // TTCN_Logger::log_matching_problem(
744 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
745 // TitanLoggerApi::MatchingProblemType_operation::catch__,
746 // false, false, port_name);
750 alt_status
PORT::any_catch(const COMPONENT_template
& sender_template
,
751 COMPONENT
*sender_ptr
)
753 if (list_head
!= NULL
) {
754 alt_status ret_val
= ALT_NO
;
755 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
756 switch (port
->get_exception(sender_template
, sender_ptr
)) {
765 TTCN_error("Internal error: Catch operation returned "
766 "unexpected status code on port %s while evaluating "
767 "`any port.catch'.", port
->port_name
);
772 TTCN_Logger::log_matching_problem(
773 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
774 TitanLoggerApi::MatchingProblemType_operation::catch__
,
780 alt_status
PORT::check_catch(const COMPONENT_template
& ,
783 // ToDo:Unnecessary log matching problem warning removed.
784 // Question: does it unnecessary
785 // TTCN_Logger::log_matching_problem(
786 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
787 // TitanLoggerApi::MatchingProblemType_operation::catch__,
788 // false, true, port_name);
792 alt_status
PORT::any_check_catch(const COMPONENT_template
& sender_template
,
793 COMPONENT
*sender_ptr
)
795 if (list_head
!= NULL
) {
796 alt_status ret_val
= ALT_NO
;
797 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
798 switch (port
->check_catch(sender_template
, sender_ptr
)) {
807 TTCN_error("Internal error: Check-catch operation returned "
808 "unexpected status code on port %s while evaluating "
809 "`any port.check(catch)'.", port
->port_name
);
814 TTCN_Logger::log_matching_problem(
815 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
816 TitanLoggerApi::MatchingProblemType_operation::catch__
,
822 alt_status
PORT::check(const COMPONENT_template
& sender_template
,
823 COMPONENT
*sender_ptr
)
825 alt_status ret_val
= ALT_NO
;
826 // the procedure-based queue must have the higher priority
827 switch (check_getcall(sender_template
, sender_ptr
)) {
836 TTCN_error("Internal error: Check-getcall operation returned "
837 "unexpected status code on port %s.", port_name
);
839 if (ret_val
!= ALT_MAYBE
) {
840 // don't try getreply if the procedure-based queue is empty
841 // (i.e. check_getcall() returned ALT_MAYBE)
842 switch (check_getreply(sender_template
, sender_ptr
)) {
851 TTCN_error("Internal error: Check-getreply operation returned "
852 "unexpected status code on port %s.", port_name
);
855 if (ret_val
!= ALT_MAYBE
) {
856 // don't try catch if the procedure-based queue is empty
857 // (i.e. check_getcall() or check_getreply() returned ALT_MAYBE)
858 switch (check_catch(sender_template
, sender_ptr
)) {
867 TTCN_error("Internal error: Check-catch operation returned "
868 "unexpected status code on port %s.", port_name
);
871 switch (check_receive(sender_template
, sender_ptr
)) {
880 TTCN_error("Internal error: Check-receive operation returned "
881 "unexpected status code on port %s.", port_name
);
886 alt_status
PORT::any_check(const COMPONENT_template
& sender_template
,
887 COMPONENT
*sender_ptr
)
889 if (list_head
!= NULL
) {
890 alt_status ret_val
= ALT_NO
;
891 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
892 switch (port
->check(sender_template
, sender_ptr
)) {
901 TTCN_error("Internal error: Check operation returned "
902 "unexpected status code on port %s while evaluating "
903 "`any port.check'.", port
->port_name
);
908 TTCN_Logger::log_matching_problem(
909 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
910 TitanLoggerApi::MatchingProblemType_operation::check__
,
916 void PORT::set_parameter(const char *parameter_name
, const char *)
918 TTCN_warning("Test port parameter %s is not supported on port %s.",
919 parameter_name
, port_name
);
922 void PORT::append_to_msg_queue(msg_queue_item_base
* new_item
)
924 new_item
->next_item
= NULL
;
925 if (msg_queue_tail
== NULL
) msg_queue_head
= new_item
;
926 else msg_queue_tail
->next_item
= new_item
;
927 msg_queue_tail
= new_item
;
930 void PORT::Handle_Fd_Event(int fd
, boolean is_readable
, boolean is_writable
,
933 // The port intends to use the finer granularity event handler functions
935 Handle_Fd_Event_Error(fd
);
936 if (!is_writable
&& !is_readable
) return;
937 fd_event_type_enum event
= Fd_And_Timeout_User::getCurReceivedEvent();
938 if ((event
& FD_EVENT_WR
) == 0) is_writable
= FALSE
;
939 if ((event
& FD_EVENT_RD
) == 0) is_readable
= FALSE
;
942 Handle_Fd_Event_Writable(fd
);
943 if (!is_readable
) return;
944 if ((Fd_And_Timeout_User::getCurReceivedEvent() & FD_EVENT_RD
) == 0)
948 Handle_Fd_Event_Readable(fd
);
951 void PORT::Handle_Fd_Event_Error(int)
954 // A port need not wait for error events
955 // Note: error events always cause event handler invocation
958 void PORT::Handle_Fd_Event_Writable(int)
960 TTCN_error("There is no Handle_Fd_Event_Writable member function "
961 "implemented in port %s. "
962 "This method or the Handle_Fd_Event method has to be implemented in "
963 "the port if the port waits for any file descriptor to be writable - "
964 "unless the port uses Install_Handler to specify the file descriptor "
965 "and timeout events for which the port waits.", port_name
);
968 void PORT::Handle_Fd_Event_Readable(int)
970 TTCN_error("There is no Handle_Fd_Event_Readable member function "
971 "implemented in port %s. "
972 "This method or the Handle_Fd_Event method has to be implemented in "
973 "the port if the port waits for any file descriptor to be readable - "
974 "unless the port uses Install_Handler to specify the file descriptor "
975 "and timeout events for which the port waits.", port_name
);
978 void PORT::Handle_Timeout(double /*time_since_last_call*/)
980 TTCN_error("There is no Handle_Timeout member function implemented in "
982 "This method has to be implemented in the port if the port waits for "
983 "timeouts unless the port uses Install_Handler to specify the timeout.",
987 void PORT::Event_Handler(const fd_set
* /*read_fds*/, const fd_set
* /*write_fds*/,
988 const fd_set
* /*error_fds*/, double /*time_since_last_call*/)
990 TTCN_error("There is no Event_Handler implemented in port %s. "
991 "Event_Handler has to be implemented in the port if "
992 "Install_Handler is used to specify the file descriptor and timeout "
993 "events for which the port waits.", port_name
);
996 void PORT::Handler_Add_Fd(int fd
, Fd_Event_Type event_mask
)
998 Fd_And_Timeout_User::add_fd(fd
, this,
999 static_cast<fd_event_type_enum
>(
1000 static_cast<int>(event_mask
)));
1003 void PORT::Handler_Add_Fd_Read(int fd
)
1005 Fd_And_Timeout_User::add_fd(fd
, this, FD_EVENT_RD
);
1008 void PORT::Handler_Add_Fd_Write(int fd
)
1010 Fd_And_Timeout_User::add_fd(fd
, this, FD_EVENT_WR
);
1013 void PORT::Handler_Remove_Fd(int fd
, Fd_Event_Type event_mask
)
1015 Fd_And_Timeout_User::remove_fd(fd
, this,
1016 static_cast<fd_event_type_enum
>(
1017 static_cast<int>(event_mask
)));
1020 void PORT::Handler_Remove_Fd_Read(int fd
)
1022 Fd_And_Timeout_User::remove_fd(fd
, this, FD_EVENT_RD
);
1025 void PORT::Handler_Remove_Fd_Write(int fd
)
1027 Fd_And_Timeout_User::remove_fd(fd
, this, FD_EVENT_WR
);
1030 void PORT::Handler_Set_Timer(double call_interval
, boolean is_timeout
,
1031 boolean call_anyway
, boolean is_periodic
)
1033 Fd_And_Timeout_User::set_timer(this, call_interval
, is_timeout
, call_anyway
,
1037 void PORT::Install_Handler(const fd_set
*read_fds
, const fd_set
*write_fds
,
1038 const fd_set
*error_fds
, double call_interval
)
1040 if (!is_active
) TTCN_error("Event handler cannot be installed for "
1041 "inactive port %s.", port_name
);
1043 if ((long) FdMap::getFdLimit() > (long) FD_SETSIZE
) {
1044 static bool once
= true;
1046 TTCN_warning("The maximum number of open file descriptors (%i)"
1047 " is greater than FD_SETSIZE (%li)."
1048 " Ensure that Test Ports using Install_Handler do not try to"
1049 " wait for events of file descriptors with values greater than"
1050 " FD_SETSIZE (%li)."
1051 " (Current caller of Install_Handler is \"%s\")",
1052 FdMap::getFdLimit(), (long) FD_SETSIZE
, (long) FD_SETSIZE
,
1058 Fd_And_Timeout_User::set_fds_with_fd_sets(this, read_fds
, write_fds
,
1060 Fd_And_Timeout_User::set_timer(this, call_interval
);
1063 void PORT::Uninstall_Handler()
1065 Fd_And_Timeout_User::remove_all_fds(this);
1066 Fd_And_Timeout_User::set_timer(this, 0.0);
1069 void PORT::user_map(const char *)
1074 void PORT::user_unmap(const char *)
1079 void PORT::user_start()
1084 void PORT::user_stop()
1089 void PORT::clear_queue()
1094 component
PORT::get_default_destination()
1096 if (connection_list_head
!= NULL
) {
1097 if (n_system_mappings
> 0) TTCN_error("Port %s has both connection(s) "
1098 "and mapping(s). Message can be sent on it only with explicit "
1099 "addressing.", port_name
);
1100 else if (connection_list_head
->list_next
!= NULL
) TTCN_error("Port %s "
1101 "has more than one active connections. Message can be sent on it "
1102 "only with explicit addressing.", port_name
);
1103 return connection_list_head
->remote_component
;
1105 if (n_system_mappings
> 1) {
1106 TTCN_error("Port %s has more than one mappings. Message cannot "
1107 "be sent on it to system.", port_name
);
1108 } else if (n_system_mappings
< 1) {
1109 TTCN_error("Port %s has neither connections nor mappings. "
1110 "Message cannot be sent on it.", port_name
);
1112 return SYSTEM_COMPREF
;
1116 void PORT::prepare_message(Text_Buf
& outgoing_buf
, const char *message_type
)
1118 outgoing_buf
.push_int(CONN_DATA_MESSAGE
);
1119 outgoing_buf
.push_string(message_type
);
1122 void PORT::prepare_call(Text_Buf
& outgoing_buf
, const char *signature_name
)
1124 outgoing_buf
.push_int(CONN_DATA_CALL
);
1125 outgoing_buf
.push_string(signature_name
);
1128 void PORT::prepare_reply(Text_Buf
& outgoing_buf
, const char *signature_name
)
1130 outgoing_buf
.push_int(CONN_DATA_REPLY
);
1131 outgoing_buf
.push_string(signature_name
);
1134 void PORT::prepare_exception(Text_Buf
& outgoing_buf
, const char *signature_name
)
1136 outgoing_buf
.push_int(CONN_DATA_EXCEPTION
);
1137 outgoing_buf
.push_string(signature_name
);
1140 void PORT::send_data(Text_Buf
&outgoing_buf
,
1141 const COMPONENT
& destination_component
)
1143 if (!destination_component
.is_bound()) TTCN_error("Internal error: "
1144 "The destination component reference is unbound when sending data on "
1145 "port %s.", port_name
);
1146 component destination_compref
= (component
)destination_component
;
1148 port_connection
*conn_ptr
=
1149 lookup_connection_to_compref(destination_compref
, &is_unique
);
1150 if (conn_ptr
== NULL
)
1151 TTCN_error("Data cannot be sent on port %s to component %d "
1152 "because there is no connection towards component %d.", port_name
,
1153 destination_compref
, destination_compref
);
1154 else if (!is_unique
)
1155 TTCN_error("Data cannot be sent on port %s to component %d "
1156 "because there are more than one connections towards component "
1157 "%d.", port_name
, destination_compref
, destination_compref
);
1158 else if (conn_ptr
->connection_state
!= CONN_CONNECTED
)
1159 TTCN_error("Data cannot be sent on port %s to component %d "
1160 "because the connection is not in active state.",
1161 port_name
, destination_compref
);
1162 switch (conn_ptr
->transport_type
) {
1163 case TRANSPORT_LOCAL
:
1164 send_data_local(conn_ptr
, outgoing_buf
);
1166 case TRANSPORT_INET_STREAM
:
1167 case TRANSPORT_UNIX_STREAM
:
1168 send_data_stream(conn_ptr
, outgoing_buf
, FALSE
);
1171 TTCN_error("Internal error: Invalid transport type (%d) in port "
1172 "connection between %s and %d:%s.", conn_ptr
->transport_type
,
1173 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1177 void PORT::process_data(port_connection
*conn_ptr
, Text_Buf
& incoming_buf
)
1179 connection_data_type_enum conn_data_type
=
1180 (connection_data_type_enum
)incoming_buf
.pull_int().get_val();
1181 if (conn_data_type
!= CONN_DATA_LAST
) {
1182 switch (conn_ptr
->connection_state
) {
1183 case CONN_CONNECTED
:
1184 case CONN_LAST_MSG_SENT
:
1186 case CONN_LAST_MSG_RCVD
:
1188 TTCN_warning("Data arrived after the indication of connection "
1189 "termination on port %s from %d:%s. Data is ignored.",
1190 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1193 TTCN_error("Internal error: Connection of port %s with %d:%s has "
1194 "invalid state (%d).", port_name
, conn_ptr
->remote_component
,
1195 conn_ptr
->remote_port
, conn_ptr
->connection_state
);
1197 char *message_type
= incoming_buf
.pull_string();
1199 switch (conn_data_type
) {
1200 case CONN_DATA_MESSAGE
:
1201 if (!process_message(message_type
, incoming_buf
,
1202 conn_ptr
->remote_component
, conn_ptr
->sliding_buffer
)) {
1203 TTCN_error("Port %s does not support incoming message "
1204 "type %s, which has arrived on the connection from "
1205 "%d:%s.", port_name
, message_type
,
1206 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1209 case CONN_DATA_CALL
:
1210 if (!process_call(message_type
, incoming_buf
,
1211 conn_ptr
->remote_component
)) {
1212 TTCN_error("Port %s does not support incoming call of "
1213 "signature %s, which has arrived on the connection "
1214 "from %d:%s.", port_name
, message_type
,
1215 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1218 case CONN_DATA_REPLY
:
1219 if (!process_reply(message_type
, incoming_buf
,
1220 conn_ptr
->remote_component
)) {
1221 TTCN_error("Port %s does not support incoming reply of "
1222 "signature %s, which has arrived on the connection "
1223 "from %d:%s.", port_name
, message_type
,
1224 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1227 case CONN_DATA_EXCEPTION
:
1228 if (!process_exception(message_type
, incoming_buf
,
1229 conn_ptr
->remote_component
)) {
1230 TTCN_error("Port %s does not support incoming exception "
1231 "of signature %s, which has arrived on the connection "
1232 "from %d:%s.", port_name
, message_type
,
1233 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1237 TTCN_error("Internal error: Data with invalid selector (%d) "
1238 "was received on port %s from %d:%s.", conn_data_type
,
1239 port_name
, conn_ptr
->remote_component
,
1240 conn_ptr
->remote_port
);
1243 // avoid memory leak
1244 delete [] message_type
;
1247 delete [] message_type
;
1248 } else process_last_message(conn_ptr
);
1251 boolean
PORT::process_message(const char *, Text_Buf
&, component
, OCTETSTRING
&)
1256 boolean
PORT::process_call(const char *, Text_Buf
&, component
)
1261 boolean
PORT::process_reply(const char *, Text_Buf
&, component
)
1266 boolean
PORT::process_exception(const char *, Text_Buf
&, component
)
1271 port_connection
*PORT::add_connection(component remote_component
,
1272 const char *remote_port
, transport_type_enum transport_type
)
1274 port_connection
*conn_ptr
;
1275 for (conn_ptr
= connection_list_head
; conn_ptr
!= NULL
;
1276 conn_ptr
= conn_ptr
->list_next
) {
1277 if (conn_ptr
->remote_component
== remote_component
) {
1278 int ret_val
= strcmp(conn_ptr
->remote_port
, remote_port
);
1279 if (ret_val
== 0) return conn_ptr
;
1280 else if (ret_val
> 0) break;
1281 } else if (conn_ptr
->remote_component
> remote_component
) break;
1284 port_connection
*new_conn
= new port_connection
;
1285 new_conn
->owner_port
= this;
1287 new_conn
->connection_state
= CONN_IDLE
;
1288 new_conn
->remote_component
= remote_component
;
1289 new_conn
->remote_port
= mcopystr(remote_port
);
1290 new_conn
->transport_type
= transport_type
;
1291 new_conn
->sliding_buffer
= OCTETSTRING(0, 0);
1292 switch (transport_type
) {
1293 case TRANSPORT_LOCAL
:
1294 new_conn
->local
.port_ptr
= NULL
;
1296 case TRANSPORT_INET_STREAM
:
1297 case TRANSPORT_UNIX_STREAM
:
1298 new_conn
->stream
.comm_fd
= -1;
1299 new_conn
->stream
.incoming_buf
= NULL
;
1303 TTCN_error("Internal error: PORT::add_connection(): invalid transport "
1304 "type (%d).", transport_type
);
1307 new_conn
->list_next
= conn_ptr
;
1308 if (conn_ptr
!= NULL
) {
1309 // new_conn will be inserted before conn_ptr in the ordered list
1310 new_conn
->list_prev
= conn_ptr
->list_prev
;
1311 conn_ptr
->list_prev
= new_conn
;
1312 if (new_conn
->list_prev
!= NULL
)
1313 new_conn
->list_prev
->list_next
= new_conn
;
1315 // new_conn will be inserted to the end of the list
1316 new_conn
->list_prev
= connection_list_tail
;
1317 if (connection_list_tail
!= NULL
)
1318 connection_list_tail
->list_next
= new_conn
;
1319 connection_list_tail
= new_conn
;
1321 if (conn_ptr
== connection_list_head
) connection_list_head
= new_conn
;
1326 void PORT::remove_connection(port_connection
*conn_ptr
)
1328 Free(conn_ptr
->remote_port
);
1330 switch (conn_ptr
->transport_type
) {
1331 case TRANSPORT_LOCAL
:
1333 case TRANSPORT_INET_STREAM
:
1334 case TRANSPORT_UNIX_STREAM
:
1335 if (conn_ptr
->stream
.comm_fd
>= 0) {
1336 Fd_And_Timeout_User::remove_fd(conn_ptr
->stream
.comm_fd
, conn_ptr
,
1338 if (conn_ptr
->connection_state
== CONN_LISTENING
&&
1339 conn_ptr
->transport_type
== TRANSPORT_UNIX_STREAM
)
1340 unlink_unix_pathname(conn_ptr
->stream
.comm_fd
);
1341 close(conn_ptr
->stream
.comm_fd
);
1342 conn_ptr
->stream
.comm_fd
= -1;
1344 delete conn_ptr
->stream
.incoming_buf
;
1347 TTCN_error("Internal error: PORT::remove_connection(): invalid "
1351 if (conn_ptr
->list_prev
!= NULL
)
1352 conn_ptr
->list_prev
->list_next
= conn_ptr
->list_next
;
1353 else if (connection_list_head
== conn_ptr
)
1354 connection_list_head
= conn_ptr
->list_next
;
1355 if (conn_ptr
->list_next
!= NULL
)
1356 conn_ptr
->list_next
->list_prev
= conn_ptr
->list_prev
;
1357 else if (connection_list_tail
== conn_ptr
)
1358 connection_list_tail
= conn_ptr
->list_prev
;
1363 port_connection
*PORT::lookup_connection_to_compref(
1364 component remote_component
, boolean
*is_unique
)
1366 for (port_connection
*conn
= connection_list_head
; conn
!= NULL
;
1367 conn
= conn
->list_next
) {
1368 if (conn
->remote_component
== remote_component
) {
1369 if (is_unique
!= NULL
) {
1370 port_connection
*nxt
= conn
->list_next
;
1371 if (nxt
!= NULL
&& nxt
->remote_component
== remote_component
)
1373 else *is_unique
= TRUE
;
1376 } else if (conn
->remote_component
> remote_component
) break;
1381 port_connection
*PORT::lookup_connection(component remote_component
,
1382 const char *remote_port
)
1384 for (port_connection
*conn
= connection_list_head
; conn
!= NULL
;
1385 conn
= conn
->list_next
) {
1386 if (conn
->remote_component
== remote_component
) {
1387 int ret_val
= strcmp(conn
->remote_port
, remote_port
);
1388 if (ret_val
== 0) return conn
;
1389 else if (ret_val
> 0) break;
1390 } else if (conn
->remote_component
> remote_component
) break;
1395 void PORT::add_local_connection(PORT
*other_endpoint
)
1397 port_connection
*conn_ptr
= add_connection(self
, other_endpoint
->port_name
,
1399 conn_ptr
->connection_state
= CONN_CONNECTED
;
1400 conn_ptr
->local
.port_ptr
= other_endpoint
;
1401 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__established
,
1402 port_name
, NULL_COMPREF
, other_endpoint
->port_name
);
1405 void PORT::remove_local_connection(port_connection
*conn_ptr
)
1407 if (conn_ptr
->transport_type
!= TRANSPORT_LOCAL
)
1408 TTCN_error("Internal error: The transport type used by the connection "
1409 "between port %s and %d:%s is not LOCAL.", port_name
,
1410 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1411 PORT
*other_endpoint
= conn_ptr
->local
.port_ptr
;
1412 remove_connection(conn_ptr
);
1413 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__terminated
,
1414 port_name
, NULL_COMPREF
, other_endpoint
->port_name
);
1417 unsigned int PORT::get_connection_hash(component local_component
,
1418 const char *local_port
, component remote_component
, const char *remote_port
)
1420 const size_t N
= sizeof(unsigned int);
1421 unsigned char hash_buffer
[N
];
1423 // fill the buffer with an initial pattern
1424 for (size_t i
= 0; i
< N
; i
++) hash_buffer
[i
] = i
% 2 ? 0x55 : 0xAA;
1426 // add the PID of the current process to the buffer
1427 pid_t pid
= getpid();
1428 for (size_t i
= 0; i
< sizeof(pid
); i
++)
1429 hash_buffer
[i
% N
] ^= (pid
>> (8 * i
)) & 0xFF;
1431 // add the local and remote component reference and port name to the buffer
1432 for (size_t i
= 0; i
< sizeof(local_component
); i
++)
1433 hash_buffer
[(N
- 1) - i
% N
] ^= (local_component
>> (8 * i
)) & 0xFF;
1434 for (size_t i
= 0; local_port
[i
] != '\0'; i
++)
1435 hash_buffer
[(N
- 1) - i
% N
] ^= local_port
[i
];
1436 for (size_t i
= 0; i
< sizeof(remote_component
); i
++)
1437 hash_buffer
[i
% N
] ^= (remote_component
>> (8 * i
)) & 0xFF;
1438 for (size_t i
= 0; remote_port
[i
] != '\0'; i
++)
1439 hash_buffer
[i
% N
] ^= remote_port
[i
];
1441 // convert the buffer to an integer value
1442 unsigned int ret_val
= 0;
1443 for (size_t i
= 0; i
< N
; i
++)
1444 ret_val
= (ret_val
<< 8) | hash_buffer
[i
];
1448 void PORT::unlink_unix_pathname(int socket_fd
)
1450 struct sockaddr_un local_addr
;
1451 // querying the local pathname used by socket_fd
1452 socklen_type addr_len
= sizeof(local_addr
);
1453 if (getsockname(socket_fd
, (struct sockaddr
*)&local_addr
, &addr_len
)) {
1454 TTCN_warning_begin("System call getsockname() failed on UNIX socket "
1455 "file descriptor %d.", socket_fd
);
1456 TTCN_Logger::OS_error();
1457 TTCN_Logger::log_event_str(" The associated socket file will not be "
1458 "removed from the file system.");
1460 } else if (local_addr
.sun_family
!= AF_UNIX
) {
1461 TTCN_warning("System call getsockname() returned invalid address "
1462 "family for UNIX socket file descriptor %d. The associated socket "
1463 "file will not be removed from the file system.", socket_fd
);
1464 } else if (unlink(local_addr
.sun_path
)) {
1465 if (errno
!= ENOENT
) {
1466 TTCN_warning_begin("System call unlink() failed when trying to "
1467 "remove UNIX socket file %s.", local_addr
.sun_path
);
1468 TTCN_Logger::OS_error();
1469 TTCN_Logger::log_event_str(" The file will remain in the file "
1476 void PORT::connect_listen_inet_stream(component remote_component
,
1477 const char *remote_port
)
1479 // creating the TCP server socket
1480 int server_fd
= NetworkHandler::socket(TTCN_Communication::get_network_family());
1481 if (server_fd
< 0) {
1482 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1483 remote_port
, "Creation of the TCP server socket failed. (%s)",
1489 // binding the socket to an ephemeral TCP port
1490 // using the same local IP address as the control connection to MC
1491 IPAddress
*local_addr
= IPAddress::create_addr(TTCN_Communication::get_network_family());
1492 *local_addr
= *TTCN_Communication::get_local_address();
1493 local_addr
->set_port(0);
1494 if (bind(server_fd
, local_addr
->get_addr(), local_addr
->get_addr_len())) {
1496 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1497 remote_port
, "Binding of server socket to an ephemeral TCP port "
1498 "failed. (%s)", strerror(errno
));
1504 // zero backlog is enough since we are waiting for only one client
1505 if (listen(server_fd
, 0)) {
1507 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1508 remote_port
, "Listening on an ephemeral TCP port failed. (%s)",
1515 // querying the IP address and port number used by the TCP server
1516 if (local_addr
->getsockname(server_fd
)) {
1518 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1519 remote_port
, "System call getsockname() failed on the TCP server "
1520 "socket. (%s)", strerror(errno
));
1526 if (!TTCN_Communication::set_close_on_exec(server_fd
)) {
1528 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1529 remote_port
, "Setting the close-on-exec flag failed on the TCP "
1535 port_connection
*new_connection
= add_connection(remote_component
,
1536 remote_port
, TRANSPORT_INET_STREAM
);
1537 new_connection
->connection_state
= CONN_LISTENING
;
1538 new_connection
->stream
.comm_fd
= server_fd
;
1539 Fd_And_Timeout_User::add_fd(server_fd
, new_connection
, FD_EVENT_RD
);
1541 TTCN_Communication::send_connect_listen_ack_inet_stream(port_name
,
1542 remote_component
, remote_port
, local_addr
);
1544 TTCN_Logger::log_port_misc(
1545 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__tcp
,
1546 port_name
, remote_component
, remote_port
);
1550 void PORT::connect_listen_unix_stream(component remote_component
,
1551 const char *remote_port
)
1553 // creating the UNIX server socket
1554 int server_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1555 if (server_fd
< 0) {
1556 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1557 remote_port
, "Creation of the UNIX server socket failed. (%s)",
1563 // binding the socket to a temporary file
1564 struct sockaddr_un local_addr
;
1565 // the file name is constructed using a hash function
1566 unsigned int hash_value
=
1567 get_connection_hash(self
, port_name
, remote_component
, remote_port
);
1568 for (unsigned int i
= 1; ; i
++) {
1569 memset(&local_addr
, 0, sizeof(local_addr
));
1570 local_addr
.sun_family
= AF_UNIX
;
1571 snprintf(local_addr
.sun_path
, sizeof(local_addr
.sun_path
),
1572 "/tmp/ttcn3-portconn-%x", hash_value
);
1573 if (bind(server_fd
, (struct sockaddr
*)&local_addr
, sizeof(local_addr
))
1575 // the operation was successful, jump out of the loop
1577 } else if (errno
== EADDRINUSE
) {
1578 // the temporary file name is already used by someone else
1580 if (i
< UNIX_BIND_MAX_ITER
) {
1581 // try another hash value
1585 TTCN_Communication::send_connect_error(port_name
,
1586 remote_component
, remote_port
, "Could not find a free "
1587 "pathname to bind the UNIX server socket to after %u "
1594 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1595 remote_port
, "Binding of UNIX server socket to pathname %s "
1596 "failed. (%s)", local_addr
.sun_path
, strerror(errno
));
1602 // zero backlog is enough since we are waiting for only one client
1603 if (listen(server_fd
, 0)) {
1605 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1606 remote_port
, "Listening on UNIX pathname %s failed. (%s)",
1607 local_addr
.sun_path
, strerror(errno
));
1612 if (!TTCN_Communication::set_close_on_exec(server_fd
)) {
1614 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1615 remote_port
, "Setting the close-on-exec flag failed on the UNIX "
1620 port_connection
*new_connection
= add_connection(remote_component
,
1621 remote_port
, TRANSPORT_UNIX_STREAM
);
1622 new_connection
->connection_state
= CONN_LISTENING
;
1623 new_connection
->stream
.comm_fd
= server_fd
;
1624 Fd_And_Timeout_User::add_fd(server_fd
, new_connection
, FD_EVENT_RD
);
1626 TTCN_Communication::send_connect_listen_ack_unix_stream(port_name
,
1627 remote_component
, remote_port
, &local_addr
);
1629 TTCN_Logger::log_port_misc(
1630 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__unix
,
1631 port_name
, remote_component
, remote_port
, local_addr
.sun_path
);
1634 void PORT::connect_local(component remote_component
, const char *remote_port
)
1636 if (self
!= remote_component
) {
1637 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1638 remote_port
, "Message CONNECT with transport type LOCAL refers "
1639 "to a port of another component (%d).", remote_component
);
1642 PORT
*remote_ptr
= lookup_by_name(remote_port
);
1643 if (remote_ptr
== NULL
) {
1644 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1645 remote_port
, "Port %s does not exist.", remote_port
);
1647 } else if (!remote_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
1648 "inactive when trying to connect it to local port %s.", remote_port
,
1650 add_local_connection(remote_ptr
);
1651 if (this != remote_ptr
) remote_ptr
->add_local_connection(this);
1652 TTCN_Communication::send_connected(port_name
, remote_component
,
1656 void PORT::connect_stream(component remote_component
, const char *remote_port
,
1657 transport_type_enum transport_type
, Text_Buf
& text_buf
)
1662 const char *transport_str
;
1664 switch (transport_type
) {
1665 case TRANSPORT_INET_STREAM
:
1666 transport_str
= "TCP";
1667 // creating the TCP client socket
1668 client_fd
= NetworkHandler::socket(TTCN_Communication::get_network_family());
1670 case TRANSPORT_UNIX_STREAM
:
1671 transport_str
= "UNIX";
1672 // creating the UNIX client socket
1673 client_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1676 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1677 "type (%d).", transport_type
);
1679 if (client_fd
< 0) {
1680 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1681 remote_port
, "Creation of the %s client socket failed. (%s)",
1682 transport_str
, strerror(errno
));
1687 switch (transport_type
) {
1688 case TRANSPORT_INET_STREAM
: {
1689 // connect to the IP address and port number given in message CONNECT
1690 IPAddress
*remote_addr
= IPAddress::create_addr(TTCN_Communication::get_network_family());
1691 remote_addr
->pull_raw(text_buf
);
1693 if (connect(client_fd
, (struct sockaddr
*)remote_addr
->get_addr(), remote_addr
->get_addr_len())) {
1695 if (connect(client_fd
, remote_addr
->get_addr(), remote_addr
->get_addr_len())) {
1698 if (errno
== EADDRINUSE
) {
1701 TTCN_warning("connect() returned error code EADDRINUSE. "
1702 "Perhaps this is a Cygwin bug. Trying to connect again.");
1707 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1708 remote_port
, "TCP connection establishment failed to %s:%d. (%s)",
1709 remote_addr
->get_addr_str(), remote_addr
->get_port(), strerror(errno
));
1716 case TRANSPORT_UNIX_STREAM
: {
1717 // connect to the UNIX pathname given in the message CONNECT
1718 struct sockaddr_un remote_addr
;
1719 memset(&remote_addr
, 0, sizeof(remote_addr
));
1720 remote_addr
.sun_family
= AF_UNIX
;
1721 size_t pathname_len
= text_buf
.pull_int().get_val();
1722 if (pathname_len
>= sizeof(remote_addr
.sun_path
)) {
1724 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1725 remote_port
, "The UNIX pathname used by the server socket is "
1726 "too long. It consists of %lu bytes although it should be "
1727 "shorter than %lu bytes to fit in the appropriate structure.",
1728 (unsigned long) pathname_len
,
1729 (unsigned long) sizeof(remote_addr
.sun_path
));
1732 text_buf
.pull_raw(pathname_len
, remote_addr
.sun_path
);
1733 if (connect(client_fd
, (struct sockaddr
*)&remote_addr
, sizeof(remote_addr
))) {
1735 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1736 remote_port
, "UNIX socket connection establishment failed to "
1737 "pathname %s. (%s)", remote_addr
.sun_path
, strerror(errno
));
1743 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1744 "type (%d).", transport_type
);
1747 if (!TTCN_Communication::set_close_on_exec(client_fd
)) {
1749 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1750 remote_port
, "Setting the close-on-exec flag failed on the %s "
1751 "client socket.", transport_str
);
1755 if (!TTCN_Communication::set_non_blocking_mode(client_fd
, TRUE
)) {
1757 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1758 remote_port
, "Setting the non-blocking mode failed on the %s "
1759 "client socket.", transport_str
);
1763 if (transport_type
== TRANSPORT_INET_STREAM
&&
1764 !TTCN_Communication::set_tcp_nodelay(client_fd
)) {
1766 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1767 remote_port
, "Setting the TCP_NODELAY flag failed on the TCP "
1772 port_connection
*new_connection
= add_connection(remote_component
,
1773 remote_port
, transport_type
);
1774 new_connection
->connection_state
= CONN_CONNECTED
;
1775 new_connection
->stream
.comm_fd
= client_fd
;
1776 Fd_And_Timeout_User::add_fd(client_fd
, new_connection
, FD_EVENT_RD
);
1778 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__established
,
1779 port_name
, remote_component
, remote_port
, transport_str
);
1782 void PORT::disconnect_local(port_connection
*conn_ptr
)
1784 PORT
*remote_ptr
= conn_ptr
->local
.port_ptr
;
1785 remove_local_connection(conn_ptr
);
1786 if (this != remote_ptr
) {
1787 port_connection
*conn2_ptr
=
1788 remote_ptr
->lookup_connection(self
, port_name
);
1789 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
1790 "connected with local port %s, but port %s does not have a "
1791 "connection to %s.", port_name
, remote_ptr
->port_name
,
1792 remote_ptr
->port_name
, port_name
);
1793 else remote_ptr
->remove_local_connection(conn2_ptr
);
1795 TTCN_Communication::send_disconnected(port_name
, self
,
1796 remote_ptr
->port_name
);
1799 void PORT::disconnect_stream(port_connection
*conn_ptr
)
1801 switch (conn_ptr
->connection_state
) {
1802 case CONN_LISTENING
:
1803 TTCN_Logger::log_port_misc(
1804 TitanLoggerApi::Port__Misc_reason::destroying__unestablished__connection
,
1805 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1806 remove_connection(conn_ptr
);
1807 // do not send back any acknowledgment
1809 case CONN_CONNECTED
: {
1810 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::terminating__connection
,
1811 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1812 Text_Buf outgoing_buf
;
1813 outgoing_buf
.push_int(CONN_DATA_LAST
);
1814 if (send_data_stream(conn_ptr
, outgoing_buf
, TRUE
)) {
1815 // sending the last message was successful
1816 // wait for the acknowledgment from the peer
1817 conn_ptr
->connection_state
= CONN_LAST_MSG_SENT
;
1819 TTCN_Logger::log_port_misc(
1820 TitanLoggerApi::Port__Misc_reason::sending__termination__request__failed
,
1821 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1822 // send an acknowledgment to MC immediately to avoid deadlock
1823 // in case of communication failure
1824 // (i.e. when the peer does not send DISCONNECTED)
1825 TTCN_Communication::send_disconnected(port_name
,
1826 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1827 TTCN_warning("The last outgoing messages on port %s may be lost.",
1829 // destroy the connection immediately
1830 remove_connection(conn_ptr
);
1834 TTCN_error("The connection of port %s to %d:%s is in unexpected "
1835 "state when trying to terminate it.", port_name
,
1836 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1840 void PORT::send_data_local(port_connection
*conn_ptr
, Text_Buf
& outgoing_data
)
1842 outgoing_data
.rewind();
1843 PORT
*dest_ptr
= conn_ptr
->local
.port_ptr
;
1844 if (this != dest_ptr
) {
1845 port_connection
*conn2_ptr
=
1846 dest_ptr
->lookup_connection(self
, port_name
);
1847 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
1848 "connected with local port %s, but port %s does not have a "
1849 "connection to %s.", port_name
, dest_ptr
->port_name
,
1850 dest_ptr
->port_name
, port_name
);
1851 dest_ptr
->process_data(conn2_ptr
, outgoing_data
);
1852 } else process_data(conn_ptr
, outgoing_data
);
1855 boolean
PORT::send_data_stream(port_connection
*conn_ptr
,
1856 Text_Buf
& outgoing_data
, boolean ignore_peer_disconnect
)
1858 bool would_block_warning
=false;
1859 outgoing_data
.calculate_length();
1860 const char *msg_ptr
= outgoing_data
.get_data();
1861 size_t msg_len
= outgoing_data
.get_len(), sent_len
= 0;
1862 while (sent_len
< msg_len
) {
1863 int ret_val
= send(conn_ptr
->stream
.comm_fd
, msg_ptr
+ sent_len
,
1864 msg_len
- sent_len
, 0);
1865 if (ret_val
> 0) sent_len
+= ret_val
;
1869 // a signal occurred: do nothing, just try again
1873 // the output buffer is full: try to increase it if possible
1875 int old_bufsize
, new_bufsize
;
1876 if (TTCN_Communication::increase_send_buffer(
1877 conn_ptr
->stream
.comm_fd
, old_bufsize
, new_bufsize
)) {
1878 TTCN_Logger::log_port_misc(
1879 TitanLoggerApi::Port__Misc_reason::sending__would__block
,
1880 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1881 NULL
, old_bufsize
, new_bufsize
);
1883 if(!would_block_warning
){
1884 TTCN_warning_begin("Sending data on the connection of "
1885 "port %s to ", port_name
);
1886 COMPONENT::log_component_reference(
1887 conn_ptr
->remote_component
);
1888 TTCN_Logger::log_event(":%s would block execution and it "
1889 "is not possible to further increase the size of the "
1890 "outgoing buffer. Trying to process incoming data to "
1891 "avoid deadlock.", conn_ptr
->remote_port
);
1893 would_block_warning
=true;
1895 TTCN_Snapshot::block_for_sending(conn_ptr
->stream
.comm_fd
);
1900 if (ignore_peer_disconnect
) return FALSE
;
1903 TTCN_error("Sending data on the connection of port %s to "
1904 "%d:%s failed.", port_name
, conn_ptr
->remote_component
,
1905 conn_ptr
->remote_port
);
1909 if(would_block_warning
){
1910 TTCN_warning_begin("The message finally was sent on "
1911 "port %s to ", port_name
);
1912 COMPONENT::log_component_reference(
1913 conn_ptr
->remote_component
);
1914 TTCN_Logger::log_event(":%s.", conn_ptr
->remote_port
);
1920 void PORT::handle_incoming_connection(port_connection
*conn_ptr
)
1922 const char *transport_str
=
1923 conn_ptr
->transport_type
== TRANSPORT_INET_STREAM
? "TCP" : "UNIX";
1924 int comm_fd
= accept(conn_ptr
->stream
.comm_fd
, NULL
, NULL
);
1926 TTCN_Communication::send_connect_error(port_name
,
1927 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1928 "Accepting of incoming %s connection failed. (%s)", transport_str
,
1931 remove_connection(conn_ptr
);
1935 if (!TTCN_Communication::set_close_on_exec(comm_fd
)) {
1937 TTCN_Communication::send_connect_error(port_name
,
1938 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1939 "Setting the close-on-exec flag failed on the server-side %s "
1940 "socket.", transport_str
);
1941 remove_connection(conn_ptr
);
1945 if (!TTCN_Communication::set_non_blocking_mode(comm_fd
, TRUE
)) {
1947 TTCN_Communication::send_connect_error(port_name
,
1948 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1949 "Setting the non-blocking mode failed on the server-side %s "
1950 "socket.", transport_str
);
1951 remove_connection(conn_ptr
);
1955 if (conn_ptr
->transport_type
== TRANSPORT_INET_STREAM
&&
1956 !TTCN_Communication::set_tcp_nodelay(comm_fd
)) {
1958 TTCN_Communication::send_connect_error(port_name
,
1959 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1960 "Setting the TCP_NODELAY flag failed on the server-side TCP "
1962 remove_connection(conn_ptr
);
1966 // shutting down the server socket and replacing it with the
1967 // communication socket of the new connection
1968 Fd_And_Timeout_User::remove_fd(conn_ptr
->stream
.comm_fd
, conn_ptr
,
1970 if (conn_ptr
->transport_type
== TRANSPORT_UNIX_STREAM
)
1971 unlink_unix_pathname(conn_ptr
->stream
.comm_fd
);
1972 close(conn_ptr
->stream
.comm_fd
);
1973 conn_ptr
->connection_state
= CONN_CONNECTED
;
1974 conn_ptr
->stream
.comm_fd
= comm_fd
;
1975 Fd_And_Timeout_User::add_fd(comm_fd
, conn_ptr
, FD_EVENT_RD
);
1977 TTCN_Communication::send_connected(port_name
, conn_ptr
->remote_component
,
1978 conn_ptr
->remote_port
);
1980 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__accepted
,
1981 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1984 void PORT::handle_incoming_data(port_connection
*conn_ptr
)
1986 if (conn_ptr
->stream
.incoming_buf
== NULL
)
1987 conn_ptr
->stream
.incoming_buf
= new Text_Buf
;
1988 Text_Buf
& incoming_buf
= *conn_ptr
->stream
.incoming_buf
;
1991 incoming_buf
.get_end(buf_ptr
, buf_len
);
1992 int recv_len
= recv(conn_ptr
->stream
.comm_fd
, buf_ptr
, buf_len
, 0);
1994 // an error occurred
1995 if (errno
== ECONNRESET
) {
1996 // TCP connection was reset by peer
1998 TTCN_Communication::send_disconnected(port_name
,
1999 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2000 TTCN_Logger::log_port_misc(
2001 TitanLoggerApi::Port__Misc_reason::connection__reset__by__peer
,
2002 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2003 TTCN_warning("The last outgoing messages on port %s may be lost.",
2005 conn_ptr
->connection_state
= CONN_IDLE
;
2007 TTCN_error("Receiving data on the connection of port %s from "
2008 "%d:%s failed.", port_name
, conn_ptr
->remote_component
,
2009 conn_ptr
->remote_port
);
2011 } else if (recv_len
> 0) {
2012 // data was received
2013 incoming_buf
.increase_length(recv_len
);
2014 // processing all messages in the buffer after each other
2015 while (incoming_buf
.is_message()) {
2016 incoming_buf
.pull_int(); // message_length
2017 process_data(conn_ptr
, incoming_buf
);
2018 incoming_buf
.cut_message();
2021 // the connection was closed by the peer
2022 TTCN_Communication::send_disconnected(port_name
,
2023 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2024 if (conn_ptr
->connection_state
!= CONN_LAST_MSG_RCVD
) {
2025 TTCN_Logger::log_port_misc(
2026 TitanLoggerApi::Port__Misc_reason::connection__closed__by__peer
,
2027 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2029 // the connection can be removed
2030 conn_ptr
->connection_state
= CONN_IDLE
;
2032 if (conn_ptr
->connection_state
== CONN_IDLE
) {
2033 // terminating and removing connection
2034 int msg_len
= incoming_buf
.get_len();
2036 TTCN_warning_begin("Message fragment remained in the buffer of "
2037 "port connection between %s and ", port_name
);
2038 COMPONENT::log_component_reference(conn_ptr
->remote_component
);
2039 TTCN_Logger::log_event(":%s: ", conn_ptr
->remote_port
);
2040 const unsigned char *msg_ptr
=
2041 (const unsigned char*)incoming_buf
.get_data();
2042 for (int i
= 0; i
< msg_len
; i
++)
2043 TTCN_Logger::log_octet(msg_ptr
[i
]);
2047 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::port__disconnected
,
2048 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2049 remove_connection(conn_ptr
);
2053 void PORT::process_last_message(port_connection
*conn_ptr
)
2055 switch (conn_ptr
->transport_type
) {
2056 case TRANSPORT_INET_STREAM
:
2057 case TRANSPORT_UNIX_STREAM
:
2060 TTCN_error("Internal error: Connection termination request was "
2061 "received on the connection of port %s with %d:%s, which has an "
2062 "invalid transport type (%d).", port_name
,
2063 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
2064 conn_ptr
->transport_type
);
2066 switch (conn_ptr
->connection_state
) {
2067 case CONN_CONNECTED
: {
2068 TTCN_Logger::log_port_misc(
2069 TitanLoggerApi::Port__Misc_reason::termination__request__received
,
2070 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2071 Text_Buf outgoing_buf
;
2072 outgoing_buf
.push_int(CONN_DATA_LAST
);
2073 if (send_data_stream(conn_ptr
, outgoing_buf
, TRUE
)) {
2074 // sending the last message was successful
2075 // wait until the peer closes the transport connection
2076 conn_ptr
->connection_state
= CONN_LAST_MSG_RCVD
;
2078 TTCN_Logger::log_port_misc(
2079 TitanLoggerApi::Port__Misc_reason::acknowledging__termination__request__failed
,
2080 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2081 // send an acknowledgment to MC immediately to avoid deadlock
2082 // in case of communication failure
2083 // (i.e. when the peer does not send DISCONNECTED)
2084 TTCN_Communication::send_disconnected(port_name
,
2085 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2086 // the connection can be removed immediately
2087 TTCN_warning("The last outgoing messages on port %s may be lost.",
2089 conn_ptr
->connection_state
= CONN_IDLE
;
2092 case CONN_LAST_MSG_SENT
:
2093 // the connection can be removed
2094 conn_ptr
->connection_state
= CONN_IDLE
;
2096 case CONN_LAST_MSG_RCVD
:
2098 TTCN_warning("Unexpected data arrived after the indication of "
2099 "connection termination on port %s from %d:%s.", port_name
,
2100 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2103 TTCN_error("Internal error: Connection of port %s with %d:%s has "
2104 "invalid state (%d).", port_name
, conn_ptr
->remote_component
,
2105 conn_ptr
->remote_port
, conn_ptr
->connection_state
);
2109 void PORT::map(const char *system_port
)
2111 if (!is_active
) TTCN_error("Inactive port %s cannot be mapped.", port_name
);
2114 for (new_posn
= 0; new_posn
< n_system_mappings
; new_posn
++) {
2115 int str_diff
= strcmp(system_port
, system_mappings
[new_posn
]);
2116 if (str_diff
< 0) break;
2117 else if (str_diff
== 0) {
2118 TTCN_warning("Port %s is already mapped to system:%s."
2119 " Map operation was ignored.", port_name
, system_port
);
2124 set_system_parameters(system_port
);
2126 user_map(system_port
);
2128 TTCN_Logger::log_port_misc(
2129 TitanLoggerApi::Port__Misc_reason::port__was__mapped__to__system
,
2130 port_name
, SYSTEM_COMPREF
, system_port
);
2132 // the mapping shall be registered in the table only if user_map() was
2134 system_mappings
= (char**)Realloc(system_mappings
,
2135 (n_system_mappings
+ 1) * sizeof(*system_mappings
));
2136 memmove(system_mappings
+ new_posn
+ 1, system_mappings
+ new_posn
,
2137 (n_system_mappings
- new_posn
) * sizeof(*system_mappings
));
2138 system_mappings
[new_posn
] = mcopystr(system_port
);
2139 n_system_mappings
++;
2141 if (n_system_mappings
> 1) TTCN_warning("Port %s has now more than one "
2142 "mappings. Message cannot be sent on it to system even with explicit "
2143 "addressing.", port_name
);
2146 void PORT::unmap(const char *system_port
)
2149 for (del_posn
= 0; del_posn
< n_system_mappings
; del_posn
++) {
2150 int str_diff
= strcmp(system_port
, system_mappings
[del_posn
]);
2151 if (str_diff
== 0) break;
2152 else if (str_diff
< 0) {
2153 del_posn
= n_system_mappings
;
2157 if (del_posn
>= n_system_mappings
) {
2158 TTCN_warning("Port %s is not mapped to system:%s. "
2159 "Unmap operation was ignored.", port_name
, system_port
);
2163 char *unmapped_port
= system_mappings
[del_posn
];
2165 // first remove the mapping from the table
2166 n_system_mappings
--;
2167 memmove(system_mappings
+ del_posn
, system_mappings
+ del_posn
+ 1,
2168 (n_system_mappings
- del_posn
) * sizeof(*system_mappings
));
2169 system_mappings
= (char**)Realloc(system_mappings
,
2170 n_system_mappings
* sizeof(*system_mappings
));
2173 user_unmap(system_port
);
2175 // prevent from memory leak
2176 Free(unmapped_port
);
2180 TTCN_Logger::log_port_misc(
2181 TitanLoggerApi::Port__Misc_reason::port__was__unmapped__from__system
,
2182 port_name
, SYSTEM_COMPREF
, system_port
);
2184 Free(unmapped_port
);
2187 void PORT::process_connect_listen(const char *local_port
,
2188 component remote_component
, const char *remote_port
,
2189 transport_type_enum transport_type
)
2191 PORT
*port_ptr
= lookup_by_name(local_port
);
2192 if (port_ptr
== NULL
) {
2193 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2194 remote_port
, "Port %s does not exist.", local_port
);
2196 } else if (!port_ptr
->is_active
) {
2197 TTCN_error("Internal error: Port %s is inactive when trying to "
2198 "connect it to %d:%s.", local_port
, remote_component
, remote_port
);
2199 } else if (port_ptr
->lookup_connection(remote_component
, remote_port
)
2201 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2202 remote_port
, "Port %s already has a connection towards %d:%s.",
2203 local_port
, remote_component
, remote_port
);
2205 } else if (port_ptr
->lookup_connection_to_compref(remote_component
, NULL
)
2207 TTCN_warning_begin("Port %s will have more than one connections with "
2208 "ports of test component ", local_port
);
2209 COMPONENT::log_component_reference(remote_component
);
2210 TTCN_Logger::log_event_str(". These connections cannot be used for "
2211 "sending even with explicit addressing.");
2215 switch (transport_type
) {
2216 case TRANSPORT_LOCAL
:
2217 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2218 remote_port
, "Message CONNECT_LISTEN cannot refer to transport "
2221 case TRANSPORT_INET_STREAM
:
2222 port_ptr
->connect_listen_inet_stream(remote_component
, remote_port
);
2224 case TRANSPORT_UNIX_STREAM
:
2225 port_ptr
->connect_listen_unix_stream(remote_component
, remote_port
);
2228 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2229 remote_port
, "Message CONNECT_LISTEN refers to invalid transport "
2230 "type (%d).", transport_type
);
2235 void PORT::process_connect(const char *local_port
,
2236 component remote_component
, const char *remote_port
,
2237 transport_type_enum transport_type
, Text_Buf
& text_buf
)
2239 PORT
*port_ptr
= lookup_by_name(local_port
);
2240 if (port_ptr
== NULL
) {
2241 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2242 remote_port
, "Port %s does not exist.", local_port
);
2244 } else if (!port_ptr
->is_active
) {
2245 TTCN_error("Internal error: Port %s is inactive when trying to "
2246 "connect it to %d:%s.", local_port
, remote_component
, remote_port
);
2247 } else if (port_ptr
->lookup_connection(remote_component
, remote_port
)
2249 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2250 remote_port
, "Port %s already has a connection towards %d:%s.",
2251 local_port
, remote_component
, remote_port
);
2253 } else if (port_ptr
->lookup_connection_to_compref(remote_component
, NULL
)
2255 TTCN_warning_begin("Port %s will have more than one connections with "
2256 "ports of test component ", local_port
);
2257 COMPONENT::log_component_reference(remote_component
);
2258 TTCN_Logger::log_event_str(". These connections cannot be used for "
2259 "sending even with explicit addressing.");
2263 switch (transport_type
) {
2264 case TRANSPORT_LOCAL
:
2265 port_ptr
->connect_local(remote_component
, remote_port
);
2267 case TRANSPORT_INET_STREAM
:
2268 case TRANSPORT_UNIX_STREAM
:
2269 port_ptr
->connect_stream(remote_component
, remote_port
, transport_type
,
2273 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2274 remote_port
, "Message CONNECT refers to invalid transport type "
2275 "(%d).", transport_type
);
2280 void PORT::process_disconnect(const char *local_port
,
2281 component remote_component
, const char *remote_port
)
2283 PORT
*port_ptr
= lookup_by_name(local_port
);
2284 if (port_ptr
== NULL
) {
2285 TTCN_Communication::send_error("Message DISCONNECT refers to "
2286 "non-existent local port %s.", local_port
);
2288 } else if (!port_ptr
->is_active
) {
2289 TTCN_error("Internal error: Port %s is inactive when trying to "
2290 "disconnect it from %d:%s.", local_port
, remote_component
,
2293 port_connection
*conn_ptr
= port_ptr
->lookup_connection(remote_component
,
2295 if (conn_ptr
== NULL
) {
2296 // the connection does not exist
2297 if (self
== remote_component
&& lookup_by_name(remote_port
) == NULL
) {
2298 // the remote endpoint is in the same component,
2299 // but it does not exist
2300 TTCN_Communication::send_error("Message DISCONNECT refers to "
2301 "non-existent port %s.", remote_port
);
2303 TTCN_Communication::send_disconnected(local_port
, remote_component
,
2308 switch (conn_ptr
->transport_type
) {
2309 case TRANSPORT_LOCAL
:
2310 port_ptr
->disconnect_local(conn_ptr
);
2312 case TRANSPORT_INET_STREAM
:
2313 case TRANSPORT_UNIX_STREAM
:
2314 port_ptr
->disconnect_stream(conn_ptr
);
2317 TTCN_error("Internal error: The connection of port %s to %d:%s has "
2318 "invalid transport type (%d) when trying to terminate the "
2319 "connection.", local_port
, remote_component
, remote_port
,
2320 conn_ptr
->transport_type
);
2324 void PORT::make_local_connection(const char *src_port
, const char *dest_port
)
2326 PORT
*src_ptr
= lookup_by_name(src_port
);
2327 if (src_ptr
== NULL
) TTCN_error("Connect operation refers to "
2328 "non-existent port %s.", src_port
);
2329 else if (!src_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2330 "inactive when trying to connect it with local port %s.", src_port
,
2332 else if (src_ptr
->lookup_connection(MTC_COMPREF
, dest_port
) != NULL
) {
2333 TTCN_warning("Port %s is already connected with local port %s. "
2334 "Connect operation had no effect.", src_port
, dest_port
);
2336 } else if (src_ptr
->lookup_connection_to_compref(MTC_COMPREF
, NULL
)
2338 TTCN_warning("Port %s will have more than one connections with local "
2339 "ports. These connections cannot be used for communication even "
2340 "with explicit addressing.", src_port
);
2342 PORT
*dest_ptr
= lookup_by_name(dest_port
);
2343 if (dest_ptr
== NULL
) TTCN_error("Connect operation refers to "
2344 "non-existent port %s.", dest_port
);
2345 else if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2346 "inactive when trying to connect it with local port %s.", dest_port
,
2348 src_ptr
->add_local_connection(dest_ptr
);
2349 if (src_ptr
!= dest_ptr
) dest_ptr
->add_local_connection(src_ptr
);
2352 void PORT::terminate_local_connection(const char *src_port
,
2353 const char *dest_port
)
2355 PORT
*src_ptr
= lookup_by_name(src_port
);
2356 if (src_ptr
== NULL
) TTCN_error("Disconnect operation refers to "
2357 "non-existent port %s.", src_port
);
2358 else if (!src_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2359 "inactive when trying to disconnect it from local port %s.", src_port
,
2361 port_connection
*conn_ptr
= src_ptr
->lookup_connection(MTC_COMPREF
,
2363 if (conn_ptr
!= NULL
) {
2364 PORT
*dest_ptr
= conn_ptr
->local
.port_ptr
;
2365 src_ptr
->remove_local_connection(conn_ptr
);
2366 if (src_ptr
!= dest_ptr
) {
2367 if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2368 "inactive when trying to disconnect it from local port %s.",
2369 dest_port
, src_port
);
2370 port_connection
*conn2_ptr
=
2371 dest_ptr
->lookup_connection(MTC_COMPREF
, src_port
);
2372 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
2373 "connected with local port %s, but port %s does not have a "
2374 "connection to %s.", src_port
, dest_port
, dest_port
, src_port
);
2375 else dest_ptr
->remove_local_connection(conn2_ptr
);
2378 PORT
*dest_ptr
= lookup_by_name(dest_port
);
2379 if (dest_ptr
== NULL
) TTCN_error("Disconnect operation refers to "
2380 "non-existent port %s.", dest_port
);
2381 else if (src_ptr
!= dest_ptr
) {
2382 if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2383 "inactive when trying to disconnect it from local port %s.",
2384 dest_port
, src_port
);
2385 else if (dest_ptr
->lookup_connection(MTC_COMPREF
, src_port
) != NULL
)
2386 TTCN_error("Internal error: Port %s is connected with local "
2387 "port %s, but port %s does not have a connection to %s.",
2388 dest_port
, src_port
, src_port
, dest_port
);
2390 TTCN_warning("Port %s does not have connection with local port %s. "
2391 "Disconnect operation had no effect.", src_port
, dest_port
);
2395 void PORT::map_port(const char *component_port
, const char *system_port
)
2397 PORT
*port_ptr
= lookup_by_name(component_port
);
2398 if (port_ptr
== NULL
) TTCN_error("Map operation refers to "
2399 "non-existent port %s.", component_port
);
2400 port_ptr
->map(system_port
);
2401 if (!TTCN_Runtime::is_single())
2402 TTCN_Communication::send_mapped(component_port
, system_port
);
2405 void PORT::unmap_port(const char *component_port
, const char *system_port
)
2407 PORT
*port_ptr
= lookup_by_name(component_port
);
2408 if (port_ptr
== NULL
) TTCN_error("Unmap operation refers to "
2409 "non-existent port %s.", component_port
);
2410 port_ptr
->unmap(system_port
);
2411 if (!TTCN_Runtime::is_single())
2412 TTCN_Communication::send_unmapped(component_port
, system_port
);