clang specific define in Runtime.cc
[deliverable/titan.core.git] / core / Port.cc
CommitLineData
d44e3c4f 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
7 *
8 * Contributors:
9 * Baji, Laszlo
10 * Balasko, Jeno
11 * Delic, Adam
12 * Feher, Csaba
13 * Forstner, Matyas
14 * Kovacs, Ferenc
15 * Pandi, Krisztian
16 * Raduly, Csaba
17 * Szabados, Kristof
0a1610f4 18 * Szabo, Bence Janos
d44e3c4f 19 * Szabo, Janos Zoltan – initial implementation
20 * Szalai, Gabor
21 * Tatarka, Gabor
22 *
23 ******************************************************************************/
970ed795
EL
24#include "Port.hh"
25
26#include <string.h>
27#include <unistd.h>
28#include <errno.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <sys/un.h>
35
36#include "../common/platform.h"
37
38#include "../common/memory.h"
39#include "Component.hh"
40#include "Error.hh"
41#include "Logger.hh"
42#include "Event_Handler.hh"
43#include "Fd_And_Timeout_User.hh"
44#include "Snapshot.hh"
45#include "Communication.hh"
46#include "Runtime.hh"
47#include "Octetstring.hh"
48#include "TitanLoggerApi.hh"
49
50 // maximum number of iterations for binding the UNIX server socket
51#define UNIX_BIND_MAX_ITER 100
52
53#include "../common/dbgnew.hh"
54
55PORT *PORT::list_head = NULL, *PORT::list_tail = NULL;
56
57void PORT::add_to_list()
58{
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);
66 }
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;
71 list_next = NULL;
72 list_tail = this;
73}
74
75void PORT::remove_from_list()
76{
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;
81 list_prev = NULL;
82 list_next = NULL;
83}
84
85PORT *PORT::lookup_by_name(const char *par_port_name)
86{
87 for (PORT *port = list_head; port != NULL; port = port->list_next)
88 if (!strcmp(par_port_name, port->port_name)) return port;
89 return NULL;
90}
91
92struct PORT::port_parameter {
93 component_id_t component_id;
94 char *port_name;
95 char *parameter_name;
96 char *parameter_value;
97 struct port_parameter *next_par;
98} *PORT::parameter_head = NULL, *PORT::parameter_tail = NULL;
99
100void PORT::apply_parameter(port_parameter *par_ptr)
101{
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);
107 } else {
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);
112 }
113}
114
115void PORT::set_system_parameters(const char *system_port)
116{
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);
121}
122
123void PORT::add_parameter(const component_id_t& component_id,
124 const char *par_port_name, const char *parameter_name,
125 const char *parameter_value)
126{
127 port_parameter *new_par = new port_parameter;
128
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);
133 break;
134 case COMPONENT_ID_COMPREF:
135 new_par->component_id.id_compref = component_id.id_compref;
136 break;
137 default:
138 break;
139 }
140
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);
145
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;
150}
151
152void PORT::clear_parameters()
153{
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;
163 }
164}
165
166void PORT::set_parameters(component component_reference,
167 const char *component_name)
168{
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);
175 break;
176 case COMPONENT_ID_COMPREF:
177 if (par->component_id.id_compref == component_reference)
178 apply_parameter(par);
179 break;
180 case COMPONENT_ID_ALL:
181 apply_parameter(par);
182 break;
183 default:
184 break;
185 }
186}
187
188enum 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
191};
192
193enum connection_state_enum {
194 CONN_IDLE, CONN_LISTENING, CONN_CONNECTED, CONN_LAST_MSG_SENT,
195 CONN_LAST_MSG_RCVD
196};
197
198struct port_connection : public Fd_Event_Handler {
199 PORT *owner_port;
200 connection_state_enum connection_state;
201 component remote_component;
202 char *remote_port;
203 transport_type_enum transport_type;
204 union {
205 struct {
206 PORT *port_ptr;
207 } local;
208 struct {
209 int comm_fd;
210 Text_Buf *incoming_buf;
211 } stream;
212 };
213 struct port_connection *list_prev, *list_next;
214 OCTETSTRING sliding_buffer;
215
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;
220};
221
222void port_connection::Handle_Fd_Event(int,
223 boolean is_readable, boolean /*is_writeable*/, boolean /*is_error*/)
224{
225 // Note event for connection with TRANSPORT_LOCAL transport_type
226 // may not arrive.
227 if (transport_type == TRANSPORT_INET_STREAM
228 || transport_type == TRANSPORT_UNIX_STREAM
229 ) {
230 if (is_readable) {
231 if (connection_state == CONN_LISTENING)
232 owner_port->handle_incoming_connection(this);
233 else owner_port->handle_incoming_data(this);
234 }
235 } else
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);
239}
240
241void port_connection::log() const
242 {
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);
247 }
248
249port_connection::~port_connection()
250{
251 if (transport_type == TRANSPORT_INET_STREAM
252 || transport_type == TRANSPORT_UNIX_STREAM
253 ) {
254 if (stream.comm_fd != -1) {
255 TTCN_warning_begin("Internal Error: File descriptor %d not "
256 "closed/removed in ", stream.comm_fd); log();
257 TTCN_warning_end();
258 }
259 }
260 sliding_buffer.clean_up();
261}
262
263PORT::PORT(const char *par_port_name)
264{
265 port_name = par_port_name != NULL ? par_port_name : "<unknown>";
266 is_active = FALSE;
267 is_started = FALSE;
268 is_halted = FALSE;
269 list_prev = NULL;
270 list_next = NULL;
271
272 connection_list_head = NULL;
273 connection_list_tail = NULL;
274 n_system_mappings = 0;
275 system_mappings = NULL;
276}
277
278PORT::~PORT()
279{
280 if (is_active) deactivate_port();
281}
282
283void PORT::set_name(const char * name)
284{
285 if (name == NULL) TTCN_error("Internal error: Setting an "
286 "invalid name for a single element of a port array.");
287 port_name = name;
288}
289
290void PORT::log() const
291 {
292 TTCN_Logger::log_event("port %s", port_name);
293 }
294
295void PORT::activate_port()
296{
297 if (!is_active) {
298 add_to_list();
299 is_active = TRUE;
300 msg_head_count = 0;
301 msg_tail_count = 0;
302 proc_head_count = 0;
303 proc_tail_count = 0;
304 }
305}
306
307void PORT::deactivate_port()
308{
309 if (is_active) {
310 /* In order to proceed with the deactivation we must ignore the
311 * following errors:
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)
314 */
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,
320 port_name,
321 connection_list_head->remote_component, connection_list_head->remote_port);
322 if (is_parallel) {
323 try {
324 TTCN_Communication::send_disconnected(port_name,
325 connection_list_head->remote_component,
326 connection_list_head->remote_port);
327 } catch (const TC_Error&) { }
328 }
329 remove_connection(connection_list_head);
330 }
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);
338 try {
339 unmap(system_port);
340 } catch (const TC_Error&) { }
341 if (is_parallel) {
342 try {
343 TTCN_Communication::send_unmapped(port_name, system_port);
344 } catch (const TC_Error&) { }
345 }
346 Free(system_port);
347 }
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) {
351 try {
352 stop();
353 } catch (const TC_Error&) { }
354 }
355 clear_queue();
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
361 remove_from_list();
362 is_active = FALSE;
363 }
364}
365
366void PORT::deactivate_all()
367{
368 while (list_head != NULL) list_head->deactivate_port();
369}
370
371void PORT::clear()
372{
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);
378 }
379 clear_queue();
380 TTCN_Logger::log_port_misc(
381 TitanLoggerApi::Port__Misc_reason::port__was__cleared, port_name);
382}
383
384void PORT::all_clear()
385{
386 for (PORT *port = list_head; port != NULL; port = port->list_next)
387 port->clear();
388}
389
390void PORT::start()
391{
392 if (!is_active) TTCN_error("Internal error: Inactive port %s cannot "
393 "be started.", port_name);
394 if (is_started) {
395 TTCN_warning("Performing start operation on port %s, which is "
396 "already started. The operation will clear the incoming queue.",
397 port_name);
398 clear_queue();
399 } else {
400 if (is_halted) {
401 // the queue might contain old messages which has to be discarded
402 clear_queue();
403 is_halted = FALSE;
404 }
405 user_start();
406 is_started = TRUE;
407 }
408 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::started,
409 port_name);
410}
411
412void PORT::all_start()
413{
414 for (PORT *port = list_head; port != NULL; port = port->list_next)
415 port->start();
416}
417
418void PORT::stop()
419{
420 if (!is_active) TTCN_error("Internal error: Inactive port %s cannot "
421 "be stopped.", port_name);
422 if (is_started) {
423 is_started = FALSE;
424 is_halted = FALSE;
425 user_stop();
426 // dropping all messages from the queue because they cannot be
427 // extracted by receiving operations anymore
428 clear_queue();
429 } else if (is_halted) {
430 is_halted = FALSE;
431 clear_queue();
432 } else {
433 TTCN_warning("Performing stop operation on port %s, which is "
434 "already stopped. The operation has no effect.", port_name);
435 }
436 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::stopped,
437 port_name);
438}
439
440void PORT::all_stop()
441{
442 for (PORT *port = list_head; port != NULL; port = port->list_next)
443 port->stop();
444}
445
446void PORT::halt()
447{
448 if (!is_active) TTCN_error("Internal error: Inactive port %s cannot "
449 "be halted.", port_name);
450 if (is_started) {
451 is_started = FALSE;
452 is_halted = TRUE;
453 user_stop();
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);
458 } else {
459 TTCN_warning("Performing halt operation on port %s, which is "
460 "already stopped. The operation has no effect.", port_name);
461 }
462 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::halted,
463 port_name);
464}
465
466void PORT::all_halt()
467{
468 for (PORT *port = list_head; port != NULL; port = port->list_next)
469 port->halt();
470}
471
472alt_status PORT::receive(const COMPONENT_template&, COMPONENT *)
473{
474 TTCN_Logger::log_matching_problem(
475 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types,
476 TitanLoggerApi::MatchingProblemType_operation::receive__,
477 false, false, port_name);
478 return ALT_NO;
479}
480
481alt_status PORT::any_receive(const COMPONENT_template& sender_template,
482 COMPONENT *sender_ptr)
483{
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)) {
488 case ALT_YES:
489 return ALT_YES;
490 case ALT_MAYBE:
491 ret_val = ALT_MAYBE;
492 break;
493 case ALT_NO:
494 break;
495 default:
496 TTCN_error("Internal error: Receive operation returned "
497 "unexpected status code on port %s while evaluating "
498 "`any port.receive'.", port->port_name);
499 }
500 }
501 return ret_val;
502 } else {
503 TTCN_Logger::log_matching_problem(
504 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
505 TitanLoggerApi::MatchingProblemType_operation::receive__,
506 true, false);
507 return ALT_NO;
508 }
509}
510
511alt_status PORT::check_receive(const COMPONENT_template&, COMPONENT *)
512{
513 TTCN_Logger::log_matching_problem(
514 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types,
515 TitanLoggerApi::MatchingProblemType_operation::receive__,
516 false, true, port_name);
517 return ALT_NO;
518}
519
520alt_status PORT::any_check_receive(const COMPONENT_template& sender_template,
521 COMPONENT *sender_ptr)
522{
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)) {
527 case ALT_YES:
528 return ALT_YES;
529 case ALT_MAYBE:
530 ret_val = ALT_MAYBE;
531 break;
532 case ALT_NO:
533 break;
534 default:
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);
538 }
539 }
540 return ret_val;
541 } else {
542 TTCN_Logger::log_matching_problem(
543 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
544 TitanLoggerApi::MatchingProblemType_operation::receive__,
545 true, true);
546 return ALT_NO;
547 }
548}
549
550alt_status PORT::trigger(const COMPONENT_template&, COMPONENT *)
551{
552 TTCN_Logger::log_matching_problem(
553 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types,
554 TitanLoggerApi::MatchingProblemType_operation::trigger__,
555 false, false, port_name);
556 return ALT_NO;
557}
558
559alt_status PORT::any_trigger(const COMPONENT_template& sender_template,
560 COMPONENT *sender_ptr)
561{
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)) {
566 case ALT_YES:
567 return ALT_YES;
568 case ALT_MAYBE:
569 ret_val = ALT_MAYBE;
570 break;
571 case ALT_NO:
572 break;
573 case ALT_REPEAT:
574 return ALT_REPEAT;
575 default:
576 TTCN_error("Internal error: Trigger operation returned "
577 "unexpected status code on port %s while evaluating "
578 "`any port.trigger'.", port->port_name);
579 }
580 }
581 return ret_val;
582 } else {
583 TTCN_Logger::log_matching_problem(
584 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
585 TitanLoggerApi::MatchingProblemType_operation::trigger__,
586 true, false);
587 return ALT_NO;
588 }
589}
590
591alt_status PORT::getcall(const COMPONENT_template&, COMPONENT *)
592{
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);
599 return ALT_NO;
600}
601
602alt_status PORT::any_getcall(const COMPONENT_template& sender_template,
603 COMPONENT *sender_ptr)
604{
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)) {
609 case ALT_YES:
610 return ALT_YES;
611 case ALT_MAYBE:
612 ret_val = ALT_MAYBE;
613 break;
614 case ALT_NO:
615 break;
616 default:
617 TTCN_error("Internal error: Getcall operation returned "
618 "unexpected status code on port %s while evaluating "
619 "`any port.getcall'.", port->port_name);
620 }
621 }
622 return ret_val;
623 } else {
624 TTCN_Logger::log_matching_problem(
625 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
626 TitanLoggerApi::MatchingProblemType_operation::getcall__,
627 true, false);
628 return ALT_NO;
629 }
630}
631
632alt_status PORT::check_getcall(const COMPONENT_template&, COMPONENT *)
633{
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);
640 return ALT_NO;
641}
642
643alt_status PORT::any_check_getcall(const COMPONENT_template& sender_template,
644 COMPONENT *sender_ptr)
645{
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)) {
650 case ALT_YES:
651 return ALT_YES;
652 case ALT_MAYBE:
653 ret_val = ALT_MAYBE;
654 break;
655 case ALT_NO:
656 break;
657 default:
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);
661 }
662 }
663 return ret_val;
664 } else {
665 TTCN_Logger::log_matching_problem(
666 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
667 TitanLoggerApi::MatchingProblemType_operation::getcall__,
668 true, true);
669 return ALT_NO;
670 }
671}
672
673alt_status PORT::getreply(const COMPONENT_template&, COMPONENT *)
674{
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);
681 return ALT_NO;
682}
683
684alt_status PORT::any_getreply(const COMPONENT_template& sender_template,
685 COMPONENT *sender_ptr)
686{
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)) {
691 case ALT_YES:
692 return ALT_YES;
693 case ALT_MAYBE:
694 ret_val = ALT_MAYBE;
695 break;
696 case ALT_NO:
697 break;
698 default:
699 TTCN_error("Internal error: Getreply operation returned "
700 "unexpected status code on port %s while evaluating "
701 "`any port.getreply'.", port->port_name);
702 }
703 }
704 return ret_val;
705 } else {
706 TTCN_Logger::log_matching_problem(
707 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
708 TitanLoggerApi::MatchingProblemType_operation::getreply__,
709 true, false);
710 return ALT_NO;
711 }
712}
713
714alt_status PORT::check_getreply(const COMPONENT_template&, COMPONENT *)
715{
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);
722 return ALT_NO;
723}
724
725alt_status PORT::any_check_getreply(const COMPONENT_template& sender_template,
726 COMPONENT *sender_ptr)
727{
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)) {
732 case ALT_YES:
733 return ALT_YES;
734 case ALT_MAYBE:
735 ret_val = ALT_MAYBE;
736 break;
737 case ALT_NO:
738 break;
739 default:
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);
743 }
744 }
745 return ret_val;
746 } else {
747 TTCN_Logger::log_matching_problem(
748 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
749 TitanLoggerApi::MatchingProblemType_operation::getreply__,
750 true, true);
751 return ALT_NO;
752 }
753}
754
755alt_status PORT::get_exception(const COMPONENT_template&, COMPONENT *)
756{
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);
763 return ALT_NO;
764}
765
766alt_status PORT::any_catch(const COMPONENT_template& sender_template,
767 COMPONENT *sender_ptr)
768{
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)) {
773 case ALT_YES:
774 return ALT_YES;
775 case ALT_MAYBE:
776 ret_val = ALT_MAYBE;
777 break;
778 case ALT_NO:
779 break;
780 default:
781 TTCN_error("Internal error: Catch operation returned "
782 "unexpected status code on port %s while evaluating "
783 "`any port.catch'.", port->port_name);
784 }
785 }
786 return ret_val;
787 } else {
788 TTCN_Logger::log_matching_problem(
789 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
790 TitanLoggerApi::MatchingProblemType_operation::catch__,
791 true, false);
792 return ALT_NO;
793 }
794}
795
796alt_status PORT::check_catch(const COMPONENT_template& ,
797 COMPONENT *)
798{
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);
805 return ALT_NO;
806}
807
808alt_status PORT::any_check_catch(const COMPONENT_template& sender_template,
809 COMPONENT *sender_ptr)
810{
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)) {
815 case ALT_YES:
816 return ALT_YES;
817 case ALT_MAYBE:
818 ret_val = ALT_MAYBE;
819 break;
820 case ALT_NO:
821 break;
822 default:
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);
826 }
827 }
828 return ret_val;
829 } else {
830 TTCN_Logger::log_matching_problem(
831 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
832 TitanLoggerApi::MatchingProblemType_operation::catch__,
833 true, true);
834 return ALT_NO;
835 }
836}
837
838alt_status PORT::check(const COMPONENT_template& sender_template,
839 COMPONENT *sender_ptr)
840{
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)) {
844 case ALT_YES:
845 return ALT_YES;
846 case ALT_MAYBE:
847 ret_val = ALT_MAYBE;
848 break;
849 case ALT_NO:
850 break;
851 default:
852 TTCN_error("Internal error: Check-getcall operation returned "
853 "unexpected status code on port %s.", port_name);
854 }
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)) {
859 case ALT_YES:
860 return ALT_YES;
861 case ALT_MAYBE:
862 ret_val = ALT_MAYBE;
863 break;
864 case ALT_NO:
865 break;
866 default:
867 TTCN_error("Internal error: Check-getreply operation returned "
868 "unexpected status code on port %s.", port_name);
869 }
870 }
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)) {
875 case ALT_YES:
876 return ALT_YES;
877 case ALT_MAYBE:
878 ret_val = ALT_MAYBE;
879 break;
880 case ALT_NO:
881 break;
882 default:
883 TTCN_error("Internal error: Check-catch operation returned "
884 "unexpected status code on port %s.", port_name);
885 }
886 }
887 switch (check_receive(sender_template, sender_ptr)) {
888 case ALT_YES:
889 return ALT_YES;
890 case ALT_MAYBE:
891 ret_val = ALT_MAYBE;
892 break;
893 case ALT_NO:
894 break;
895 default:
896 TTCN_error("Internal error: Check-receive operation returned "
897 "unexpected status code on port %s.", port_name);
898 }
899 return ret_val;
900}
901
902alt_status PORT::any_check(const COMPONENT_template& sender_template,
903 COMPONENT *sender_ptr)
904{
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)) {
909 case ALT_YES:
910 return ALT_YES;
911 case ALT_MAYBE:
912 ret_val = ALT_MAYBE;
913 break;
914 case ALT_NO:
915 break;
916 default:
917 TTCN_error("Internal error: Check operation returned "
918 "unexpected status code on port %s while evaluating "
919 "`any port.check'.", port->port_name);
920 }
921 }
922 return ret_val;
923 } else {
924 TTCN_Logger::log_matching_problem(
925 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
926 TitanLoggerApi::MatchingProblemType_operation::check__,
927 true, false);
928 return ALT_NO;
929 }
930}
931
932void PORT::set_parameter(const char *parameter_name, const char *)
933{
934 TTCN_warning("Test port parameter %s is not supported on port %s.",
935 parameter_name, port_name);
936}
937
938void PORT::append_to_msg_queue(msg_queue_item_base* new_item)
939{
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;
944}
945
946void PORT::Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable,
947 boolean is_error)
948{
949 // The port intends to use the finer granularity event handler functions
950 if (is_error) {
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;
956 }
957 if (is_writable) {
958 Handle_Fd_Event_Writable(fd);
959 if (!is_readable) return;
960 if ((Fd_And_Timeout_User::getCurReceivedEvent() & FD_EVENT_RD) == 0)
961 return;
962 }
963 if (is_readable)
964 Handle_Fd_Event_Readable(fd);
965}
966
967void PORT::Handle_Fd_Event_Error(int)
968{
969 // Silently ignore
970 // A port need not wait for error events
971 // Note: error events always cause event handler invocation
972}
973
974void PORT::Handle_Fd_Event_Writable(int)
975{
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);
982}
983
984void PORT::Handle_Fd_Event_Readable(int)
985{
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);
992}
993
994void PORT::Handle_Timeout(double /*time_since_last_call*/)
995{
996 TTCN_error("There is no Handle_Timeout member function implemented in "
997 "port %s. "
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.",
1000 port_name);
1001}
1002
1003void PORT::Event_Handler(const fd_set * /*read_fds*/, const fd_set * /*write_fds*/,
1004 const fd_set * /*error_fds*/, double /*time_since_last_call*/)
1005{
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);
1010}
1011
1012void PORT::Handler_Add_Fd(int fd, Fd_Event_Type event_mask)
1013{
1014 Fd_And_Timeout_User::add_fd(fd, this,
1015 static_cast<fd_event_type_enum>(
1016 static_cast<int>(event_mask)));
1017}
1018
1019void PORT::Handler_Add_Fd_Read(int fd)
1020{
1021 Fd_And_Timeout_User::add_fd(fd, this, FD_EVENT_RD);
1022}
1023
1024void PORT::Handler_Add_Fd_Write(int fd)
1025{
1026 Fd_And_Timeout_User::add_fd(fd, this, FD_EVENT_WR);
1027}
1028
1029void PORT::Handler_Remove_Fd(int fd, Fd_Event_Type event_mask)
1030{
1031 Fd_And_Timeout_User::remove_fd(fd, this,
1032 static_cast<fd_event_type_enum>(
1033 static_cast<int>(event_mask)));
1034}
1035
1036void PORT::Handler_Remove_Fd_Read(int fd)
1037{
1038 Fd_And_Timeout_User::remove_fd(fd, this, FD_EVENT_RD);
1039}
1040
1041void PORT::Handler_Remove_Fd_Write(int fd)
1042{
1043 Fd_And_Timeout_User::remove_fd(fd, this, FD_EVENT_WR);
1044}
1045
1046void PORT::Handler_Set_Timer(double call_interval, boolean is_timeout,
1047 boolean call_anyway, boolean is_periodic)
1048{
1049 Fd_And_Timeout_User::set_timer(this, call_interval, is_timeout, call_anyway,
1050 is_periodic);
1051}
1052
1053void PORT::Install_Handler(const fd_set *read_fds, const fd_set *write_fds,
1054 const fd_set *error_fds, double call_interval)
1055{
1056 if (!is_active) TTCN_error("Event handler cannot be installed for "
1057 "inactive port %s.", port_name);
1058
1059 if ((long) FdMap::getFdLimit() > (long) FD_SETSIZE) {
1060 static bool once = true;
1061 if (once) {
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,
1069 port_name);
1070 }
1071 once = false;
1072 }
1073
1074 Fd_And_Timeout_User::set_fds_with_fd_sets(this, read_fds, write_fds,
1075 error_fds);
1076 Fd_And_Timeout_User::set_timer(this, call_interval);
1077}
1078
1079void PORT::Uninstall_Handler()
1080{
1081 Fd_And_Timeout_User::remove_all_fds(this);
1082 Fd_And_Timeout_User::set_timer(this, 0.0);
1083}
1084
1085void PORT::user_map(const char *)
1086{
1087
1088}
1089
1090void PORT::user_unmap(const char *)
1091{
1092
1093}
1094
1095void PORT::user_start()
1096{
1097
1098}
1099
1100void PORT::user_stop()
1101{
1102
1103}
1104
1105void PORT::clear_queue()
1106{
1107
1108}
1109
1110component PORT::get_default_destination()
1111{
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;
1120 } else {
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);
1127 }
1128 return SYSTEM_COMPREF;
1129 }
1130}
1131
1132void PORT::prepare_message(Text_Buf& outgoing_buf, const char *message_type)
1133{
1134 outgoing_buf.push_int(CONN_DATA_MESSAGE);
1135 outgoing_buf.push_string(message_type);
1136}
1137
1138void PORT::prepare_call(Text_Buf& outgoing_buf, const char *signature_name)
1139{
1140 outgoing_buf.push_int(CONN_DATA_CALL);
1141 outgoing_buf.push_string(signature_name);
1142}
1143
1144void PORT::prepare_reply(Text_Buf& outgoing_buf, const char *signature_name)
1145{
1146 outgoing_buf.push_int(CONN_DATA_REPLY);
1147 outgoing_buf.push_string(signature_name);
1148}
1149
1150void PORT::prepare_exception(Text_Buf& outgoing_buf, const char *signature_name)
1151{
1152 outgoing_buf.push_int(CONN_DATA_EXCEPTION);
1153 outgoing_buf.push_string(signature_name);
1154}
1155
1156void PORT::send_data(Text_Buf &outgoing_buf,
1157 const COMPONENT& destination_component)
1158{
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;
1163 boolean is_unique;
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);
1181 break;
1182 case TRANSPORT_INET_STREAM:
1183 case TRANSPORT_UNIX_STREAM:
1184 send_data_stream(conn_ptr, outgoing_buf, FALSE);
1185 break;
1186 default:
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);
1190 }
1191}
1192
1193void PORT::process_data(port_connection *conn_ptr, Text_Buf& incoming_buf)
1194{
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:
1201 break;
1202 case CONN_LAST_MSG_RCVD:
1203 case CONN_IDLE:
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);
1207 return;
1208 default:
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);
1212 }
1213 char *message_type = incoming_buf.pull_string();
1214 try {
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);
1223 }
1224 break;
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);
1232 }
1233 break;
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);
1241 }
1242 break;
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);
1250 }
1251 break;
1252 default:
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);
1257 }
1258 } catch (...) {
1259 // avoid memory leak
1260 delete [] message_type;
1261 throw;
1262 }
1263 delete [] message_type;
1264 } else process_last_message(conn_ptr);
1265}
1266
1267boolean PORT::process_message(const char *, Text_Buf&, component, OCTETSTRING&)
1268{
1269 return FALSE;
1270}
1271
1272boolean PORT::process_call(const char *, Text_Buf&, component)
1273{
1274 return FALSE;
1275}
1276
1277boolean PORT::process_reply(const char *, Text_Buf&, component)
1278{
1279 return FALSE;
1280}
1281
1282boolean PORT::process_exception(const char *, Text_Buf&, component)
1283{
1284 return FALSE;
1285}
1286
1287port_connection *PORT::add_connection(component remote_component,
1288 const char *remote_port, transport_type_enum transport_type)
1289{
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;
1298 }
1299
1300 port_connection *new_conn = new port_connection;
1301 new_conn->owner_port = this;
1302
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;
1311 break;
1312 case TRANSPORT_INET_STREAM:
1313 case TRANSPORT_UNIX_STREAM:
1314 new_conn->stream.comm_fd = -1;
1315 new_conn->stream.incoming_buf = NULL;
1316 break;
1317 default:
1318 delete new_conn;
1319 TTCN_error("Internal error: PORT::add_connection(): invalid transport "
1320 "type (%d).", transport_type);
1321 }
1322
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;
1330 } else {
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;
1336 }
1337 if (conn_ptr == connection_list_head) connection_list_head = new_conn;
1338
1339 return new_conn;
1340}
1341
1342void PORT::remove_connection(port_connection *conn_ptr)
1343{
1344 Free(conn_ptr->remote_port);
1345
1346 switch (conn_ptr->transport_type) {
1347 case TRANSPORT_LOCAL:
1348 break;
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,
1353 FD_EVENT_RD);
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;
1359 }
1360 delete conn_ptr->stream.incoming_buf;
1361 break;
1362 default:
1363 TTCN_error("Internal error: PORT::remove_connection(): invalid "
1364 "transport type.");
1365 }
1366
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;
1375
1376 delete conn_ptr;
1377}
1378
1379port_connection *PORT::lookup_connection_to_compref(
1380 component remote_component, boolean *is_unique)
1381{
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)
1388 *is_unique = FALSE;
1389 else *is_unique = TRUE;
1390 }
1391 return conn;
1392 } else if (conn->remote_component > remote_component) break;
1393 }
1394 return NULL;
1395}
1396
1397port_connection *PORT::lookup_connection(component remote_component,
1398 const char *remote_port)
1399{
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;
1407 }
1408 return NULL;
1409}
1410
1411void PORT::add_local_connection(PORT *other_endpoint)
1412{
1413 port_connection *conn_ptr = add_connection(self, other_endpoint->port_name,
1414 TRANSPORT_LOCAL);
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);
1419}
1420
1421void PORT::remove_local_connection(port_connection *conn_ptr)
1422{
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);
1431}
1432
1433unsigned int PORT::get_connection_hash(component local_component,
1434 const char *local_port, component remote_component, const char *remote_port)
1435{
1436 const size_t N = sizeof(unsigned int);
1437 unsigned char hash_buffer[N];
1438
1439 // fill the buffer with an initial pattern
1440 for (size_t i = 0; i < N; i++) hash_buffer[i] = i % 2 ? 0x55 : 0xAA;
1441
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;
1446
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];
1456
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];
1461 return ret_val;
1462}
1463
1464void PORT::unlink_unix_pathname(int socket_fd)
1465{
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.");
1475 TTCN_warning_end();
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 "
1486 "system.");
1487 TTCN_warning_end();
1488 } else errno = 0;
1489 }
1490}
1491
1492void PORT::connect_listen_inet_stream(component remote_component,
1493 const char *remote_port)
1494{
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)",
1500 strerror(errno));
1501 errno = 0;
1502 return;
1503 }
1504
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())) {
1511 close(server_fd);
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));
1515 errno = 0;
1516 delete local_addr;
1517 return;
1518 }
1519
1520 // zero backlog is enough since we are waiting for only one client
1521 if (listen(server_fd, 0)) {
1522 close(server_fd);
1523 TTCN_Communication::send_connect_error(port_name, remote_component,
1524 remote_port, "Listening on an ephemeral TCP port failed. (%s)",
1525 strerror(errno));
1526 errno = 0;
1527 delete local_addr;
1528 return;
1529 }
1530
1531 // querying the IP address and port number used by the TCP server
1532 if (local_addr->getsockname(server_fd)) {
1533 close(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));
1537 errno = 0;
1538 delete local_addr;
1539 return;
1540 }
1541
1542 if (!TTCN_Communication::set_close_on_exec(server_fd)) {
1543 close(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 "
1546 "server socket.");
1547 delete local_addr;
1548 return;
1549 }
1550
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);
1556
1557 TTCN_Communication::send_connect_listen_ack_inet_stream(port_name,
1558 remote_component, remote_port, local_addr);
1559
1560 TTCN_Logger::log_port_misc(
1561 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__tcp,
1562 port_name, remote_component, remote_port);
1563 delete local_addr;
1564}
1565
1566void PORT::connect_listen_unix_stream(component remote_component,
1567 const char *remote_port)
1568{
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)",
1574 strerror(errno));
1575 errno = 0;
1576 return;
1577 }
1578
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))
1590 == 0) {
1591 // the operation was successful, jump out of the loop
1592 break;
1593 } else if (errno == EADDRINUSE) {
1594 // the temporary file name is already used by someone else
1595 errno = 0;
1596 if (i < UNIX_BIND_MAX_ITER) {
1597 // try another hash value
1598 hash_value++;
1599 } else {
1600 close(server_fd);
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 "
1604 "iterations.", i);
1605 errno = 0;
1606 return;
1607 }
1608 } else {
1609 close(server_fd);
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));
1613 errno = 0;
1614 return;
1615 }
1616 }
1617
1618 // zero backlog is enough since we are waiting for only one client
1619 if (listen(server_fd, 0)) {
1620 close(server_fd);
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));
1624 errno = 0;
1625 return;
1626 }
1627
1628 if (!TTCN_Communication::set_close_on_exec(server_fd)) {
1629 close(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 "
1632 "server socket.");
1633 return;
1634 }
1635
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);
1641
1642 TTCN_Communication::send_connect_listen_ack_unix_stream(port_name,
1643 remote_component, remote_port, &local_addr);
1644
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);
1648}
1649
1650void PORT::connect_local(component remote_component, const char *remote_port)
1651{
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);
1656 return;
1657 }
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);
1662 return;
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,
1665 port_name);
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,
1669 remote_port);
1670}
1671
1672void PORT::connect_stream(component remote_component, const char *remote_port,
1673 transport_type_enum transport_type, Text_Buf& text_buf)
1674{
1675#ifdef WIN32
1676 again:
1677#endif
1678 const char *transport_str;
1679 int client_fd;
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());
1685 break;
1686 case TRANSPORT_UNIX_STREAM:
1687 transport_str = "UNIX";
1688 // creating the UNIX client socket
1689 client_fd = socket(PF_UNIX, SOCK_STREAM, 0);
1690 break;
1691 default:
1692 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1693 "type (%d).", transport_type);
1694 }
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));
1699 errno = 0;
1700 return;
1701 }
1702
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);
1708#ifdef SOLARIS
1709 if (connect(client_fd, (struct sockaddr*)remote_addr->get_addr(), remote_addr->get_addr_len())) {
1710#else
1711 if (connect(client_fd, remote_addr->get_addr(), remote_addr->get_addr_len())) {
1712#endif
1713#ifdef WIN32
1714 if (errno == EADDRINUSE) {
1715 close(client_fd);
1716 errno = 0;
1717 TTCN_warning("connect() returned error code EADDRINUSE. "
1718 "Perhaps this is a Cygwin bug. Trying to connect again.");
1719 goto again;
1720 }
1721#endif
1722 close(client_fd);
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));
1726 errno = 0;
1727 delete remote_addr;
1728 return;
1729 }
1730 delete remote_addr;
1731 break; }
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)) {
1739 close(client_fd);
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));
1746 return;
1747 }
1748 text_buf.pull_raw(pathname_len, remote_addr.sun_path);
1749 if (connect(client_fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr))) {
1750 close(client_fd);
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));
1754 errno = 0;
1755 return;
1756 }
1757 break; }
1758 default:
1759 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1760 "type (%d).", transport_type);
1761 }
1762
1763 if (!TTCN_Communication::set_close_on_exec(client_fd)) {
1764 close(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);
1768 return;
1769 }
1770
1771 if (!TTCN_Communication::set_non_blocking_mode(client_fd, TRUE)) {
1772 close(client_fd);
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);
1776 return;
1777 }
1778
1779 if (transport_type == TRANSPORT_INET_STREAM &&
1780 !TTCN_Communication::set_tcp_nodelay(client_fd)) {
1781 close(client_fd);
1782 TTCN_Communication::send_connect_error(port_name, remote_component,
1783 remote_port, "Setting the TCP_NODELAY flag failed on the TCP "
1784 "client socket.");
1785 return;
1786 }
1787
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);
1793
1794 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__established,
1795 port_name, remote_component, remote_port, transport_str);
1796}
1797
1798void PORT::disconnect_local(port_connection *conn_ptr)
1799{
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);
1810 }
1811 TTCN_Communication::send_disconnected(port_name, self,
1812 remote_ptr->port_name);
1813}
1814
1815void PORT::disconnect_stream(port_connection *conn_ptr)
1816{
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
1824 break;
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;
1834 } else {
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.",
1844 port_name);
1845 // destroy the connection immediately
1846 remove_connection(conn_ptr);
1847 }
1848 break; }
1849 default:
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);
1853 }
1854}
1855
1856void PORT::send_data_local(port_connection *conn_ptr, Text_Buf& outgoing_data)
1857{
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);
1869}
1870
1871boolean PORT::send_data_stream(port_connection *conn_ptr,
1872 Text_Buf& outgoing_data, boolean ignore_peer_disconnect)
1873{
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;
1882 else {
1883 switch (errno) {
1884 case EINTR:
1885 // a signal occurred: do nothing, just try again
1886 errno = 0;
1887 break;
1888 case EAGAIN: {
1889 // the output buffer is full: try to increase it if possible
1890 errno = 0;
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);
1898 } else {
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);
1908 TTCN_warning_end();
1909 would_block_warning=true;
1910 }
1911 TTCN_Snapshot::block_for_sending(conn_ptr->stream.comm_fd);
1912 }
1913 break; }
1914 case ECONNRESET:
1915 case EPIPE:
1916 if (ignore_peer_disconnect) return FALSE;
1917 // no break
1918 default:
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);
1922 }
1923 }
1924 }
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);
1931 TTCN_warning_end();
1932 }
1933 return TRUE;
1934}
1935
1936void PORT::handle_incoming_connection(port_connection *conn_ptr)
1937{
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);
1941 if (comm_fd < 0) {
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,
1945 strerror(errno));
1946 errno = 0;
1947 remove_connection(conn_ptr);
1948 return;
1949 }
1950
1951 if (!TTCN_Communication::set_close_on_exec(comm_fd)) {
1952 close(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);
1958 return;
1959 }
1960
1961 if (!TTCN_Communication::set_non_blocking_mode(comm_fd, TRUE)) {
1962 close(comm_fd);
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);
1968 return;
1969 }
1970
1971 if (conn_ptr->transport_type == TRANSPORT_INET_STREAM &&
1972 !TTCN_Communication::set_tcp_nodelay(comm_fd)) {
1973 close(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 "
1977 "socket.");
1978 remove_connection(conn_ptr);
1979 return;
1980 }
1981
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,
1985 FD_EVENT_RD);
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);
1992
1993 TTCN_Communication::send_connected(port_name, conn_ptr->remote_component,
1994 conn_ptr->remote_port);
1995
1996 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__accepted,
1997 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
1998}
1999
2000void PORT::handle_incoming_data(port_connection *conn_ptr)
2001{
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;
2005 char *buf_ptr;
2006 int buf_len;
2007 incoming_buf.get_end(buf_ptr, buf_len);
2008 int recv_len = recv(conn_ptr->stream.comm_fd, buf_ptr, buf_len, 0);
2009 if (recv_len < 0) {
2010 // an error occurred
2011 if (errno == ECONNRESET) {
2012 // TCP connection was reset by peer
2013 errno = 0;
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.",
2020 port_name);
2021 conn_ptr->connection_state = CONN_IDLE;
2022 } else {
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);
2026 }
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();
2035 }
2036 } else {
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);
2044 }
2045 // the connection can be removed
2046 conn_ptr->connection_state = CONN_IDLE;
2047 }
2048 if (conn_ptr->connection_state == CONN_IDLE) {
2049 // terminating and removing connection
2050 int msg_len = incoming_buf.get_len();
2051 if (msg_len > 0) {
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]);
2060 TTCN_warning_end();
2061 }
2062
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);
2066 }
2067}
2068
2069void PORT::process_last_message(port_connection *conn_ptr)
2070{
2071 switch (conn_ptr->transport_type) {
2072 case TRANSPORT_INET_STREAM:
2073 case TRANSPORT_UNIX_STREAM:
2074 break;
2075 default:
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);
2081 }
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;
2093 } else {
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.",
2104 port_name);
2105 conn_ptr->connection_state = CONN_IDLE;
2106 }
2107 break; }
2108 case CONN_LAST_MSG_SENT:
2109 // the connection can be removed
2110 conn_ptr->connection_state = CONN_IDLE;
2111 break;
2112 case CONN_LAST_MSG_RCVD:
2113 case CONN_IDLE:
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);
2117 break;
2118 default:
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);
2122 }
2123}
2124
2125void PORT::map(const char *system_port)
2126{
2127 if (!is_active) TTCN_error("Inactive port %s cannot be mapped.", port_name);
2128
2129 int new_posn;
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);
2136 return;
2137 }
2138 }
2139
2140 set_system_parameters(system_port);
2141
2142 user_map(system_port);
2143
2144 TTCN_Logger::log_port_misc(
2145 TitanLoggerApi::Port__Misc_reason::port__was__mapped__to__system,
2146 port_name, SYSTEM_COMPREF, system_port);
2147
2148 // the mapping shall be registered in the table only if user_map() was
2149 // successful
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++;
2156
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);
2160}
2161
2162void PORT::unmap(const char *system_port)
2163{
2164 int del_posn;
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;
2170 break;
2171 }
2172 }
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);
2176 return;
2177 }
2178
2179 char *unmapped_port = system_mappings[del_posn];
2180
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));
2187
2188 try {
2189 user_unmap(system_port);
2190 } catch (...) {
2191 // prevent from memory leak
2192 Free(unmapped_port);
2193 throw;
2194 }
2195
2196 TTCN_Logger::log_port_misc(
2197 TitanLoggerApi::Port__Misc_reason::port__was__unmapped__from__system,
2198 port_name, SYSTEM_COMPREF, system_port);
2199
2200 Free(unmapped_port);
2201}
2202
2203void PORT::process_connect_listen(const char *local_port,
2204 component remote_component, const char *remote_port,
2205 transport_type_enum transport_type)
2206{
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);
2211 return;
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)
2216 != NULL) {
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);
2220 return;
2221 } else if (port_ptr->lookup_connection_to_compref(remote_component, NULL)
2222 != 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.");
2228 TTCN_warning_end();
2229 }
2230
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 "
2235 "type LOCAL.");
2236 break;
2237 case TRANSPORT_INET_STREAM:
2238 port_ptr->connect_listen_inet_stream(remote_component, remote_port);
2239 break;
2240 case TRANSPORT_UNIX_STREAM:
2241 port_ptr->connect_listen_unix_stream(remote_component, remote_port);
2242 break;
2243 default:
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);
2247 break;
2248 }
2249}
2250
2251void 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)
2254{
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);
2259 return;
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)
2264 != NULL) {
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);
2268 return;
2269 } else if (port_ptr->lookup_connection_to_compref(remote_component, NULL)
2270 != 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.");
2276 TTCN_warning_end();
2277 }
2278
2279 switch (transport_type) {
2280 case TRANSPORT_LOCAL:
2281 port_ptr->connect_local(remote_component, remote_port);
2282 break;
2283 case TRANSPORT_INET_STREAM:
2284 case TRANSPORT_UNIX_STREAM:
2285 port_ptr->connect_stream(remote_component, remote_port, transport_type,
2286 text_buf);
2287 break;
2288 default:
2289 TTCN_Communication::send_connect_error(local_port, remote_component,
2290 remote_port, "Message CONNECT refers to invalid transport type "
2291 "(%d).", transport_type);
2292 break;
2293 }
2294}
2295
2296void PORT::process_disconnect(const char *local_port,
2297 component remote_component, const char *remote_port)
2298{
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);
2303 return;
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,
2307 remote_port);
2308 }
2309 port_connection *conn_ptr = port_ptr->lookup_connection(remote_component,
2310 remote_port);
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);
2318 } else {
2319 TTCN_Communication::send_disconnected(local_port, remote_component,
2320 remote_port);
2321 }
2322 return;
2323 }
2324 switch (conn_ptr->transport_type) {
2325 case TRANSPORT_LOCAL:
2326 port_ptr->disconnect_local(conn_ptr);
2327 break;
2328 case TRANSPORT_INET_STREAM:
2329 case TRANSPORT_UNIX_STREAM:
2330 port_ptr->disconnect_stream(conn_ptr);
2331 break;
2332 default:
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);
2337 }
2338}
2339
2340void PORT::make_local_connection(const char *src_port, const char *dest_port)
2341{
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,
2347 dest_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);
2351 return;
2352 } else if (src_ptr->lookup_connection_to_compref(MTC_COMPREF, NULL)
2353 != 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);
2357 }
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,
2363 src_port);
2364 src_ptr->add_local_connection(dest_ptr);
2365 if (src_ptr != dest_ptr) dest_ptr->add_local_connection(src_ptr);
2366}
2367
2368void PORT::terminate_local_connection(const char *src_port,
2369 const char *dest_port)
2370{
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,
2376 dest_port);
2377 port_connection *conn_ptr = src_ptr->lookup_connection(MTC_COMPREF,
2378 dest_port);
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);
2392 }
2393 } else {
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);
2405 }
2406 TTCN_warning("Port %s does not have connection with local port %s. "
2407 "Disconnect operation had no effect.", src_port, dest_port);
2408 }
2409}
2410
2411void PORT::map_port(const char *component_port, const char *system_port)
2412{
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);
2419}
2420
2421void PORT::unmap_port(const char *component_port, const char *system_port)
2422{
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);
2429}
0a1610f4 2430
2431bool PORT::check_port_state(const CHARSTRING& type) const
2432{
2433 if (type == "Started") {
2434 return is_started;
2435 } else if (type == "Halted") {
2436 return is_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);
2445 }
2446 TTCN_error("%s is not an allowed parameter of checkstate().", (const char*)type);
2447}
2448
2449bool PORT::any_check_port_state(const CHARSTRING& type)
2450{
2451 bool result = false;
2452 for (PORT *port = list_head; port != NULL; port = port->list_next) {
2453 result = port->check_port_state(type);
2454 if (result) {
2455 return true;
2456 }
2457 }
2458 return false;
2459}
2460
2461bool PORT::all_check_port_state(const CHARSTRING& type)
2462{
2463 bool result = true;
2464 for (PORT *port = list_head; port != NULL && result; port = port->list_next) {
2465 result = port->check_port_state(type);
2466 }
2467 return result;
2468}
This page took 0.11377 seconds and 5 git commands to generate.