1 /******************************************************************************
2 * Copyright (c) 2000-2016 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
19 * Szabo, Janos Zoltan – initial implementation
23 ******************************************************************************/
29 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
36 #include "../common/platform.h"
38 #include "../common/memory.h"
39 #include "Component.hh"
42 #include "Event_Handler.hh"
43 #include "Fd_And_Timeout_User.hh"
44 #include "Snapshot.hh"
45 #include "Communication.hh"
47 #include "Octetstring.hh"
48 #include "TitanLoggerApi.hh"
50 // maximum number of iterations for binding the UNIX server socket
51 #define UNIX_BIND_MAX_ITER 100
53 #include "../common/dbgnew.hh"
55 PORT
*PORT::list_head
= NULL
, *PORT::list_tail
= NULL
;
57 void PORT::add_to_list()
59 // check for duplicate names
60 for (PORT
*p
= list_head
; p
!= NULL
; p
= p
->list_next
) {
61 // do nothing if this is already a member of the list
62 if (p
== this) return;
63 else if (!strcmp(p
->port_name
, port_name
))
64 TTCN_error("Internal error: There are more than one ports with "
65 "name %s.", port_name
);
67 // append this to the list
68 if (list_head
== NULL
) list_head
= this;
69 else if (list_tail
!= NULL
) list_tail
->list_next
= this;
70 list_prev
= list_tail
;
75 void PORT::remove_from_list()
77 if (list_prev
!= NULL
) list_prev
->list_next
= list_next
;
78 else if (list_head
== this) list_head
= list_next
;
79 if (list_next
!= NULL
) list_next
->list_prev
= list_prev
;
80 else if (list_tail
== this) list_tail
= list_prev
;
85 PORT
*PORT::lookup_by_name(const char *par_port_name
)
87 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
88 if (!strcmp(par_port_name
, port
->port_name
)) return port
;
92 struct PORT::port_parameter
{
93 component_id_t component_id
;
96 char *parameter_value
;
97 struct port_parameter
*next_par
;
98 } *PORT::parameter_head
= NULL
, *PORT::parameter_tail
= NULL
;
100 void PORT::apply_parameter(port_parameter
*par_ptr
)
102 if (par_ptr
->port_name
!= NULL
) {
103 // the parameter refers to a specific port
104 PORT
*port
= lookup_by_name(par_ptr
->port_name
);
105 if (port
!= NULL
) port
->set_parameter(par_ptr
->parameter_name
,
106 par_ptr
->parameter_value
);
108 // the parameter refers to all ports (*)
109 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
110 port
->set_parameter(par_ptr
->parameter_name
,
111 par_ptr
->parameter_value
);
115 void PORT::set_system_parameters(const char *system_port
)
117 for (port_parameter
*par
= parameter_head
; par
!= NULL
; par
= par
->next_par
)
118 if (par
->component_id
.id_selector
== COMPONENT_ID_SYSTEM
&&
119 (par
->port_name
== NULL
|| !strcmp(par
->port_name
, system_port
)))
120 set_parameter(par
->parameter_name
, par
->parameter_value
);
123 void PORT::add_parameter(const component_id_t
& component_id
,
124 const char *par_port_name
, const char *parameter_name
,
125 const char *parameter_value
)
127 port_parameter
*new_par
= new port_parameter
;
129 new_par
->component_id
.id_selector
= component_id
.id_selector
;
130 switch (component_id
.id_selector
) {
131 case COMPONENT_ID_NAME
:
132 new_par
->component_id
.id_name
= mcopystr(component_id
.id_name
);
134 case COMPONENT_ID_COMPREF
:
135 new_par
->component_id
.id_compref
= component_id
.id_compref
;
141 if (par_port_name
== NULL
) new_par
->port_name
= NULL
;
142 else new_par
->port_name
= mcopystr(par_port_name
);
143 new_par
->parameter_name
= mcopystr(parameter_name
);
144 new_par
->parameter_value
= mcopystr(parameter_value
);
146 new_par
->next_par
= NULL
;
147 if (parameter_head
== NULL
) parameter_head
= new_par
;
148 if (parameter_tail
!= NULL
) parameter_tail
->next_par
= new_par
;
149 parameter_tail
= new_par
;
152 void PORT::clear_parameters()
154 while (parameter_head
!= NULL
) {
155 port_parameter
*next_par
= parameter_head
->next_par
;
156 if (parameter_head
->component_id
.id_selector
== COMPONENT_ID_NAME
)
157 Free(parameter_head
->component_id
.id_name
);
158 Free(parameter_head
->port_name
);
159 Free(parameter_head
->parameter_name
);
160 Free(parameter_head
->parameter_value
);
161 delete parameter_head
;
162 parameter_head
= next_par
;
166 void PORT::set_parameters(component component_reference
,
167 const char *component_name
)
169 for (port_parameter
*par
= parameter_head
; par
!= NULL
; par
= par
->next_par
)
170 switch (par
->component_id
.id_selector
) {
171 case COMPONENT_ID_NAME
:
172 if (component_name
!= NULL
&&
173 !strcmp(par
->component_id
.id_name
, component_name
))
174 apply_parameter(par
);
176 case COMPONENT_ID_COMPREF
:
177 if (par
->component_id
.id_compref
== component_reference
)
178 apply_parameter(par
);
180 case COMPONENT_ID_ALL
:
181 apply_parameter(par
);
188 enum connection_data_type_enum
{
189 CONN_DATA_LAST
= 0, CONN_DATA_MESSAGE
= 1, CONN_DATA_CALL
= 2,
190 CONN_DATA_REPLY
= 3, CONN_DATA_EXCEPTION
= 4
193 enum connection_state_enum
{
194 CONN_IDLE
, CONN_LISTENING
, CONN_CONNECTED
, CONN_LAST_MSG_SENT
,
198 struct port_connection
: public Fd_Event_Handler
{
200 connection_state_enum connection_state
;
201 component remote_component
;
203 transport_type_enum transport_type
;
210 Text_Buf
*incoming_buf
;
213 struct port_connection
*list_prev
, *list_next
;
214 OCTETSTRING sliding_buffer
;
216 virtual void Handle_Fd_Event(int fd
,
217 boolean is_readable
, boolean is_writeable
, boolean is_error
);
218 virtual ~port_connection();
219 virtual void log() const;
222 void port_connection::Handle_Fd_Event(int,
223 boolean is_readable
, boolean
/*is_writeable*/, boolean
/*is_error*/)
225 // Note event for connection with TRANSPORT_LOCAL transport_type
227 if (transport_type
== TRANSPORT_INET_STREAM
228 || transport_type
== TRANSPORT_UNIX_STREAM
231 if (connection_state
== CONN_LISTENING
)
232 owner_port
->handle_incoming_connection(this);
233 else owner_port
->handle_incoming_data(this);
236 TTCN_error("Internal error: Invalid transport type (%d) in port "
237 "connection between %s and %d:%s.", transport_type
,
238 owner_port
->get_name(), remote_component
, remote_port
);
241 void port_connection::log() const
243 TTCN_Logger::log_event("port connection between ");
244 owner_port
->log(); TTCN_Logger::log_event(" and ");
245 TTCN_Logger::log_event(remote_component
); TTCN_Logger::log_event(":");
246 TTCN_Logger::log_event("%s", remote_port
);
249 port_connection::~port_connection()
251 if (transport_type
== TRANSPORT_INET_STREAM
252 || transport_type
== TRANSPORT_UNIX_STREAM
254 if (stream
.comm_fd
!= -1) {
255 TTCN_warning_begin("Internal Error: File descriptor %d not "
256 "closed/removed in ", stream
.comm_fd
); log();
260 sliding_buffer
.clean_up();
263 PORT::PORT(const char *par_port_name
)
265 port_name
= par_port_name
!= NULL
? par_port_name
: "<unknown>";
272 connection_list_head
= NULL
;
273 connection_list_tail
= NULL
;
274 n_system_mappings
= 0;
275 system_mappings
= NULL
;
280 if (is_active
) deactivate_port();
283 void PORT::set_name(const char * name
)
285 if (name
== NULL
) TTCN_error("Internal error: Setting an "
286 "invalid name for a single element of a port array.");
290 void PORT::log() const
292 TTCN_Logger::log_event("port %s", port_name
);
295 void PORT::activate_port()
307 void PORT::deactivate_port()
310 /* In order to proceed with the deactivation we must ignore the
312 * - errors in user code of Test Port (i.e. user_stop, user_unmap)
313 * - failures when sending messages to MC (the link may be down)
315 boolean is_parallel
= !TTCN_Runtime::is_single();
316 // terminate all connections
317 while (connection_list_head
!= NULL
) {
318 TTCN_Logger::log_port_misc(
319 TitanLoggerApi::Port__Misc_reason::removing__unterminated__connection
,
321 connection_list_head
->remote_component
, connection_list_head
->remote_port
);
324 TTCN_Communication::send_disconnected(port_name
,
325 connection_list_head
->remote_component
,
326 connection_list_head
->remote_port
);
327 } catch (const TC_Error
&) { }
329 remove_connection(connection_list_head
);
331 // terminate all mappings
332 while (n_system_mappings
> 0) {
333 // we must make a copy of the string because unmap() will destroy it
334 char *system_port
= mcopystr(system_mappings
[0]);
335 TTCN_Logger::log_port_misc(
336 TitanLoggerApi::Port__Misc_reason::removing__unterminated__mapping
,
337 port_name
, NULL_COMPREF
, system_port
);
340 } catch (const TC_Error
&) { }
343 TTCN_Communication::send_unmapped(port_name
, system_port
);
344 } catch (const TC_Error
&) { }
348 // the previous disconnect/unmap operations may generate incoming events
349 // so we should stop and clear the queue after them
350 if (is_started
|| is_halted
) {
353 } catch (const TC_Error
&) { }
356 // deactivate all event handlers
357 Fd_And_Timeout_User::remove_all_fds(this);
358 Fd_And_Timeout_User::set_timer(this, 0.0);
359 // File descriptor events of port connections are removed
360 // in remove_connection
366 void PORT::deactivate_all()
368 while (list_head
!= NULL
) list_head
->deactivate_port();
373 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
374 "be cleared.", port_name
);
375 if (!is_started
&& !is_halted
) {
376 TTCN_warning("Performing clear operation on port %s, which is "
377 "already stopped. The operation has no effect.", port_name
);
380 TTCN_Logger::log_port_misc(
381 TitanLoggerApi::Port__Misc_reason::port__was__cleared
, port_name
);
384 void PORT::all_clear()
386 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
392 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
393 "be started.", port_name
);
395 TTCN_warning("Performing start operation on port %s, which is "
396 "already started. The operation will clear the incoming queue.",
401 // the queue might contain old messages which has to be discarded
408 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::started
,
412 void PORT::all_start()
414 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
420 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
421 "be stopped.", port_name
);
426 // dropping all messages from the queue because they cannot be
427 // extracted by receiving operations anymore
429 } else if (is_halted
) {
433 TTCN_warning("Performing stop operation on port %s, which is "
434 "already stopped. The operation has no effect.", port_name
);
436 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::stopped
,
440 void PORT::all_stop()
442 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
448 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
449 "be halted.", port_name
);
454 // keep the messages in the queue
455 } else if (is_halted
) {
456 TTCN_warning("Performing halt operation on port %s, which is "
457 "already halted. The operation has no effect.", port_name
);
459 TTCN_warning("Performing halt operation on port %s, which is "
460 "already stopped. The operation has no effect.", port_name
);
462 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::halted
,
466 void PORT::all_halt()
468 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
472 alt_status
PORT::receive(const COMPONENT_template
&, COMPONENT
*)
474 TTCN_Logger::log_matching_problem(
475 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
476 TitanLoggerApi::MatchingProblemType_operation::receive__
,
477 false, false, port_name
);
481 alt_status
PORT::any_receive(const COMPONENT_template
& sender_template
,
482 COMPONENT
*sender_ptr
)
484 if (list_head
!= NULL
) {
485 alt_status ret_val
= ALT_NO
;
486 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
487 switch (port
->receive(sender_template
, sender_ptr
)) {
496 TTCN_error("Internal error: Receive operation returned "
497 "unexpected status code on port %s while evaluating "
498 "`any port.receive'.", port
->port_name
);
503 TTCN_Logger::log_matching_problem(
504 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
505 TitanLoggerApi::MatchingProblemType_operation::receive__
,
511 alt_status
PORT::check_receive(const COMPONENT_template
&, COMPONENT
*)
513 TTCN_Logger::log_matching_problem(
514 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
515 TitanLoggerApi::MatchingProblemType_operation::receive__
,
516 false, true, port_name
);
520 alt_status
PORT::any_check_receive(const COMPONENT_template
& sender_template
,
521 COMPONENT
*sender_ptr
)
523 if (list_head
!= NULL
) {
524 alt_status ret_val
= ALT_NO
;
525 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
526 switch (port
->check_receive(sender_template
, sender_ptr
)) {
535 TTCN_error("Internal error: Check-receive operation returned "
536 "unexpected status code on port %s while evaluating "
537 "`any port.check(receive)'.", port
->port_name
);
542 TTCN_Logger::log_matching_problem(
543 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
544 TitanLoggerApi::MatchingProblemType_operation::receive__
,
550 alt_status
PORT::trigger(const COMPONENT_template
&, COMPONENT
*)
552 TTCN_Logger::log_matching_problem(
553 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
554 TitanLoggerApi::MatchingProblemType_operation::trigger__
,
555 false, false, port_name
);
559 alt_status
PORT::any_trigger(const COMPONENT_template
& sender_template
,
560 COMPONENT
*sender_ptr
)
562 if (list_head
!= NULL
) {
563 alt_status ret_val
= ALT_NO
;
564 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
565 switch (port
->trigger(sender_template
, sender_ptr
)) {
576 TTCN_error("Internal error: Trigger operation returned "
577 "unexpected status code on port %s while evaluating "
578 "`any port.trigger'.", port
->port_name
);
583 TTCN_Logger::log_matching_problem(
584 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
585 TitanLoggerApi::MatchingProblemType_operation::trigger__
,
591 alt_status
PORT::getcall(const COMPONENT_template
&, COMPONENT
*)
593 // ToDo:Unnecessary log matching problem warning removed.
594 // Question: does it unnecessary?
595 // TTCN_Logger::log_matching_problem(
596 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
597 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
598 // false, false, port_name);
602 alt_status
PORT::any_getcall(const COMPONENT_template
& sender_template
,
603 COMPONENT
*sender_ptr
)
605 if (list_head
!= NULL
) {
606 alt_status ret_val
= ALT_NO
;
607 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
608 switch (port
->getcall(sender_template
, sender_ptr
)) {
617 TTCN_error("Internal error: Getcall operation returned "
618 "unexpected status code on port %s while evaluating "
619 "`any port.getcall'.", port
->port_name
);
624 TTCN_Logger::log_matching_problem(
625 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
626 TitanLoggerApi::MatchingProblemType_operation::getcall__
,
632 alt_status
PORT::check_getcall(const COMPONENT_template
&, COMPONENT
*)
634 // ToDo:Unnecessary log matching problem warning removed.
635 // Question: does it unnecessary
636 // TTCN_Logger::log_matching_problem(
637 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
638 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
639 // false, false, port_name);
643 alt_status
PORT::any_check_getcall(const COMPONENT_template
& sender_template
,
644 COMPONENT
*sender_ptr
)
646 if (list_head
!= NULL
) {
647 alt_status ret_val
= ALT_NO
;
648 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
649 switch (port
->check_getcall(sender_template
, sender_ptr
)) {
658 TTCN_error("Internal error: Check-getcall operation returned "
659 "unexpected status code on port %s while evaluating "
660 "`any port.check(getcall)'.", port
->port_name
);
665 TTCN_Logger::log_matching_problem(
666 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
667 TitanLoggerApi::MatchingProblemType_operation::getcall__
,
673 alt_status
PORT::getreply(const COMPONENT_template
&, COMPONENT
*)
675 // ToDo:Unnecessary log matching problem warning removed.
676 // Question: does it unnecessary
677 // TTCN_Logger::log_matching_problem(
678 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
679 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
680 // false, false, port_name);
684 alt_status
PORT::any_getreply(const COMPONENT_template
& sender_template
,
685 COMPONENT
*sender_ptr
)
687 if (list_head
!= NULL
) {
688 alt_status ret_val
= ALT_NO
;
689 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
690 switch (port
->getreply(sender_template
, sender_ptr
)) {
699 TTCN_error("Internal error: Getreply operation returned "
700 "unexpected status code on port %s while evaluating "
701 "`any port.getreply'.", port
->port_name
);
706 TTCN_Logger::log_matching_problem(
707 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
708 TitanLoggerApi::MatchingProblemType_operation::getreply__
,
714 alt_status
PORT::check_getreply(const COMPONENT_template
&, COMPONENT
*)
716 // ToDo:Unnecessary log matching problem warning removed.
717 // Question: does it unnecessary
718 // TTCN_Logger::log_matching_problem(
719 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
720 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
721 // false, true, port_name);
725 alt_status
PORT::any_check_getreply(const COMPONENT_template
& sender_template
,
726 COMPONENT
*sender_ptr
)
728 if (list_head
!= NULL
) {
729 alt_status ret_val
= ALT_NO
;
730 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
731 switch (port
->check_getreply(sender_template
, sender_ptr
)) {
740 TTCN_error("Internal error: Check-getreply operation returned "
741 "unexpected status code on port %s while evaluating "
742 "`any port.check(getreply)'.", port
->port_name
);
747 TTCN_Logger::log_matching_problem(
748 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
749 TitanLoggerApi::MatchingProblemType_operation::getreply__
,
755 alt_status
PORT::get_exception(const COMPONENT_template
&, COMPONENT
*)
757 // ToDo:Unnecessary log matching problem warning removed.
758 // Question: does it unnecessary
759 // TTCN_Logger::log_matching_problem(
760 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
761 // TitanLoggerApi::MatchingProblemType_operation::catch__,
762 // false, false, port_name);
766 alt_status
PORT::any_catch(const COMPONENT_template
& sender_template
,
767 COMPONENT
*sender_ptr
)
769 if (list_head
!= NULL
) {
770 alt_status ret_val
= ALT_NO
;
771 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
772 switch (port
->get_exception(sender_template
, sender_ptr
)) {
781 TTCN_error("Internal error: Catch operation returned "
782 "unexpected status code on port %s while evaluating "
783 "`any port.catch'.", port
->port_name
);
788 TTCN_Logger::log_matching_problem(
789 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
790 TitanLoggerApi::MatchingProblemType_operation::catch__
,
796 alt_status
PORT::check_catch(const COMPONENT_template
& ,
799 // ToDo:Unnecessary log matching problem warning removed.
800 // Question: does it unnecessary
801 // TTCN_Logger::log_matching_problem(
802 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
803 // TitanLoggerApi::MatchingProblemType_operation::catch__,
804 // false, true, port_name);
808 alt_status
PORT::any_check_catch(const COMPONENT_template
& sender_template
,
809 COMPONENT
*sender_ptr
)
811 if (list_head
!= NULL
) {
812 alt_status ret_val
= ALT_NO
;
813 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
814 switch (port
->check_catch(sender_template
, sender_ptr
)) {
823 TTCN_error("Internal error: Check-catch operation returned "
824 "unexpected status code on port %s while evaluating "
825 "`any port.check(catch)'.", port
->port_name
);
830 TTCN_Logger::log_matching_problem(
831 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
832 TitanLoggerApi::MatchingProblemType_operation::catch__
,
838 alt_status
PORT::check(const COMPONENT_template
& sender_template
,
839 COMPONENT
*sender_ptr
)
841 alt_status ret_val
= ALT_NO
;
842 // the procedure-based queue must have the higher priority
843 switch (check_getcall(sender_template
, sender_ptr
)) {
852 TTCN_error("Internal error: Check-getcall operation returned "
853 "unexpected status code on port %s.", port_name
);
855 if (ret_val
!= ALT_MAYBE
) {
856 // don't try getreply if the procedure-based queue is empty
857 // (i.e. check_getcall() returned ALT_MAYBE)
858 switch (check_getreply(sender_template
, sender_ptr
)) {
867 TTCN_error("Internal error: Check-getreply operation returned "
868 "unexpected status code on port %s.", port_name
);
871 if (ret_val
!= ALT_MAYBE
) {
872 // don't try catch if the procedure-based queue is empty
873 // (i.e. check_getcall() or check_getreply() returned ALT_MAYBE)
874 switch (check_catch(sender_template
, sender_ptr
)) {
883 TTCN_error("Internal error: Check-catch operation returned "
884 "unexpected status code on port %s.", port_name
);
887 switch (check_receive(sender_template
, sender_ptr
)) {
896 TTCN_error("Internal error: Check-receive operation returned "
897 "unexpected status code on port %s.", port_name
);
902 alt_status
PORT::any_check(const COMPONENT_template
& sender_template
,
903 COMPONENT
*sender_ptr
)
905 if (list_head
!= NULL
) {
906 alt_status ret_val
= ALT_NO
;
907 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
908 switch (port
->check(sender_template
, sender_ptr
)) {
917 TTCN_error("Internal error: Check operation returned "
918 "unexpected status code on port %s while evaluating "
919 "`any port.check'.", port
->port_name
);
924 TTCN_Logger::log_matching_problem(
925 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
926 TitanLoggerApi::MatchingProblemType_operation::check__
,
932 void PORT::set_parameter(const char *parameter_name
, const char *)
934 TTCN_warning("Test port parameter %s is not supported on port %s.",
935 parameter_name
, port_name
);
938 void PORT::append_to_msg_queue(msg_queue_item_base
* new_item
)
940 new_item
->next_item
= NULL
;
941 if (msg_queue_tail
== NULL
) msg_queue_head
= new_item
;
942 else msg_queue_tail
->next_item
= new_item
;
943 msg_queue_tail
= new_item
;
946 void PORT::Handle_Fd_Event(int fd
, boolean is_readable
, boolean is_writable
,
949 // The port intends to use the finer granularity event handler functions
951 Handle_Fd_Event_Error(fd
);
952 if (!is_writable
&& !is_readable
) return;
953 fd_event_type_enum event
= Fd_And_Timeout_User::getCurReceivedEvent();
954 if ((event
& FD_EVENT_WR
) == 0) is_writable
= FALSE
;
955 if ((event
& FD_EVENT_RD
) == 0) is_readable
= FALSE
;
958 Handle_Fd_Event_Writable(fd
);
959 if (!is_readable
) return;
960 if ((Fd_And_Timeout_User::getCurReceivedEvent() & FD_EVENT_RD
) == 0)
964 Handle_Fd_Event_Readable(fd
);
967 void PORT::Handle_Fd_Event_Error(int)
970 // A port need not wait for error events
971 // Note: error events always cause event handler invocation
974 void PORT::Handle_Fd_Event_Writable(int)
976 TTCN_error("There is no Handle_Fd_Event_Writable member function "
977 "implemented in port %s. "
978 "This method or the Handle_Fd_Event method has to be implemented in "
979 "the port if the port waits for any file descriptor to be writable - "
980 "unless the port uses Install_Handler to specify the file descriptor "
981 "and timeout events for which the port waits.", port_name
);
984 void PORT::Handle_Fd_Event_Readable(int)
986 TTCN_error("There is no Handle_Fd_Event_Readable member function "
987 "implemented in port %s. "
988 "This method or the Handle_Fd_Event method has to be implemented in "
989 "the port if the port waits for any file descriptor to be readable - "
990 "unless the port uses Install_Handler to specify the file descriptor "
991 "and timeout events for which the port waits.", port_name
);
994 void PORT::Handle_Timeout(double /*time_since_last_call*/)
996 TTCN_error("There is no Handle_Timeout member function implemented in "
998 "This method has to be implemented in the port if the port waits for "
999 "timeouts unless the port uses Install_Handler to specify the timeout.",
1003 void PORT::Event_Handler(const fd_set
* /*read_fds*/, const fd_set
* /*write_fds*/,
1004 const fd_set
* /*error_fds*/, double /*time_since_last_call*/)
1006 TTCN_error("There is no Event_Handler implemented in port %s. "
1007 "Event_Handler has to be implemented in the port if "
1008 "Install_Handler is used to specify the file descriptor and timeout "
1009 "events for which the port waits.", port_name
);
1012 void PORT::Handler_Add_Fd(int fd
, Fd_Event_Type event_mask
)
1014 Fd_And_Timeout_User::add_fd(fd
, this,
1015 static_cast<fd_event_type_enum
>(
1016 static_cast<int>(event_mask
)));
1019 void PORT::Handler_Add_Fd_Read(int fd
)
1021 Fd_And_Timeout_User::add_fd(fd
, this, FD_EVENT_RD
);
1024 void PORT::Handler_Add_Fd_Write(int fd
)
1026 Fd_And_Timeout_User::add_fd(fd
, this, FD_EVENT_WR
);
1029 void PORT::Handler_Remove_Fd(int fd
, Fd_Event_Type event_mask
)
1031 Fd_And_Timeout_User::remove_fd(fd
, this,
1032 static_cast<fd_event_type_enum
>(
1033 static_cast<int>(event_mask
)));
1036 void PORT::Handler_Remove_Fd_Read(int fd
)
1038 Fd_And_Timeout_User::remove_fd(fd
, this, FD_EVENT_RD
);
1041 void PORT::Handler_Remove_Fd_Write(int fd
)
1043 Fd_And_Timeout_User::remove_fd(fd
, this, FD_EVENT_WR
);
1046 void PORT::Handler_Set_Timer(double call_interval
, boolean is_timeout
,
1047 boolean call_anyway
, boolean is_periodic
)
1049 Fd_And_Timeout_User::set_timer(this, call_interval
, is_timeout
, call_anyway
,
1053 void PORT::Install_Handler(const fd_set
*read_fds
, const fd_set
*write_fds
,
1054 const fd_set
*error_fds
, double call_interval
)
1056 if (!is_active
) TTCN_error("Event handler cannot be installed for "
1057 "inactive port %s.", port_name
);
1059 if ((long) FdMap::getFdLimit() > (long) FD_SETSIZE
) {
1060 static bool once
= true;
1062 TTCN_warning("The maximum number of open file descriptors (%i)"
1063 " is greater than FD_SETSIZE (%li)."
1064 " Ensure that Test Ports using Install_Handler do not try to"
1065 " wait for events of file descriptors with values greater than"
1066 " FD_SETSIZE (%li)."
1067 " (Current caller of Install_Handler is \"%s\")",
1068 FdMap::getFdLimit(), (long) FD_SETSIZE
, (long) FD_SETSIZE
,
1074 Fd_And_Timeout_User::set_fds_with_fd_sets(this, read_fds
, write_fds
,
1076 Fd_And_Timeout_User::set_timer(this, call_interval
);
1079 void PORT::Uninstall_Handler()
1081 Fd_And_Timeout_User::remove_all_fds(this);
1082 Fd_And_Timeout_User::set_timer(this, 0.0);
1085 void PORT::user_map(const char *)
1090 void PORT::user_unmap(const char *)
1095 void PORT::user_start()
1100 void PORT::user_stop()
1105 void PORT::clear_queue()
1110 component
PORT::get_default_destination()
1112 if (connection_list_head
!= NULL
) {
1113 if (n_system_mappings
> 0) TTCN_error("Port %s has both connection(s) "
1114 "and mapping(s). Message can be sent on it only with explicit "
1115 "addressing.", port_name
);
1116 else if (connection_list_head
->list_next
!= NULL
) TTCN_error("Port %s "
1117 "has more than one active connections. Message can be sent on it "
1118 "only with explicit addressing.", port_name
);
1119 return connection_list_head
->remote_component
;
1121 if (n_system_mappings
> 1) {
1122 TTCN_error("Port %s has more than one mappings. Message cannot "
1123 "be sent on it to system.", port_name
);
1124 } else if (n_system_mappings
< 1) {
1125 TTCN_error("Port %s has neither connections nor mappings. "
1126 "Message cannot be sent on it.", port_name
);
1128 return SYSTEM_COMPREF
;
1132 void PORT::prepare_message(Text_Buf
& outgoing_buf
, const char *message_type
)
1134 outgoing_buf
.push_int(CONN_DATA_MESSAGE
);
1135 outgoing_buf
.push_string(message_type
);
1138 void PORT::prepare_call(Text_Buf
& outgoing_buf
, const char *signature_name
)
1140 outgoing_buf
.push_int(CONN_DATA_CALL
);
1141 outgoing_buf
.push_string(signature_name
);
1144 void PORT::prepare_reply(Text_Buf
& outgoing_buf
, const char *signature_name
)
1146 outgoing_buf
.push_int(CONN_DATA_REPLY
);
1147 outgoing_buf
.push_string(signature_name
);
1150 void PORT::prepare_exception(Text_Buf
& outgoing_buf
, const char *signature_name
)
1152 outgoing_buf
.push_int(CONN_DATA_EXCEPTION
);
1153 outgoing_buf
.push_string(signature_name
);
1156 void PORT::send_data(Text_Buf
&outgoing_buf
,
1157 const COMPONENT
& destination_component
)
1159 if (!destination_component
.is_bound()) TTCN_error("Internal error: "
1160 "The destination component reference is unbound when sending data on "
1161 "port %s.", port_name
);
1162 component destination_compref
= (component
)destination_component
;
1164 port_connection
*conn_ptr
=
1165 lookup_connection_to_compref(destination_compref
, &is_unique
);
1166 if (conn_ptr
== NULL
)
1167 TTCN_error("Data cannot be sent on port %s to component %d "
1168 "because there is no connection towards component %d.", port_name
,
1169 destination_compref
, destination_compref
);
1170 else if (!is_unique
)
1171 TTCN_error("Data cannot be sent on port %s to component %d "
1172 "because there are more than one connections towards component "
1173 "%d.", port_name
, destination_compref
, destination_compref
);
1174 else if (conn_ptr
->connection_state
!= CONN_CONNECTED
)
1175 TTCN_error("Data cannot be sent on port %s to component %d "
1176 "because the connection is not in active state.",
1177 port_name
, destination_compref
);
1178 switch (conn_ptr
->transport_type
) {
1179 case TRANSPORT_LOCAL
:
1180 send_data_local(conn_ptr
, outgoing_buf
);
1182 case TRANSPORT_INET_STREAM
:
1183 case TRANSPORT_UNIX_STREAM
:
1184 send_data_stream(conn_ptr
, outgoing_buf
, FALSE
);
1187 TTCN_error("Internal error: Invalid transport type (%d) in port "
1188 "connection between %s and %d:%s.", conn_ptr
->transport_type
,
1189 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1193 void PORT::process_data(port_connection
*conn_ptr
, Text_Buf
& incoming_buf
)
1195 connection_data_type_enum conn_data_type
=
1196 (connection_data_type_enum
)incoming_buf
.pull_int().get_val();
1197 if (conn_data_type
!= CONN_DATA_LAST
) {
1198 switch (conn_ptr
->connection_state
) {
1199 case CONN_CONNECTED
:
1200 case CONN_LAST_MSG_SENT
:
1202 case CONN_LAST_MSG_RCVD
:
1204 TTCN_warning("Data arrived after the indication of connection "
1205 "termination on port %s from %d:%s. Data is ignored.",
1206 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1209 TTCN_error("Internal error: Connection of port %s with %d:%s has "
1210 "invalid state (%d).", port_name
, conn_ptr
->remote_component
,
1211 conn_ptr
->remote_port
, conn_ptr
->connection_state
);
1213 char *message_type
= incoming_buf
.pull_string();
1215 switch (conn_data_type
) {
1216 case CONN_DATA_MESSAGE
:
1217 if (!process_message(message_type
, incoming_buf
,
1218 conn_ptr
->remote_component
, conn_ptr
->sliding_buffer
)) {
1219 TTCN_error("Port %s does not support incoming message "
1220 "type %s, which has arrived on the connection from "
1221 "%d:%s.", port_name
, message_type
,
1222 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1225 case CONN_DATA_CALL
:
1226 if (!process_call(message_type
, incoming_buf
,
1227 conn_ptr
->remote_component
)) {
1228 TTCN_error("Port %s does not support incoming call of "
1229 "signature %s, which has arrived on the connection "
1230 "from %d:%s.", port_name
, message_type
,
1231 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1234 case CONN_DATA_REPLY
:
1235 if (!process_reply(message_type
, incoming_buf
,
1236 conn_ptr
->remote_component
)) {
1237 TTCN_error("Port %s does not support incoming reply of "
1238 "signature %s, which has arrived on the connection "
1239 "from %d:%s.", port_name
, message_type
,
1240 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1243 case CONN_DATA_EXCEPTION
:
1244 if (!process_exception(message_type
, incoming_buf
,
1245 conn_ptr
->remote_component
)) {
1246 TTCN_error("Port %s does not support incoming exception "
1247 "of signature %s, which has arrived on the connection "
1248 "from %d:%s.", port_name
, message_type
,
1249 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1253 TTCN_error("Internal error: Data with invalid selector (%d) "
1254 "was received on port %s from %d:%s.", conn_data_type
,
1255 port_name
, conn_ptr
->remote_component
,
1256 conn_ptr
->remote_port
);
1259 // avoid memory leak
1260 delete [] message_type
;
1263 delete [] message_type
;
1264 } else process_last_message(conn_ptr
);
1267 boolean
PORT::process_message(const char *, Text_Buf
&, component
, OCTETSTRING
&)
1272 boolean
PORT::process_call(const char *, Text_Buf
&, component
)
1277 boolean
PORT::process_reply(const char *, Text_Buf
&, component
)
1282 boolean
PORT::process_exception(const char *, Text_Buf
&, component
)
1287 port_connection
*PORT::add_connection(component remote_component
,
1288 const char *remote_port
, transport_type_enum transport_type
)
1290 port_connection
*conn_ptr
;
1291 for (conn_ptr
= connection_list_head
; conn_ptr
!= NULL
;
1292 conn_ptr
= conn_ptr
->list_next
) {
1293 if (conn_ptr
->remote_component
== remote_component
) {
1294 int ret_val
= strcmp(conn_ptr
->remote_port
, remote_port
);
1295 if (ret_val
== 0) return conn_ptr
;
1296 else if (ret_val
> 0) break;
1297 } else if (conn_ptr
->remote_component
> remote_component
) break;
1300 port_connection
*new_conn
= new port_connection
;
1301 new_conn
->owner_port
= this;
1303 new_conn
->connection_state
= CONN_IDLE
;
1304 new_conn
->remote_component
= remote_component
;
1305 new_conn
->remote_port
= mcopystr(remote_port
);
1306 new_conn
->transport_type
= transport_type
;
1307 new_conn
->sliding_buffer
= OCTETSTRING(0, 0);
1308 switch (transport_type
) {
1309 case TRANSPORT_LOCAL
:
1310 new_conn
->local
.port_ptr
= NULL
;
1312 case TRANSPORT_INET_STREAM
:
1313 case TRANSPORT_UNIX_STREAM
:
1314 new_conn
->stream
.comm_fd
= -1;
1315 new_conn
->stream
.incoming_buf
= NULL
;
1319 TTCN_error("Internal error: PORT::add_connection(): invalid transport "
1320 "type (%d).", transport_type
);
1323 new_conn
->list_next
= conn_ptr
;
1324 if (conn_ptr
!= NULL
) {
1325 // new_conn will be inserted before conn_ptr in the ordered list
1326 new_conn
->list_prev
= conn_ptr
->list_prev
;
1327 conn_ptr
->list_prev
= new_conn
;
1328 if (new_conn
->list_prev
!= NULL
)
1329 new_conn
->list_prev
->list_next
= new_conn
;
1331 // new_conn will be inserted to the end of the list
1332 new_conn
->list_prev
= connection_list_tail
;
1333 if (connection_list_tail
!= NULL
)
1334 connection_list_tail
->list_next
= new_conn
;
1335 connection_list_tail
= new_conn
;
1337 if (conn_ptr
== connection_list_head
) connection_list_head
= new_conn
;
1342 void PORT::remove_connection(port_connection
*conn_ptr
)
1344 Free(conn_ptr
->remote_port
);
1346 switch (conn_ptr
->transport_type
) {
1347 case TRANSPORT_LOCAL
:
1349 case TRANSPORT_INET_STREAM
:
1350 case TRANSPORT_UNIX_STREAM
:
1351 if (conn_ptr
->stream
.comm_fd
>= 0) {
1352 Fd_And_Timeout_User::remove_fd(conn_ptr
->stream
.comm_fd
, conn_ptr
,
1354 if (conn_ptr
->connection_state
== CONN_LISTENING
&&
1355 conn_ptr
->transport_type
== TRANSPORT_UNIX_STREAM
)
1356 unlink_unix_pathname(conn_ptr
->stream
.comm_fd
);
1357 close(conn_ptr
->stream
.comm_fd
);
1358 conn_ptr
->stream
.comm_fd
= -1;
1360 delete conn_ptr
->stream
.incoming_buf
;
1363 TTCN_error("Internal error: PORT::remove_connection(): invalid "
1367 if (conn_ptr
->list_prev
!= NULL
)
1368 conn_ptr
->list_prev
->list_next
= conn_ptr
->list_next
;
1369 else if (connection_list_head
== conn_ptr
)
1370 connection_list_head
= conn_ptr
->list_next
;
1371 if (conn_ptr
->list_next
!= NULL
)
1372 conn_ptr
->list_next
->list_prev
= conn_ptr
->list_prev
;
1373 else if (connection_list_tail
== conn_ptr
)
1374 connection_list_tail
= conn_ptr
->list_prev
;
1379 port_connection
*PORT::lookup_connection_to_compref(
1380 component remote_component
, boolean
*is_unique
)
1382 for (port_connection
*conn
= connection_list_head
; conn
!= NULL
;
1383 conn
= conn
->list_next
) {
1384 if (conn
->remote_component
== remote_component
) {
1385 if (is_unique
!= NULL
) {
1386 port_connection
*nxt
= conn
->list_next
;
1387 if (nxt
!= NULL
&& nxt
->remote_component
== remote_component
)
1389 else *is_unique
= TRUE
;
1392 } else if (conn
->remote_component
> remote_component
) break;
1397 port_connection
*PORT::lookup_connection(component remote_component
,
1398 const char *remote_port
)
1400 for (port_connection
*conn
= connection_list_head
; conn
!= NULL
;
1401 conn
= conn
->list_next
) {
1402 if (conn
->remote_component
== remote_component
) {
1403 int ret_val
= strcmp(conn
->remote_port
, remote_port
);
1404 if (ret_val
== 0) return conn
;
1405 else if (ret_val
> 0) break;
1406 } else if (conn
->remote_component
> remote_component
) break;
1411 void PORT::add_local_connection(PORT
*other_endpoint
)
1413 port_connection
*conn_ptr
= add_connection(self
, other_endpoint
->port_name
,
1415 conn_ptr
->connection_state
= CONN_CONNECTED
;
1416 conn_ptr
->local
.port_ptr
= other_endpoint
;
1417 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__established
,
1418 port_name
, NULL_COMPREF
, other_endpoint
->port_name
);
1421 void PORT::remove_local_connection(port_connection
*conn_ptr
)
1423 if (conn_ptr
->transport_type
!= TRANSPORT_LOCAL
)
1424 TTCN_error("Internal error: The transport type used by the connection "
1425 "between port %s and %d:%s is not LOCAL.", port_name
,
1426 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1427 PORT
*other_endpoint
= conn_ptr
->local
.port_ptr
;
1428 remove_connection(conn_ptr
);
1429 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__terminated
,
1430 port_name
, NULL_COMPREF
, other_endpoint
->port_name
);
1433 unsigned int PORT::get_connection_hash(component local_component
,
1434 const char *local_port
, component remote_component
, const char *remote_port
)
1436 const size_t N
= sizeof(unsigned int);
1437 unsigned char hash_buffer
[N
];
1439 // fill the buffer with an initial pattern
1440 for (size_t i
= 0; i
< N
; i
++) hash_buffer
[i
] = i
% 2 ? 0x55 : 0xAA;
1442 // add the PID of the current process to the buffer
1443 pid_t pid
= getpid();
1444 for (size_t i
= 0; i
< sizeof(pid
); i
++)
1445 hash_buffer
[i
% N
] ^= (pid
>> (8 * i
)) & 0xFF;
1447 // add the local and remote component reference and port name to the buffer
1448 for (size_t i
= 0; i
< sizeof(local_component
); i
++)
1449 hash_buffer
[(N
- 1) - i
% N
] ^= (local_component
>> (8 * i
)) & 0xFF;
1450 for (size_t i
= 0; local_port
[i
] != '\0'; i
++)
1451 hash_buffer
[(N
- 1) - i
% N
] ^= local_port
[i
];
1452 for (size_t i
= 0; i
< sizeof(remote_component
); i
++)
1453 hash_buffer
[i
% N
] ^= (remote_component
>> (8 * i
)) & 0xFF;
1454 for (size_t i
= 0; remote_port
[i
] != '\0'; i
++)
1455 hash_buffer
[i
% N
] ^= remote_port
[i
];
1457 // convert the buffer to an integer value
1458 unsigned int ret_val
= 0;
1459 for (size_t i
= 0; i
< N
; i
++)
1460 ret_val
= (ret_val
<< 8) | hash_buffer
[i
];
1464 void PORT::unlink_unix_pathname(int socket_fd
)
1466 struct sockaddr_un local_addr
;
1467 // querying the local pathname used by socket_fd
1468 socklen_type addr_len
= sizeof(local_addr
);
1469 if (getsockname(socket_fd
, (struct sockaddr
*)&local_addr
, &addr_len
)) {
1470 TTCN_warning_begin("System call getsockname() failed on UNIX socket "
1471 "file descriptor %d.", socket_fd
);
1472 TTCN_Logger::OS_error();
1473 TTCN_Logger::log_event_str(" The associated socket file will not be "
1474 "removed from the file system.");
1476 } else if (local_addr
.sun_family
!= AF_UNIX
) {
1477 TTCN_warning("System call getsockname() returned invalid address "
1478 "family for UNIX socket file descriptor %d. The associated socket "
1479 "file will not be removed from the file system.", socket_fd
);
1480 } else if (unlink(local_addr
.sun_path
)) {
1481 if (errno
!= ENOENT
) {
1482 TTCN_warning_begin("System call unlink() failed when trying to "
1483 "remove UNIX socket file %s.", local_addr
.sun_path
);
1484 TTCN_Logger::OS_error();
1485 TTCN_Logger::log_event_str(" The file will remain in the file "
1492 void PORT::connect_listen_inet_stream(component remote_component
,
1493 const char *remote_port
)
1495 // creating the TCP server socket
1496 int server_fd
= NetworkHandler::socket(TTCN_Communication::get_network_family());
1497 if (server_fd
< 0) {
1498 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1499 remote_port
, "Creation of the TCP server socket failed. (%s)",
1505 // binding the socket to an ephemeral TCP port
1506 // using the same local IP address as the control connection to MC
1507 IPAddress
*local_addr
= IPAddress::create_addr(TTCN_Communication::get_network_family());
1508 *local_addr
= *TTCN_Communication::get_local_address();
1509 local_addr
->set_port(0);
1510 if (bind(server_fd
, local_addr
->get_addr(), local_addr
->get_addr_len())) {
1512 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1513 remote_port
, "Binding of server socket to an ephemeral TCP port "
1514 "failed. (%s)", strerror(errno
));
1520 // zero backlog is enough since we are waiting for only one client
1521 if (listen(server_fd
, 0)) {
1523 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1524 remote_port
, "Listening on an ephemeral TCP port failed. (%s)",
1531 // querying the IP address and port number used by the TCP server
1532 if (local_addr
->getsockname(server_fd
)) {
1534 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1535 remote_port
, "System call getsockname() failed on the TCP server "
1536 "socket. (%s)", strerror(errno
));
1542 if (!TTCN_Communication::set_close_on_exec(server_fd
)) {
1544 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1545 remote_port
, "Setting the close-on-exec flag failed on the TCP "
1551 port_connection
*new_connection
= add_connection(remote_component
,
1552 remote_port
, TRANSPORT_INET_STREAM
);
1553 new_connection
->connection_state
= CONN_LISTENING
;
1554 new_connection
->stream
.comm_fd
= server_fd
;
1555 Fd_And_Timeout_User::add_fd(server_fd
, new_connection
, FD_EVENT_RD
);
1557 TTCN_Communication::send_connect_listen_ack_inet_stream(port_name
,
1558 remote_component
, remote_port
, local_addr
);
1560 TTCN_Logger::log_port_misc(
1561 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__tcp
,
1562 port_name
, remote_component
, remote_port
);
1566 void PORT::connect_listen_unix_stream(component remote_component
,
1567 const char *remote_port
)
1569 // creating the UNIX server socket
1570 int server_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1571 if (server_fd
< 0) {
1572 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1573 remote_port
, "Creation of the UNIX server socket failed. (%s)",
1579 // binding the socket to a temporary file
1580 struct sockaddr_un local_addr
;
1581 // the file name is constructed using a hash function
1582 unsigned int hash_value
=
1583 get_connection_hash(self
, port_name
, remote_component
, remote_port
);
1584 for (unsigned int i
= 1; ; i
++) {
1585 memset(&local_addr
, 0, sizeof(local_addr
));
1586 local_addr
.sun_family
= AF_UNIX
;
1587 snprintf(local_addr
.sun_path
, sizeof(local_addr
.sun_path
),
1588 "/tmp/ttcn3-portconn-%x", hash_value
);
1589 if (bind(server_fd
, (struct sockaddr
*)&local_addr
, sizeof(local_addr
))
1591 // the operation was successful, jump out of the loop
1593 } else if (errno
== EADDRINUSE
) {
1594 // the temporary file name is already used by someone else
1596 if (i
< UNIX_BIND_MAX_ITER
) {
1597 // try another hash value
1601 TTCN_Communication::send_connect_error(port_name
,
1602 remote_component
, remote_port
, "Could not find a free "
1603 "pathname to bind the UNIX server socket to after %u "
1610 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1611 remote_port
, "Binding of UNIX server socket to pathname %s "
1612 "failed. (%s)", local_addr
.sun_path
, strerror(errno
));
1618 // zero backlog is enough since we are waiting for only one client
1619 if (listen(server_fd
, 0)) {
1621 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1622 remote_port
, "Listening on UNIX pathname %s failed. (%s)",
1623 local_addr
.sun_path
, strerror(errno
));
1628 if (!TTCN_Communication::set_close_on_exec(server_fd
)) {
1630 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1631 remote_port
, "Setting the close-on-exec flag failed on the UNIX "
1636 port_connection
*new_connection
= add_connection(remote_component
,
1637 remote_port
, TRANSPORT_UNIX_STREAM
);
1638 new_connection
->connection_state
= CONN_LISTENING
;
1639 new_connection
->stream
.comm_fd
= server_fd
;
1640 Fd_And_Timeout_User::add_fd(server_fd
, new_connection
, FD_EVENT_RD
);
1642 TTCN_Communication::send_connect_listen_ack_unix_stream(port_name
,
1643 remote_component
, remote_port
, &local_addr
);
1645 TTCN_Logger::log_port_misc(
1646 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__unix
,
1647 port_name
, remote_component
, remote_port
, local_addr
.sun_path
);
1650 void PORT::connect_local(component remote_component
, const char *remote_port
)
1652 if (self
!= remote_component
) {
1653 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1654 remote_port
, "Message CONNECT with transport type LOCAL refers "
1655 "to a port of another component (%d).", remote_component
);
1658 PORT
*remote_ptr
= lookup_by_name(remote_port
);
1659 if (remote_ptr
== NULL
) {
1660 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1661 remote_port
, "Port %s does not exist.", remote_port
);
1663 } else if (!remote_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
1664 "inactive when trying to connect it to local port %s.", remote_port
,
1666 add_local_connection(remote_ptr
);
1667 if (this != remote_ptr
) remote_ptr
->add_local_connection(this);
1668 TTCN_Communication::send_connected(port_name
, remote_component
,
1672 void PORT::connect_stream(component remote_component
, const char *remote_port
,
1673 transport_type_enum transport_type
, Text_Buf
& text_buf
)
1678 const char *transport_str
;
1680 switch (transport_type
) {
1681 case TRANSPORT_INET_STREAM
:
1682 transport_str
= "TCP";
1683 // creating the TCP client socket
1684 client_fd
= NetworkHandler::socket(TTCN_Communication::get_network_family());
1686 case TRANSPORT_UNIX_STREAM
:
1687 transport_str
= "UNIX";
1688 // creating the UNIX client socket
1689 client_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1692 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1693 "type (%d).", transport_type
);
1695 if (client_fd
< 0) {
1696 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1697 remote_port
, "Creation of the %s client socket failed. (%s)",
1698 transport_str
, strerror(errno
));
1703 switch (transport_type
) {
1704 case TRANSPORT_INET_STREAM
: {
1705 // connect to the IP address and port number given in message CONNECT
1706 IPAddress
*remote_addr
= IPAddress::create_addr(TTCN_Communication::get_network_family());
1707 remote_addr
->pull_raw(text_buf
);
1709 if (connect(client_fd
, (struct sockaddr
*)remote_addr
->get_addr(), remote_addr
->get_addr_len())) {
1711 if (connect(client_fd
, remote_addr
->get_addr(), remote_addr
->get_addr_len())) {
1714 if (errno
== EADDRINUSE
) {
1717 TTCN_warning("connect() returned error code EADDRINUSE. "
1718 "Perhaps this is a Cygwin bug. Trying to connect again.");
1723 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1724 remote_port
, "TCP connection establishment failed to %s:%d. (%s)",
1725 remote_addr
->get_addr_str(), remote_addr
->get_port(), strerror(errno
));
1732 case TRANSPORT_UNIX_STREAM
: {
1733 // connect to the UNIX pathname given in the message CONNECT
1734 struct sockaddr_un remote_addr
;
1735 memset(&remote_addr
, 0, sizeof(remote_addr
));
1736 remote_addr
.sun_family
= AF_UNIX
;
1737 size_t pathname_len
= text_buf
.pull_int().get_val();
1738 if (pathname_len
>= sizeof(remote_addr
.sun_path
)) {
1740 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1741 remote_port
, "The UNIX pathname used by the server socket is "
1742 "too long. It consists of %lu bytes although it should be "
1743 "shorter than %lu bytes to fit in the appropriate structure.",
1744 (unsigned long) pathname_len
,
1745 (unsigned long) sizeof(remote_addr
.sun_path
));
1748 text_buf
.pull_raw(pathname_len
, remote_addr
.sun_path
);
1749 if (connect(client_fd
, (struct sockaddr
*)&remote_addr
, sizeof(remote_addr
))) {
1751 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1752 remote_port
, "UNIX socket connection establishment failed to "
1753 "pathname %s. (%s)", remote_addr
.sun_path
, strerror(errno
));
1759 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1760 "type (%d).", transport_type
);
1763 if (!TTCN_Communication::set_close_on_exec(client_fd
)) {
1765 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1766 remote_port
, "Setting the close-on-exec flag failed on the %s "
1767 "client socket.", transport_str
);
1771 if (!TTCN_Communication::set_non_blocking_mode(client_fd
, TRUE
)) {
1773 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1774 remote_port
, "Setting the non-blocking mode failed on the %s "
1775 "client socket.", transport_str
);
1779 if (transport_type
== TRANSPORT_INET_STREAM
&&
1780 !TTCN_Communication::set_tcp_nodelay(client_fd
)) {
1782 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1783 remote_port
, "Setting the TCP_NODELAY flag failed on the TCP "
1788 port_connection
*new_connection
= add_connection(remote_component
,
1789 remote_port
, transport_type
);
1790 new_connection
->connection_state
= CONN_CONNECTED
;
1791 new_connection
->stream
.comm_fd
= client_fd
;
1792 Fd_And_Timeout_User::add_fd(client_fd
, new_connection
, FD_EVENT_RD
);
1794 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__established
,
1795 port_name
, remote_component
, remote_port
, transport_str
);
1798 void PORT::disconnect_local(port_connection
*conn_ptr
)
1800 PORT
*remote_ptr
= conn_ptr
->local
.port_ptr
;
1801 remove_local_connection(conn_ptr
);
1802 if (this != remote_ptr
) {
1803 port_connection
*conn2_ptr
=
1804 remote_ptr
->lookup_connection(self
, port_name
);
1805 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
1806 "connected with local port %s, but port %s does not have a "
1807 "connection to %s.", port_name
, remote_ptr
->port_name
,
1808 remote_ptr
->port_name
, port_name
);
1809 else remote_ptr
->remove_local_connection(conn2_ptr
);
1811 TTCN_Communication::send_disconnected(port_name
, self
,
1812 remote_ptr
->port_name
);
1815 void PORT::disconnect_stream(port_connection
*conn_ptr
)
1817 switch (conn_ptr
->connection_state
) {
1818 case CONN_LISTENING
:
1819 TTCN_Logger::log_port_misc(
1820 TitanLoggerApi::Port__Misc_reason::destroying__unestablished__connection
,
1821 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1822 remove_connection(conn_ptr
);
1823 // do not send back any acknowledgment
1825 case CONN_CONNECTED
: {
1826 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::terminating__connection
,
1827 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1828 Text_Buf outgoing_buf
;
1829 outgoing_buf
.push_int(CONN_DATA_LAST
);
1830 if (send_data_stream(conn_ptr
, outgoing_buf
, TRUE
)) {
1831 // sending the last message was successful
1832 // wait for the acknowledgment from the peer
1833 conn_ptr
->connection_state
= CONN_LAST_MSG_SENT
;
1835 TTCN_Logger::log_port_misc(
1836 TitanLoggerApi::Port__Misc_reason::sending__termination__request__failed
,
1837 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1838 // send an acknowledgment to MC immediately to avoid deadlock
1839 // in case of communication failure
1840 // (i.e. when the peer does not send DISCONNECTED)
1841 TTCN_Communication::send_disconnected(port_name
,
1842 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1843 TTCN_warning("The last outgoing messages on port %s may be lost.",
1845 // destroy the connection immediately
1846 remove_connection(conn_ptr
);
1850 TTCN_error("The connection of port %s to %d:%s is in unexpected "
1851 "state when trying to terminate it.", port_name
,
1852 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1856 void PORT::send_data_local(port_connection
*conn_ptr
, Text_Buf
& outgoing_data
)
1858 outgoing_data
.rewind();
1859 PORT
*dest_ptr
= conn_ptr
->local
.port_ptr
;
1860 if (this != dest_ptr
) {
1861 port_connection
*conn2_ptr
=
1862 dest_ptr
->lookup_connection(self
, port_name
);
1863 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
1864 "connected with local port %s, but port %s does not have a "
1865 "connection to %s.", port_name
, dest_ptr
->port_name
,
1866 dest_ptr
->port_name
, port_name
);
1867 dest_ptr
->process_data(conn2_ptr
, outgoing_data
);
1868 } else process_data(conn_ptr
, outgoing_data
);
1871 boolean
PORT::send_data_stream(port_connection
*conn_ptr
,
1872 Text_Buf
& outgoing_data
, boolean ignore_peer_disconnect
)
1874 bool would_block_warning
=false;
1875 outgoing_data
.calculate_length();
1876 const char *msg_ptr
= outgoing_data
.get_data();
1877 size_t msg_len
= outgoing_data
.get_len(), sent_len
= 0;
1878 while (sent_len
< msg_len
) {
1879 int ret_val
= send(conn_ptr
->stream
.comm_fd
, msg_ptr
+ sent_len
,
1880 msg_len
- sent_len
, 0);
1881 if (ret_val
> 0) sent_len
+= ret_val
;
1885 // a signal occurred: do nothing, just try again
1889 // the output buffer is full: try to increase it if possible
1891 int old_bufsize
, new_bufsize
;
1892 if (TTCN_Communication::increase_send_buffer(
1893 conn_ptr
->stream
.comm_fd
, old_bufsize
, new_bufsize
)) {
1894 TTCN_Logger::log_port_misc(
1895 TitanLoggerApi::Port__Misc_reason::sending__would__block
,
1896 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1897 NULL
, old_bufsize
, new_bufsize
);
1899 if(!would_block_warning
){
1900 TTCN_warning_begin("Sending data on the connection of "
1901 "port %s to ", port_name
);
1902 COMPONENT::log_component_reference(
1903 conn_ptr
->remote_component
);
1904 TTCN_Logger::log_event(":%s would block execution and it "
1905 "is not possible to further increase the size of the "
1906 "outgoing buffer. Trying to process incoming data to "
1907 "avoid deadlock.", conn_ptr
->remote_port
);
1909 would_block_warning
=true;
1911 TTCN_Snapshot::block_for_sending(conn_ptr
->stream
.comm_fd
);
1916 if (ignore_peer_disconnect
) return FALSE
;
1919 TTCN_error("Sending data on the connection of port %s to "
1920 "%d:%s failed.", port_name
, conn_ptr
->remote_component
,
1921 conn_ptr
->remote_port
);
1925 if(would_block_warning
){
1926 TTCN_warning_begin("The message finally was sent on "
1927 "port %s to ", port_name
);
1928 COMPONENT::log_component_reference(
1929 conn_ptr
->remote_component
);
1930 TTCN_Logger::log_event(":%s.", conn_ptr
->remote_port
);
1936 void PORT::handle_incoming_connection(port_connection
*conn_ptr
)
1938 const char *transport_str
=
1939 conn_ptr
->transport_type
== TRANSPORT_INET_STREAM
? "TCP" : "UNIX";
1940 int comm_fd
= accept(conn_ptr
->stream
.comm_fd
, NULL
, NULL
);
1942 TTCN_Communication::send_connect_error(port_name
,
1943 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1944 "Accepting of incoming %s connection failed. (%s)", transport_str
,
1947 remove_connection(conn_ptr
);
1951 if (!TTCN_Communication::set_close_on_exec(comm_fd
)) {
1953 TTCN_Communication::send_connect_error(port_name
,
1954 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1955 "Setting the close-on-exec flag failed on the server-side %s "
1956 "socket.", transport_str
);
1957 remove_connection(conn_ptr
);
1961 if (!TTCN_Communication::set_non_blocking_mode(comm_fd
, TRUE
)) {
1963 TTCN_Communication::send_connect_error(port_name
,
1964 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1965 "Setting the non-blocking mode failed on the server-side %s "
1966 "socket.", transport_str
);
1967 remove_connection(conn_ptr
);
1971 if (conn_ptr
->transport_type
== TRANSPORT_INET_STREAM
&&
1972 !TTCN_Communication::set_tcp_nodelay(comm_fd
)) {
1974 TTCN_Communication::send_connect_error(port_name
,
1975 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1976 "Setting the TCP_NODELAY flag failed on the server-side TCP "
1978 remove_connection(conn_ptr
);
1982 // shutting down the server socket and replacing it with the
1983 // communication socket of the new connection
1984 Fd_And_Timeout_User::remove_fd(conn_ptr
->stream
.comm_fd
, conn_ptr
,
1986 if (conn_ptr
->transport_type
== TRANSPORT_UNIX_STREAM
)
1987 unlink_unix_pathname(conn_ptr
->stream
.comm_fd
);
1988 close(conn_ptr
->stream
.comm_fd
);
1989 conn_ptr
->connection_state
= CONN_CONNECTED
;
1990 conn_ptr
->stream
.comm_fd
= comm_fd
;
1991 Fd_And_Timeout_User::add_fd(comm_fd
, conn_ptr
, FD_EVENT_RD
);
1993 TTCN_Communication::send_connected(port_name
, conn_ptr
->remote_component
,
1994 conn_ptr
->remote_port
);
1996 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__accepted
,
1997 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2000 void PORT::handle_incoming_data(port_connection
*conn_ptr
)
2002 if (conn_ptr
->stream
.incoming_buf
== NULL
)
2003 conn_ptr
->stream
.incoming_buf
= new Text_Buf
;
2004 Text_Buf
& incoming_buf
= *conn_ptr
->stream
.incoming_buf
;
2007 incoming_buf
.get_end(buf_ptr
, buf_len
);
2008 int recv_len
= recv(conn_ptr
->stream
.comm_fd
, buf_ptr
, buf_len
, 0);
2010 // an error occurred
2011 if (errno
== ECONNRESET
) {
2012 // TCP connection was reset by peer
2014 TTCN_Communication::send_disconnected(port_name
,
2015 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2016 TTCN_Logger::log_port_misc(
2017 TitanLoggerApi::Port__Misc_reason::connection__reset__by__peer
,
2018 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2019 TTCN_warning("The last outgoing messages on port %s may be lost.",
2021 conn_ptr
->connection_state
= CONN_IDLE
;
2023 TTCN_error("Receiving data on the connection of port %s from "
2024 "%d:%s failed.", port_name
, conn_ptr
->remote_component
,
2025 conn_ptr
->remote_port
);
2027 } else if (recv_len
> 0) {
2028 // data was received
2029 incoming_buf
.increase_length(recv_len
);
2030 // processing all messages in the buffer after each other
2031 while (incoming_buf
.is_message()) {
2032 incoming_buf
.pull_int(); // message_length
2033 process_data(conn_ptr
, incoming_buf
);
2034 incoming_buf
.cut_message();
2037 // the connection was closed by the peer
2038 TTCN_Communication::send_disconnected(port_name
,
2039 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2040 if (conn_ptr
->connection_state
!= CONN_LAST_MSG_RCVD
) {
2041 TTCN_Logger::log_port_misc(
2042 TitanLoggerApi::Port__Misc_reason::connection__closed__by__peer
,
2043 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2045 // the connection can be removed
2046 conn_ptr
->connection_state
= CONN_IDLE
;
2048 if (conn_ptr
->connection_state
== CONN_IDLE
) {
2049 // terminating and removing connection
2050 int msg_len
= incoming_buf
.get_len();
2052 TTCN_warning_begin("Message fragment remained in the buffer of "
2053 "port connection between %s and ", port_name
);
2054 COMPONENT::log_component_reference(conn_ptr
->remote_component
);
2055 TTCN_Logger::log_event(":%s: ", conn_ptr
->remote_port
);
2056 const unsigned char *msg_ptr
=
2057 (const unsigned char*)incoming_buf
.get_data();
2058 for (int i
= 0; i
< msg_len
; i
++)
2059 TTCN_Logger::log_octet(msg_ptr
[i
]);
2063 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::port__disconnected
,
2064 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2065 remove_connection(conn_ptr
);
2069 void PORT::process_last_message(port_connection
*conn_ptr
)
2071 switch (conn_ptr
->transport_type
) {
2072 case TRANSPORT_INET_STREAM
:
2073 case TRANSPORT_UNIX_STREAM
:
2076 TTCN_error("Internal error: Connection termination request was "
2077 "received on the connection of port %s with %d:%s, which has an "
2078 "invalid transport type (%d).", port_name
,
2079 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
2080 conn_ptr
->transport_type
);
2082 switch (conn_ptr
->connection_state
) {
2083 case CONN_CONNECTED
: {
2084 TTCN_Logger::log_port_misc(
2085 TitanLoggerApi::Port__Misc_reason::termination__request__received
,
2086 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2087 Text_Buf outgoing_buf
;
2088 outgoing_buf
.push_int(CONN_DATA_LAST
);
2089 if (send_data_stream(conn_ptr
, outgoing_buf
, TRUE
)) {
2090 // sending the last message was successful
2091 // wait until the peer closes the transport connection
2092 conn_ptr
->connection_state
= CONN_LAST_MSG_RCVD
;
2094 TTCN_Logger::log_port_misc(
2095 TitanLoggerApi::Port__Misc_reason::acknowledging__termination__request__failed
,
2096 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2097 // send an acknowledgment to MC immediately to avoid deadlock
2098 // in case of communication failure
2099 // (i.e. when the peer does not send DISCONNECTED)
2100 TTCN_Communication::send_disconnected(port_name
,
2101 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2102 // the connection can be removed immediately
2103 TTCN_warning("The last outgoing messages on port %s may be lost.",
2105 conn_ptr
->connection_state
= CONN_IDLE
;
2108 case CONN_LAST_MSG_SENT
:
2109 // the connection can be removed
2110 conn_ptr
->connection_state
= CONN_IDLE
;
2112 case CONN_LAST_MSG_RCVD
:
2114 TTCN_warning("Unexpected data arrived after the indication of "
2115 "connection termination on port %s from %d:%s.", port_name
,
2116 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2119 TTCN_error("Internal error: Connection of port %s with %d:%s has "
2120 "invalid state (%d).", port_name
, conn_ptr
->remote_component
,
2121 conn_ptr
->remote_port
, conn_ptr
->connection_state
);
2125 void PORT::map(const char *system_port
)
2127 if (!is_active
) TTCN_error("Inactive port %s cannot be mapped.", port_name
);
2130 for (new_posn
= 0; new_posn
< n_system_mappings
; new_posn
++) {
2131 int str_diff
= strcmp(system_port
, system_mappings
[new_posn
]);
2132 if (str_diff
< 0) break;
2133 else if (str_diff
== 0) {
2134 TTCN_warning("Port %s is already mapped to system:%s."
2135 " Map operation was ignored.", port_name
, system_port
);
2140 set_system_parameters(system_port
);
2142 user_map(system_port
);
2144 TTCN_Logger::log_port_misc(
2145 TitanLoggerApi::Port__Misc_reason::port__was__mapped__to__system
,
2146 port_name
, SYSTEM_COMPREF
, system_port
);
2148 // the mapping shall be registered in the table only if user_map() was
2150 system_mappings
= (char**)Realloc(system_mappings
,
2151 (n_system_mappings
+ 1) * sizeof(*system_mappings
));
2152 memmove(system_mappings
+ new_posn
+ 1, system_mappings
+ new_posn
,
2153 (n_system_mappings
- new_posn
) * sizeof(*system_mappings
));
2154 system_mappings
[new_posn
] = mcopystr(system_port
);
2155 n_system_mappings
++;
2157 if (n_system_mappings
> 1) TTCN_warning("Port %s has now more than one "
2158 "mappings. Message cannot be sent on it to system even with explicit "
2159 "addressing.", port_name
);
2162 void PORT::unmap(const char *system_port
)
2165 for (del_posn
= 0; del_posn
< n_system_mappings
; del_posn
++) {
2166 int str_diff
= strcmp(system_port
, system_mappings
[del_posn
]);
2167 if (str_diff
== 0) break;
2168 else if (str_diff
< 0) {
2169 del_posn
= n_system_mappings
;
2173 if (del_posn
>= n_system_mappings
) {
2174 TTCN_warning("Port %s is not mapped to system:%s. "
2175 "Unmap operation was ignored.", port_name
, system_port
);
2179 char *unmapped_port
= system_mappings
[del_posn
];
2181 // first remove the mapping from the table
2182 n_system_mappings
--;
2183 memmove(system_mappings
+ del_posn
, system_mappings
+ del_posn
+ 1,
2184 (n_system_mappings
- del_posn
) * sizeof(*system_mappings
));
2185 system_mappings
= (char**)Realloc(system_mappings
,
2186 n_system_mappings
* sizeof(*system_mappings
));
2189 user_unmap(system_port
);
2191 // prevent from memory leak
2192 Free(unmapped_port
);
2196 TTCN_Logger::log_port_misc(
2197 TitanLoggerApi::Port__Misc_reason::port__was__unmapped__from__system
,
2198 port_name
, SYSTEM_COMPREF
, system_port
);
2200 Free(unmapped_port
);
2203 void PORT::process_connect_listen(const char *local_port
,
2204 component remote_component
, const char *remote_port
,
2205 transport_type_enum transport_type
)
2207 PORT
*port_ptr
= lookup_by_name(local_port
);
2208 if (port_ptr
== NULL
) {
2209 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2210 remote_port
, "Port %s does not exist.", local_port
);
2212 } else if (!port_ptr
->is_active
) {
2213 TTCN_error("Internal error: Port %s is inactive when trying to "
2214 "connect it to %d:%s.", local_port
, remote_component
, remote_port
);
2215 } else if (port_ptr
->lookup_connection(remote_component
, remote_port
)
2217 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2218 remote_port
, "Port %s already has a connection towards %d:%s.",
2219 local_port
, remote_component
, remote_port
);
2221 } else if (port_ptr
->lookup_connection_to_compref(remote_component
, NULL
)
2223 TTCN_warning_begin("Port %s will have more than one connections with "
2224 "ports of test component ", local_port
);
2225 COMPONENT::log_component_reference(remote_component
);
2226 TTCN_Logger::log_event_str(". These connections cannot be used for "
2227 "sending even with explicit addressing.");
2231 switch (transport_type
) {
2232 case TRANSPORT_LOCAL
:
2233 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2234 remote_port
, "Message CONNECT_LISTEN cannot refer to transport "
2237 case TRANSPORT_INET_STREAM
:
2238 port_ptr
->connect_listen_inet_stream(remote_component
, remote_port
);
2240 case TRANSPORT_UNIX_STREAM
:
2241 port_ptr
->connect_listen_unix_stream(remote_component
, remote_port
);
2244 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2245 remote_port
, "Message CONNECT_LISTEN refers to invalid transport "
2246 "type (%d).", transport_type
);
2251 void PORT::process_connect(const char *local_port
,
2252 component remote_component
, const char *remote_port
,
2253 transport_type_enum transport_type
, Text_Buf
& text_buf
)
2255 PORT
*port_ptr
= lookup_by_name(local_port
);
2256 if (port_ptr
== NULL
) {
2257 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2258 remote_port
, "Port %s does not exist.", local_port
);
2260 } else if (!port_ptr
->is_active
) {
2261 TTCN_error("Internal error: Port %s is inactive when trying to "
2262 "connect it to %d:%s.", local_port
, remote_component
, remote_port
);
2263 } else if (port_ptr
->lookup_connection(remote_component
, remote_port
)
2265 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2266 remote_port
, "Port %s already has a connection towards %d:%s.",
2267 local_port
, remote_component
, remote_port
);
2269 } else if (port_ptr
->lookup_connection_to_compref(remote_component
, NULL
)
2271 TTCN_warning_begin("Port %s will have more than one connections with "
2272 "ports of test component ", local_port
);
2273 COMPONENT::log_component_reference(remote_component
);
2274 TTCN_Logger::log_event_str(". These connections cannot be used for "
2275 "sending even with explicit addressing.");
2279 switch (transport_type
) {
2280 case TRANSPORT_LOCAL
:
2281 port_ptr
->connect_local(remote_component
, remote_port
);
2283 case TRANSPORT_INET_STREAM
:
2284 case TRANSPORT_UNIX_STREAM
:
2285 port_ptr
->connect_stream(remote_component
, remote_port
, transport_type
,
2289 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2290 remote_port
, "Message CONNECT refers to invalid transport type "
2291 "(%d).", transport_type
);
2296 void PORT::process_disconnect(const char *local_port
,
2297 component remote_component
, const char *remote_port
)
2299 PORT
*port_ptr
= lookup_by_name(local_port
);
2300 if (port_ptr
== NULL
) {
2301 TTCN_Communication::send_error("Message DISCONNECT refers to "
2302 "non-existent local port %s.", local_port
);
2304 } else if (!port_ptr
->is_active
) {
2305 TTCN_error("Internal error: Port %s is inactive when trying to "
2306 "disconnect it from %d:%s.", local_port
, remote_component
,
2309 port_connection
*conn_ptr
= port_ptr
->lookup_connection(remote_component
,
2311 if (conn_ptr
== NULL
) {
2312 // the connection does not exist
2313 if (self
== remote_component
&& lookup_by_name(remote_port
) == NULL
) {
2314 // the remote endpoint is in the same component,
2315 // but it does not exist
2316 TTCN_Communication::send_error("Message DISCONNECT refers to "
2317 "non-existent port %s.", remote_port
);
2319 TTCN_Communication::send_disconnected(local_port
, remote_component
,
2324 switch (conn_ptr
->transport_type
) {
2325 case TRANSPORT_LOCAL
:
2326 port_ptr
->disconnect_local(conn_ptr
);
2328 case TRANSPORT_INET_STREAM
:
2329 case TRANSPORT_UNIX_STREAM
:
2330 port_ptr
->disconnect_stream(conn_ptr
);
2333 TTCN_error("Internal error: The connection of port %s to %d:%s has "
2334 "invalid transport type (%d) when trying to terminate the "
2335 "connection.", local_port
, remote_component
, remote_port
,
2336 conn_ptr
->transport_type
);
2340 void PORT::make_local_connection(const char *src_port
, const char *dest_port
)
2342 PORT
*src_ptr
= lookup_by_name(src_port
);
2343 if (src_ptr
== NULL
) TTCN_error("Connect operation refers to "
2344 "non-existent port %s.", src_port
);
2345 else if (!src_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2346 "inactive when trying to connect it with local port %s.", src_port
,
2348 else if (src_ptr
->lookup_connection(MTC_COMPREF
, dest_port
) != NULL
) {
2349 TTCN_warning("Port %s is already connected with local port %s. "
2350 "Connect operation had no effect.", src_port
, dest_port
);
2352 } else if (src_ptr
->lookup_connection_to_compref(MTC_COMPREF
, NULL
)
2354 TTCN_warning("Port %s will have more than one connections with local "
2355 "ports. These connections cannot be used for communication even "
2356 "with explicit addressing.", src_port
);
2358 PORT
*dest_ptr
= lookup_by_name(dest_port
);
2359 if (dest_ptr
== NULL
) TTCN_error("Connect operation refers to "
2360 "non-existent port %s.", dest_port
);
2361 else if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2362 "inactive when trying to connect it with local port %s.", dest_port
,
2364 src_ptr
->add_local_connection(dest_ptr
);
2365 if (src_ptr
!= dest_ptr
) dest_ptr
->add_local_connection(src_ptr
);
2368 void PORT::terminate_local_connection(const char *src_port
,
2369 const char *dest_port
)
2371 PORT
*src_ptr
= lookup_by_name(src_port
);
2372 if (src_ptr
== NULL
) TTCN_error("Disconnect operation refers to "
2373 "non-existent port %s.", src_port
);
2374 else if (!src_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2375 "inactive when trying to disconnect it from local port %s.", src_port
,
2377 port_connection
*conn_ptr
= src_ptr
->lookup_connection(MTC_COMPREF
,
2379 if (conn_ptr
!= NULL
) {
2380 PORT
*dest_ptr
= conn_ptr
->local
.port_ptr
;
2381 src_ptr
->remove_local_connection(conn_ptr
);
2382 if (src_ptr
!= dest_ptr
) {
2383 if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2384 "inactive when trying to disconnect it from local port %s.",
2385 dest_port
, src_port
);
2386 port_connection
*conn2_ptr
=
2387 dest_ptr
->lookup_connection(MTC_COMPREF
, src_port
);
2388 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
2389 "connected with local port %s, but port %s does not have a "
2390 "connection to %s.", src_port
, dest_port
, dest_port
, src_port
);
2391 else dest_ptr
->remove_local_connection(conn2_ptr
);
2394 PORT
*dest_ptr
= lookup_by_name(dest_port
);
2395 if (dest_ptr
== NULL
) TTCN_error("Disconnect operation refers to "
2396 "non-existent port %s.", dest_port
);
2397 else if (src_ptr
!= dest_ptr
) {
2398 if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2399 "inactive when trying to disconnect it from local port %s.",
2400 dest_port
, src_port
);
2401 else if (dest_ptr
->lookup_connection(MTC_COMPREF
, src_port
) != NULL
)
2402 TTCN_error("Internal error: Port %s is connected with local "
2403 "port %s, but port %s does not have a connection to %s.",
2404 dest_port
, src_port
, src_port
, dest_port
);
2406 TTCN_warning("Port %s does not have connection with local port %s. "
2407 "Disconnect operation had no effect.", src_port
, dest_port
);
2411 void PORT::map_port(const char *component_port
, const char *system_port
)
2413 PORT
*port_ptr
= lookup_by_name(component_port
);
2414 if (port_ptr
== NULL
) TTCN_error("Map operation refers to "
2415 "non-existent port %s.", component_port
);
2416 port_ptr
->map(system_port
);
2417 if (!TTCN_Runtime::is_single())
2418 TTCN_Communication::send_mapped(component_port
, system_port
);
2421 void PORT::unmap_port(const char *component_port
, const char *system_port
)
2423 PORT
*port_ptr
= lookup_by_name(component_port
);
2424 if (port_ptr
== NULL
) TTCN_error("Unmap operation refers to "
2425 "non-existent port %s.", component_port
);
2426 port_ptr
->unmap(system_port
);
2427 if (!TTCN_Runtime::is_single())
2428 TTCN_Communication::send_unmapped(component_port
, system_port
);
2431 bool PORT::check_port_state(const CHARSTRING
& type
) const
2433 if (type
== "Started") {
2435 } else if (type
== "Halted") {
2437 } else if (type
== "Stopped") {
2438 return (!is_started
&& !is_halted
);
2439 } else if (type
== "Connected") {
2440 return connection_list_head
!= NULL
;
2441 } else if (type
== "Mapped") {
2442 return n_system_mappings
> 0;
2443 } else if (type
== "Linked") {
2444 return (connection_list_head
!= NULL
|| n_system_mappings
> 0);
2446 TTCN_error("%s is not an allowed parameter of checkstate().", (const char*)type
);
2449 bool PORT::any_check_port_state(const CHARSTRING
& type
)
2451 bool result
= false;
2452 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
2453 result
= port
->check_port_state(type
);
2461 bool PORT::all_check_port_state(const CHARSTRING
& type
)
2464 for (PORT
*port
= list_head
; port
!= NULL
&& result
; port
= port
->list_next
) {
2465 result
= port
->check_port_state(type
);