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
18 * Szabo, Janos Zoltan – initial implementation
22 ******************************************************************************/
28 #include <sys/types.h>
29 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
35 #include "../common/platform.h"
37 #include "../common/memory.h"
38 #include "Component.hh"
41 #include "Event_Handler.hh"
42 #include "Fd_And_Timeout_User.hh"
43 #include "Snapshot.hh"
44 #include "Communication.hh"
46 #include "Octetstring.hh"
47 #include "TitanLoggerApi.hh"
49 // maximum number of iterations for binding the UNIX server socket
50 #define UNIX_BIND_MAX_ITER 100
52 #include "../common/dbgnew.hh"
54 PORT
*PORT::list_head
= NULL
, *PORT::list_tail
= NULL
;
56 void PORT::add_to_list()
58 // check for duplicate names
59 for (PORT
*p
= list_head
; p
!= NULL
; p
= p
->list_next
) {
60 // do nothing if this is already a member of the list
61 if (p
== this) return;
62 else if (!strcmp(p
->port_name
, port_name
))
63 TTCN_error("Internal error: There are more than one ports with "
64 "name %s.", port_name
);
66 // append this to the list
67 if (list_head
== NULL
) list_head
= this;
68 else if (list_tail
!= NULL
) list_tail
->list_next
= this;
69 list_prev
= list_tail
;
74 void PORT::remove_from_list()
76 if (list_prev
!= NULL
) list_prev
->list_next
= list_next
;
77 else if (list_head
== this) list_head
= list_next
;
78 if (list_next
!= NULL
) list_next
->list_prev
= list_prev
;
79 else if (list_tail
== this) list_tail
= list_prev
;
84 PORT
*PORT::lookup_by_name(const char *par_port_name
)
86 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
87 if (!strcmp(par_port_name
, port
->port_name
)) return port
;
91 struct PORT::port_parameter
{
92 component_id_t component_id
;
95 char *parameter_value
;
96 struct port_parameter
*next_par
;
97 } *PORT::parameter_head
= NULL
, *PORT::parameter_tail
= NULL
;
99 void PORT::apply_parameter(port_parameter
*par_ptr
)
101 if (par_ptr
->port_name
!= NULL
) {
102 // the parameter refers to a specific port
103 PORT
*port
= lookup_by_name(par_ptr
->port_name
);
104 if (port
!= NULL
) port
->set_parameter(par_ptr
->parameter_name
,
105 par_ptr
->parameter_value
);
107 // the parameter refers to all ports (*)
108 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
109 port
->set_parameter(par_ptr
->parameter_name
,
110 par_ptr
->parameter_value
);
114 void PORT::set_system_parameters(const char *system_port
)
116 for (port_parameter
*par
= parameter_head
; par
!= NULL
; par
= par
->next_par
)
117 if (par
->component_id
.id_selector
== COMPONENT_ID_SYSTEM
&&
118 (par
->port_name
== NULL
|| !strcmp(par
->port_name
, system_port
)))
119 set_parameter(par
->parameter_name
, par
->parameter_value
);
122 void PORT::add_parameter(const component_id_t
& component_id
,
123 const char *par_port_name
, const char *parameter_name
,
124 const char *parameter_value
)
126 port_parameter
*new_par
= new port_parameter
;
128 new_par
->component_id
.id_selector
= component_id
.id_selector
;
129 switch (component_id
.id_selector
) {
130 case COMPONENT_ID_NAME
:
131 new_par
->component_id
.id_name
= mcopystr(component_id
.id_name
);
133 case COMPONENT_ID_COMPREF
:
134 new_par
->component_id
.id_compref
= component_id
.id_compref
;
140 if (par_port_name
== NULL
) new_par
->port_name
= NULL
;
141 else new_par
->port_name
= mcopystr(par_port_name
);
142 new_par
->parameter_name
= mcopystr(parameter_name
);
143 new_par
->parameter_value
= mcopystr(parameter_value
);
145 new_par
->next_par
= NULL
;
146 if (parameter_head
== NULL
) parameter_head
= new_par
;
147 if (parameter_tail
!= NULL
) parameter_tail
->next_par
= new_par
;
148 parameter_tail
= new_par
;
151 void PORT::clear_parameters()
153 while (parameter_head
!= NULL
) {
154 port_parameter
*next_par
= parameter_head
->next_par
;
155 if (parameter_head
->component_id
.id_selector
== COMPONENT_ID_NAME
)
156 Free(parameter_head
->component_id
.id_name
);
157 Free(parameter_head
->port_name
);
158 Free(parameter_head
->parameter_name
);
159 Free(parameter_head
->parameter_value
);
160 delete parameter_head
;
161 parameter_head
= next_par
;
165 void PORT::set_parameters(component component_reference
,
166 const char *component_name
)
168 for (port_parameter
*par
= parameter_head
; par
!= NULL
; par
= par
->next_par
)
169 switch (par
->component_id
.id_selector
) {
170 case COMPONENT_ID_NAME
:
171 if (component_name
!= NULL
&&
172 !strcmp(par
->component_id
.id_name
, component_name
))
173 apply_parameter(par
);
175 case COMPONENT_ID_COMPREF
:
176 if (par
->component_id
.id_compref
== component_reference
)
177 apply_parameter(par
);
179 case COMPONENT_ID_ALL
:
180 apply_parameter(par
);
187 enum connection_data_type_enum
{
188 CONN_DATA_LAST
= 0, CONN_DATA_MESSAGE
= 1, CONN_DATA_CALL
= 2,
189 CONN_DATA_REPLY
= 3, CONN_DATA_EXCEPTION
= 4
192 enum connection_state_enum
{
193 CONN_IDLE
, CONN_LISTENING
, CONN_CONNECTED
, CONN_LAST_MSG_SENT
,
197 struct port_connection
: public Fd_Event_Handler
{
199 connection_state_enum connection_state
;
200 component remote_component
;
202 transport_type_enum transport_type
;
209 Text_Buf
*incoming_buf
;
212 struct port_connection
*list_prev
, *list_next
;
213 OCTETSTRING sliding_buffer
;
215 virtual void Handle_Fd_Event(int fd
,
216 boolean is_readable
, boolean is_writeable
, boolean is_error
);
217 virtual ~port_connection();
218 virtual void log() const;
221 void port_connection::Handle_Fd_Event(int,
222 boolean is_readable
, boolean
/*is_writeable*/, boolean
/*is_error*/)
224 // Note event for connection with TRANSPORT_LOCAL transport_type
226 if (transport_type
== TRANSPORT_INET_STREAM
227 || transport_type
== TRANSPORT_UNIX_STREAM
230 if (connection_state
== CONN_LISTENING
)
231 owner_port
->handle_incoming_connection(this);
232 else owner_port
->handle_incoming_data(this);
235 TTCN_error("Internal error: Invalid transport type (%d) in port "
236 "connection between %s and %d:%s.", transport_type
,
237 owner_port
->get_name(), remote_component
, remote_port
);
240 void port_connection::log() const
242 TTCN_Logger::log_event("port connection between ");
243 owner_port
->log(); TTCN_Logger::log_event(" and ");
244 TTCN_Logger::log_event(remote_component
); TTCN_Logger::log_event(":");
245 TTCN_Logger::log_event("%s", remote_port
);
248 port_connection::~port_connection()
250 if (transport_type
== TRANSPORT_INET_STREAM
251 || transport_type
== TRANSPORT_UNIX_STREAM
253 if (stream
.comm_fd
!= -1) {
254 TTCN_warning_begin("Internal Error: File descriptor %d not "
255 "closed/removed in ", stream
.comm_fd
); log();
259 sliding_buffer
.clean_up();
262 PORT::PORT(const char *par_port_name
)
264 port_name
= par_port_name
!= NULL
? par_port_name
: "<unknown>";
271 connection_list_head
= NULL
;
272 connection_list_tail
= NULL
;
273 n_system_mappings
= 0;
274 system_mappings
= NULL
;
279 if (is_active
) deactivate_port();
282 void PORT::set_name(const char * name
)
284 if (name
== NULL
) TTCN_error("Internal error: Setting an "
285 "invalid name for a single element of a port array.");
289 void PORT::log() const
291 TTCN_Logger::log_event("port %s", port_name
);
294 void PORT::activate_port()
306 void PORT::deactivate_port()
309 /* In order to proceed with the deactivation we must ignore the
311 * - errors in user code of Test Port (i.e. user_stop, user_unmap)
312 * - failures when sending messages to MC (the link may be down)
314 boolean is_parallel
= !TTCN_Runtime::is_single();
315 // terminate all connections
316 while (connection_list_head
!= NULL
) {
317 TTCN_Logger::log_port_misc(
318 TitanLoggerApi::Port__Misc_reason::removing__unterminated__connection
,
320 connection_list_head
->remote_component
, connection_list_head
->remote_port
);
323 TTCN_Communication::send_disconnected(port_name
,
324 connection_list_head
->remote_component
,
325 connection_list_head
->remote_port
);
326 } catch (const TC_Error
&) { }
328 remove_connection(connection_list_head
);
330 // terminate all mappings
331 while (n_system_mappings
> 0) {
332 // we must make a copy of the string because unmap() will destroy it
333 char *system_port
= mcopystr(system_mappings
[0]);
334 TTCN_Logger::log_port_misc(
335 TitanLoggerApi::Port__Misc_reason::removing__unterminated__mapping
,
336 port_name
, NULL_COMPREF
, system_port
);
339 } catch (const TC_Error
&) { }
342 TTCN_Communication::send_unmapped(port_name
, system_port
);
343 } catch (const TC_Error
&) { }
347 // the previous disconnect/unmap operations may generate incoming events
348 // so we should stop and clear the queue after them
349 if (is_started
|| is_halted
) {
352 } catch (const TC_Error
&) { }
355 // deactivate all event handlers
356 Fd_And_Timeout_User::remove_all_fds(this);
357 Fd_And_Timeout_User::set_timer(this, 0.0);
358 // File descriptor events of port connections are removed
359 // in remove_connection
365 void PORT::deactivate_all()
367 while (list_head
!= NULL
) list_head
->deactivate_port();
372 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
373 "be cleared.", port_name
);
374 if (!is_started
&& !is_halted
) {
375 TTCN_warning("Performing clear operation on port %s, which is "
376 "already stopped. The operation has no effect.", port_name
);
379 TTCN_Logger::log_port_misc(
380 TitanLoggerApi::Port__Misc_reason::port__was__cleared
, port_name
);
383 void PORT::all_clear()
385 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
391 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
392 "be started.", port_name
);
394 TTCN_warning("Performing start operation on port %s, which is "
395 "already started. The operation will clear the incoming queue.",
400 // the queue might contain old messages which has to be discarded
407 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::started
,
411 void PORT::all_start()
413 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
419 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
420 "be stopped.", port_name
);
425 // dropping all messages from the queue because they cannot be
426 // extracted by receiving operations anymore
428 } else if (is_halted
) {
432 TTCN_warning("Performing stop operation on port %s, which is "
433 "already stopped. The operation has no effect.", port_name
);
435 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::stopped
,
439 void PORT::all_stop()
441 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
447 if (!is_active
) TTCN_error("Internal error: Inactive port %s cannot "
448 "be halted.", port_name
);
453 // keep the messages in the queue
454 } else if (is_halted
) {
455 TTCN_warning("Performing halt operation on port %s, which is "
456 "already halted. The operation has no effect.", port_name
);
458 TTCN_warning("Performing halt operation on port %s, which is "
459 "already stopped. The operation has no effect.", port_name
);
461 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::halted
,
465 void PORT::all_halt()
467 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
)
471 alt_status
PORT::receive(const COMPONENT_template
&, COMPONENT
*)
473 TTCN_Logger::log_matching_problem(
474 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
475 TitanLoggerApi::MatchingProblemType_operation::receive__
,
476 false, false, port_name
);
480 alt_status
PORT::any_receive(const COMPONENT_template
& sender_template
,
481 COMPONENT
*sender_ptr
)
483 if (list_head
!= NULL
) {
484 alt_status ret_val
= ALT_NO
;
485 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
486 switch (port
->receive(sender_template
, sender_ptr
)) {
495 TTCN_error("Internal error: Receive operation returned "
496 "unexpected status code on port %s while evaluating "
497 "`any port.receive'.", port
->port_name
);
502 TTCN_Logger::log_matching_problem(
503 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
504 TitanLoggerApi::MatchingProblemType_operation::receive__
,
510 alt_status
PORT::check_receive(const COMPONENT_template
&, COMPONENT
*)
512 TTCN_Logger::log_matching_problem(
513 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
514 TitanLoggerApi::MatchingProblemType_operation::receive__
,
515 false, true, port_name
);
519 alt_status
PORT::any_check_receive(const COMPONENT_template
& sender_template
,
520 COMPONENT
*sender_ptr
)
522 if (list_head
!= NULL
) {
523 alt_status ret_val
= ALT_NO
;
524 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
525 switch (port
->check_receive(sender_template
, sender_ptr
)) {
534 TTCN_error("Internal error: Check-receive operation returned "
535 "unexpected status code on port %s while evaluating "
536 "`any port.check(receive)'.", port
->port_name
);
541 TTCN_Logger::log_matching_problem(
542 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
543 TitanLoggerApi::MatchingProblemType_operation::receive__
,
549 alt_status
PORT::trigger(const COMPONENT_template
&, COMPONENT
*)
551 TTCN_Logger::log_matching_problem(
552 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types
,
553 TitanLoggerApi::MatchingProblemType_operation::trigger__
,
554 false, false, port_name
);
558 alt_status
PORT::any_trigger(const COMPONENT_template
& sender_template
,
559 COMPONENT
*sender_ptr
)
561 if (list_head
!= NULL
) {
562 alt_status ret_val
= ALT_NO
;
563 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
564 switch (port
->trigger(sender_template
, sender_ptr
)) {
575 TTCN_error("Internal error: Trigger operation returned "
576 "unexpected status code on port %s while evaluating "
577 "`any port.trigger'.", port
->port_name
);
582 TTCN_Logger::log_matching_problem(
583 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
584 TitanLoggerApi::MatchingProblemType_operation::trigger__
,
590 alt_status
PORT::getcall(const COMPONENT_template
&, COMPONENT
*)
592 // ToDo:Unnecessary log matching problem warning removed.
593 // Question: does it unnecessary?
594 // TTCN_Logger::log_matching_problem(
595 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
596 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
597 // false, false, port_name);
601 alt_status
PORT::any_getcall(const COMPONENT_template
& sender_template
,
602 COMPONENT
*sender_ptr
)
604 if (list_head
!= NULL
) {
605 alt_status ret_val
= ALT_NO
;
606 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
607 switch (port
->getcall(sender_template
, sender_ptr
)) {
616 TTCN_error("Internal error: Getcall operation returned "
617 "unexpected status code on port %s while evaluating "
618 "`any port.getcall'.", port
->port_name
);
623 TTCN_Logger::log_matching_problem(
624 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
625 TitanLoggerApi::MatchingProblemType_operation::getcall__
,
631 alt_status
PORT::check_getcall(const COMPONENT_template
&, COMPONENT
*)
633 // ToDo:Unnecessary log matching problem warning removed.
634 // Question: does it unnecessary
635 // TTCN_Logger::log_matching_problem(
636 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
637 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
638 // false, false, port_name);
642 alt_status
PORT::any_check_getcall(const COMPONENT_template
& sender_template
,
643 COMPONENT
*sender_ptr
)
645 if (list_head
!= NULL
) {
646 alt_status ret_val
= ALT_NO
;
647 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
648 switch (port
->check_getcall(sender_template
, sender_ptr
)) {
657 TTCN_error("Internal error: Check-getcall operation returned "
658 "unexpected status code on port %s while evaluating "
659 "`any port.check(getcall)'.", port
->port_name
);
664 TTCN_Logger::log_matching_problem(
665 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
666 TitanLoggerApi::MatchingProblemType_operation::getcall__
,
672 alt_status
PORT::getreply(const COMPONENT_template
&, COMPONENT
*)
674 // ToDo:Unnecessary log matching problem warning removed.
675 // Question: does it unnecessary
676 // TTCN_Logger::log_matching_problem(
677 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
678 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
679 // false, false, port_name);
683 alt_status
PORT::any_getreply(const COMPONENT_template
& sender_template
,
684 COMPONENT
*sender_ptr
)
686 if (list_head
!= NULL
) {
687 alt_status ret_val
= ALT_NO
;
688 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
689 switch (port
->getreply(sender_template
, sender_ptr
)) {
698 TTCN_error("Internal error: Getreply operation returned "
699 "unexpected status code on port %s while evaluating "
700 "`any port.getreply'.", port
->port_name
);
705 TTCN_Logger::log_matching_problem(
706 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
707 TitanLoggerApi::MatchingProblemType_operation::getreply__
,
713 alt_status
PORT::check_getreply(const COMPONENT_template
&, COMPONENT
*)
715 // ToDo:Unnecessary log matching problem warning removed.
716 // Question: does it unnecessary
717 // TTCN_Logger::log_matching_problem(
718 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
719 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
720 // false, true, port_name);
724 alt_status
PORT::any_check_getreply(const COMPONENT_template
& sender_template
,
725 COMPONENT
*sender_ptr
)
727 if (list_head
!= NULL
) {
728 alt_status ret_val
= ALT_NO
;
729 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
730 switch (port
->check_getreply(sender_template
, sender_ptr
)) {
739 TTCN_error("Internal error: Check-getreply operation returned "
740 "unexpected status code on port %s while evaluating "
741 "`any port.check(getreply)'.", port
->port_name
);
746 TTCN_Logger::log_matching_problem(
747 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
748 TitanLoggerApi::MatchingProblemType_operation::getreply__
,
754 alt_status
PORT::get_exception(const COMPONENT_template
&, COMPONENT
*)
756 // ToDo:Unnecessary log matching problem warning removed.
757 // Question: does it unnecessary
758 // TTCN_Logger::log_matching_problem(
759 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
760 // TitanLoggerApi::MatchingProblemType_operation::catch__,
761 // false, false, port_name);
765 alt_status
PORT::any_catch(const COMPONENT_template
& sender_template
,
766 COMPONENT
*sender_ptr
)
768 if (list_head
!= NULL
) {
769 alt_status ret_val
= ALT_NO
;
770 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
771 switch (port
->get_exception(sender_template
, sender_ptr
)) {
780 TTCN_error("Internal error: Catch operation returned "
781 "unexpected status code on port %s while evaluating "
782 "`any port.catch'.", port
->port_name
);
787 TTCN_Logger::log_matching_problem(
788 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
789 TitanLoggerApi::MatchingProblemType_operation::catch__
,
795 alt_status
PORT::check_catch(const COMPONENT_template
& ,
798 // ToDo:Unnecessary log matching problem warning removed.
799 // Question: does it unnecessary
800 // TTCN_Logger::log_matching_problem(
801 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
802 // TitanLoggerApi::MatchingProblemType_operation::catch__,
803 // false, true, port_name);
807 alt_status
PORT::any_check_catch(const COMPONENT_template
& sender_template
,
808 COMPONENT
*sender_ptr
)
810 if (list_head
!= NULL
) {
811 alt_status ret_val
= ALT_NO
;
812 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
813 switch (port
->check_catch(sender_template
, sender_ptr
)) {
822 TTCN_error("Internal error: Check-catch operation returned "
823 "unexpected status code on port %s while evaluating "
824 "`any port.check(catch)'.", port
->port_name
);
829 TTCN_Logger::log_matching_problem(
830 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
831 TitanLoggerApi::MatchingProblemType_operation::catch__
,
837 alt_status
PORT::check(const COMPONENT_template
& sender_template
,
838 COMPONENT
*sender_ptr
)
840 alt_status ret_val
= ALT_NO
;
841 // the procedure-based queue must have the higher priority
842 switch (check_getcall(sender_template
, sender_ptr
)) {
851 TTCN_error("Internal error: Check-getcall operation returned "
852 "unexpected status code on port %s.", port_name
);
854 if (ret_val
!= ALT_MAYBE
) {
855 // don't try getreply if the procedure-based queue is empty
856 // (i.e. check_getcall() returned ALT_MAYBE)
857 switch (check_getreply(sender_template
, sender_ptr
)) {
866 TTCN_error("Internal error: Check-getreply operation returned "
867 "unexpected status code on port %s.", port_name
);
870 if (ret_val
!= ALT_MAYBE
) {
871 // don't try catch if the procedure-based queue is empty
872 // (i.e. check_getcall() or check_getreply() returned ALT_MAYBE)
873 switch (check_catch(sender_template
, sender_ptr
)) {
882 TTCN_error("Internal error: Check-catch operation returned "
883 "unexpected status code on port %s.", port_name
);
886 switch (check_receive(sender_template
, sender_ptr
)) {
895 TTCN_error("Internal error: Check-receive operation returned "
896 "unexpected status code on port %s.", port_name
);
901 alt_status
PORT::any_check(const COMPONENT_template
& sender_template
,
902 COMPONENT
*sender_ptr
)
904 if (list_head
!= NULL
) {
905 alt_status ret_val
= ALT_NO
;
906 for (PORT
*port
= list_head
; port
!= NULL
; port
= port
->list_next
) {
907 switch (port
->check(sender_template
, sender_ptr
)) {
916 TTCN_error("Internal error: Check operation returned "
917 "unexpected status code on port %s while evaluating "
918 "`any port.check'.", port
->port_name
);
923 TTCN_Logger::log_matching_problem(
924 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports
,
925 TitanLoggerApi::MatchingProblemType_operation::check__
,
931 void PORT::set_parameter(const char *parameter_name
, const char *)
933 TTCN_warning("Test port parameter %s is not supported on port %s.",
934 parameter_name
, port_name
);
937 void PORT::append_to_msg_queue(msg_queue_item_base
* new_item
)
939 new_item
->next_item
= NULL
;
940 if (msg_queue_tail
== NULL
) msg_queue_head
= new_item
;
941 else msg_queue_tail
->next_item
= new_item
;
942 msg_queue_tail
= new_item
;
945 void PORT::Handle_Fd_Event(int fd
, boolean is_readable
, boolean is_writable
,
948 // The port intends to use the finer granularity event handler functions
950 Handle_Fd_Event_Error(fd
);
951 if (!is_writable
&& !is_readable
) return;
952 fd_event_type_enum event
= Fd_And_Timeout_User::getCurReceivedEvent();
953 if ((event
& FD_EVENT_WR
) == 0) is_writable
= FALSE
;
954 if ((event
& FD_EVENT_RD
) == 0) is_readable
= FALSE
;
957 Handle_Fd_Event_Writable(fd
);
958 if (!is_readable
) return;
959 if ((Fd_And_Timeout_User::getCurReceivedEvent() & FD_EVENT_RD
) == 0)
963 Handle_Fd_Event_Readable(fd
);
966 void PORT::Handle_Fd_Event_Error(int)
969 // A port need not wait for error events
970 // Note: error events always cause event handler invocation
973 void PORT::Handle_Fd_Event_Writable(int)
975 TTCN_error("There is no Handle_Fd_Event_Writable member function "
976 "implemented in port %s. "
977 "This method or the Handle_Fd_Event method has to be implemented in "
978 "the port if the port waits for any file descriptor to be writable - "
979 "unless the port uses Install_Handler to specify the file descriptor "
980 "and timeout events for which the port waits.", port_name
);
983 void PORT::Handle_Fd_Event_Readable(int)
985 TTCN_error("There is no Handle_Fd_Event_Readable member function "
986 "implemented in port %s. "
987 "This method or the Handle_Fd_Event method has to be implemented in "
988 "the port if the port waits for any file descriptor to be readable - "
989 "unless the port uses Install_Handler to specify the file descriptor "
990 "and timeout events for which the port waits.", port_name
);
993 void PORT::Handle_Timeout(double /*time_since_last_call*/)
995 TTCN_error("There is no Handle_Timeout member function implemented in "
997 "This method has to be implemented in the port if the port waits for "
998 "timeouts unless the port uses Install_Handler to specify the timeout.",
1002 void PORT::Event_Handler(const fd_set
* /*read_fds*/, const fd_set
* /*write_fds*/,
1003 const fd_set
* /*error_fds*/, double /*time_since_last_call*/)
1005 TTCN_error("There is no Event_Handler implemented in port %s. "
1006 "Event_Handler has to be implemented in the port if "
1007 "Install_Handler is used to specify the file descriptor and timeout "
1008 "events for which the port waits.", port_name
);
1011 void PORT::Handler_Add_Fd(int fd
, Fd_Event_Type event_mask
)
1013 Fd_And_Timeout_User::add_fd(fd
, this,
1014 static_cast<fd_event_type_enum
>(
1015 static_cast<int>(event_mask
)));
1018 void PORT::Handler_Add_Fd_Read(int fd
)
1020 Fd_And_Timeout_User::add_fd(fd
, this, FD_EVENT_RD
);
1023 void PORT::Handler_Add_Fd_Write(int fd
)
1025 Fd_And_Timeout_User::add_fd(fd
, this, FD_EVENT_WR
);
1028 void PORT::Handler_Remove_Fd(int fd
, Fd_Event_Type event_mask
)
1030 Fd_And_Timeout_User::remove_fd(fd
, this,
1031 static_cast<fd_event_type_enum
>(
1032 static_cast<int>(event_mask
)));
1035 void PORT::Handler_Remove_Fd_Read(int fd
)
1037 Fd_And_Timeout_User::remove_fd(fd
, this, FD_EVENT_RD
);
1040 void PORT::Handler_Remove_Fd_Write(int fd
)
1042 Fd_And_Timeout_User::remove_fd(fd
, this, FD_EVENT_WR
);
1045 void PORT::Handler_Set_Timer(double call_interval
, boolean is_timeout
,
1046 boolean call_anyway
, boolean is_periodic
)
1048 Fd_And_Timeout_User::set_timer(this, call_interval
, is_timeout
, call_anyway
,
1052 void PORT::Install_Handler(const fd_set
*read_fds
, const fd_set
*write_fds
,
1053 const fd_set
*error_fds
, double call_interval
)
1055 if (!is_active
) TTCN_error("Event handler cannot be installed for "
1056 "inactive port %s.", port_name
);
1058 if ((long) FdMap::getFdLimit() > (long) FD_SETSIZE
) {
1059 static bool once
= true;
1061 TTCN_warning("The maximum number of open file descriptors (%i)"
1062 " is greater than FD_SETSIZE (%li)."
1063 " Ensure that Test Ports using Install_Handler do not try to"
1064 " wait for events of file descriptors with values greater than"
1065 " FD_SETSIZE (%li)."
1066 " (Current caller of Install_Handler is \"%s\")",
1067 FdMap::getFdLimit(), (long) FD_SETSIZE
, (long) FD_SETSIZE
,
1073 Fd_And_Timeout_User::set_fds_with_fd_sets(this, read_fds
, write_fds
,
1075 Fd_And_Timeout_User::set_timer(this, call_interval
);
1078 void PORT::Uninstall_Handler()
1080 Fd_And_Timeout_User::remove_all_fds(this);
1081 Fd_And_Timeout_User::set_timer(this, 0.0);
1084 void PORT::user_map(const char *)
1089 void PORT::user_unmap(const char *)
1094 void PORT::user_start()
1099 void PORT::user_stop()
1104 void PORT::clear_queue()
1109 component
PORT::get_default_destination()
1111 if (connection_list_head
!= NULL
) {
1112 if (n_system_mappings
> 0) TTCN_error("Port %s has both connection(s) "
1113 "and mapping(s). Message can be sent on it only with explicit "
1114 "addressing.", port_name
);
1115 else if (connection_list_head
->list_next
!= NULL
) TTCN_error("Port %s "
1116 "has more than one active connections. Message can be sent on it "
1117 "only with explicit addressing.", port_name
);
1118 return connection_list_head
->remote_component
;
1120 if (n_system_mappings
> 1) {
1121 TTCN_error("Port %s has more than one mappings. Message cannot "
1122 "be sent on it to system.", port_name
);
1123 } else if (n_system_mappings
< 1) {
1124 TTCN_error("Port %s has neither connections nor mappings. "
1125 "Message cannot be sent on it.", port_name
);
1127 return SYSTEM_COMPREF
;
1131 void PORT::prepare_message(Text_Buf
& outgoing_buf
, const char *message_type
)
1133 outgoing_buf
.push_int(CONN_DATA_MESSAGE
);
1134 outgoing_buf
.push_string(message_type
);
1137 void PORT::prepare_call(Text_Buf
& outgoing_buf
, const char *signature_name
)
1139 outgoing_buf
.push_int(CONN_DATA_CALL
);
1140 outgoing_buf
.push_string(signature_name
);
1143 void PORT::prepare_reply(Text_Buf
& outgoing_buf
, const char *signature_name
)
1145 outgoing_buf
.push_int(CONN_DATA_REPLY
);
1146 outgoing_buf
.push_string(signature_name
);
1149 void PORT::prepare_exception(Text_Buf
& outgoing_buf
, const char *signature_name
)
1151 outgoing_buf
.push_int(CONN_DATA_EXCEPTION
);
1152 outgoing_buf
.push_string(signature_name
);
1155 void PORT::send_data(Text_Buf
&outgoing_buf
,
1156 const COMPONENT
& destination_component
)
1158 if (!destination_component
.is_bound()) TTCN_error("Internal error: "
1159 "The destination component reference is unbound when sending data on "
1160 "port %s.", port_name
);
1161 component destination_compref
= (component
)destination_component
;
1163 port_connection
*conn_ptr
=
1164 lookup_connection_to_compref(destination_compref
, &is_unique
);
1165 if (conn_ptr
== NULL
)
1166 TTCN_error("Data cannot be sent on port %s to component %d "
1167 "because there is no connection towards component %d.", port_name
,
1168 destination_compref
, destination_compref
);
1169 else if (!is_unique
)
1170 TTCN_error("Data cannot be sent on port %s to component %d "
1171 "because there are more than one connections towards component "
1172 "%d.", port_name
, destination_compref
, destination_compref
);
1173 else if (conn_ptr
->connection_state
!= CONN_CONNECTED
)
1174 TTCN_error("Data cannot be sent on port %s to component %d "
1175 "because the connection is not in active state.",
1176 port_name
, destination_compref
);
1177 switch (conn_ptr
->transport_type
) {
1178 case TRANSPORT_LOCAL
:
1179 send_data_local(conn_ptr
, outgoing_buf
);
1181 case TRANSPORT_INET_STREAM
:
1182 case TRANSPORT_UNIX_STREAM
:
1183 send_data_stream(conn_ptr
, outgoing_buf
, FALSE
);
1186 TTCN_error("Internal error: Invalid transport type (%d) in port "
1187 "connection between %s and %d:%s.", conn_ptr
->transport_type
,
1188 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1192 void PORT::process_data(port_connection
*conn_ptr
, Text_Buf
& incoming_buf
)
1194 connection_data_type_enum conn_data_type
=
1195 (connection_data_type_enum
)incoming_buf
.pull_int().get_val();
1196 if (conn_data_type
!= CONN_DATA_LAST
) {
1197 switch (conn_ptr
->connection_state
) {
1198 case CONN_CONNECTED
:
1199 case CONN_LAST_MSG_SENT
:
1201 case CONN_LAST_MSG_RCVD
:
1203 TTCN_warning("Data arrived after the indication of connection "
1204 "termination on port %s from %d:%s. Data is ignored.",
1205 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1208 TTCN_error("Internal error: Connection of port %s with %d:%s has "
1209 "invalid state (%d).", port_name
, conn_ptr
->remote_component
,
1210 conn_ptr
->remote_port
, conn_ptr
->connection_state
);
1212 char *message_type
= incoming_buf
.pull_string();
1214 switch (conn_data_type
) {
1215 case CONN_DATA_MESSAGE
:
1216 if (!process_message(message_type
, incoming_buf
,
1217 conn_ptr
->remote_component
, conn_ptr
->sliding_buffer
)) {
1218 TTCN_error("Port %s does not support incoming message "
1219 "type %s, which has arrived on the connection from "
1220 "%d:%s.", port_name
, message_type
,
1221 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1224 case CONN_DATA_CALL
:
1225 if (!process_call(message_type
, incoming_buf
,
1226 conn_ptr
->remote_component
)) {
1227 TTCN_error("Port %s does not support incoming call of "
1228 "signature %s, which has arrived on the connection "
1229 "from %d:%s.", port_name
, message_type
,
1230 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1233 case CONN_DATA_REPLY
:
1234 if (!process_reply(message_type
, incoming_buf
,
1235 conn_ptr
->remote_component
)) {
1236 TTCN_error("Port %s does not support incoming reply of "
1237 "signature %s, which has arrived on the connection "
1238 "from %d:%s.", port_name
, message_type
,
1239 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1242 case CONN_DATA_EXCEPTION
:
1243 if (!process_exception(message_type
, incoming_buf
,
1244 conn_ptr
->remote_component
)) {
1245 TTCN_error("Port %s does not support incoming exception "
1246 "of signature %s, which has arrived on the connection "
1247 "from %d:%s.", port_name
, message_type
,
1248 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1252 TTCN_error("Internal error: Data with invalid selector (%d) "
1253 "was received on port %s from %d:%s.", conn_data_type
,
1254 port_name
, conn_ptr
->remote_component
,
1255 conn_ptr
->remote_port
);
1258 // avoid memory leak
1259 delete [] message_type
;
1262 delete [] message_type
;
1263 } else process_last_message(conn_ptr
);
1266 boolean
PORT::process_message(const char *, Text_Buf
&, component
, OCTETSTRING
&)
1271 boolean
PORT::process_call(const char *, Text_Buf
&, component
)
1276 boolean
PORT::process_reply(const char *, Text_Buf
&, component
)
1281 boolean
PORT::process_exception(const char *, Text_Buf
&, component
)
1286 port_connection
*PORT::add_connection(component remote_component
,
1287 const char *remote_port
, transport_type_enum transport_type
)
1289 port_connection
*conn_ptr
;
1290 for (conn_ptr
= connection_list_head
; conn_ptr
!= NULL
;
1291 conn_ptr
= conn_ptr
->list_next
) {
1292 if (conn_ptr
->remote_component
== remote_component
) {
1293 int ret_val
= strcmp(conn_ptr
->remote_port
, remote_port
);
1294 if (ret_val
== 0) return conn_ptr
;
1295 else if (ret_val
> 0) break;
1296 } else if (conn_ptr
->remote_component
> remote_component
) break;
1299 port_connection
*new_conn
= new port_connection
;
1300 new_conn
->owner_port
= this;
1302 new_conn
->connection_state
= CONN_IDLE
;
1303 new_conn
->remote_component
= remote_component
;
1304 new_conn
->remote_port
= mcopystr(remote_port
);
1305 new_conn
->transport_type
= transport_type
;
1306 new_conn
->sliding_buffer
= OCTETSTRING(0, 0);
1307 switch (transport_type
) {
1308 case TRANSPORT_LOCAL
:
1309 new_conn
->local
.port_ptr
= NULL
;
1311 case TRANSPORT_INET_STREAM
:
1312 case TRANSPORT_UNIX_STREAM
:
1313 new_conn
->stream
.comm_fd
= -1;
1314 new_conn
->stream
.incoming_buf
= NULL
;
1318 TTCN_error("Internal error: PORT::add_connection(): invalid transport "
1319 "type (%d).", transport_type
);
1322 new_conn
->list_next
= conn_ptr
;
1323 if (conn_ptr
!= NULL
) {
1324 // new_conn will be inserted before conn_ptr in the ordered list
1325 new_conn
->list_prev
= conn_ptr
->list_prev
;
1326 conn_ptr
->list_prev
= new_conn
;
1327 if (new_conn
->list_prev
!= NULL
)
1328 new_conn
->list_prev
->list_next
= new_conn
;
1330 // new_conn will be inserted to the end of the list
1331 new_conn
->list_prev
= connection_list_tail
;
1332 if (connection_list_tail
!= NULL
)
1333 connection_list_tail
->list_next
= new_conn
;
1334 connection_list_tail
= new_conn
;
1336 if (conn_ptr
== connection_list_head
) connection_list_head
= new_conn
;
1341 void PORT::remove_connection(port_connection
*conn_ptr
)
1343 Free(conn_ptr
->remote_port
);
1345 switch (conn_ptr
->transport_type
) {
1346 case TRANSPORT_LOCAL
:
1348 case TRANSPORT_INET_STREAM
:
1349 case TRANSPORT_UNIX_STREAM
:
1350 if (conn_ptr
->stream
.comm_fd
>= 0) {
1351 Fd_And_Timeout_User::remove_fd(conn_ptr
->stream
.comm_fd
, conn_ptr
,
1353 if (conn_ptr
->connection_state
== CONN_LISTENING
&&
1354 conn_ptr
->transport_type
== TRANSPORT_UNIX_STREAM
)
1355 unlink_unix_pathname(conn_ptr
->stream
.comm_fd
);
1356 close(conn_ptr
->stream
.comm_fd
);
1357 conn_ptr
->stream
.comm_fd
= -1;
1359 delete conn_ptr
->stream
.incoming_buf
;
1362 TTCN_error("Internal error: PORT::remove_connection(): invalid "
1366 if (conn_ptr
->list_prev
!= NULL
)
1367 conn_ptr
->list_prev
->list_next
= conn_ptr
->list_next
;
1368 else if (connection_list_head
== conn_ptr
)
1369 connection_list_head
= conn_ptr
->list_next
;
1370 if (conn_ptr
->list_next
!= NULL
)
1371 conn_ptr
->list_next
->list_prev
= conn_ptr
->list_prev
;
1372 else if (connection_list_tail
== conn_ptr
)
1373 connection_list_tail
= conn_ptr
->list_prev
;
1378 port_connection
*PORT::lookup_connection_to_compref(
1379 component remote_component
, boolean
*is_unique
)
1381 for (port_connection
*conn
= connection_list_head
; conn
!= NULL
;
1382 conn
= conn
->list_next
) {
1383 if (conn
->remote_component
== remote_component
) {
1384 if (is_unique
!= NULL
) {
1385 port_connection
*nxt
= conn
->list_next
;
1386 if (nxt
!= NULL
&& nxt
->remote_component
== remote_component
)
1388 else *is_unique
= TRUE
;
1391 } else if (conn
->remote_component
> remote_component
) break;
1396 port_connection
*PORT::lookup_connection(component remote_component
,
1397 const char *remote_port
)
1399 for (port_connection
*conn
= connection_list_head
; conn
!= NULL
;
1400 conn
= conn
->list_next
) {
1401 if (conn
->remote_component
== remote_component
) {
1402 int ret_val
= strcmp(conn
->remote_port
, remote_port
);
1403 if (ret_val
== 0) return conn
;
1404 else if (ret_val
> 0) break;
1405 } else if (conn
->remote_component
> remote_component
) break;
1410 void PORT::add_local_connection(PORT
*other_endpoint
)
1412 port_connection
*conn_ptr
= add_connection(self
, other_endpoint
->port_name
,
1414 conn_ptr
->connection_state
= CONN_CONNECTED
;
1415 conn_ptr
->local
.port_ptr
= other_endpoint
;
1416 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__established
,
1417 port_name
, NULL_COMPREF
, other_endpoint
->port_name
);
1420 void PORT::remove_local_connection(port_connection
*conn_ptr
)
1422 if (conn_ptr
->transport_type
!= TRANSPORT_LOCAL
)
1423 TTCN_error("Internal error: The transport type used by the connection "
1424 "between port %s and %d:%s is not LOCAL.", port_name
,
1425 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1426 PORT
*other_endpoint
= conn_ptr
->local
.port_ptr
;
1427 remove_connection(conn_ptr
);
1428 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__terminated
,
1429 port_name
, NULL_COMPREF
, other_endpoint
->port_name
);
1432 unsigned int PORT::get_connection_hash(component local_component
,
1433 const char *local_port
, component remote_component
, const char *remote_port
)
1435 const size_t N
= sizeof(unsigned int);
1436 unsigned char hash_buffer
[N
];
1438 // fill the buffer with an initial pattern
1439 for (size_t i
= 0; i
< N
; i
++) hash_buffer
[i
] = i
% 2 ? 0x55 : 0xAA;
1441 // add the PID of the current process to the buffer
1442 pid_t pid
= getpid();
1443 for (size_t i
= 0; i
< sizeof(pid
); i
++)
1444 hash_buffer
[i
% N
] ^= (pid
>> (8 * i
)) & 0xFF;
1446 // add the local and remote component reference and port name to the buffer
1447 for (size_t i
= 0; i
< sizeof(local_component
); i
++)
1448 hash_buffer
[(N
- 1) - i
% N
] ^= (local_component
>> (8 * i
)) & 0xFF;
1449 for (size_t i
= 0; local_port
[i
] != '\0'; i
++)
1450 hash_buffer
[(N
- 1) - i
% N
] ^= local_port
[i
];
1451 for (size_t i
= 0; i
< sizeof(remote_component
); i
++)
1452 hash_buffer
[i
% N
] ^= (remote_component
>> (8 * i
)) & 0xFF;
1453 for (size_t i
= 0; remote_port
[i
] != '\0'; i
++)
1454 hash_buffer
[i
% N
] ^= remote_port
[i
];
1456 // convert the buffer to an integer value
1457 unsigned int ret_val
= 0;
1458 for (size_t i
= 0; i
< N
; i
++)
1459 ret_val
= (ret_val
<< 8) | hash_buffer
[i
];
1463 void PORT::unlink_unix_pathname(int socket_fd
)
1465 struct sockaddr_un local_addr
;
1466 // querying the local pathname used by socket_fd
1467 socklen_type addr_len
= sizeof(local_addr
);
1468 if (getsockname(socket_fd
, (struct sockaddr
*)&local_addr
, &addr_len
)) {
1469 TTCN_warning_begin("System call getsockname() failed on UNIX socket "
1470 "file descriptor %d.", socket_fd
);
1471 TTCN_Logger::OS_error();
1472 TTCN_Logger::log_event_str(" The associated socket file will not be "
1473 "removed from the file system.");
1475 } else if (local_addr
.sun_family
!= AF_UNIX
) {
1476 TTCN_warning("System call getsockname() returned invalid address "
1477 "family for UNIX socket file descriptor %d. The associated socket "
1478 "file will not be removed from the file system.", socket_fd
);
1479 } else if (unlink(local_addr
.sun_path
)) {
1480 if (errno
!= ENOENT
) {
1481 TTCN_warning_begin("System call unlink() failed when trying to "
1482 "remove UNIX socket file %s.", local_addr
.sun_path
);
1483 TTCN_Logger::OS_error();
1484 TTCN_Logger::log_event_str(" The file will remain in the file "
1491 void PORT::connect_listen_inet_stream(component remote_component
,
1492 const char *remote_port
)
1494 // creating the TCP server socket
1495 int server_fd
= NetworkHandler::socket(TTCN_Communication::get_network_family());
1496 if (server_fd
< 0) {
1497 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1498 remote_port
, "Creation of the TCP server socket failed. (%s)",
1504 // binding the socket to an ephemeral TCP port
1505 // using the same local IP address as the control connection to MC
1506 IPAddress
*local_addr
= IPAddress::create_addr(TTCN_Communication::get_network_family());
1507 *local_addr
= *TTCN_Communication::get_local_address();
1508 local_addr
->set_port(0);
1509 if (bind(server_fd
, local_addr
->get_addr(), local_addr
->get_addr_len())) {
1511 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1512 remote_port
, "Binding of server socket to an ephemeral TCP port "
1513 "failed. (%s)", strerror(errno
));
1519 // zero backlog is enough since we are waiting for only one client
1520 if (listen(server_fd
, 0)) {
1522 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1523 remote_port
, "Listening on an ephemeral TCP port failed. (%s)",
1530 // querying the IP address and port number used by the TCP server
1531 if (local_addr
->getsockname(server_fd
)) {
1533 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1534 remote_port
, "System call getsockname() failed on the TCP server "
1535 "socket. (%s)", strerror(errno
));
1541 if (!TTCN_Communication::set_close_on_exec(server_fd
)) {
1543 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1544 remote_port
, "Setting the close-on-exec flag failed on the TCP "
1550 port_connection
*new_connection
= add_connection(remote_component
,
1551 remote_port
, TRANSPORT_INET_STREAM
);
1552 new_connection
->connection_state
= CONN_LISTENING
;
1553 new_connection
->stream
.comm_fd
= server_fd
;
1554 Fd_And_Timeout_User::add_fd(server_fd
, new_connection
, FD_EVENT_RD
);
1556 TTCN_Communication::send_connect_listen_ack_inet_stream(port_name
,
1557 remote_component
, remote_port
, local_addr
);
1559 TTCN_Logger::log_port_misc(
1560 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__tcp
,
1561 port_name
, remote_component
, remote_port
);
1565 void PORT::connect_listen_unix_stream(component remote_component
,
1566 const char *remote_port
)
1568 // creating the UNIX server socket
1569 int server_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1570 if (server_fd
< 0) {
1571 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1572 remote_port
, "Creation of the UNIX server socket failed. (%s)",
1578 // binding the socket to a temporary file
1579 struct sockaddr_un local_addr
;
1580 // the file name is constructed using a hash function
1581 unsigned int hash_value
=
1582 get_connection_hash(self
, port_name
, remote_component
, remote_port
);
1583 for (unsigned int i
= 1; ; i
++) {
1584 memset(&local_addr
, 0, sizeof(local_addr
));
1585 local_addr
.sun_family
= AF_UNIX
;
1586 snprintf(local_addr
.sun_path
, sizeof(local_addr
.sun_path
),
1587 "/tmp/ttcn3-portconn-%x", hash_value
);
1588 if (bind(server_fd
, (struct sockaddr
*)&local_addr
, sizeof(local_addr
))
1590 // the operation was successful, jump out of the loop
1592 } else if (errno
== EADDRINUSE
) {
1593 // the temporary file name is already used by someone else
1595 if (i
< UNIX_BIND_MAX_ITER
) {
1596 // try another hash value
1600 TTCN_Communication::send_connect_error(port_name
,
1601 remote_component
, remote_port
, "Could not find a free "
1602 "pathname to bind the UNIX server socket to after %u "
1609 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1610 remote_port
, "Binding of UNIX server socket to pathname %s "
1611 "failed. (%s)", local_addr
.sun_path
, strerror(errno
));
1617 // zero backlog is enough since we are waiting for only one client
1618 if (listen(server_fd
, 0)) {
1620 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1621 remote_port
, "Listening on UNIX pathname %s failed. (%s)",
1622 local_addr
.sun_path
, strerror(errno
));
1627 if (!TTCN_Communication::set_close_on_exec(server_fd
)) {
1629 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1630 remote_port
, "Setting the close-on-exec flag failed on the UNIX "
1635 port_connection
*new_connection
= add_connection(remote_component
,
1636 remote_port
, TRANSPORT_UNIX_STREAM
);
1637 new_connection
->connection_state
= CONN_LISTENING
;
1638 new_connection
->stream
.comm_fd
= server_fd
;
1639 Fd_And_Timeout_User::add_fd(server_fd
, new_connection
, FD_EVENT_RD
);
1641 TTCN_Communication::send_connect_listen_ack_unix_stream(port_name
,
1642 remote_component
, remote_port
, &local_addr
);
1644 TTCN_Logger::log_port_misc(
1645 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__unix
,
1646 port_name
, remote_component
, remote_port
, local_addr
.sun_path
);
1649 void PORT::connect_local(component remote_component
, const char *remote_port
)
1651 if (self
!= remote_component
) {
1652 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1653 remote_port
, "Message CONNECT with transport type LOCAL refers "
1654 "to a port of another component (%d).", remote_component
);
1657 PORT
*remote_ptr
= lookup_by_name(remote_port
);
1658 if (remote_ptr
== NULL
) {
1659 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1660 remote_port
, "Port %s does not exist.", remote_port
);
1662 } else if (!remote_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
1663 "inactive when trying to connect it to local port %s.", remote_port
,
1665 add_local_connection(remote_ptr
);
1666 if (this != remote_ptr
) remote_ptr
->add_local_connection(this);
1667 TTCN_Communication::send_connected(port_name
, remote_component
,
1671 void PORT::connect_stream(component remote_component
, const char *remote_port
,
1672 transport_type_enum transport_type
, Text_Buf
& text_buf
)
1677 const char *transport_str
;
1679 switch (transport_type
) {
1680 case TRANSPORT_INET_STREAM
:
1681 transport_str
= "TCP";
1682 // creating the TCP client socket
1683 client_fd
= NetworkHandler::socket(TTCN_Communication::get_network_family());
1685 case TRANSPORT_UNIX_STREAM
:
1686 transport_str
= "UNIX";
1687 // creating the UNIX client socket
1688 client_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0);
1691 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1692 "type (%d).", transport_type
);
1694 if (client_fd
< 0) {
1695 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1696 remote_port
, "Creation of the %s client socket failed. (%s)",
1697 transport_str
, strerror(errno
));
1702 switch (transport_type
) {
1703 case TRANSPORT_INET_STREAM
: {
1704 // connect to the IP address and port number given in message CONNECT
1705 IPAddress
*remote_addr
= IPAddress::create_addr(TTCN_Communication::get_network_family());
1706 remote_addr
->pull_raw(text_buf
);
1708 if (connect(client_fd
, (struct sockaddr
*)remote_addr
->get_addr(), remote_addr
->get_addr_len())) {
1710 if (connect(client_fd
, remote_addr
->get_addr(), remote_addr
->get_addr_len())) {
1713 if (errno
== EADDRINUSE
) {
1716 TTCN_warning("connect() returned error code EADDRINUSE. "
1717 "Perhaps this is a Cygwin bug. Trying to connect again.");
1722 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1723 remote_port
, "TCP connection establishment failed to %s:%d. (%s)",
1724 remote_addr
->get_addr_str(), remote_addr
->get_port(), strerror(errno
));
1731 case TRANSPORT_UNIX_STREAM
: {
1732 // connect to the UNIX pathname given in the message CONNECT
1733 struct sockaddr_un remote_addr
;
1734 memset(&remote_addr
, 0, sizeof(remote_addr
));
1735 remote_addr
.sun_family
= AF_UNIX
;
1736 size_t pathname_len
= text_buf
.pull_int().get_val();
1737 if (pathname_len
>= sizeof(remote_addr
.sun_path
)) {
1739 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1740 remote_port
, "The UNIX pathname used by the server socket is "
1741 "too long. It consists of %lu bytes although it should be "
1742 "shorter than %lu bytes to fit in the appropriate structure.",
1743 (unsigned long) pathname_len
,
1744 (unsigned long) sizeof(remote_addr
.sun_path
));
1747 text_buf
.pull_raw(pathname_len
, remote_addr
.sun_path
);
1748 if (connect(client_fd
, (struct sockaddr
*)&remote_addr
, sizeof(remote_addr
))) {
1750 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1751 remote_port
, "UNIX socket connection establishment failed to "
1752 "pathname %s. (%s)", remote_addr
.sun_path
, strerror(errno
));
1758 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1759 "type (%d).", transport_type
);
1762 if (!TTCN_Communication::set_close_on_exec(client_fd
)) {
1764 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1765 remote_port
, "Setting the close-on-exec flag failed on the %s "
1766 "client socket.", transport_str
);
1770 if (!TTCN_Communication::set_non_blocking_mode(client_fd
, TRUE
)) {
1772 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1773 remote_port
, "Setting the non-blocking mode failed on the %s "
1774 "client socket.", transport_str
);
1778 if (transport_type
== TRANSPORT_INET_STREAM
&&
1779 !TTCN_Communication::set_tcp_nodelay(client_fd
)) {
1781 TTCN_Communication::send_connect_error(port_name
, remote_component
,
1782 remote_port
, "Setting the TCP_NODELAY flag failed on the TCP "
1787 port_connection
*new_connection
= add_connection(remote_component
,
1788 remote_port
, transport_type
);
1789 new_connection
->connection_state
= CONN_CONNECTED
;
1790 new_connection
->stream
.comm_fd
= client_fd
;
1791 Fd_And_Timeout_User::add_fd(client_fd
, new_connection
, FD_EVENT_RD
);
1793 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__established
,
1794 port_name
, remote_component
, remote_port
, transport_str
);
1797 void PORT::disconnect_local(port_connection
*conn_ptr
)
1799 PORT
*remote_ptr
= conn_ptr
->local
.port_ptr
;
1800 remove_local_connection(conn_ptr
);
1801 if (this != remote_ptr
) {
1802 port_connection
*conn2_ptr
=
1803 remote_ptr
->lookup_connection(self
, port_name
);
1804 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
1805 "connected with local port %s, but port %s does not have a "
1806 "connection to %s.", port_name
, remote_ptr
->port_name
,
1807 remote_ptr
->port_name
, port_name
);
1808 else remote_ptr
->remove_local_connection(conn2_ptr
);
1810 TTCN_Communication::send_disconnected(port_name
, self
,
1811 remote_ptr
->port_name
);
1814 void PORT::disconnect_stream(port_connection
*conn_ptr
)
1816 switch (conn_ptr
->connection_state
) {
1817 case CONN_LISTENING
:
1818 TTCN_Logger::log_port_misc(
1819 TitanLoggerApi::Port__Misc_reason::destroying__unestablished__connection
,
1820 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1821 remove_connection(conn_ptr
);
1822 // do not send back any acknowledgment
1824 case CONN_CONNECTED
: {
1825 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::terminating__connection
,
1826 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1827 Text_Buf outgoing_buf
;
1828 outgoing_buf
.push_int(CONN_DATA_LAST
);
1829 if (send_data_stream(conn_ptr
, outgoing_buf
, TRUE
)) {
1830 // sending the last message was successful
1831 // wait for the acknowledgment from the peer
1832 conn_ptr
->connection_state
= CONN_LAST_MSG_SENT
;
1834 TTCN_Logger::log_port_misc(
1835 TitanLoggerApi::Port__Misc_reason::sending__termination__request__failed
,
1836 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1837 // send an acknowledgment to MC immediately to avoid deadlock
1838 // in case of communication failure
1839 // (i.e. when the peer does not send DISCONNECTED)
1840 TTCN_Communication::send_disconnected(port_name
,
1841 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1842 TTCN_warning("The last outgoing messages on port %s may be lost.",
1844 // destroy the connection immediately
1845 remove_connection(conn_ptr
);
1849 TTCN_error("The connection of port %s to %d:%s is in unexpected "
1850 "state when trying to terminate it.", port_name
,
1851 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1855 void PORT::send_data_local(port_connection
*conn_ptr
, Text_Buf
& outgoing_data
)
1857 outgoing_data
.rewind();
1858 PORT
*dest_ptr
= conn_ptr
->local
.port_ptr
;
1859 if (this != dest_ptr
) {
1860 port_connection
*conn2_ptr
=
1861 dest_ptr
->lookup_connection(self
, port_name
);
1862 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
1863 "connected with local port %s, but port %s does not have a "
1864 "connection to %s.", port_name
, dest_ptr
->port_name
,
1865 dest_ptr
->port_name
, port_name
);
1866 dest_ptr
->process_data(conn2_ptr
, outgoing_data
);
1867 } else process_data(conn_ptr
, outgoing_data
);
1870 boolean
PORT::send_data_stream(port_connection
*conn_ptr
,
1871 Text_Buf
& outgoing_data
, boolean ignore_peer_disconnect
)
1873 bool would_block_warning
=false;
1874 outgoing_data
.calculate_length();
1875 const char *msg_ptr
= outgoing_data
.get_data();
1876 size_t msg_len
= outgoing_data
.get_len(), sent_len
= 0;
1877 while (sent_len
< msg_len
) {
1878 int ret_val
= send(conn_ptr
->stream
.comm_fd
, msg_ptr
+ sent_len
,
1879 msg_len
- sent_len
, 0);
1880 if (ret_val
> 0) sent_len
+= ret_val
;
1884 // a signal occurred: do nothing, just try again
1888 // the output buffer is full: try to increase it if possible
1890 int old_bufsize
, new_bufsize
;
1891 if (TTCN_Communication::increase_send_buffer(
1892 conn_ptr
->stream
.comm_fd
, old_bufsize
, new_bufsize
)) {
1893 TTCN_Logger::log_port_misc(
1894 TitanLoggerApi::Port__Misc_reason::sending__would__block
,
1895 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1896 NULL
, old_bufsize
, new_bufsize
);
1898 if(!would_block_warning
){
1899 TTCN_warning_begin("Sending data on the connection of "
1900 "port %s to ", port_name
);
1901 COMPONENT::log_component_reference(
1902 conn_ptr
->remote_component
);
1903 TTCN_Logger::log_event(":%s would block execution and it "
1904 "is not possible to further increase the size of the "
1905 "outgoing buffer. Trying to process incoming data to "
1906 "avoid deadlock.", conn_ptr
->remote_port
);
1908 would_block_warning
=true;
1910 TTCN_Snapshot::block_for_sending(conn_ptr
->stream
.comm_fd
);
1915 if (ignore_peer_disconnect
) return FALSE
;
1918 TTCN_error("Sending data on the connection of port %s to "
1919 "%d:%s failed.", port_name
, conn_ptr
->remote_component
,
1920 conn_ptr
->remote_port
);
1924 if(would_block_warning
){
1925 TTCN_warning_begin("The message finally was sent on "
1926 "port %s to ", port_name
);
1927 COMPONENT::log_component_reference(
1928 conn_ptr
->remote_component
);
1929 TTCN_Logger::log_event(":%s.", conn_ptr
->remote_port
);
1935 void PORT::handle_incoming_connection(port_connection
*conn_ptr
)
1937 const char *transport_str
=
1938 conn_ptr
->transport_type
== TRANSPORT_INET_STREAM
? "TCP" : "UNIX";
1939 int comm_fd
= accept(conn_ptr
->stream
.comm_fd
, NULL
, NULL
);
1941 TTCN_Communication::send_connect_error(port_name
,
1942 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1943 "Accepting of incoming %s connection failed. (%s)", transport_str
,
1946 remove_connection(conn_ptr
);
1950 if (!TTCN_Communication::set_close_on_exec(comm_fd
)) {
1952 TTCN_Communication::send_connect_error(port_name
,
1953 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1954 "Setting the close-on-exec flag failed on the server-side %s "
1955 "socket.", transport_str
);
1956 remove_connection(conn_ptr
);
1960 if (!TTCN_Communication::set_non_blocking_mode(comm_fd
, TRUE
)) {
1962 TTCN_Communication::send_connect_error(port_name
,
1963 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1964 "Setting the non-blocking mode failed on the server-side %s "
1965 "socket.", transport_str
);
1966 remove_connection(conn_ptr
);
1970 if (conn_ptr
->transport_type
== TRANSPORT_INET_STREAM
&&
1971 !TTCN_Communication::set_tcp_nodelay(comm_fd
)) {
1973 TTCN_Communication::send_connect_error(port_name
,
1974 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
1975 "Setting the TCP_NODELAY flag failed on the server-side TCP "
1977 remove_connection(conn_ptr
);
1981 // shutting down the server socket and replacing it with the
1982 // communication socket of the new connection
1983 Fd_And_Timeout_User::remove_fd(conn_ptr
->stream
.comm_fd
, conn_ptr
,
1985 if (conn_ptr
->transport_type
== TRANSPORT_UNIX_STREAM
)
1986 unlink_unix_pathname(conn_ptr
->stream
.comm_fd
);
1987 close(conn_ptr
->stream
.comm_fd
);
1988 conn_ptr
->connection_state
= CONN_CONNECTED
;
1989 conn_ptr
->stream
.comm_fd
= comm_fd
;
1990 Fd_And_Timeout_User::add_fd(comm_fd
, conn_ptr
, FD_EVENT_RD
);
1992 TTCN_Communication::send_connected(port_name
, conn_ptr
->remote_component
,
1993 conn_ptr
->remote_port
);
1995 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__accepted
,
1996 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
1999 void PORT::handle_incoming_data(port_connection
*conn_ptr
)
2001 if (conn_ptr
->stream
.incoming_buf
== NULL
)
2002 conn_ptr
->stream
.incoming_buf
= new Text_Buf
;
2003 Text_Buf
& incoming_buf
= *conn_ptr
->stream
.incoming_buf
;
2006 incoming_buf
.get_end(buf_ptr
, buf_len
);
2007 int recv_len
= recv(conn_ptr
->stream
.comm_fd
, buf_ptr
, buf_len
, 0);
2009 // an error occurred
2010 if (errno
== ECONNRESET
) {
2011 // TCP connection was reset by peer
2013 TTCN_Communication::send_disconnected(port_name
,
2014 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2015 TTCN_Logger::log_port_misc(
2016 TitanLoggerApi::Port__Misc_reason::connection__reset__by__peer
,
2017 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2018 TTCN_warning("The last outgoing messages on port %s may be lost.",
2020 conn_ptr
->connection_state
= CONN_IDLE
;
2022 TTCN_error("Receiving data on the connection of port %s from "
2023 "%d:%s failed.", port_name
, conn_ptr
->remote_component
,
2024 conn_ptr
->remote_port
);
2026 } else if (recv_len
> 0) {
2027 // data was received
2028 incoming_buf
.increase_length(recv_len
);
2029 // processing all messages in the buffer after each other
2030 while (incoming_buf
.is_message()) {
2031 incoming_buf
.pull_int(); // message_length
2032 process_data(conn_ptr
, incoming_buf
);
2033 incoming_buf
.cut_message();
2036 // the connection was closed by the peer
2037 TTCN_Communication::send_disconnected(port_name
,
2038 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2039 if (conn_ptr
->connection_state
!= CONN_LAST_MSG_RCVD
) {
2040 TTCN_Logger::log_port_misc(
2041 TitanLoggerApi::Port__Misc_reason::connection__closed__by__peer
,
2042 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2044 // the connection can be removed
2045 conn_ptr
->connection_state
= CONN_IDLE
;
2047 if (conn_ptr
->connection_state
== CONN_IDLE
) {
2048 // terminating and removing connection
2049 int msg_len
= incoming_buf
.get_len();
2051 TTCN_warning_begin("Message fragment remained in the buffer of "
2052 "port connection between %s and ", port_name
);
2053 COMPONENT::log_component_reference(conn_ptr
->remote_component
);
2054 TTCN_Logger::log_event(":%s: ", conn_ptr
->remote_port
);
2055 const unsigned char *msg_ptr
=
2056 (const unsigned char*)incoming_buf
.get_data();
2057 for (int i
= 0; i
< msg_len
; i
++)
2058 TTCN_Logger::log_octet(msg_ptr
[i
]);
2062 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::port__disconnected
,
2063 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2064 remove_connection(conn_ptr
);
2068 void PORT::process_last_message(port_connection
*conn_ptr
)
2070 switch (conn_ptr
->transport_type
) {
2071 case TRANSPORT_INET_STREAM
:
2072 case TRANSPORT_UNIX_STREAM
:
2075 TTCN_error("Internal error: Connection termination request was "
2076 "received on the connection of port %s with %d:%s, which has an "
2077 "invalid transport type (%d).", port_name
,
2078 conn_ptr
->remote_component
, conn_ptr
->remote_port
,
2079 conn_ptr
->transport_type
);
2081 switch (conn_ptr
->connection_state
) {
2082 case CONN_CONNECTED
: {
2083 TTCN_Logger::log_port_misc(
2084 TitanLoggerApi::Port__Misc_reason::termination__request__received
,
2085 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2086 Text_Buf outgoing_buf
;
2087 outgoing_buf
.push_int(CONN_DATA_LAST
);
2088 if (send_data_stream(conn_ptr
, outgoing_buf
, TRUE
)) {
2089 // sending the last message was successful
2090 // wait until the peer closes the transport connection
2091 conn_ptr
->connection_state
= CONN_LAST_MSG_RCVD
;
2093 TTCN_Logger::log_port_misc(
2094 TitanLoggerApi::Port__Misc_reason::acknowledging__termination__request__failed
,
2095 port_name
, conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2096 // send an acknowledgment to MC immediately to avoid deadlock
2097 // in case of communication failure
2098 // (i.e. when the peer does not send DISCONNECTED)
2099 TTCN_Communication::send_disconnected(port_name
,
2100 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2101 // the connection can be removed immediately
2102 TTCN_warning("The last outgoing messages on port %s may be lost.",
2104 conn_ptr
->connection_state
= CONN_IDLE
;
2107 case CONN_LAST_MSG_SENT
:
2108 // the connection can be removed
2109 conn_ptr
->connection_state
= CONN_IDLE
;
2111 case CONN_LAST_MSG_RCVD
:
2113 TTCN_warning("Unexpected data arrived after the indication of "
2114 "connection termination on port %s from %d:%s.", port_name
,
2115 conn_ptr
->remote_component
, conn_ptr
->remote_port
);
2118 TTCN_error("Internal error: Connection of port %s with %d:%s has "
2119 "invalid state (%d).", port_name
, conn_ptr
->remote_component
,
2120 conn_ptr
->remote_port
, conn_ptr
->connection_state
);
2124 void PORT::map(const char *system_port
)
2126 if (!is_active
) TTCN_error("Inactive port %s cannot be mapped.", port_name
);
2129 for (new_posn
= 0; new_posn
< n_system_mappings
; new_posn
++) {
2130 int str_diff
= strcmp(system_port
, system_mappings
[new_posn
]);
2131 if (str_diff
< 0) break;
2132 else if (str_diff
== 0) {
2133 TTCN_warning("Port %s is already mapped to system:%s."
2134 " Map operation was ignored.", port_name
, system_port
);
2139 set_system_parameters(system_port
);
2141 user_map(system_port
);
2143 TTCN_Logger::log_port_misc(
2144 TitanLoggerApi::Port__Misc_reason::port__was__mapped__to__system
,
2145 port_name
, SYSTEM_COMPREF
, system_port
);
2147 // the mapping shall be registered in the table only if user_map() was
2149 system_mappings
= (char**)Realloc(system_mappings
,
2150 (n_system_mappings
+ 1) * sizeof(*system_mappings
));
2151 memmove(system_mappings
+ new_posn
+ 1, system_mappings
+ new_posn
,
2152 (n_system_mappings
- new_posn
) * sizeof(*system_mappings
));
2153 system_mappings
[new_posn
] = mcopystr(system_port
);
2154 n_system_mappings
++;
2156 if (n_system_mappings
> 1) TTCN_warning("Port %s has now more than one "
2157 "mappings. Message cannot be sent on it to system even with explicit "
2158 "addressing.", port_name
);
2161 void PORT::unmap(const char *system_port
)
2164 for (del_posn
= 0; del_posn
< n_system_mappings
; del_posn
++) {
2165 int str_diff
= strcmp(system_port
, system_mappings
[del_posn
]);
2166 if (str_diff
== 0) break;
2167 else if (str_diff
< 0) {
2168 del_posn
= n_system_mappings
;
2172 if (del_posn
>= n_system_mappings
) {
2173 TTCN_warning("Port %s is not mapped to system:%s. "
2174 "Unmap operation was ignored.", port_name
, system_port
);
2178 char *unmapped_port
= system_mappings
[del_posn
];
2180 // first remove the mapping from the table
2181 n_system_mappings
--;
2182 memmove(system_mappings
+ del_posn
, system_mappings
+ del_posn
+ 1,
2183 (n_system_mappings
- del_posn
) * sizeof(*system_mappings
));
2184 system_mappings
= (char**)Realloc(system_mappings
,
2185 n_system_mappings
* sizeof(*system_mappings
));
2188 user_unmap(system_port
);
2190 // prevent from memory leak
2191 Free(unmapped_port
);
2195 TTCN_Logger::log_port_misc(
2196 TitanLoggerApi::Port__Misc_reason::port__was__unmapped__from__system
,
2197 port_name
, SYSTEM_COMPREF
, system_port
);
2199 Free(unmapped_port
);
2202 void PORT::process_connect_listen(const char *local_port
,
2203 component remote_component
, const char *remote_port
,
2204 transport_type_enum transport_type
)
2206 PORT
*port_ptr
= lookup_by_name(local_port
);
2207 if (port_ptr
== NULL
) {
2208 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2209 remote_port
, "Port %s does not exist.", local_port
);
2211 } else if (!port_ptr
->is_active
) {
2212 TTCN_error("Internal error: Port %s is inactive when trying to "
2213 "connect it to %d:%s.", local_port
, remote_component
, remote_port
);
2214 } else if (port_ptr
->lookup_connection(remote_component
, remote_port
)
2216 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2217 remote_port
, "Port %s already has a connection towards %d:%s.",
2218 local_port
, remote_component
, remote_port
);
2220 } else if (port_ptr
->lookup_connection_to_compref(remote_component
, NULL
)
2222 TTCN_warning_begin("Port %s will have more than one connections with "
2223 "ports of test component ", local_port
);
2224 COMPONENT::log_component_reference(remote_component
);
2225 TTCN_Logger::log_event_str(". These connections cannot be used for "
2226 "sending even with explicit addressing.");
2230 switch (transport_type
) {
2231 case TRANSPORT_LOCAL
:
2232 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2233 remote_port
, "Message CONNECT_LISTEN cannot refer to transport "
2236 case TRANSPORT_INET_STREAM
:
2237 port_ptr
->connect_listen_inet_stream(remote_component
, remote_port
);
2239 case TRANSPORT_UNIX_STREAM
:
2240 port_ptr
->connect_listen_unix_stream(remote_component
, remote_port
);
2243 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2244 remote_port
, "Message CONNECT_LISTEN refers to invalid transport "
2245 "type (%d).", transport_type
);
2250 void PORT::process_connect(const char *local_port
,
2251 component remote_component
, const char *remote_port
,
2252 transport_type_enum transport_type
, Text_Buf
& text_buf
)
2254 PORT
*port_ptr
= lookup_by_name(local_port
);
2255 if (port_ptr
== NULL
) {
2256 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2257 remote_port
, "Port %s does not exist.", local_port
);
2259 } else if (!port_ptr
->is_active
) {
2260 TTCN_error("Internal error: Port %s is inactive when trying to "
2261 "connect it to %d:%s.", local_port
, remote_component
, remote_port
);
2262 } else if (port_ptr
->lookup_connection(remote_component
, remote_port
)
2264 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2265 remote_port
, "Port %s already has a connection towards %d:%s.",
2266 local_port
, remote_component
, remote_port
);
2268 } else if (port_ptr
->lookup_connection_to_compref(remote_component
, NULL
)
2270 TTCN_warning_begin("Port %s will have more than one connections with "
2271 "ports of test component ", local_port
);
2272 COMPONENT::log_component_reference(remote_component
);
2273 TTCN_Logger::log_event_str(". These connections cannot be used for "
2274 "sending even with explicit addressing.");
2278 switch (transport_type
) {
2279 case TRANSPORT_LOCAL
:
2280 port_ptr
->connect_local(remote_component
, remote_port
);
2282 case TRANSPORT_INET_STREAM
:
2283 case TRANSPORT_UNIX_STREAM
:
2284 port_ptr
->connect_stream(remote_component
, remote_port
, transport_type
,
2288 TTCN_Communication::send_connect_error(local_port
, remote_component
,
2289 remote_port
, "Message CONNECT refers to invalid transport type "
2290 "(%d).", transport_type
);
2295 void PORT::process_disconnect(const char *local_port
,
2296 component remote_component
, const char *remote_port
)
2298 PORT
*port_ptr
= lookup_by_name(local_port
);
2299 if (port_ptr
== NULL
) {
2300 TTCN_Communication::send_error("Message DISCONNECT refers to "
2301 "non-existent local port %s.", local_port
);
2303 } else if (!port_ptr
->is_active
) {
2304 TTCN_error("Internal error: Port %s is inactive when trying to "
2305 "disconnect it from %d:%s.", local_port
, remote_component
,
2308 port_connection
*conn_ptr
= port_ptr
->lookup_connection(remote_component
,
2310 if (conn_ptr
== NULL
) {
2311 // the connection does not exist
2312 if (self
== remote_component
&& lookup_by_name(remote_port
) == NULL
) {
2313 // the remote endpoint is in the same component,
2314 // but it does not exist
2315 TTCN_Communication::send_error("Message DISCONNECT refers to "
2316 "non-existent port %s.", remote_port
);
2318 TTCN_Communication::send_disconnected(local_port
, remote_component
,
2323 switch (conn_ptr
->transport_type
) {
2324 case TRANSPORT_LOCAL
:
2325 port_ptr
->disconnect_local(conn_ptr
);
2327 case TRANSPORT_INET_STREAM
:
2328 case TRANSPORT_UNIX_STREAM
:
2329 port_ptr
->disconnect_stream(conn_ptr
);
2332 TTCN_error("Internal error: The connection of port %s to %d:%s has "
2333 "invalid transport type (%d) when trying to terminate the "
2334 "connection.", local_port
, remote_component
, remote_port
,
2335 conn_ptr
->transport_type
);
2339 void PORT::make_local_connection(const char *src_port
, const char *dest_port
)
2341 PORT
*src_ptr
= lookup_by_name(src_port
);
2342 if (src_ptr
== NULL
) TTCN_error("Connect operation refers to "
2343 "non-existent port %s.", src_port
);
2344 else if (!src_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2345 "inactive when trying to connect it with local port %s.", src_port
,
2347 else if (src_ptr
->lookup_connection(MTC_COMPREF
, dest_port
) != NULL
) {
2348 TTCN_warning("Port %s is already connected with local port %s. "
2349 "Connect operation had no effect.", src_port
, dest_port
);
2351 } else if (src_ptr
->lookup_connection_to_compref(MTC_COMPREF
, NULL
)
2353 TTCN_warning("Port %s will have more than one connections with local "
2354 "ports. These connections cannot be used for communication even "
2355 "with explicit addressing.", src_port
);
2357 PORT
*dest_ptr
= lookup_by_name(dest_port
);
2358 if (dest_ptr
== NULL
) TTCN_error("Connect operation refers to "
2359 "non-existent port %s.", dest_port
);
2360 else if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2361 "inactive when trying to connect it with local port %s.", dest_port
,
2363 src_ptr
->add_local_connection(dest_ptr
);
2364 if (src_ptr
!= dest_ptr
) dest_ptr
->add_local_connection(src_ptr
);
2367 void PORT::terminate_local_connection(const char *src_port
,
2368 const char *dest_port
)
2370 PORT
*src_ptr
= lookup_by_name(src_port
);
2371 if (src_ptr
== NULL
) TTCN_error("Disconnect operation refers to "
2372 "non-existent port %s.", src_port
);
2373 else if (!src_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2374 "inactive when trying to disconnect it from local port %s.", src_port
,
2376 port_connection
*conn_ptr
= src_ptr
->lookup_connection(MTC_COMPREF
,
2378 if (conn_ptr
!= NULL
) {
2379 PORT
*dest_ptr
= conn_ptr
->local
.port_ptr
;
2380 src_ptr
->remove_local_connection(conn_ptr
);
2381 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 port_connection
*conn2_ptr
=
2386 dest_ptr
->lookup_connection(MTC_COMPREF
, src_port
);
2387 if (conn2_ptr
== NULL
) TTCN_error("Internal error: Port %s is "
2388 "connected with local port %s, but port %s does not have a "
2389 "connection to %s.", src_port
, dest_port
, dest_port
, src_port
);
2390 else dest_ptr
->remove_local_connection(conn2_ptr
);
2393 PORT
*dest_ptr
= lookup_by_name(dest_port
);
2394 if (dest_ptr
== NULL
) TTCN_error("Disconnect operation refers to "
2395 "non-existent port %s.", dest_port
);
2396 else if (src_ptr
!= dest_ptr
) {
2397 if (!dest_ptr
->is_active
) TTCN_error("Internal error: Port %s is "
2398 "inactive when trying to disconnect it from local port %s.",
2399 dest_port
, src_port
);
2400 else if (dest_ptr
->lookup_connection(MTC_COMPREF
, src_port
) != NULL
)
2401 TTCN_error("Internal error: Port %s is connected with local "
2402 "port %s, but port %s does not have a connection to %s.",
2403 dest_port
, src_port
, src_port
, dest_port
);
2405 TTCN_warning("Port %s does not have connection with local port %s. "
2406 "Disconnect operation had no effect.", src_port
, dest_port
);
2410 void PORT::map_port(const char *component_port
, const char *system_port
)
2412 PORT
*port_ptr
= lookup_by_name(component_port
);
2413 if (port_ptr
== NULL
) TTCN_error("Map operation refers to "
2414 "non-existent port %s.", component_port
);
2415 port_ptr
->map(system_port
);
2416 if (!TTCN_Runtime::is_single())
2417 TTCN_Communication::send_mapped(component_port
, system_port
);
2420 void PORT::unmap_port(const char *component_port
, const char *system_port
)
2422 PORT
*port_ptr
= lookup_by_name(component_port
);
2423 if (port_ptr
== NULL
) TTCN_error("Unmap operation refers to "
2424 "non-existent port %s.", component_port
);
2425 port_ptr
->unmap(system_port
);
2426 if (!TTCN_Runtime::is_single())
2427 TTCN_Communication::send_unmapped(component_port
, system_port
);