fc22f55ecc93d5af1f74411f4ab378edfb2b02c5
[deliverable/titan.core.git] / core / Port.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 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 #include "Port.hh"
9
10 #include <string.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <sys/un.h>
19
20 #include "../common/platform.h"
21
22 #include "../common/memory.h"
23 #include "Component.hh"
24 #include "Error.hh"
25 #include "Logger.hh"
26 #include "Event_Handler.hh"
27 #include "Fd_And_Timeout_User.hh"
28 #include "Snapshot.hh"
29 #include "Communication.hh"
30 #include "Runtime.hh"
31 #include "Octetstring.hh"
32 #include "TitanLoggerApi.hh"
33
34 // maximum number of iterations for binding the UNIX server socket
35 #define UNIX_BIND_MAX_ITER 100
36
37 #include "../common/dbgnew.hh"
38
39 PORT *PORT::list_head = NULL, *PORT::list_tail = NULL;
40
41 void PORT::add_to_list()
42 {
43 // check for duplicate names
44 for (PORT *p = list_head; p != NULL; p = p->list_next) {
45 // do nothing if this is already a member of the list
46 if (p == this) return;
47 else if (!strcmp(p->port_name, port_name))
48 TTCN_error("Internal error: There are more than one ports with "
49 "name %s.", port_name);
50 }
51 // append this to the list
52 if (list_head == NULL) list_head = this;
53 else if (list_tail != NULL) list_tail->list_next = this;
54 list_prev = list_tail;
55 list_next = NULL;
56 list_tail = this;
57 }
58
59 void PORT::remove_from_list()
60 {
61 if (list_prev != NULL) list_prev->list_next = list_next;
62 else if (list_head == this) list_head = list_next;
63 if (list_next != NULL) list_next->list_prev = list_prev;
64 else if (list_tail == this) list_tail = list_prev;
65 list_prev = NULL;
66 list_next = NULL;
67 }
68
69 PORT *PORT::lookup_by_name(const char *par_port_name)
70 {
71 for (PORT *port = list_head; port != NULL; port = port->list_next)
72 if (!strcmp(par_port_name, port->port_name)) return port;
73 return NULL;
74 }
75
76 struct PORT::port_parameter {
77 component_id_t component_id;
78 char *port_name;
79 char *parameter_name;
80 char *parameter_value;
81 struct port_parameter *next_par;
82 } *PORT::parameter_head = NULL, *PORT::parameter_tail = NULL;
83
84 void PORT::apply_parameter(port_parameter *par_ptr)
85 {
86 if (par_ptr->port_name != NULL) {
87 // the parameter refers to a specific port
88 PORT *port = lookup_by_name(par_ptr->port_name);
89 if (port != NULL) port->set_parameter(par_ptr->parameter_name,
90 par_ptr->parameter_value);
91 } else {
92 // the parameter refers to all ports (*)
93 for (PORT *port = list_head; port != NULL; port = port->list_next)
94 port->set_parameter(par_ptr->parameter_name,
95 par_ptr->parameter_value);
96 }
97 }
98
99 void PORT::set_system_parameters(const char *system_port)
100 {
101 for (port_parameter *par = parameter_head; par != NULL; par = par->next_par)
102 if (par->component_id.id_selector == COMPONENT_ID_SYSTEM &&
103 (par->port_name == NULL || !strcmp(par->port_name, system_port)))
104 set_parameter(par->parameter_name, par->parameter_value);
105 }
106
107 void PORT::add_parameter(const component_id_t& component_id,
108 const char *par_port_name, const char *parameter_name,
109 const char *parameter_value)
110 {
111 port_parameter *new_par = new port_parameter;
112
113 new_par->component_id.id_selector = component_id.id_selector;
114 switch (component_id.id_selector) {
115 case COMPONENT_ID_NAME:
116 new_par->component_id.id_name = mcopystr(component_id.id_name);
117 break;
118 case COMPONENT_ID_COMPREF:
119 new_par->component_id.id_compref = component_id.id_compref;
120 break;
121 default:
122 break;
123 }
124
125 if (par_port_name == NULL) new_par->port_name = NULL;
126 else new_par->port_name = mcopystr(par_port_name);
127 new_par->parameter_name = mcopystr(parameter_name);
128 new_par->parameter_value = mcopystr(parameter_value);
129
130 new_par->next_par = NULL;
131 if (parameter_head == NULL) parameter_head = new_par;
132 if (parameter_tail != NULL) parameter_tail->next_par = new_par;
133 parameter_tail = new_par;
134 }
135
136 void PORT::clear_parameters()
137 {
138 while (parameter_head != NULL) {
139 port_parameter *next_par = parameter_head->next_par;
140 if (parameter_head->component_id.id_selector == COMPONENT_ID_NAME)
141 Free(parameter_head->component_id.id_name);
142 Free(parameter_head->port_name);
143 Free(parameter_head->parameter_name);
144 Free(parameter_head->parameter_value);
145 delete parameter_head;
146 parameter_head = next_par;
147 }
148 }
149
150 void PORT::set_parameters(component component_reference,
151 const char *component_name)
152 {
153 for (port_parameter *par = parameter_head; par != NULL; par = par->next_par)
154 switch (par->component_id.id_selector) {
155 case COMPONENT_ID_NAME:
156 if (component_name != NULL &&
157 !strcmp(par->component_id.id_name, component_name))
158 apply_parameter(par);
159 break;
160 case COMPONENT_ID_COMPREF:
161 if (par->component_id.id_compref == component_reference)
162 apply_parameter(par);
163 break;
164 case COMPONENT_ID_ALL:
165 apply_parameter(par);
166 break;
167 default:
168 break;
169 }
170 }
171
172 enum connection_data_type_enum {
173 CONN_DATA_LAST = 0, CONN_DATA_MESSAGE = 1, CONN_DATA_CALL = 2,
174 CONN_DATA_REPLY = 3, CONN_DATA_EXCEPTION = 4
175 };
176
177 enum connection_state_enum {
178 CONN_IDLE, CONN_LISTENING, CONN_CONNECTED, CONN_LAST_MSG_SENT,
179 CONN_LAST_MSG_RCVD
180 };
181
182 struct port_connection : public Fd_Event_Handler {
183 PORT *owner_port;
184 connection_state_enum connection_state;
185 component remote_component;
186 char *remote_port;
187 transport_type_enum transport_type;
188 union {
189 struct {
190 PORT *port_ptr;
191 } local;
192 struct {
193 int comm_fd;
194 Text_Buf *incoming_buf;
195 } stream;
196 };
197 struct port_connection *list_prev, *list_next;
198 OCTETSTRING sliding_buffer;
199
200 virtual void Handle_Fd_Event(int fd,
201 boolean is_readable, boolean is_writeable, boolean is_error);
202 virtual ~port_connection();
203 virtual void log() const;
204 };
205
206 void port_connection::Handle_Fd_Event(int,
207 boolean is_readable, boolean /*is_writeable*/, boolean /*is_error*/)
208 {
209 // Note event for connection with TRANSPORT_LOCAL transport_type
210 // may not arrive.
211 if (transport_type == TRANSPORT_INET_STREAM
212 || transport_type == TRANSPORT_UNIX_STREAM
213 ) {
214 if (is_readable) {
215 if (connection_state == CONN_LISTENING)
216 owner_port->handle_incoming_connection(this);
217 else owner_port->handle_incoming_data(this);
218 }
219 } else
220 TTCN_error("Internal error: Invalid transport type (%d) in port "
221 "connection between %s and %d:%s.", transport_type,
222 owner_port->get_name(), remote_component, remote_port);
223 }
224
225 void port_connection::log() const
226 {
227 TTCN_Logger::log_event("port connection between ");
228 owner_port->log(); TTCN_Logger::log_event(" and ");
229 TTCN_Logger::log_event(remote_component); TTCN_Logger::log_event(":");
230 TTCN_Logger::log_event("%s", remote_port);
231 }
232
233 port_connection::~port_connection()
234 {
235 if (transport_type == TRANSPORT_INET_STREAM
236 || transport_type == TRANSPORT_UNIX_STREAM
237 ) {
238 if (stream.comm_fd != -1) {
239 TTCN_warning_begin("Internal Error: File descriptor %d not "
240 "closed/removed in ", stream.comm_fd); log();
241 TTCN_warning_end();
242 }
243 }
244 sliding_buffer.clean_up();
245 }
246
247 PORT::PORT(const char *par_port_name)
248 {
249 port_name = par_port_name != NULL ? par_port_name : "<unknown>";
250 is_active = FALSE;
251 is_started = FALSE;
252 is_halted = FALSE;
253 list_prev = NULL;
254 list_next = NULL;
255
256 connection_list_head = NULL;
257 connection_list_tail = NULL;
258 n_system_mappings = 0;
259 system_mappings = NULL;
260 }
261
262 PORT::~PORT()
263 {
264 if (is_active) deactivate_port();
265 }
266
267 void PORT::set_name(const char * name)
268 {
269 if (name == NULL) TTCN_error("Internal error: Setting an "
270 "invalid name for a single element of a port array.");
271 port_name = name;
272 }
273
274 void PORT::log() const
275 {
276 TTCN_Logger::log_event("port %s", port_name);
277 }
278
279 void PORT::activate_port()
280 {
281 if (!is_active) {
282 add_to_list();
283 is_active = TRUE;
284 msg_head_count = 0;
285 msg_tail_count = 0;
286 proc_head_count = 0;
287 proc_tail_count = 0;
288 }
289 }
290
291 void PORT::deactivate_port()
292 {
293 if (is_active) {
294 /* In order to proceed with the deactivation we must ignore the
295 * following errors:
296 * - errors in user code of Test Port (i.e. user_stop, user_unmap)
297 * - failures when sending messages to MC (the link may be down)
298 */
299 boolean is_parallel = !TTCN_Runtime::is_single();
300 // terminate all connections
301 while (connection_list_head != NULL) {
302 TTCN_Logger::log_port_misc(
303 TitanLoggerApi::Port__Misc_reason::removing__unterminated__connection,
304 port_name,
305 connection_list_head->remote_component, connection_list_head->remote_port);
306 if (is_parallel) {
307 try {
308 TTCN_Communication::send_disconnected(port_name,
309 connection_list_head->remote_component,
310 connection_list_head->remote_port);
311 } catch (const TC_Error&) { }
312 }
313 remove_connection(connection_list_head);
314 }
315 // terminate all mappings
316 while (n_system_mappings > 0) {
317 // we must make a copy of the string because unmap() will destroy it
318 char *system_port = mcopystr(system_mappings[0]);
319 TTCN_Logger::log_port_misc(
320 TitanLoggerApi::Port__Misc_reason::removing__unterminated__mapping,
321 port_name, NULL_COMPREF, system_port);
322 try {
323 unmap(system_port);
324 } catch (const TC_Error&) { }
325 if (is_parallel) {
326 try {
327 TTCN_Communication::send_unmapped(port_name, system_port);
328 } catch (const TC_Error&) { }
329 }
330 Free(system_port);
331 }
332 // the previous disconnect/unmap operations may generate incoming events
333 // so we should stop and clear the queue after them
334 if (is_started || is_halted) {
335 try {
336 stop();
337 } catch (const TC_Error&) { }
338 }
339 clear_queue();
340 // deactivate all event handlers
341 Fd_And_Timeout_User::remove_all_fds(this);
342 Fd_And_Timeout_User::set_timer(this, 0.0);
343 // File descriptor events of port connections are removed
344 // in remove_connection
345 remove_from_list();
346 is_active = FALSE;
347 }
348 }
349
350 void PORT::deactivate_all()
351 {
352 while (list_head != NULL) list_head->deactivate_port();
353 }
354
355 void PORT::clear()
356 {
357 if (!is_active) TTCN_error("Internal error: Inactive port %s cannot "
358 "be cleared.", port_name);
359 if (!is_started && !is_halted) {
360 TTCN_warning("Performing clear operation on port %s, which is "
361 "already stopped. The operation has no effect.", port_name);
362 }
363 clear_queue();
364 TTCN_Logger::log_port_misc(
365 TitanLoggerApi::Port__Misc_reason::port__was__cleared, port_name);
366 }
367
368 void PORT::all_clear()
369 {
370 for (PORT *port = list_head; port != NULL; port = port->list_next)
371 port->clear();
372 }
373
374 void PORT::start()
375 {
376 if (!is_active) TTCN_error("Internal error: Inactive port %s cannot "
377 "be started.", port_name);
378 if (is_started) {
379 TTCN_warning("Performing start operation on port %s, which is "
380 "already started. The operation will clear the incoming queue.",
381 port_name);
382 clear_queue();
383 } else {
384 if (is_halted) {
385 // the queue might contain old messages which has to be discarded
386 clear_queue();
387 is_halted = FALSE;
388 }
389 user_start();
390 is_started = TRUE;
391 }
392 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::started,
393 port_name);
394 }
395
396 void PORT::all_start()
397 {
398 for (PORT *port = list_head; port != NULL; port = port->list_next)
399 port->start();
400 }
401
402 void PORT::stop()
403 {
404 if (!is_active) TTCN_error("Internal error: Inactive port %s cannot "
405 "be stopped.", port_name);
406 if (is_started) {
407 is_started = FALSE;
408 is_halted = FALSE;
409 user_stop();
410 // dropping all messages from the queue because they cannot be
411 // extracted by receiving operations anymore
412 clear_queue();
413 } else if (is_halted) {
414 is_halted = FALSE;
415 clear_queue();
416 } else {
417 TTCN_warning("Performing stop operation on port %s, which is "
418 "already stopped. The operation has no effect.", port_name);
419 }
420 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::stopped,
421 port_name);
422 }
423
424 void PORT::all_stop()
425 {
426 for (PORT *port = list_head; port != NULL; port = port->list_next)
427 port->stop();
428 }
429
430 void PORT::halt()
431 {
432 if (!is_active) TTCN_error("Internal error: Inactive port %s cannot "
433 "be halted.", port_name);
434 if (is_started) {
435 is_started = FALSE;
436 is_halted = TRUE;
437 user_stop();
438 // keep the messages in the queue
439 } else if (is_halted) {
440 TTCN_warning("Performing halt operation on port %s, which is "
441 "already halted. The operation has no effect.", port_name);
442 } else {
443 TTCN_warning("Performing halt operation on port %s, which is "
444 "already stopped. The operation has no effect.", port_name);
445 }
446 TTCN_Logger::log_port_state(TitanLoggerApi::Port__State_operation::halted,
447 port_name);
448 }
449
450 void PORT::all_halt()
451 {
452 for (PORT *port = list_head; port != NULL; port = port->list_next)
453 port->halt();
454 }
455
456 alt_status PORT::receive(const COMPONENT_template&, COMPONENT *)
457 {
458 TTCN_Logger::log_matching_problem(
459 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types,
460 TitanLoggerApi::MatchingProblemType_operation::receive__,
461 false, false, port_name);
462 return ALT_NO;
463 }
464
465 alt_status PORT::any_receive(const COMPONENT_template& sender_template,
466 COMPONENT *sender_ptr)
467 {
468 if (list_head != NULL) {
469 alt_status ret_val = ALT_NO;
470 for (PORT *port = list_head; port != NULL; port = port->list_next) {
471 switch (port->receive(sender_template, sender_ptr)) {
472 case ALT_YES:
473 return ALT_YES;
474 case ALT_MAYBE:
475 ret_val = ALT_MAYBE;
476 break;
477 case ALT_NO:
478 break;
479 default:
480 TTCN_error("Internal error: Receive operation returned "
481 "unexpected status code on port %s while evaluating "
482 "`any port.receive'.", port->port_name);
483 }
484 }
485 return ret_val;
486 } else {
487 TTCN_Logger::log_matching_problem(
488 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
489 TitanLoggerApi::MatchingProblemType_operation::receive__,
490 true, false);
491 return ALT_NO;
492 }
493 }
494
495 alt_status PORT::check_receive(const COMPONENT_template&, COMPONENT *)
496 {
497 TTCN_Logger::log_matching_problem(
498 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types,
499 TitanLoggerApi::MatchingProblemType_operation::receive__,
500 false, true, port_name);
501 return ALT_NO;
502 }
503
504 alt_status PORT::any_check_receive(const COMPONENT_template& sender_template,
505 COMPONENT *sender_ptr)
506 {
507 if (list_head != NULL) {
508 alt_status ret_val = ALT_NO;
509 for (PORT *port = list_head; port != NULL; port = port->list_next) {
510 switch (port->check_receive(sender_template, sender_ptr)) {
511 case ALT_YES:
512 return ALT_YES;
513 case ALT_MAYBE:
514 ret_val = ALT_MAYBE;
515 break;
516 case ALT_NO:
517 break;
518 default:
519 TTCN_error("Internal error: Check-receive operation returned "
520 "unexpected status code on port %s while evaluating "
521 "`any port.check(receive)'.", port->port_name);
522 }
523 }
524 return ret_val;
525 } else {
526 TTCN_Logger::log_matching_problem(
527 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
528 TitanLoggerApi::MatchingProblemType_operation::receive__,
529 true, true);
530 return ALT_NO;
531 }
532 }
533
534 alt_status PORT::trigger(const COMPONENT_template&, COMPONENT *)
535 {
536 TTCN_Logger::log_matching_problem(
537 TitanLoggerApi::MatchingProblemType_reason::no__incoming__types,
538 TitanLoggerApi::MatchingProblemType_operation::trigger__,
539 false, false, port_name);
540 return ALT_NO;
541 }
542
543 alt_status PORT::any_trigger(const COMPONENT_template& sender_template,
544 COMPONENT *sender_ptr)
545 {
546 if (list_head != NULL) {
547 alt_status ret_val = ALT_NO;
548 for (PORT *port = list_head; port != NULL; port = port->list_next) {
549 switch (port->trigger(sender_template, sender_ptr)) {
550 case ALT_YES:
551 return ALT_YES;
552 case ALT_MAYBE:
553 ret_val = ALT_MAYBE;
554 break;
555 case ALT_NO:
556 break;
557 case ALT_REPEAT:
558 return ALT_REPEAT;
559 default:
560 TTCN_error("Internal error: Trigger operation returned "
561 "unexpected status code on port %s while evaluating "
562 "`any port.trigger'.", port->port_name);
563 }
564 }
565 return ret_val;
566 } else {
567 TTCN_Logger::log_matching_problem(
568 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
569 TitanLoggerApi::MatchingProblemType_operation::trigger__,
570 true, false);
571 return ALT_NO;
572 }
573 }
574
575 alt_status PORT::getcall(const COMPONENT_template&, COMPONENT *)
576 {
577 // ToDo:Unnecessary log matching problem warning removed.
578 // Question: does it unnecessary?
579 // TTCN_Logger::log_matching_problem(
580 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
581 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
582 // false, false, port_name);
583 return ALT_NO;
584 }
585
586 alt_status PORT::any_getcall(const COMPONENT_template& sender_template,
587 COMPONENT *sender_ptr)
588 {
589 if (list_head != NULL) {
590 alt_status ret_val = ALT_NO;
591 for (PORT *port = list_head; port != NULL; port = port->list_next) {
592 switch (port->getcall(sender_template, sender_ptr)) {
593 case ALT_YES:
594 return ALT_YES;
595 case ALT_MAYBE:
596 ret_val = ALT_MAYBE;
597 break;
598 case ALT_NO:
599 break;
600 default:
601 TTCN_error("Internal error: Getcall operation returned "
602 "unexpected status code on port %s while evaluating "
603 "`any port.getcall'.", port->port_name);
604 }
605 }
606 return ret_val;
607 } else {
608 TTCN_Logger::log_matching_problem(
609 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
610 TitanLoggerApi::MatchingProblemType_operation::getcall__,
611 true, false);
612 return ALT_NO;
613 }
614 }
615
616 alt_status PORT::check_getcall(const COMPONENT_template&, COMPONENT *)
617 {
618 // ToDo:Unnecessary log matching problem warning removed.
619 // Question: does it unnecessary
620 // TTCN_Logger::log_matching_problem(
621 // TitanLoggerApi::MatchingProblemType_reason::no__incoming__signatures,
622 // TitanLoggerApi::MatchingProblemType_operation::getcall__,
623 // false, false, port_name);
624 return ALT_NO;
625 }
626
627 alt_status PORT::any_check_getcall(const COMPONENT_template& sender_template,
628 COMPONENT *sender_ptr)
629 {
630 if (list_head != NULL) {
631 alt_status ret_val = ALT_NO;
632 for (PORT *port = list_head; port != NULL; port = port->list_next) {
633 switch (port->check_getcall(sender_template, sender_ptr)) {
634 case ALT_YES:
635 return ALT_YES;
636 case ALT_MAYBE:
637 ret_val = ALT_MAYBE;
638 break;
639 case ALT_NO:
640 break;
641 default:
642 TTCN_error("Internal error: Check-getcall operation returned "
643 "unexpected status code on port %s while evaluating "
644 "`any port.check(getcall)'.", port->port_name);
645 }
646 }
647 return ret_val;
648 } else {
649 TTCN_Logger::log_matching_problem(
650 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
651 TitanLoggerApi::MatchingProblemType_operation::getcall__,
652 true, true);
653 return ALT_NO;
654 }
655 }
656
657 alt_status PORT::getreply(const COMPONENT_template&, COMPONENT *)
658 {
659 // ToDo:Unnecessary log matching problem warning removed.
660 // Question: does it unnecessary
661 // TTCN_Logger::log_matching_problem(
662 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
663 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
664 // false, false, port_name);
665 return ALT_NO;
666 }
667
668 alt_status PORT::any_getreply(const COMPONENT_template& sender_template,
669 COMPONENT *sender_ptr)
670 {
671 if (list_head != NULL) {
672 alt_status ret_val = ALT_NO;
673 for (PORT *port = list_head; port != NULL; port = port->list_next) {
674 switch (port->getreply(sender_template, sender_ptr)) {
675 case ALT_YES:
676 return ALT_YES;
677 case ALT_MAYBE:
678 ret_val = ALT_MAYBE;
679 break;
680 case ALT_NO:
681 break;
682 default:
683 TTCN_error("Internal error: Getreply operation returned "
684 "unexpected status code on port %s while evaluating "
685 "`any port.getreply'.", port->port_name);
686 }
687 }
688 return ret_val;
689 } else {
690 TTCN_Logger::log_matching_problem(
691 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
692 TitanLoggerApi::MatchingProblemType_operation::getreply__,
693 true, false);
694 return ALT_NO;
695 }
696 }
697
698 alt_status PORT::check_getreply(const COMPONENT_template&, COMPONENT *)
699 {
700 // ToDo:Unnecessary log matching problem warning removed.
701 // Question: does it unnecessary
702 // TTCN_Logger::log_matching_problem(
703 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures,
704 // TitanLoggerApi::MatchingProblemType_operation::getreply__,
705 // false, true, port_name);
706 return ALT_NO;
707 }
708
709 alt_status PORT::any_check_getreply(const COMPONENT_template& sender_template,
710 COMPONENT *sender_ptr)
711 {
712 if (list_head != NULL) {
713 alt_status ret_val = ALT_NO;
714 for (PORT *port = list_head; port != NULL; port = port->list_next) {
715 switch (port->check_getreply(sender_template, sender_ptr)) {
716 case ALT_YES:
717 return ALT_YES;
718 case ALT_MAYBE:
719 ret_val = ALT_MAYBE;
720 break;
721 case ALT_NO:
722 break;
723 default:
724 TTCN_error("Internal error: Check-getreply operation returned "
725 "unexpected status code on port %s while evaluating "
726 "`any port.check(getreply)'.", port->port_name);
727 }
728 }
729 return ret_val;
730 } else {
731 TTCN_Logger::log_matching_problem(
732 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
733 TitanLoggerApi::MatchingProblemType_operation::getreply__,
734 true, true);
735 return ALT_NO;
736 }
737 }
738
739 alt_status PORT::get_exception(const COMPONENT_template&, COMPONENT *)
740 {
741 // ToDo:Unnecessary log matching problem warning removed.
742 // Question: does it unnecessary
743 // TTCN_Logger::log_matching_problem(
744 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
745 // TitanLoggerApi::MatchingProblemType_operation::catch__,
746 // false, false, port_name);
747 return ALT_NO;
748 }
749
750 alt_status PORT::any_catch(const COMPONENT_template& sender_template,
751 COMPONENT *sender_ptr)
752 {
753 if (list_head != NULL) {
754 alt_status ret_val = ALT_NO;
755 for (PORT *port = list_head; port != NULL; port = port->list_next) {
756 switch (port->get_exception(sender_template, sender_ptr)) {
757 case ALT_YES:
758 return ALT_YES;
759 case ALT_MAYBE:
760 ret_val = ALT_MAYBE;
761 break;
762 case ALT_NO:
763 break;
764 default:
765 TTCN_error("Internal error: Catch operation returned "
766 "unexpected status code on port %s while evaluating "
767 "`any port.catch'.", port->port_name);
768 }
769 }
770 return ret_val;
771 } else {
772 TTCN_Logger::log_matching_problem(
773 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
774 TitanLoggerApi::MatchingProblemType_operation::catch__,
775 true, false);
776 return ALT_NO;
777 }
778 }
779
780 alt_status PORT::check_catch(const COMPONENT_template& ,
781 COMPONENT *)
782 {
783 // ToDo:Unnecessary log matching problem warning removed.
784 // Question: does it unnecessary
785 // TTCN_Logger::log_matching_problem(
786 // TitanLoggerApi::MatchingProblemType_reason::no__outgoing__blocking__signatures__that__support__exceptions,
787 // TitanLoggerApi::MatchingProblemType_operation::catch__,
788 // false, true, port_name);
789 return ALT_NO;
790 }
791
792 alt_status PORT::any_check_catch(const COMPONENT_template& sender_template,
793 COMPONENT *sender_ptr)
794 {
795 if (list_head != NULL) {
796 alt_status ret_val = ALT_NO;
797 for (PORT *port = list_head; port != NULL; port = port->list_next) {
798 switch (port->check_catch(sender_template, sender_ptr)) {
799 case ALT_YES:
800 return ALT_YES;
801 case ALT_MAYBE:
802 ret_val = ALT_MAYBE;
803 break;
804 case ALT_NO:
805 break;
806 default:
807 TTCN_error("Internal error: Check-catch operation returned "
808 "unexpected status code on port %s while evaluating "
809 "`any port.check(catch)'.", port->port_name);
810 }
811 }
812 return ret_val;
813 } else {
814 TTCN_Logger::log_matching_problem(
815 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
816 TitanLoggerApi::MatchingProblemType_operation::catch__,
817 true, true);
818 return ALT_NO;
819 }
820 }
821
822 alt_status PORT::check(const COMPONENT_template& sender_template,
823 COMPONENT *sender_ptr)
824 {
825 alt_status ret_val = ALT_NO;
826 // the procedure-based queue must have the higher priority
827 switch (check_getcall(sender_template, sender_ptr)) {
828 case ALT_YES:
829 return ALT_YES;
830 case ALT_MAYBE:
831 ret_val = ALT_MAYBE;
832 break;
833 case ALT_NO:
834 break;
835 default:
836 TTCN_error("Internal error: Check-getcall operation returned "
837 "unexpected status code on port %s.", port_name);
838 }
839 if (ret_val != ALT_MAYBE) {
840 // don't try getreply if the procedure-based queue is empty
841 // (i.e. check_getcall() returned ALT_MAYBE)
842 switch (check_getreply(sender_template, sender_ptr)) {
843 case ALT_YES:
844 return ALT_YES;
845 case ALT_MAYBE:
846 ret_val = ALT_MAYBE;
847 break;
848 case ALT_NO:
849 break;
850 default:
851 TTCN_error("Internal error: Check-getreply operation returned "
852 "unexpected status code on port %s.", port_name);
853 }
854 }
855 if (ret_val != ALT_MAYBE) {
856 // don't try catch if the procedure-based queue is empty
857 // (i.e. check_getcall() or check_getreply() returned ALT_MAYBE)
858 switch (check_catch(sender_template, sender_ptr)) {
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-catch operation returned "
868 "unexpected status code on port %s.", port_name);
869 }
870 }
871 switch (check_receive(sender_template, sender_ptr)) {
872 case ALT_YES:
873 return ALT_YES;
874 case ALT_MAYBE:
875 ret_val = ALT_MAYBE;
876 break;
877 case ALT_NO:
878 break;
879 default:
880 TTCN_error("Internal error: Check-receive operation returned "
881 "unexpected status code on port %s.", port_name);
882 }
883 return ret_val;
884 }
885
886 alt_status PORT::any_check(const COMPONENT_template& sender_template,
887 COMPONENT *sender_ptr)
888 {
889 if (list_head != NULL) {
890 alt_status ret_val = ALT_NO;
891 for (PORT *port = list_head; port != NULL; port = port->list_next) {
892 switch (port->check(sender_template, sender_ptr)) {
893 case ALT_YES:
894 return ALT_YES;
895 case ALT_MAYBE:
896 ret_val = ALT_MAYBE;
897 break;
898 case ALT_NO:
899 break;
900 default:
901 TTCN_error("Internal error: Check operation returned "
902 "unexpected status code on port %s while evaluating "
903 "`any port.check'.", port->port_name);
904 }
905 }
906 return ret_val;
907 } else {
908 TTCN_Logger::log_matching_problem(
909 TitanLoggerApi::MatchingProblemType_reason::component__has__no__ports,
910 TitanLoggerApi::MatchingProblemType_operation::check__,
911 true, false);
912 return ALT_NO;
913 }
914 }
915
916 void PORT::set_parameter(const char *parameter_name, const char *)
917 {
918 TTCN_warning("Test port parameter %s is not supported on port %s.",
919 parameter_name, port_name);
920 }
921
922 void PORT::append_to_msg_queue(msg_queue_item_base* new_item)
923 {
924 new_item->next_item = NULL;
925 if (msg_queue_tail == NULL) msg_queue_head = new_item;
926 else msg_queue_tail->next_item = new_item;
927 msg_queue_tail = new_item;
928 }
929
930 void PORT::Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable,
931 boolean is_error)
932 {
933 // The port intends to use the finer granularity event handler functions
934 if (is_error) {
935 Handle_Fd_Event_Error(fd);
936 if (!is_writable && !is_readable) return;
937 fd_event_type_enum event = Fd_And_Timeout_User::getCurReceivedEvent();
938 if ((event & FD_EVENT_WR) == 0) is_writable = FALSE;
939 if ((event & FD_EVENT_RD) == 0) is_readable = FALSE;
940 }
941 if (is_writable) {
942 Handle_Fd_Event_Writable(fd);
943 if (!is_readable) return;
944 if ((Fd_And_Timeout_User::getCurReceivedEvent() & FD_EVENT_RD) == 0)
945 return;
946 }
947 if (is_readable)
948 Handle_Fd_Event_Readable(fd);
949 }
950
951 void PORT::Handle_Fd_Event_Error(int)
952 {
953 // Silently ignore
954 // A port need not wait for error events
955 // Note: error events always cause event handler invocation
956 }
957
958 void PORT::Handle_Fd_Event_Writable(int)
959 {
960 TTCN_error("There is no Handle_Fd_Event_Writable member function "
961 "implemented in port %s. "
962 "This method or the Handle_Fd_Event method has to be implemented in "
963 "the port if the port waits for any file descriptor to be writable - "
964 "unless the port uses Install_Handler to specify the file descriptor "
965 "and timeout events for which the port waits.", port_name);
966 }
967
968 void PORT::Handle_Fd_Event_Readable(int)
969 {
970 TTCN_error("There is no Handle_Fd_Event_Readable member function "
971 "implemented in port %s. "
972 "This method or the Handle_Fd_Event method has to be implemented in "
973 "the port if the port waits for any file descriptor to be readable - "
974 "unless the port uses Install_Handler to specify the file descriptor "
975 "and timeout events for which the port waits.", port_name);
976 }
977
978 void PORT::Handle_Timeout(double /*time_since_last_call*/)
979 {
980 TTCN_error("There is no Handle_Timeout member function implemented in "
981 "port %s. "
982 "This method has to be implemented in the port if the port waits for "
983 "timeouts unless the port uses Install_Handler to specify the timeout.",
984 port_name);
985 }
986
987 void PORT::Event_Handler(const fd_set * /*read_fds*/, const fd_set * /*write_fds*/,
988 const fd_set * /*error_fds*/, double /*time_since_last_call*/)
989 {
990 TTCN_error("There is no Event_Handler implemented in port %s. "
991 "Event_Handler has to be implemented in the port if "
992 "Install_Handler is used to specify the file descriptor and timeout "
993 "events for which the port waits.", port_name);
994 }
995
996 void PORT::Handler_Add_Fd(int fd, Fd_Event_Type event_mask)
997 {
998 Fd_And_Timeout_User::add_fd(fd, this,
999 static_cast<fd_event_type_enum>(
1000 static_cast<int>(event_mask)));
1001 }
1002
1003 void PORT::Handler_Add_Fd_Read(int fd)
1004 {
1005 Fd_And_Timeout_User::add_fd(fd, this, FD_EVENT_RD);
1006 }
1007
1008 void PORT::Handler_Add_Fd_Write(int fd)
1009 {
1010 Fd_And_Timeout_User::add_fd(fd, this, FD_EVENT_WR);
1011 }
1012
1013 void PORT::Handler_Remove_Fd(int fd, Fd_Event_Type event_mask)
1014 {
1015 Fd_And_Timeout_User::remove_fd(fd, this,
1016 static_cast<fd_event_type_enum>(
1017 static_cast<int>(event_mask)));
1018 }
1019
1020 void PORT::Handler_Remove_Fd_Read(int fd)
1021 {
1022 Fd_And_Timeout_User::remove_fd(fd, this, FD_EVENT_RD);
1023 }
1024
1025 void PORT::Handler_Remove_Fd_Write(int fd)
1026 {
1027 Fd_And_Timeout_User::remove_fd(fd, this, FD_EVENT_WR);
1028 }
1029
1030 void PORT::Handler_Set_Timer(double call_interval, boolean is_timeout,
1031 boolean call_anyway, boolean is_periodic)
1032 {
1033 Fd_And_Timeout_User::set_timer(this, call_interval, is_timeout, call_anyway,
1034 is_periodic);
1035 }
1036
1037 void PORT::Install_Handler(const fd_set *read_fds, const fd_set *write_fds,
1038 const fd_set *error_fds, double call_interval)
1039 {
1040 if (!is_active) TTCN_error("Event handler cannot be installed for "
1041 "inactive port %s.", port_name);
1042
1043 if ((long) FdMap::getFdLimit() > (long) FD_SETSIZE) {
1044 static bool once = true;
1045 if (once) {
1046 TTCN_warning("The maximum number of open file descriptors (%i)"
1047 " is greater than FD_SETSIZE (%li)."
1048 " Ensure that Test Ports using Install_Handler do not try to"
1049 " wait for events of file descriptors with values greater than"
1050 " FD_SETSIZE (%li)."
1051 " (Current caller of Install_Handler is \"%s\")",
1052 FdMap::getFdLimit(), (long) FD_SETSIZE, (long) FD_SETSIZE,
1053 port_name);
1054 }
1055 once = false;
1056 }
1057
1058 Fd_And_Timeout_User::set_fds_with_fd_sets(this, read_fds, write_fds,
1059 error_fds);
1060 Fd_And_Timeout_User::set_timer(this, call_interval);
1061 }
1062
1063 void PORT::Uninstall_Handler()
1064 {
1065 Fd_And_Timeout_User::remove_all_fds(this);
1066 Fd_And_Timeout_User::set_timer(this, 0.0);
1067 }
1068
1069 void PORT::user_map(const char *)
1070 {
1071
1072 }
1073
1074 void PORT::user_unmap(const char *)
1075 {
1076
1077 }
1078
1079 void PORT::user_start()
1080 {
1081
1082 }
1083
1084 void PORT::user_stop()
1085 {
1086
1087 }
1088
1089 void PORT::clear_queue()
1090 {
1091
1092 }
1093
1094 component PORT::get_default_destination()
1095 {
1096 if (connection_list_head != NULL) {
1097 if (n_system_mappings > 0) TTCN_error("Port %s has both connection(s) "
1098 "and mapping(s). Message can be sent on it only with explicit "
1099 "addressing.", port_name);
1100 else if (connection_list_head->list_next != NULL) TTCN_error("Port %s "
1101 "has more than one active connections. Message can be sent on it "
1102 "only with explicit addressing.", port_name);
1103 return connection_list_head->remote_component;
1104 } else {
1105 if (n_system_mappings > 1) {
1106 TTCN_error("Port %s has more than one mappings. Message cannot "
1107 "be sent on it to system.", port_name);
1108 } else if (n_system_mappings < 1) {
1109 TTCN_error("Port %s has neither connections nor mappings. "
1110 "Message cannot be sent on it.", port_name);
1111 }
1112 return SYSTEM_COMPREF;
1113 }
1114 }
1115
1116 void PORT::prepare_message(Text_Buf& outgoing_buf, const char *message_type)
1117 {
1118 outgoing_buf.push_int(CONN_DATA_MESSAGE);
1119 outgoing_buf.push_string(message_type);
1120 }
1121
1122 void PORT::prepare_call(Text_Buf& outgoing_buf, const char *signature_name)
1123 {
1124 outgoing_buf.push_int(CONN_DATA_CALL);
1125 outgoing_buf.push_string(signature_name);
1126 }
1127
1128 void PORT::prepare_reply(Text_Buf& outgoing_buf, const char *signature_name)
1129 {
1130 outgoing_buf.push_int(CONN_DATA_REPLY);
1131 outgoing_buf.push_string(signature_name);
1132 }
1133
1134 void PORT::prepare_exception(Text_Buf& outgoing_buf, const char *signature_name)
1135 {
1136 outgoing_buf.push_int(CONN_DATA_EXCEPTION);
1137 outgoing_buf.push_string(signature_name);
1138 }
1139
1140 void PORT::send_data(Text_Buf &outgoing_buf,
1141 const COMPONENT& destination_component)
1142 {
1143 if (!destination_component.is_bound()) TTCN_error("Internal error: "
1144 "The destination component reference is unbound when sending data on "
1145 "port %s.", port_name);
1146 component destination_compref = (component)destination_component;
1147 boolean is_unique;
1148 port_connection *conn_ptr =
1149 lookup_connection_to_compref(destination_compref, &is_unique);
1150 if (conn_ptr == NULL)
1151 TTCN_error("Data cannot be sent on port %s to component %d "
1152 "because there is no connection towards component %d.", port_name,
1153 destination_compref, destination_compref);
1154 else if (!is_unique)
1155 TTCN_error("Data cannot be sent on port %s to component %d "
1156 "because there are more than one connections towards component "
1157 "%d.", port_name, destination_compref, destination_compref);
1158 else if (conn_ptr->connection_state != CONN_CONNECTED)
1159 TTCN_error("Data cannot be sent on port %s to component %d "
1160 "because the connection is not in active state.",
1161 port_name, destination_compref);
1162 switch (conn_ptr->transport_type) {
1163 case TRANSPORT_LOCAL:
1164 send_data_local(conn_ptr, outgoing_buf);
1165 break;
1166 case TRANSPORT_INET_STREAM:
1167 case TRANSPORT_UNIX_STREAM:
1168 send_data_stream(conn_ptr, outgoing_buf, FALSE);
1169 break;
1170 default:
1171 TTCN_error("Internal error: Invalid transport type (%d) in port "
1172 "connection between %s and %d:%s.", conn_ptr->transport_type,
1173 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
1174 }
1175 }
1176
1177 void PORT::process_data(port_connection *conn_ptr, Text_Buf& incoming_buf)
1178 {
1179 connection_data_type_enum conn_data_type =
1180 (connection_data_type_enum)incoming_buf.pull_int().get_val();
1181 if (conn_data_type != CONN_DATA_LAST) {
1182 switch (conn_ptr->connection_state) {
1183 case CONN_CONNECTED:
1184 case CONN_LAST_MSG_SENT:
1185 break;
1186 case CONN_LAST_MSG_RCVD:
1187 case CONN_IDLE:
1188 TTCN_warning("Data arrived after the indication of connection "
1189 "termination on port %s from %d:%s. Data is ignored.",
1190 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
1191 return;
1192 default:
1193 TTCN_error("Internal error: Connection of port %s with %d:%s has "
1194 "invalid state (%d).", port_name, conn_ptr->remote_component,
1195 conn_ptr->remote_port, conn_ptr->connection_state);
1196 }
1197 char *message_type = incoming_buf.pull_string();
1198 try {
1199 switch (conn_data_type) {
1200 case CONN_DATA_MESSAGE:
1201 if (!process_message(message_type, incoming_buf,
1202 conn_ptr->remote_component, conn_ptr->sliding_buffer)) {
1203 TTCN_error("Port %s does not support incoming message "
1204 "type %s, which has arrived on the connection from "
1205 "%d:%s.", port_name, message_type,
1206 conn_ptr->remote_component, conn_ptr->remote_port);
1207 }
1208 break;
1209 case CONN_DATA_CALL:
1210 if (!process_call(message_type, incoming_buf,
1211 conn_ptr->remote_component)) {
1212 TTCN_error("Port %s does not support incoming call of "
1213 "signature %s, which has arrived on the connection "
1214 "from %d:%s.", port_name, message_type,
1215 conn_ptr->remote_component, conn_ptr->remote_port);
1216 }
1217 break;
1218 case CONN_DATA_REPLY:
1219 if (!process_reply(message_type, incoming_buf,
1220 conn_ptr->remote_component)) {
1221 TTCN_error("Port %s does not support incoming reply of "
1222 "signature %s, which has arrived on the connection "
1223 "from %d:%s.", port_name, message_type,
1224 conn_ptr->remote_component, conn_ptr->remote_port);
1225 }
1226 break;
1227 case CONN_DATA_EXCEPTION:
1228 if (!process_exception(message_type, incoming_buf,
1229 conn_ptr->remote_component)) {
1230 TTCN_error("Port %s does not support incoming exception "
1231 "of signature %s, which has arrived on the connection "
1232 "from %d:%s.", port_name, message_type,
1233 conn_ptr->remote_component, conn_ptr->remote_port);
1234 }
1235 break;
1236 default:
1237 TTCN_error("Internal error: Data with invalid selector (%d) "
1238 "was received on port %s from %d:%s.", conn_data_type,
1239 port_name, conn_ptr->remote_component,
1240 conn_ptr->remote_port);
1241 }
1242 } catch (...) {
1243 // avoid memory leak
1244 delete [] message_type;
1245 throw;
1246 }
1247 delete [] message_type;
1248 } else process_last_message(conn_ptr);
1249 }
1250
1251 boolean PORT::process_message(const char *, Text_Buf&, component, OCTETSTRING&)
1252 {
1253 return FALSE;
1254 }
1255
1256 boolean PORT::process_call(const char *, Text_Buf&, component)
1257 {
1258 return FALSE;
1259 }
1260
1261 boolean PORT::process_reply(const char *, Text_Buf&, component)
1262 {
1263 return FALSE;
1264 }
1265
1266 boolean PORT::process_exception(const char *, Text_Buf&, component)
1267 {
1268 return FALSE;
1269 }
1270
1271 port_connection *PORT::add_connection(component remote_component,
1272 const char *remote_port, transport_type_enum transport_type)
1273 {
1274 port_connection *conn_ptr;
1275 for (conn_ptr = connection_list_head; conn_ptr != NULL;
1276 conn_ptr = conn_ptr->list_next) {
1277 if (conn_ptr->remote_component == remote_component) {
1278 int ret_val = strcmp(conn_ptr->remote_port, remote_port);
1279 if (ret_val == 0) return conn_ptr;
1280 else if (ret_val > 0) break;
1281 } else if (conn_ptr->remote_component > remote_component) break;
1282 }
1283
1284 port_connection *new_conn = new port_connection;
1285 new_conn->owner_port = this;
1286
1287 new_conn->connection_state = CONN_IDLE;
1288 new_conn->remote_component = remote_component;
1289 new_conn->remote_port = mcopystr(remote_port);
1290 new_conn->transport_type = transport_type;
1291 new_conn->sliding_buffer = OCTETSTRING(0, 0);
1292 switch (transport_type) {
1293 case TRANSPORT_LOCAL:
1294 new_conn->local.port_ptr = NULL;
1295 break;
1296 case TRANSPORT_INET_STREAM:
1297 case TRANSPORT_UNIX_STREAM:
1298 new_conn->stream.comm_fd = -1;
1299 new_conn->stream.incoming_buf = NULL;
1300 break;
1301 default:
1302 delete new_conn;
1303 TTCN_error("Internal error: PORT::add_connection(): invalid transport "
1304 "type (%d).", transport_type);
1305 }
1306
1307 new_conn->list_next = conn_ptr;
1308 if (conn_ptr != NULL) {
1309 // new_conn will be inserted before conn_ptr in the ordered list
1310 new_conn->list_prev = conn_ptr->list_prev;
1311 conn_ptr->list_prev = new_conn;
1312 if (new_conn->list_prev != NULL)
1313 new_conn->list_prev->list_next = new_conn;
1314 } else {
1315 // new_conn will be inserted to the end of the list
1316 new_conn->list_prev = connection_list_tail;
1317 if (connection_list_tail != NULL)
1318 connection_list_tail->list_next = new_conn;
1319 connection_list_tail = new_conn;
1320 }
1321 if (conn_ptr == connection_list_head) connection_list_head = new_conn;
1322
1323 return new_conn;
1324 }
1325
1326 void PORT::remove_connection(port_connection *conn_ptr)
1327 {
1328 Free(conn_ptr->remote_port);
1329
1330 switch (conn_ptr->transport_type) {
1331 case TRANSPORT_LOCAL:
1332 break;
1333 case TRANSPORT_INET_STREAM:
1334 case TRANSPORT_UNIX_STREAM:
1335 if (conn_ptr->stream.comm_fd >= 0) {
1336 Fd_And_Timeout_User::remove_fd(conn_ptr->stream.comm_fd, conn_ptr,
1337 FD_EVENT_RD);
1338 if (conn_ptr->connection_state == CONN_LISTENING &&
1339 conn_ptr->transport_type == TRANSPORT_UNIX_STREAM)
1340 unlink_unix_pathname(conn_ptr->stream.comm_fd);
1341 close(conn_ptr->stream.comm_fd);
1342 conn_ptr->stream.comm_fd = -1;
1343 }
1344 delete conn_ptr->stream.incoming_buf;
1345 break;
1346 default:
1347 TTCN_error("Internal error: PORT::remove_connection(): invalid "
1348 "transport type.");
1349 }
1350
1351 if (conn_ptr->list_prev != NULL)
1352 conn_ptr->list_prev->list_next = conn_ptr->list_next;
1353 else if (connection_list_head == conn_ptr)
1354 connection_list_head = conn_ptr->list_next;
1355 if (conn_ptr->list_next != NULL)
1356 conn_ptr->list_next->list_prev = conn_ptr->list_prev;
1357 else if (connection_list_tail == conn_ptr)
1358 connection_list_tail = conn_ptr->list_prev;
1359
1360 delete conn_ptr;
1361 }
1362
1363 port_connection *PORT::lookup_connection_to_compref(
1364 component remote_component, boolean *is_unique)
1365 {
1366 for (port_connection *conn = connection_list_head; conn != NULL;
1367 conn = conn->list_next) {
1368 if (conn->remote_component == remote_component) {
1369 if (is_unique != NULL) {
1370 port_connection *nxt = conn->list_next;
1371 if (nxt != NULL && nxt->remote_component == remote_component)
1372 *is_unique = FALSE;
1373 else *is_unique = TRUE;
1374 }
1375 return conn;
1376 } else if (conn->remote_component > remote_component) break;
1377 }
1378 return NULL;
1379 }
1380
1381 port_connection *PORT::lookup_connection(component remote_component,
1382 const char *remote_port)
1383 {
1384 for (port_connection *conn = connection_list_head; conn != NULL;
1385 conn = conn->list_next) {
1386 if (conn->remote_component == remote_component) {
1387 int ret_val = strcmp(conn->remote_port, remote_port);
1388 if (ret_val == 0) return conn;
1389 else if (ret_val > 0) break;
1390 } else if (conn->remote_component > remote_component) break;
1391 }
1392 return NULL;
1393 }
1394
1395 void PORT::add_local_connection(PORT *other_endpoint)
1396 {
1397 port_connection *conn_ptr = add_connection(self, other_endpoint->port_name,
1398 TRANSPORT_LOCAL);
1399 conn_ptr->connection_state = CONN_CONNECTED;
1400 conn_ptr->local.port_ptr = other_endpoint;
1401 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__established,
1402 port_name, NULL_COMPREF, other_endpoint->port_name);
1403 }
1404
1405 void PORT::remove_local_connection(port_connection *conn_ptr)
1406 {
1407 if (conn_ptr->transport_type != TRANSPORT_LOCAL)
1408 TTCN_error("Internal error: The transport type used by the connection "
1409 "between port %s and %d:%s is not LOCAL.", port_name,
1410 conn_ptr->remote_component, conn_ptr->remote_port);
1411 PORT *other_endpoint = conn_ptr->local.port_ptr;
1412 remove_connection(conn_ptr);
1413 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::local__connection__terminated,
1414 port_name, NULL_COMPREF, other_endpoint->port_name);
1415 }
1416
1417 unsigned int PORT::get_connection_hash(component local_component,
1418 const char *local_port, component remote_component, const char *remote_port)
1419 {
1420 const size_t N = sizeof(unsigned int);
1421 unsigned char hash_buffer[N];
1422
1423 // fill the buffer with an initial pattern
1424 for (size_t i = 0; i < N; i++) hash_buffer[i] = i % 2 ? 0x55 : 0xAA;
1425
1426 // add the PID of the current process to the buffer
1427 pid_t pid = getpid();
1428 for (size_t i = 0; i < sizeof(pid); i++)
1429 hash_buffer[i % N] ^= (pid >> (8 * i)) & 0xFF;
1430
1431 // add the local and remote component reference and port name to the buffer
1432 for (size_t i = 0; i < sizeof(local_component); i++)
1433 hash_buffer[(N - 1) - i % N] ^= (local_component >> (8 * i)) & 0xFF;
1434 for (size_t i = 0; local_port[i] != '\0'; i++)
1435 hash_buffer[(N - 1) - i % N] ^= local_port[i];
1436 for (size_t i = 0; i < sizeof(remote_component); i++)
1437 hash_buffer[i % N] ^= (remote_component >> (8 * i)) & 0xFF;
1438 for (size_t i = 0; remote_port[i] != '\0'; i++)
1439 hash_buffer[i % N] ^= remote_port[i];
1440
1441 // convert the buffer to an integer value
1442 unsigned int ret_val = 0;
1443 for (size_t i = 0; i < N; i++)
1444 ret_val = (ret_val << 8) | hash_buffer[i];
1445 return ret_val;
1446 }
1447
1448 void PORT::unlink_unix_pathname(int socket_fd)
1449 {
1450 struct sockaddr_un local_addr;
1451 // querying the local pathname used by socket_fd
1452 socklen_type addr_len = sizeof(local_addr);
1453 if (getsockname(socket_fd, (struct sockaddr*)&local_addr, &addr_len)) {
1454 TTCN_warning_begin("System call getsockname() failed on UNIX socket "
1455 "file descriptor %d.", socket_fd);
1456 TTCN_Logger::OS_error();
1457 TTCN_Logger::log_event_str(" The associated socket file will not be "
1458 "removed from the file system.");
1459 TTCN_warning_end();
1460 } else if (local_addr.sun_family != AF_UNIX) {
1461 TTCN_warning("System call getsockname() returned invalid address "
1462 "family for UNIX socket file descriptor %d. The associated socket "
1463 "file will not be removed from the file system.", socket_fd);
1464 } else if (unlink(local_addr.sun_path)) {
1465 if (errno != ENOENT) {
1466 TTCN_warning_begin("System call unlink() failed when trying to "
1467 "remove UNIX socket file %s.", local_addr.sun_path);
1468 TTCN_Logger::OS_error();
1469 TTCN_Logger::log_event_str(" The file will remain in the file "
1470 "system.");
1471 TTCN_warning_end();
1472 } else errno = 0;
1473 }
1474 }
1475
1476 void PORT::connect_listen_inet_stream(component remote_component,
1477 const char *remote_port)
1478 {
1479 // creating the TCP server socket
1480 int server_fd = NetworkHandler::socket(TTCN_Communication::get_network_family());
1481 if (server_fd < 0) {
1482 TTCN_Communication::send_connect_error(port_name, remote_component,
1483 remote_port, "Creation of the TCP server socket failed. (%s)",
1484 strerror(errno));
1485 errno = 0;
1486 return;
1487 }
1488
1489 // binding the socket to an ephemeral TCP port
1490 // using the same local IP address as the control connection to MC
1491 IPAddress *local_addr = IPAddress::create_addr(TTCN_Communication::get_network_family());
1492 *local_addr = *TTCN_Communication::get_local_address();
1493 local_addr->set_port(0);
1494 if (bind(server_fd, local_addr->get_addr(), local_addr->get_addr_len())) {
1495 close(server_fd);
1496 TTCN_Communication::send_connect_error(port_name, remote_component,
1497 remote_port, "Binding of server socket to an ephemeral TCP port "
1498 "failed. (%s)", strerror(errno));
1499 errno = 0;
1500 delete local_addr;
1501 return;
1502 }
1503
1504 // zero backlog is enough since we are waiting for only one client
1505 if (listen(server_fd, 0)) {
1506 close(server_fd);
1507 TTCN_Communication::send_connect_error(port_name, remote_component,
1508 remote_port, "Listening on an ephemeral TCP port failed. (%s)",
1509 strerror(errno));
1510 errno = 0;
1511 delete local_addr;
1512 return;
1513 }
1514
1515 // querying the IP address and port number used by the TCP server
1516 if (local_addr->getsockname(server_fd)) {
1517 close(server_fd);
1518 TTCN_Communication::send_connect_error(port_name, remote_component,
1519 remote_port, "System call getsockname() failed on the TCP server "
1520 "socket. (%s)", strerror(errno));
1521 errno = 0;
1522 delete local_addr;
1523 return;
1524 }
1525
1526 if (!TTCN_Communication::set_close_on_exec(server_fd)) {
1527 close(server_fd);
1528 TTCN_Communication::send_connect_error(port_name, remote_component,
1529 remote_port, "Setting the close-on-exec flag failed on the TCP "
1530 "server socket.");
1531 delete local_addr;
1532 return;
1533 }
1534
1535 port_connection *new_connection = add_connection(remote_component,
1536 remote_port, TRANSPORT_INET_STREAM);
1537 new_connection->connection_state = CONN_LISTENING;
1538 new_connection->stream.comm_fd = server_fd;
1539 Fd_And_Timeout_User::add_fd(server_fd, new_connection, FD_EVENT_RD);
1540
1541 TTCN_Communication::send_connect_listen_ack_inet_stream(port_name,
1542 remote_component, remote_port, local_addr);
1543
1544 TTCN_Logger::log_port_misc(
1545 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__tcp,
1546 port_name, remote_component, remote_port);
1547 delete local_addr;
1548 }
1549
1550 void PORT::connect_listen_unix_stream(component remote_component,
1551 const char *remote_port)
1552 {
1553 // creating the UNIX server socket
1554 int server_fd = socket(PF_UNIX, SOCK_STREAM, 0);
1555 if (server_fd < 0) {
1556 TTCN_Communication::send_connect_error(port_name, remote_component,
1557 remote_port, "Creation of the UNIX server socket failed. (%s)",
1558 strerror(errno));
1559 errno = 0;
1560 return;
1561 }
1562
1563 // binding the socket to a temporary file
1564 struct sockaddr_un local_addr;
1565 // the file name is constructed using a hash function
1566 unsigned int hash_value =
1567 get_connection_hash(self, port_name, remote_component, remote_port);
1568 for (unsigned int i = 1; ; i++) {
1569 memset(&local_addr, 0, sizeof(local_addr));
1570 local_addr.sun_family = AF_UNIX;
1571 snprintf(local_addr.sun_path, sizeof(local_addr.sun_path),
1572 "/tmp/ttcn3-portconn-%x", hash_value);
1573 if (bind(server_fd, (struct sockaddr*)&local_addr, sizeof(local_addr))
1574 == 0) {
1575 // the operation was successful, jump out of the loop
1576 break;
1577 } else if (errno == EADDRINUSE) {
1578 // the temporary file name is already used by someone else
1579 errno = 0;
1580 if (i < UNIX_BIND_MAX_ITER) {
1581 // try another hash value
1582 hash_value++;
1583 } else {
1584 close(server_fd);
1585 TTCN_Communication::send_connect_error(port_name,
1586 remote_component, remote_port, "Could not find a free "
1587 "pathname to bind the UNIX server socket to after %u "
1588 "iterations.", i);
1589 errno = 0;
1590 return;
1591 }
1592 } else {
1593 close(server_fd);
1594 TTCN_Communication::send_connect_error(port_name, remote_component,
1595 remote_port, "Binding of UNIX server socket to pathname %s "
1596 "failed. (%s)", local_addr.sun_path, strerror(errno));
1597 errno = 0;
1598 return;
1599 }
1600 }
1601
1602 // zero backlog is enough since we are waiting for only one client
1603 if (listen(server_fd, 0)) {
1604 close(server_fd);
1605 TTCN_Communication::send_connect_error(port_name, remote_component,
1606 remote_port, "Listening on UNIX pathname %s failed. (%s)",
1607 local_addr.sun_path, strerror(errno));
1608 errno = 0;
1609 return;
1610 }
1611
1612 if (!TTCN_Communication::set_close_on_exec(server_fd)) {
1613 close(server_fd);
1614 TTCN_Communication::send_connect_error(port_name, remote_component,
1615 remote_port, "Setting the close-on-exec flag failed on the UNIX "
1616 "server socket.");
1617 return;
1618 }
1619
1620 port_connection *new_connection = add_connection(remote_component,
1621 remote_port, TRANSPORT_UNIX_STREAM);
1622 new_connection->connection_state = CONN_LISTENING;
1623 new_connection->stream.comm_fd = server_fd;
1624 Fd_And_Timeout_User::add_fd(server_fd, new_connection, FD_EVENT_RD);
1625
1626 TTCN_Communication::send_connect_listen_ack_unix_stream(port_name,
1627 remote_component, remote_port, &local_addr);
1628
1629 TTCN_Logger::log_port_misc(
1630 TitanLoggerApi::Port__Misc_reason::port__is__waiting__for__connection__unix,
1631 port_name, remote_component, remote_port, local_addr.sun_path);
1632 }
1633
1634 void PORT::connect_local(component remote_component, const char *remote_port)
1635 {
1636 if (self != remote_component) {
1637 TTCN_Communication::send_connect_error(port_name, remote_component,
1638 remote_port, "Message CONNECT with transport type LOCAL refers "
1639 "to a port of another component (%d).", remote_component);
1640 return;
1641 }
1642 PORT *remote_ptr = lookup_by_name(remote_port);
1643 if (remote_ptr == NULL) {
1644 TTCN_Communication::send_connect_error(port_name, remote_component,
1645 remote_port, "Port %s does not exist.", remote_port);
1646 return;
1647 } else if (!remote_ptr->is_active) TTCN_error("Internal error: Port %s is "
1648 "inactive when trying to connect it to local port %s.", remote_port,
1649 port_name);
1650 add_local_connection(remote_ptr);
1651 if (this != remote_ptr) remote_ptr->add_local_connection(this);
1652 TTCN_Communication::send_connected(port_name, remote_component,
1653 remote_port);
1654 }
1655
1656 void PORT::connect_stream(component remote_component, const char *remote_port,
1657 transport_type_enum transport_type, Text_Buf& text_buf)
1658 {
1659 #ifdef WIN32
1660 again:
1661 #endif
1662 const char *transport_str;
1663 int client_fd;
1664 switch (transport_type) {
1665 case TRANSPORT_INET_STREAM:
1666 transport_str = "TCP";
1667 // creating the TCP client socket
1668 client_fd = NetworkHandler::socket(TTCN_Communication::get_network_family());
1669 break;
1670 case TRANSPORT_UNIX_STREAM:
1671 transport_str = "UNIX";
1672 // creating the UNIX client socket
1673 client_fd = socket(PF_UNIX, SOCK_STREAM, 0);
1674 break;
1675 default:
1676 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1677 "type (%d).", transport_type);
1678 }
1679 if (client_fd < 0) {
1680 TTCN_Communication::send_connect_error(port_name, remote_component,
1681 remote_port, "Creation of the %s client socket failed. (%s)",
1682 transport_str, strerror(errno));
1683 errno = 0;
1684 return;
1685 }
1686
1687 switch (transport_type) {
1688 case TRANSPORT_INET_STREAM: {
1689 // connect to the IP address and port number given in message CONNECT
1690 IPAddress *remote_addr = IPAddress::create_addr(TTCN_Communication::get_network_family());
1691 remote_addr->pull_raw(text_buf);
1692 #ifdef SOLARIS
1693 if (connect(client_fd, (struct sockaddr*)remote_addr->get_addr(), remote_addr->get_addr_len())) {
1694 #else
1695 if (connect(client_fd, remote_addr->get_addr(), remote_addr->get_addr_len())) {
1696 #endif
1697 #ifdef WIN32
1698 if (errno == EADDRINUSE) {
1699 close(client_fd);
1700 errno = 0;
1701 TTCN_warning("connect() returned error code EADDRINUSE. "
1702 "Perhaps this is a Cygwin bug. Trying to connect again.");
1703 goto again;
1704 }
1705 #endif
1706 close(client_fd);
1707 TTCN_Communication::send_connect_error(port_name, remote_component,
1708 remote_port, "TCP connection establishment failed to %s:%d. (%s)",
1709 remote_addr->get_addr_str(), remote_addr->get_port(), strerror(errno));
1710 errno = 0;
1711 delete remote_addr;
1712 return;
1713 }
1714 delete remote_addr;
1715 break; }
1716 case TRANSPORT_UNIX_STREAM: {
1717 // connect to the UNIX pathname given in the message CONNECT
1718 struct sockaddr_un remote_addr;
1719 memset(&remote_addr, 0, sizeof(remote_addr));
1720 remote_addr.sun_family = AF_UNIX;
1721 size_t pathname_len = text_buf.pull_int().get_val();
1722 if (pathname_len >= sizeof(remote_addr.sun_path)) {
1723 close(client_fd);
1724 TTCN_Communication::send_connect_error(port_name, remote_component,
1725 remote_port, "The UNIX pathname used by the server socket is "
1726 "too long. It consists of %lu bytes although it should be "
1727 "shorter than %lu bytes to fit in the appropriate structure.",
1728 (unsigned long) pathname_len,
1729 (unsigned long) sizeof(remote_addr.sun_path));
1730 return;
1731 }
1732 text_buf.pull_raw(pathname_len, remote_addr.sun_path);
1733 if (connect(client_fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr))) {
1734 close(client_fd);
1735 TTCN_Communication::send_connect_error(port_name, remote_component,
1736 remote_port, "UNIX socket connection establishment failed to "
1737 "pathname %s. (%s)", remote_addr.sun_path, strerror(errno));
1738 errno = 0;
1739 return;
1740 }
1741 break; }
1742 default:
1743 TTCN_error("Internal error: PORT::connect_stream(): invalid transport "
1744 "type (%d).", transport_type);
1745 }
1746
1747 if (!TTCN_Communication::set_close_on_exec(client_fd)) {
1748 close(client_fd);
1749 TTCN_Communication::send_connect_error(port_name, remote_component,
1750 remote_port, "Setting the close-on-exec flag failed on the %s "
1751 "client socket.", transport_str);
1752 return;
1753 }
1754
1755 if (!TTCN_Communication::set_non_blocking_mode(client_fd, TRUE)) {
1756 close(client_fd);
1757 TTCN_Communication::send_connect_error(port_name, remote_component,
1758 remote_port, "Setting the non-blocking mode failed on the %s "
1759 "client socket.", transport_str);
1760 return;
1761 }
1762
1763 if (transport_type == TRANSPORT_INET_STREAM &&
1764 !TTCN_Communication::set_tcp_nodelay(client_fd)) {
1765 close(client_fd);
1766 TTCN_Communication::send_connect_error(port_name, remote_component,
1767 remote_port, "Setting the TCP_NODELAY flag failed on the TCP "
1768 "client socket.");
1769 return;
1770 }
1771
1772 port_connection *new_connection = add_connection(remote_component,
1773 remote_port, transport_type);
1774 new_connection->connection_state = CONN_CONNECTED;
1775 new_connection->stream.comm_fd = client_fd;
1776 Fd_And_Timeout_User::add_fd(client_fd, new_connection, FD_EVENT_RD);
1777
1778 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__established,
1779 port_name, remote_component, remote_port, transport_str);
1780 }
1781
1782 void PORT::disconnect_local(port_connection *conn_ptr)
1783 {
1784 PORT *remote_ptr = conn_ptr->local.port_ptr;
1785 remove_local_connection(conn_ptr);
1786 if (this != remote_ptr) {
1787 port_connection *conn2_ptr =
1788 remote_ptr->lookup_connection(self, port_name);
1789 if (conn2_ptr == NULL) TTCN_error("Internal error: Port %s is "
1790 "connected with local port %s, but port %s does not have a "
1791 "connection to %s.", port_name, remote_ptr->port_name,
1792 remote_ptr->port_name, port_name);
1793 else remote_ptr->remove_local_connection(conn2_ptr);
1794 }
1795 TTCN_Communication::send_disconnected(port_name, self,
1796 remote_ptr->port_name);
1797 }
1798
1799 void PORT::disconnect_stream(port_connection *conn_ptr)
1800 {
1801 switch (conn_ptr->connection_state) {
1802 case CONN_LISTENING:
1803 TTCN_Logger::log_port_misc(
1804 TitanLoggerApi::Port__Misc_reason::destroying__unestablished__connection,
1805 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
1806 remove_connection(conn_ptr);
1807 // do not send back any acknowledgment
1808 break;
1809 case CONN_CONNECTED: {
1810 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::terminating__connection,
1811 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
1812 Text_Buf outgoing_buf;
1813 outgoing_buf.push_int(CONN_DATA_LAST);
1814 if (send_data_stream(conn_ptr, outgoing_buf, TRUE)) {
1815 // sending the last message was successful
1816 // wait for the acknowledgment from the peer
1817 conn_ptr->connection_state = CONN_LAST_MSG_SENT;
1818 } else {
1819 TTCN_Logger::log_port_misc(
1820 TitanLoggerApi::Port__Misc_reason::sending__termination__request__failed,
1821 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
1822 // send an acknowledgment to MC immediately to avoid deadlock
1823 // in case of communication failure
1824 // (i.e. when the peer does not send DISCONNECTED)
1825 TTCN_Communication::send_disconnected(port_name,
1826 conn_ptr->remote_component, conn_ptr->remote_port);
1827 TTCN_warning("The last outgoing messages on port %s may be lost.",
1828 port_name);
1829 // destroy the connection immediately
1830 remove_connection(conn_ptr);
1831 }
1832 break; }
1833 default:
1834 TTCN_error("The connection of port %s to %d:%s is in unexpected "
1835 "state when trying to terminate it.", port_name,
1836 conn_ptr->remote_component, conn_ptr->remote_port);
1837 }
1838 }
1839
1840 void PORT::send_data_local(port_connection *conn_ptr, Text_Buf& outgoing_data)
1841 {
1842 outgoing_data.rewind();
1843 PORT *dest_ptr = conn_ptr->local.port_ptr;
1844 if (this != dest_ptr) {
1845 port_connection *conn2_ptr =
1846 dest_ptr->lookup_connection(self, port_name);
1847 if (conn2_ptr == NULL) TTCN_error("Internal error: Port %s is "
1848 "connected with local port %s, but port %s does not have a "
1849 "connection to %s.", port_name, dest_ptr->port_name,
1850 dest_ptr->port_name, port_name);
1851 dest_ptr->process_data(conn2_ptr, outgoing_data);
1852 } else process_data(conn_ptr, outgoing_data);
1853 }
1854
1855 boolean PORT::send_data_stream(port_connection *conn_ptr,
1856 Text_Buf& outgoing_data, boolean ignore_peer_disconnect)
1857 {
1858 bool would_block_warning=false;
1859 outgoing_data.calculate_length();
1860 const char *msg_ptr = outgoing_data.get_data();
1861 size_t msg_len = outgoing_data.get_len(), sent_len = 0;
1862 while (sent_len < msg_len) {
1863 int ret_val = send(conn_ptr->stream.comm_fd, msg_ptr + sent_len,
1864 msg_len - sent_len, 0);
1865 if (ret_val > 0) sent_len += ret_val;
1866 else {
1867 switch (errno) {
1868 case EINTR:
1869 // a signal occurred: do nothing, just try again
1870 errno = 0;
1871 break;
1872 case EAGAIN: {
1873 // the output buffer is full: try to increase it if possible
1874 errno = 0;
1875 int old_bufsize, new_bufsize;
1876 if (TTCN_Communication::increase_send_buffer(
1877 conn_ptr->stream.comm_fd, old_bufsize, new_bufsize)) {
1878 TTCN_Logger::log_port_misc(
1879 TitanLoggerApi::Port__Misc_reason::sending__would__block,
1880 port_name, conn_ptr->remote_component, conn_ptr->remote_port,
1881 NULL, old_bufsize, new_bufsize);
1882 } else {
1883 if(!would_block_warning){
1884 TTCN_warning_begin("Sending data on the connection of "
1885 "port %s to ", port_name);
1886 COMPONENT::log_component_reference(
1887 conn_ptr->remote_component);
1888 TTCN_Logger::log_event(":%s would block execution and it "
1889 "is not possible to further increase the size of the "
1890 "outgoing buffer. Trying to process incoming data to "
1891 "avoid deadlock.", conn_ptr->remote_port);
1892 TTCN_warning_end();
1893 would_block_warning=true;
1894 }
1895 TTCN_Snapshot::block_for_sending(conn_ptr->stream.comm_fd);
1896 }
1897 break; }
1898 case ECONNRESET:
1899 case EPIPE:
1900 if (ignore_peer_disconnect) return FALSE;
1901 // no break
1902 default:
1903 TTCN_error("Sending data on the connection of port %s to "
1904 "%d:%s failed.", port_name, conn_ptr->remote_component,
1905 conn_ptr->remote_port);
1906 }
1907 }
1908 }
1909 if(would_block_warning){
1910 TTCN_warning_begin("The message finally was sent on "
1911 "port %s to ", port_name);
1912 COMPONENT::log_component_reference(
1913 conn_ptr->remote_component);
1914 TTCN_Logger::log_event(":%s.", conn_ptr->remote_port);
1915 TTCN_warning_end();
1916 }
1917 return TRUE;
1918 }
1919
1920 void PORT::handle_incoming_connection(port_connection *conn_ptr)
1921 {
1922 const char *transport_str =
1923 conn_ptr->transport_type == TRANSPORT_INET_STREAM ? "TCP" : "UNIX";
1924 int comm_fd = accept(conn_ptr->stream.comm_fd, NULL, NULL);
1925 if (comm_fd < 0) {
1926 TTCN_Communication::send_connect_error(port_name,
1927 conn_ptr->remote_component, conn_ptr->remote_port,
1928 "Accepting of incoming %s connection failed. (%s)", transport_str,
1929 strerror(errno));
1930 errno = 0;
1931 remove_connection(conn_ptr);
1932 return;
1933 }
1934
1935 if (!TTCN_Communication::set_close_on_exec(comm_fd)) {
1936 close(comm_fd);
1937 TTCN_Communication::send_connect_error(port_name,
1938 conn_ptr->remote_component, conn_ptr->remote_port,
1939 "Setting the close-on-exec flag failed on the server-side %s "
1940 "socket.", transport_str);
1941 remove_connection(conn_ptr);
1942 return;
1943 }
1944
1945 if (!TTCN_Communication::set_non_blocking_mode(comm_fd, TRUE)) {
1946 close(comm_fd);
1947 TTCN_Communication::send_connect_error(port_name,
1948 conn_ptr->remote_component, conn_ptr->remote_port,
1949 "Setting the non-blocking mode failed on the server-side %s "
1950 "socket.", transport_str);
1951 remove_connection(conn_ptr);
1952 return;
1953 }
1954
1955 if (conn_ptr->transport_type == TRANSPORT_INET_STREAM &&
1956 !TTCN_Communication::set_tcp_nodelay(comm_fd)) {
1957 close(comm_fd);
1958 TTCN_Communication::send_connect_error(port_name,
1959 conn_ptr->remote_component, conn_ptr->remote_port,
1960 "Setting the TCP_NODELAY flag failed on the server-side TCP "
1961 "socket.");
1962 remove_connection(conn_ptr);
1963 return;
1964 }
1965
1966 // shutting down the server socket and replacing it with the
1967 // communication socket of the new connection
1968 Fd_And_Timeout_User::remove_fd(conn_ptr->stream.comm_fd, conn_ptr,
1969 FD_EVENT_RD);
1970 if (conn_ptr->transport_type == TRANSPORT_UNIX_STREAM)
1971 unlink_unix_pathname(conn_ptr->stream.comm_fd);
1972 close(conn_ptr->stream.comm_fd);
1973 conn_ptr->connection_state = CONN_CONNECTED;
1974 conn_ptr->stream.comm_fd = comm_fd;
1975 Fd_And_Timeout_User::add_fd(comm_fd, conn_ptr, FD_EVENT_RD);
1976
1977 TTCN_Communication::send_connected(port_name, conn_ptr->remote_component,
1978 conn_ptr->remote_port);
1979
1980 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::connection__accepted,
1981 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
1982 }
1983
1984 void PORT::handle_incoming_data(port_connection *conn_ptr)
1985 {
1986 if (conn_ptr->stream.incoming_buf == NULL)
1987 conn_ptr->stream.incoming_buf = new Text_Buf;
1988 Text_Buf& incoming_buf = *conn_ptr->stream.incoming_buf;
1989 char *buf_ptr;
1990 int buf_len;
1991 incoming_buf.get_end(buf_ptr, buf_len);
1992 int recv_len = recv(conn_ptr->stream.comm_fd, buf_ptr, buf_len, 0);
1993 if (recv_len < 0) {
1994 // an error occurred
1995 if (errno == ECONNRESET) {
1996 // TCP connection was reset by peer
1997 errno = 0;
1998 TTCN_Communication::send_disconnected(port_name,
1999 conn_ptr->remote_component, conn_ptr->remote_port);
2000 TTCN_Logger::log_port_misc(
2001 TitanLoggerApi::Port__Misc_reason::connection__reset__by__peer,
2002 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
2003 TTCN_warning("The last outgoing messages on port %s may be lost.",
2004 port_name);
2005 conn_ptr->connection_state = CONN_IDLE;
2006 } else {
2007 TTCN_error("Receiving data on the connection of port %s from "
2008 "%d:%s failed.", port_name, conn_ptr->remote_component,
2009 conn_ptr->remote_port);
2010 }
2011 } else if (recv_len > 0) {
2012 // data was received
2013 incoming_buf.increase_length(recv_len);
2014 // processing all messages in the buffer after each other
2015 while (incoming_buf.is_message()) {
2016 incoming_buf.pull_int(); // message_length
2017 process_data(conn_ptr, incoming_buf);
2018 incoming_buf.cut_message();
2019 }
2020 } else {
2021 // the connection was closed by the peer
2022 TTCN_Communication::send_disconnected(port_name,
2023 conn_ptr->remote_component, conn_ptr->remote_port);
2024 if (conn_ptr->connection_state != CONN_LAST_MSG_RCVD) {
2025 TTCN_Logger::log_port_misc(
2026 TitanLoggerApi::Port__Misc_reason::connection__closed__by__peer,
2027 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
2028 }
2029 // the connection can be removed
2030 conn_ptr->connection_state = CONN_IDLE;
2031 }
2032 if (conn_ptr->connection_state == CONN_IDLE) {
2033 // terminating and removing connection
2034 int msg_len = incoming_buf.get_len();
2035 if (msg_len > 0) {
2036 TTCN_warning_begin("Message fragment remained in the buffer of "
2037 "port connection between %s and ", port_name);
2038 COMPONENT::log_component_reference(conn_ptr->remote_component);
2039 TTCN_Logger::log_event(":%s: ", conn_ptr->remote_port);
2040 const unsigned char *msg_ptr =
2041 (const unsigned char*)incoming_buf.get_data();
2042 for (int i = 0; i < msg_len; i++)
2043 TTCN_Logger::log_octet(msg_ptr[i]);
2044 TTCN_warning_end();
2045 }
2046
2047 TTCN_Logger::log_port_misc(TitanLoggerApi::Port__Misc_reason::port__disconnected,
2048 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
2049 remove_connection(conn_ptr);
2050 }
2051 }
2052
2053 void PORT::process_last_message(port_connection *conn_ptr)
2054 {
2055 switch (conn_ptr->transport_type) {
2056 case TRANSPORT_INET_STREAM:
2057 case TRANSPORT_UNIX_STREAM:
2058 break;
2059 default:
2060 TTCN_error("Internal error: Connection termination request was "
2061 "received on the connection of port %s with %d:%s, which has an "
2062 "invalid transport type (%d).", port_name,
2063 conn_ptr->remote_component, conn_ptr->remote_port,
2064 conn_ptr->transport_type);
2065 }
2066 switch (conn_ptr->connection_state) {
2067 case CONN_CONNECTED: {
2068 TTCN_Logger::log_port_misc(
2069 TitanLoggerApi::Port__Misc_reason::termination__request__received,
2070 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
2071 Text_Buf outgoing_buf;
2072 outgoing_buf.push_int(CONN_DATA_LAST);
2073 if (send_data_stream(conn_ptr, outgoing_buf, TRUE)) {
2074 // sending the last message was successful
2075 // wait until the peer closes the transport connection
2076 conn_ptr->connection_state = CONN_LAST_MSG_RCVD;
2077 } else {
2078 TTCN_Logger::log_port_misc(
2079 TitanLoggerApi::Port__Misc_reason::acknowledging__termination__request__failed,
2080 port_name, conn_ptr->remote_component, conn_ptr->remote_port);
2081 // send an acknowledgment to MC immediately to avoid deadlock
2082 // in case of communication failure
2083 // (i.e. when the peer does not send DISCONNECTED)
2084 TTCN_Communication::send_disconnected(port_name,
2085 conn_ptr->remote_component, conn_ptr->remote_port);
2086 // the connection can be removed immediately
2087 TTCN_warning("The last outgoing messages on port %s may be lost.",
2088 port_name);
2089 conn_ptr->connection_state = CONN_IDLE;
2090 }
2091 break; }
2092 case CONN_LAST_MSG_SENT:
2093 // the connection can be removed
2094 conn_ptr->connection_state = CONN_IDLE;
2095 break;
2096 case CONN_LAST_MSG_RCVD:
2097 case CONN_IDLE:
2098 TTCN_warning("Unexpected data arrived after the indication of "
2099 "connection termination on port %s from %d:%s.", port_name,
2100 conn_ptr->remote_component, conn_ptr->remote_port);
2101 break;
2102 default:
2103 TTCN_error("Internal error: Connection of port %s with %d:%s has "
2104 "invalid state (%d).", port_name, conn_ptr->remote_component,
2105 conn_ptr->remote_port, conn_ptr->connection_state);
2106 }
2107 }
2108
2109 void PORT::map(const char *system_port)
2110 {
2111 if (!is_active) TTCN_error("Inactive port %s cannot be mapped.", port_name);
2112
2113 int new_posn;
2114 for (new_posn = 0; new_posn < n_system_mappings; new_posn++) {
2115 int str_diff = strcmp(system_port, system_mappings[new_posn]);
2116 if (str_diff < 0) break;
2117 else if (str_diff == 0) {
2118 TTCN_warning("Port %s is already mapped to system:%s."
2119 " Map operation was ignored.", port_name, system_port);
2120 return;
2121 }
2122 }
2123
2124 set_system_parameters(system_port);
2125
2126 user_map(system_port);
2127
2128 TTCN_Logger::log_port_misc(
2129 TitanLoggerApi::Port__Misc_reason::port__was__mapped__to__system,
2130 port_name, SYSTEM_COMPREF, system_port);
2131
2132 // the mapping shall be registered in the table only if user_map() was
2133 // successful
2134 system_mappings = (char**)Realloc(system_mappings,
2135 (n_system_mappings + 1) * sizeof(*system_mappings));
2136 memmove(system_mappings + new_posn + 1, system_mappings + new_posn,
2137 (n_system_mappings - new_posn) * sizeof(*system_mappings));
2138 system_mappings[new_posn] = mcopystr(system_port);
2139 n_system_mappings++;
2140
2141 if (n_system_mappings > 1) TTCN_warning("Port %s has now more than one "
2142 "mappings. Message cannot be sent on it to system even with explicit "
2143 "addressing.", port_name);
2144 }
2145
2146 void PORT::unmap(const char *system_port)
2147 {
2148 int del_posn;
2149 for (del_posn = 0; del_posn < n_system_mappings; del_posn++) {
2150 int str_diff = strcmp(system_port, system_mappings[del_posn]);
2151 if (str_diff == 0) break;
2152 else if (str_diff < 0) {
2153 del_posn = n_system_mappings;
2154 break;
2155 }
2156 }
2157 if (del_posn >= n_system_mappings) {
2158 TTCN_warning("Port %s is not mapped to system:%s. "
2159 "Unmap operation was ignored.", port_name, system_port);
2160 return;
2161 }
2162
2163 char *unmapped_port = system_mappings[del_posn];
2164
2165 // first remove the mapping from the table
2166 n_system_mappings--;
2167 memmove(system_mappings + del_posn, system_mappings + del_posn + 1,
2168 (n_system_mappings - del_posn) * sizeof(*system_mappings));
2169 system_mappings = (char**)Realloc(system_mappings,
2170 n_system_mappings * sizeof(*system_mappings));
2171
2172 try {
2173 user_unmap(system_port);
2174 } catch (...) {
2175 // prevent from memory leak
2176 Free(unmapped_port);
2177 throw;
2178 }
2179
2180 TTCN_Logger::log_port_misc(
2181 TitanLoggerApi::Port__Misc_reason::port__was__unmapped__from__system,
2182 port_name, SYSTEM_COMPREF, system_port);
2183
2184 Free(unmapped_port);
2185 }
2186
2187 void PORT::process_connect_listen(const char *local_port,
2188 component remote_component, const char *remote_port,
2189 transport_type_enum transport_type)
2190 {
2191 PORT *port_ptr = lookup_by_name(local_port);
2192 if (port_ptr == NULL) {
2193 TTCN_Communication::send_connect_error(local_port, remote_component,
2194 remote_port, "Port %s does not exist.", local_port);
2195 return;
2196 } else if (!port_ptr->is_active) {
2197 TTCN_error("Internal error: Port %s is inactive when trying to "
2198 "connect it to %d:%s.", local_port, remote_component, remote_port);
2199 } else if (port_ptr->lookup_connection(remote_component, remote_port)
2200 != NULL) {
2201 TTCN_Communication::send_connect_error(local_port, remote_component,
2202 remote_port, "Port %s already has a connection towards %d:%s.",
2203 local_port, remote_component, remote_port);
2204 return;
2205 } else if (port_ptr->lookup_connection_to_compref(remote_component, NULL)
2206 != NULL) {
2207 TTCN_warning_begin("Port %s will have more than one connections with "
2208 "ports of test component ", local_port);
2209 COMPONENT::log_component_reference(remote_component);
2210 TTCN_Logger::log_event_str(". These connections cannot be used for "
2211 "sending even with explicit addressing.");
2212 TTCN_warning_end();
2213 }
2214
2215 switch (transport_type) {
2216 case TRANSPORT_LOCAL:
2217 TTCN_Communication::send_connect_error(local_port, remote_component,
2218 remote_port, "Message CONNECT_LISTEN cannot refer to transport "
2219 "type LOCAL.");
2220 break;
2221 case TRANSPORT_INET_STREAM:
2222 port_ptr->connect_listen_inet_stream(remote_component, remote_port);
2223 break;
2224 case TRANSPORT_UNIX_STREAM:
2225 port_ptr->connect_listen_unix_stream(remote_component, remote_port);
2226 break;
2227 default:
2228 TTCN_Communication::send_connect_error(local_port, remote_component,
2229 remote_port, "Message CONNECT_LISTEN refers to invalid transport "
2230 "type (%d).", transport_type);
2231 break;
2232 }
2233 }
2234
2235 void PORT::process_connect(const char *local_port,
2236 component remote_component, const char *remote_port,
2237 transport_type_enum transport_type, Text_Buf& text_buf)
2238 {
2239 PORT *port_ptr = lookup_by_name(local_port);
2240 if (port_ptr == NULL) {
2241 TTCN_Communication::send_connect_error(local_port, remote_component,
2242 remote_port, "Port %s does not exist.", local_port);
2243 return;
2244 } else if (!port_ptr->is_active) {
2245 TTCN_error("Internal error: Port %s is inactive when trying to "
2246 "connect it to %d:%s.", local_port, remote_component, remote_port);
2247 } else if (port_ptr->lookup_connection(remote_component, remote_port)
2248 != NULL) {
2249 TTCN_Communication::send_connect_error(local_port, remote_component,
2250 remote_port, "Port %s already has a connection towards %d:%s.",
2251 local_port, remote_component, remote_port);
2252 return;
2253 } else if (port_ptr->lookup_connection_to_compref(remote_component, NULL)
2254 != NULL) {
2255 TTCN_warning_begin("Port %s will have more than one connections with "
2256 "ports of test component ", local_port);
2257 COMPONENT::log_component_reference(remote_component);
2258 TTCN_Logger::log_event_str(". These connections cannot be used for "
2259 "sending even with explicit addressing.");
2260 TTCN_warning_end();
2261 }
2262
2263 switch (transport_type) {
2264 case TRANSPORT_LOCAL:
2265 port_ptr->connect_local(remote_component, remote_port);
2266 break;
2267 case TRANSPORT_INET_STREAM:
2268 case TRANSPORT_UNIX_STREAM:
2269 port_ptr->connect_stream(remote_component, remote_port, transport_type,
2270 text_buf);
2271 break;
2272 default:
2273 TTCN_Communication::send_connect_error(local_port, remote_component,
2274 remote_port, "Message CONNECT refers to invalid transport type "
2275 "(%d).", transport_type);
2276 break;
2277 }
2278 }
2279
2280 void PORT::process_disconnect(const char *local_port,
2281 component remote_component, const char *remote_port)
2282 {
2283 PORT *port_ptr = lookup_by_name(local_port);
2284 if (port_ptr == NULL) {
2285 TTCN_Communication::send_error("Message DISCONNECT refers to "
2286 "non-existent local port %s.", local_port);
2287 return;
2288 } else if (!port_ptr->is_active) {
2289 TTCN_error("Internal error: Port %s is inactive when trying to "
2290 "disconnect it from %d:%s.", local_port, remote_component,
2291 remote_port);
2292 }
2293 port_connection *conn_ptr = port_ptr->lookup_connection(remote_component,
2294 remote_port);
2295 if (conn_ptr == NULL) {
2296 // the connection does not exist
2297 if (self == remote_component && lookup_by_name(remote_port) == NULL) {
2298 // the remote endpoint is in the same component,
2299 // but it does not exist
2300 TTCN_Communication::send_error("Message DISCONNECT refers to "
2301 "non-existent port %s.", remote_port);
2302 } else {
2303 TTCN_Communication::send_disconnected(local_port, remote_component,
2304 remote_port);
2305 }
2306 return;
2307 }
2308 switch (conn_ptr->transport_type) {
2309 case TRANSPORT_LOCAL:
2310 port_ptr->disconnect_local(conn_ptr);
2311 break;
2312 case TRANSPORT_INET_STREAM:
2313 case TRANSPORT_UNIX_STREAM:
2314 port_ptr->disconnect_stream(conn_ptr);
2315 break;
2316 default:
2317 TTCN_error("Internal error: The connection of port %s to %d:%s has "
2318 "invalid transport type (%d) when trying to terminate the "
2319 "connection.", local_port, remote_component, remote_port,
2320 conn_ptr->transport_type);
2321 }
2322 }
2323
2324 void PORT::make_local_connection(const char *src_port, const char *dest_port)
2325 {
2326 PORT *src_ptr = lookup_by_name(src_port);
2327 if (src_ptr == NULL) TTCN_error("Connect operation refers to "
2328 "non-existent port %s.", src_port);
2329 else if (!src_ptr->is_active) TTCN_error("Internal error: Port %s is "
2330 "inactive when trying to connect it with local port %s.", src_port,
2331 dest_port);
2332 else if (src_ptr->lookup_connection(MTC_COMPREF, dest_port) != NULL) {
2333 TTCN_warning("Port %s is already connected with local port %s. "
2334 "Connect operation had no effect.", src_port, dest_port);
2335 return;
2336 } else if (src_ptr->lookup_connection_to_compref(MTC_COMPREF, NULL)
2337 != NULL) {
2338 TTCN_warning("Port %s will have more than one connections with local "
2339 "ports. These connections cannot be used for communication even "
2340 "with explicit addressing.", src_port);
2341 }
2342 PORT *dest_ptr = lookup_by_name(dest_port);
2343 if (dest_ptr == NULL) TTCN_error("Connect operation refers to "
2344 "non-existent port %s.", dest_port);
2345 else if (!dest_ptr->is_active) TTCN_error("Internal error: Port %s is "
2346 "inactive when trying to connect it with local port %s.", dest_port,
2347 src_port);
2348 src_ptr->add_local_connection(dest_ptr);
2349 if (src_ptr != dest_ptr) dest_ptr->add_local_connection(src_ptr);
2350 }
2351
2352 void PORT::terminate_local_connection(const char *src_port,
2353 const char *dest_port)
2354 {
2355 PORT *src_ptr = lookup_by_name(src_port);
2356 if (src_ptr == NULL) TTCN_error("Disconnect operation refers to "
2357 "non-existent port %s.", src_port);
2358 else if (!src_ptr->is_active) TTCN_error("Internal error: Port %s is "
2359 "inactive when trying to disconnect it from local port %s.", src_port,
2360 dest_port);
2361 port_connection *conn_ptr = src_ptr->lookup_connection(MTC_COMPREF,
2362 dest_port);
2363 if (conn_ptr != NULL) {
2364 PORT *dest_ptr = conn_ptr->local.port_ptr;
2365 src_ptr->remove_local_connection(conn_ptr);
2366 if (src_ptr != dest_ptr) {
2367 if (!dest_ptr->is_active) TTCN_error("Internal error: Port %s is "
2368 "inactive when trying to disconnect it from local port %s.",
2369 dest_port, src_port);
2370 port_connection *conn2_ptr =
2371 dest_ptr->lookup_connection(MTC_COMPREF, src_port);
2372 if (conn2_ptr == NULL) TTCN_error("Internal error: Port %s is "
2373 "connected with local port %s, but port %s does not have a "
2374 "connection to %s.", src_port, dest_port, dest_port, src_port);
2375 else dest_ptr->remove_local_connection(conn2_ptr);
2376 }
2377 } else {
2378 PORT *dest_ptr = lookup_by_name(dest_port);
2379 if (dest_ptr == NULL) TTCN_error("Disconnect operation refers to "
2380 "non-existent port %s.", dest_port);
2381 else if (src_ptr != dest_ptr) {
2382 if (!dest_ptr->is_active) TTCN_error("Internal error: Port %s is "
2383 "inactive when trying to disconnect it from local port %s.",
2384 dest_port, src_port);
2385 else if (dest_ptr->lookup_connection(MTC_COMPREF, src_port) != NULL)
2386 TTCN_error("Internal error: Port %s is connected with local "
2387 "port %s, but port %s does not have a connection to %s.",
2388 dest_port, src_port, src_port, dest_port);
2389 }
2390 TTCN_warning("Port %s does not have connection with local port %s. "
2391 "Disconnect operation had no effect.", src_port, dest_port);
2392 }
2393 }
2394
2395 void PORT::map_port(const char *component_port, const char *system_port)
2396 {
2397 PORT *port_ptr = lookup_by_name(component_port);
2398 if (port_ptr == NULL) TTCN_error("Map operation refers to "
2399 "non-existent port %s.", component_port);
2400 port_ptr->map(system_port);
2401 if (!TTCN_Runtime::is_single())
2402 TTCN_Communication::send_mapped(component_port, system_port);
2403 }
2404
2405 void PORT::unmap_port(const char *component_port, const char *system_port)
2406 {
2407 PORT *port_ptr = lookup_by_name(component_port);
2408 if (port_ptr == NULL) TTCN_error("Unmap operation refers to "
2409 "non-existent port %s.", component_port);
2410 port_ptr->unmap(system_port);
2411 if (!TTCN_Runtime::is_single())
2412 TTCN_Communication::send_unmapped(component_port, system_port);
2413 }
This page took 0.079211 seconds and 4 git commands to generate.