Merge pull request #63 from BenceJanosSzabo/master
[deliverable/titan.core.git] / core / Communication.cc
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 * Beres, Szabolcs
12 * Delic, Adam
13 * Feher, Csaba
14 * Forstner, Matyas
15 * Kovacs, Ferenc
16 * Raduly, Csaba
17 * Szabo, Janos Zoltan – initial implementation
18 * Szalai, Gabor
19 * Zalanyi, Balazs Andor
20 *
21 ******************************************************************************/
22 #include "Communication.hh"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <netdb.h>
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/utsname.h>
35 #include <netinet/in.h>
36 #include <netinet/tcp.h>
37 #include <arpa/inet.h>
38 #include <sys/un.h>
39
40 #include "../common/dbgnew.hh"
41 #include "Types.h"
42 #include "Message_types.hh"
43 #include "Module_list.hh"
44 #include "Verdicttype.hh"
45 #include "Fd_And_Timeout_User.hh"
46 #include "Runtime.hh"
47 #include "Logger.hh"
48 #include "Port.hh"
49 #include "Component.hh"
50
51 #include "TitanLoggerApiSimple.hh"
52 #include "../common/version.h"
53
54 #include "Event_Handler.hh"
55 #include "Debugger.hh"
56 #include "DebugCommands.hh"
57
58 class MC_Connection : public Fd_And_Timeout_Event_Handler {
59 virtual void Handle_Fd_Event(int fd,
60 boolean is_readable, boolean is_writable, boolean is_error);
61 virtual void Handle_Timeout(double time_since_last_call);
62 public:
63 MC_Connection(const int * fd, Text_Buf * buf) :
64 Fd_And_Timeout_Event_Handler(), mc_fd(fd), incoming_buf(buf) {}
65 virtual void log() const;
66 private:
67 const int * mc_fd;
68 Text_Buf * incoming_buf;
69 };
70
71 int TTCN_Communication::mc_fd = -1;
72 HCNetworkHandler TTCN_Communication::hcnh;
73 boolean TTCN_Communication::local_addr_set = FALSE,
74 TTCN_Communication::mc_addr_set = FALSE,
75 TTCN_Communication::is_connected = FALSE;
76 Text_Buf TTCN_Communication::incoming_buf;
77 MC_Connection TTCN_Communication::mc_connection(
78 &TTCN_Communication::mc_fd, &TTCN_Communication::incoming_buf);
79 double TTCN_Communication::call_interval = 0.0;
80
81 void TTCN_Communication::set_local_address(const char *host_name)
82 {
83 if (local_addr_set)
84 TTCN_warning("The local address has already been set.");
85 if (is_connected)
86 TTCN_error("Trying to change the local address, but there is an existing "
87 "control connection to MC.");
88 if (host_name == NULL){
89 fprintf(stderr,"TTCN_Communication::set_local_address: internal error: " // There is no connection to the MC
90 "invalid host name.\r\n"); // We should log to the console also
91 TTCN_error("TTCN_Communication::set_local_address: internal error: "
92 "invalid host name.");
93 }
94 if (!hcnh.set_local_addr(host_name, 0)){
95 fprintf(stderr,"Could not get the IP address for the local address " // There is no connection to the MC
96 "(%s): Host name lookup failure.\r\n", host_name); // We should log to the console also
97 TTCN_error("Could not get the IP address for the local address "
98 "(%s): Host name lookup failure.", host_name);
99 }
100 TTCN_Logger::log_executor_misc(TitanLoggerApiSimple::ExecutorUnqualified_reason::local__address__was__set,
101 hcnh.get_local_host_str(), hcnh.get_local_addr_str(), 0);
102 local_addr_set = TRUE;
103 }
104
105 const IPAddress *TTCN_Communication::get_local_address()
106 {
107 if (!local_addr_set)
108 TTCN_error("TTCN_Communication::get_local_address: internal error: the "
109 "local address has not been set.");
110 return hcnh.get_local_addr();
111 }
112
113 void TTCN_Communication::set_mc_address(const char *host_name,
114 unsigned short tcp_port)
115 {
116 if (mc_addr_set)
117 TTCN_warning("The address of MC has already been set.");
118 if (is_connected)
119 TTCN_error("Trying to change the address of MC, but there is an existing connection.");
120 if (host_name == NULL){
121 fprintf(stderr,"TTCN_Communication::set_mc_address: internal error: invalid host name.\r\n");
122 TTCN_error("TTCN_Communication::set_mc_address: internal error: invalid host name.");
123 }
124 if (tcp_port <= 0){
125 fprintf(stderr,"TTCN_Communication::set_mc_address: internal error: invalid TCP port. %hu\r\n",tcp_port);
126 TTCN_error("TTCN_Communication::set_mc_address: internal error: invalid TCP port.");
127 }
128 hcnh.set_family(host_name);
129 if (!hcnh.set_mc_addr(host_name, tcp_port)){
130 fprintf(stderr,"Could not get the IP address of MC (%s): Host name lookup "
131 "failure.\r\n", host_name);
132 TTCN_error("Could not get the IP address of MC (%s): Host name lookup "
133 "failure.", host_name);
134 }
135 if ((hcnh.get_mc_addr())->is_local()){
136 fprintf(stderr,"The address of MC was set to a local IP address. This may "
137 "cause incorrect behavior if a HC from a remote host also "
138 "connects to MC.\r\n");
139 TTCN_warning("The address of MC was set to a local IP address. This may "
140 "cause incorrect behavior if a HC from a remote host also "
141 "connects to MC.");
142 }
143 TTCN_Logger::log_executor_misc(TitanLoggerApiSimple::ExecutorUnqualified_reason::address__of__mc__was__set,
144 hcnh.get_mc_host_str(), hcnh.get_mc_addr_str(), 0);
145 mc_addr_set = TRUE;
146 }
147
148 const IPAddress *TTCN_Communication::get_mc_address()
149 {
150 if (!mc_addr_set)
151 TTCN_error("TTCN_Communication::get_mc_address: internal error: the "
152 "address of MC has not been set.");
153 return hcnh.get_mc_addr();
154 }
155
156 bool TTCN_Communication::is_mc_connected()
157 {
158 return is_connected;
159 }
160
161 void TTCN_Communication::connect_mc()
162 {
163 if (is_connected) TTCN_error("Trying to re-connect to MC, but there is an "
164 "existing connection.");
165 if (!mc_addr_set) TTCN_error("Trying to connect to MC, but the address of "
166 "MC has not yet been set.");
167
168 // Trying to connect to local mc through unix domain socket
169 // TODO: Disable if config file parameter is set
170 if ((hcnh.get_mc_addr())->is_local()
171 || (local_addr_set && *(hcnh.get_mc_addr()) == *(hcnh.get_local_addr()))) {
172 sockaddr_un localaddr_unix;
173 memset(&localaddr_unix, 0, sizeof(localaddr_unix));
174 localaddr_unix.sun_family = AF_UNIX;
175 snprintf(localaddr_unix.sun_path, sizeof(localaddr_unix.sun_path),
176 "/tmp/ttcn3-mctr-%u", hcnh.get_mc_port());
177 mc_fd = socket(PF_UNIX, SOCK_STREAM, 0);
178 if (mc_fd >= (int)FD_SETSIZE) {
179 close(mc_fd);
180 } else if (mc_fd >= 0) {
181 if (connect(mc_fd, (struct sockaddr*)&localaddr_unix,
182 sizeof(localaddr_unix)) == 0) {
183 goto unix_end; // connected successfully
184 } else {
185 close(mc_fd);
186 }
187 }
188 }
189
190 #ifdef WIN32
191 again:
192 #endif
193 mc_fd = hcnh.socket();
194 if (mc_fd < 0) {
195 fprintf(stderr,"Socket creation failed when connecting to MC.");
196 TTCN_error("Socket creation failed when connecting to MC.");
197 }
198 else if (mc_fd >= (int)FD_SETSIZE) {
199 close(mc_fd);
200 fprintf(stderr,"When connecting to MC: "
201 "The file descriptor returned by the operating system (%d) is "
202 "too large for use with the select() system call.\r\n", mc_fd);
203 TTCN_error("When connecting to MC: "
204 "The file descriptor returned by the operating system (%d) is "
205 "too large for use with the select() system call.", mc_fd);
206 }
207
208 if (local_addr_set) {
209 if (hcnh.bind_local_addr(mc_fd)) {
210 fprintf(stderr,"Binding IP address %s to the local endpoint of the "
211 "control connection failed when connecting to MC.\r\n", hcnh.get_local_addr_str());
212 TTCN_error("Binding IP address %s to the local endpoint of the "
213 "control connection failed when connecting to MC.",
214 hcnh.get_local_addr_str());
215 close(mc_fd);
216 }
217 }
218
219 if (hcnh.connect_to_mc(mc_fd)) {
220 #ifdef WIN32
221 if (errno == EADDRINUSE) {
222 close(mc_fd);
223 errno = 0;
224 TTCN_warning("connect() returned error code EADDRINUSE. "
225 "Perhaps this is a Cygwin bug. Trying to connect again.");
226 goto again;
227 }
228 #endif
229 fprintf(stderr,"Connecting to MC failed. MC address: %s:%hu %s\r\n",hcnh.get_mc_addr_str(),hcnh.get_mc_port(),strerror(errno));
230 TTCN_error("Connecting to MC failed.");
231 close(mc_fd);
232 }
233
234 if (!local_addr_set) {
235 if (hcnh.getsockname_local_addr(mc_fd)) {
236 close(mc_fd);
237 TTCN_error("getsockname() system call failed on the socket of the "
238 "control connection to MC.");
239 }
240 TTCN_Logger::log_executor_misc(
241 TitanLoggerApiSimple::ExecutorUnqualified_reason::address__of__control__connection,
242 NULL, hcnh.get_local_addr_str(), 0);
243 local_addr_set = TRUE;
244 }
245
246 if (!set_tcp_nodelay(mc_fd)) {
247 close(mc_fd);
248 TTCN_error("Setting the TCP_NODELAY flag failed on the socket of "
249 "the control connection to MC.");
250 }
251
252 unix_end:
253
254 if (!set_close_on_exec(mc_fd)) {
255 close(mc_fd);
256 TTCN_error("Setting the close-on-exec flag failed on the socket of "
257 "the control connection to MC.");
258 }
259
260 Fd_And_Timeout_User::add_fd(mc_fd, &mc_connection, FD_EVENT_RD);
261
262 TTCN_Logger::log_executor_runtime(
263 TitanLoggerApiSimple::ExecutorRuntime_reason::connected__to__mc);
264
265 is_connected = TRUE;
266 }
267
268 void TTCN_Communication::disconnect_mc()
269 {
270 if (is_connected) {
271 shutdown(mc_fd, 1);
272 int recv_len;
273 do {
274 char buf[1024];
275 recv_len = recv(mc_fd, buf, sizeof(buf), 0);
276 } while (recv_len > 0);
277 errno = 0;
278 close_mc_connection();
279 TTCN_Logger::log_executor_runtime(
280 TitanLoggerApiSimple::ExecutorRuntime_reason::disconnected__from__mc);
281 }
282 }
283
284 void TTCN_Communication::close_mc_connection()
285 {
286 if (is_connected) {
287 int tmp_mc_fd = mc_fd;
288 call_interval = 0.0;
289 close(mc_fd);
290 mc_fd = -1;
291 is_connected = FALSE;
292 incoming_buf.reset();
293 // Removing the fd has to be done after closing the mc connection
294 // to prevent segmentation fault or broken pipe error
295 // in case remove_fd would try to print an error log.
296 Fd_And_Timeout_User::remove_fd(tmp_mc_fd, &mc_connection, FD_EVENT_RD);
297 Fd_And_Timeout_User::set_timer(&mc_connection, 0.0);
298 }
299 }
300
301 boolean TTCN_Communication::transport_unix_stream_supported()
302 {
303 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
304 if (fd >= 0) {
305 close(fd);
306 TTCN_Logger::log_executor_misc(
307 TitanLoggerApiSimple::ExecutorUnqualified_reason::host__support__unix__domain__sockets,
308 NULL, NULL, 0);
309 return TRUE;
310 } else {
311 TTCN_Logger::log_executor_misc(
312 TitanLoggerApiSimple::ExecutorUnqualified_reason::host__support__unix__domain__sockets,
313 NULL, NULL, errno);
314 return FALSE;
315 }
316 }
317
318 boolean TTCN_Communication::set_close_on_exec(int fd)
319 {
320 int flags = fcntl(fd, F_GETFD);
321 if (flags < 0) {
322 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
323 TTCN_Logger::log_event("System call fcntl(F_GETFD) failed on file "
324 "descriptor %d.", fd);
325 TTCN_Logger::OS_error();
326 TTCN_Logger::end_event();
327 return FALSE;
328 }
329
330 flags |= FD_CLOEXEC;
331
332 if (fcntl(fd, F_SETFD, flags) == -1) {
333 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
334 TTCN_Logger::log_event("System call fcntl(F_SETFD) failed on file "
335 "descriptor %d.", fd);
336 TTCN_Logger::OS_error();
337 TTCN_Logger::end_event();
338 return FALSE;
339 }
340 return TRUE;
341 }
342
343 boolean TTCN_Communication::set_non_blocking_mode(int fd,
344 boolean enable_nonblock)
345 {
346 int flags = fcntl(fd, F_GETFL);
347 if (flags < 0) {
348 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
349 TTCN_Logger::log_event("System call fcntl(F_GETFL) failed on file "
350 "descriptor %d.", fd);
351 TTCN_Logger::OS_error();
352 TTCN_Logger::end_event();
353 return FALSE;
354 }
355
356 if (enable_nonblock) flags |= O_NONBLOCK;
357 else flags &= ~O_NONBLOCK;
358
359 if (fcntl(fd, F_SETFL, flags) == -1) {
360 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
361 TTCN_Logger::log_event("System call fcntl(F_SETFL) failed on file "
362 "descriptor %d.", fd);
363 TTCN_Logger::OS_error();
364 TTCN_Logger::end_event();
365 return FALSE;
366 }
367 return TRUE;
368 }
369
370 boolean TTCN_Communication::set_tcp_nodelay(int fd)
371 {
372 const int on = 1;
373 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&on,
374 sizeof(on))) {
375 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
376 TTCN_Logger::log_event("System call setsockopt(TCP_NODELAY) failed on "
377 "file descriptor %d.", fd);
378 TTCN_Logger::OS_error();
379 TTCN_Logger::end_event();
380 return FALSE;
381 }
382 return TRUE;
383 }
384
385 boolean TTCN_Communication::increase_send_buffer(int fd,
386 int &old_size, int& new_size)
387 {
388 int set_size;
389 socklen_type optlen = sizeof(old_size);
390 // obtaining the current buffer size first
391 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&old_size, &optlen))
392 goto getsockopt_failure;
393 if (old_size <= 0) {
394 TTCN_Logger::log(TTCN_Logger::ERROR_UNQUALIFIED,
395 "System call getsockopt(SO_SNDBUF) returned invalid buffer size (%d) "
396 "on file descriptor %d.", old_size, fd);
397 return FALSE;
398 }
399 // trying to double the buffer size
400 set_size = 2 * old_size;
401 if (set_size > old_size) {
402 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&set_size,
403 sizeof(set_size))) {
404 // the operation failed
405 switch (errno) {
406 case ENOMEM:
407 case ENOBUFS:
408 errno = 0;
409 break;
410 default:
411 // other error codes indicate a fatal error
412 goto setsockopt_failure;
413 }
414 } else {
415 // the operation was successful
416 goto success;
417 }
418 }
419 // trying to perform a binary search to determine the maximum buffer size
420 set_size = old_size;
421 for (int size_step = old_size / 2; size_step > 0; size_step /= 2) {
422 int tried_size = set_size + size_step;
423 if (tried_size > set_size) {
424 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&tried_size,
425 sizeof(tried_size))) {
426 // the operation failed
427 switch (errno) {
428 case ENOMEM:
429 case ENOBUFS:
430 errno = 0;
431 break;
432 default:
433 // other error codes indicate a fatal error
434 goto setsockopt_failure;
435 }
436 } else {
437 // the operation was successful
438 set_size = tried_size;
439 }
440 }
441 }
442 if (set_size <= old_size) return FALSE;
443 success:
444 // querying the new effective buffer size (it might be smaller
445 // than set_size but should not be smaller than old_size)
446 optlen = sizeof(new_size);
447 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&new_size,
448 &optlen)) goto getsockopt_failure;
449 if (new_size > old_size) return TRUE;
450 else {
451 if (new_size < old_size) TTCN_Logger::log(TTCN_Logger::ERROR_UNQUALIFIED,
452 "System call getsockopt(SO_SNDBUF) returned unexpected buffer size "
453 "(%d, after increasing it from %d to %d) on file descriptor %d.",
454 new_size, old_size, set_size, fd);
455 return FALSE;
456 }
457 getsockopt_failure:
458 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
459 TTCN_Logger::log_event("System call getsockopt(SO_SNDBUF) failed on file "
460 "descriptor %d.", fd);
461 TTCN_Logger::OS_error();
462 TTCN_Logger::end_event();
463 return FALSE;
464 setsockopt_failure:
465 TTCN_Logger::begin_event(TTCN_Logger::ERROR_UNQUALIFIED);
466 TTCN_Logger::log_event("System call setsockopt(SO_SNDBUF) failed on file "
467 "descriptor %d.", fd);
468 TTCN_Logger::OS_error();
469 TTCN_Logger::end_event();
470 return FALSE;
471 }
472
473 #define INITIAL_CALL_INTERVAL 1.0
474 #define CALL_INTERVAL_INCREMENT 2.0
475
476 void TTCN_Communication::enable_periodic_call()
477 {
478 call_interval = INITIAL_CALL_INTERVAL;
479 Fd_And_Timeout_User::set_timer(&mc_connection, call_interval, TRUE,
480 FALSE /*call_anyway*/);
481 }
482
483 void TTCN_Communication::increase_call_interval()
484 {
485 if (call_interval <= 0.0) TTCN_error("Internal error: "
486 "TTCN_Communication::increase_call_interval() was called when call "
487 "interval is not set.");
488 call_interval *= CALL_INTERVAL_INCREMENT;
489 Fd_And_Timeout_User::set_timer(&mc_connection, call_interval, TRUE,
490 FALSE /*call_anyway*/);
491 }
492
493 void TTCN_Communication::disable_periodic_call()
494 {
495 Fd_And_Timeout_User::set_timer(&mc_connection, 0.0);
496 call_interval = 0.0;
497 }
498
499 void MC_Connection::Handle_Fd_Event(int fd, boolean is_readable, boolean,
500 boolean is_error)
501 {
502 if (fd != *mc_fd)
503 TTCN_error("MC_Connection::Fd_And_Timeout_Event_Handler: unexpected "
504 "file descriptor"); // not necessary - debugging
505 if (is_error)
506 TTCN_warning("Error occurred on the control connection to MC");
507 if (is_readable) {
508 char *buf_ptr;
509 int buf_len;
510 incoming_buf->get_end(buf_ptr, buf_len);
511
512 int recv_len = recv(*mc_fd, buf_ptr, buf_len, 0);
513
514 if (recv_len > 0) {
515 // reason: data has arrived
516 incoming_buf->increase_length(recv_len);
517 // If the component is idle the processing is done in the outer
518 // stack frame (i.e. in TTCN_Runtime::xxx_main()).
519 if (!TTCN_Runtime::is_idle())
520 TTCN_Communication::process_all_messages_tc();
521 } else {
522 // First closing the TCP connection to avoid EPIPE ("Broken pipe")
523 // errors and/or SIGPIPE signals when trying to send anything
524 // (e.g. log events or error messages) towards MC.
525 TTCN_Communication::close_mc_connection();
526 if (recv_len == 0) {
527 // reason: TCP connection was closed by peer
528 TTCN_error("Control connection was closed unexpectedly by MC.");
529 } else {
530 // reason: error occurred
531 TTCN_error("Receiving data on the control connection from MC "
532 "failed.");
533 }
534 }
535 }
536 }
537
538 void MC_Connection::Handle_Timeout(double /*time_since_last_call*/)
539 {
540 if (TTCN_Runtime::get_state() == TTCN_Runtime::HC_OVERLOADED) {
541 // indicate the timeout to be handled in process_all_messages_hc()
542 TTCN_Runtime::set_state(TTCN_Runtime::HC_OVERLOADED_TIMEOUT);
543 } else {
544 TTCN_warning("Unexpected timeout occurred on the control "
545 "connection to MC.");
546 TTCN_Communication::disable_periodic_call();
547 }
548 }
549
550 void MC_Connection::log() const
551 {
552 TTCN_Logger::log_event("mc connection");
553 }
554
555 void TTCN_Communication::process_all_messages_hc()
556 {
557 if (!TTCN_Runtime::is_hc()) TTCN_error("Internal error: "
558 "TTCN_Communication::process_all_messages_hc() was called in invalid "
559 "state.");
560 TTCN_Runtime::wait_terminated_processes();
561 boolean wait_flag = FALSE;
562 boolean check_overload = TTCN_Runtime::is_overloaded();
563 while (incoming_buf.is_message()) {
564 wait_flag = TRUE;
565 int msg_len = incoming_buf.pull_int().get_val();
566 int msg_end = incoming_buf.get_pos() + msg_len;
567 int msg_type = incoming_buf.pull_int().get_val();
568 // messages: MC -> HC
569 switch (msg_type) {
570 case MSG_ERROR:
571 process_error();
572 break;
573 case MSG_CONFIGURE:
574 process_configure(msg_end);
575 break;
576 case MSG_CREATE_MTC:
577 process_create_mtc();
578 TTCN_Runtime::wait_terminated_processes();
579 wait_flag = FALSE;
580 check_overload = FALSE;
581 break;
582 case MSG_CREATE_PTC:
583 process_create_ptc();
584 TTCN_Runtime::wait_terminated_processes();
585 wait_flag = FALSE;
586 check_overload = FALSE;
587 break;
588 case MSG_KILL_PROCESS:
589 process_kill_process();
590 TTCN_Runtime::wait_terminated_processes();
591 wait_flag = FALSE;
592 break;
593 case MSG_EXIT_HC:
594 process_exit_hc();
595 break;
596 case MSG_DEBUG_COMMAND:
597 process_debug_command();
598 break;
599 default:
600 process_unsupported_message(msg_type, msg_end);
601 }
602 }
603 if (wait_flag) TTCN_Runtime::wait_terminated_processes();
604 if (check_overload && TTCN_Runtime::is_overloaded())
605 TTCN_Runtime::check_overload();
606 }
607
608 void TTCN_Communication::process_all_messages_tc()
609 {
610 if (!TTCN_Runtime::is_tc()) TTCN_error("Internal error: "
611 "TTCN_Communication::process_all_messages_tc() was called in invalid "
612 "state.");
613 while (incoming_buf.is_message()) {
614 int msg_len = incoming_buf.pull_int().get_val();
615 int msg_end = incoming_buf.get_pos() + msg_len;
616 int msg_type = incoming_buf.pull_int().get_val();
617 // messages: MC -> TC
618 switch (msg_type) {
619 case MSG_ERROR:
620 process_error();
621 break;
622 case MSG_CREATE_ACK:
623 process_create_ack();
624 break;
625 case MSG_START_ACK:
626 process_start_ack();
627 break;
628 case MSG_STOP:
629 process_stop();
630 break;
631 case MSG_STOP_ACK:
632 process_stop_ack();
633 break;
634 case MSG_KILL_ACK:
635 process_kill_ack();
636 break;
637 case MSG_RUNNING:
638 process_running();
639 break;
640 case MSG_ALIVE:
641 process_alive();
642 break;
643 case MSG_DONE_ACK:
644 process_done_ack(msg_end);
645 break;
646 case MSG_KILLED_ACK:
647 process_killed_ack();
648 break;
649 case MSG_CANCEL_DONE:
650 if (TTCN_Runtime::is_mtc()) process_cancel_done_mtc();
651 else process_cancel_done_ptc();
652 break;
653 case MSG_COMPONENT_STATUS:
654 if (TTCN_Runtime::is_mtc()) process_component_status_mtc(msg_end);
655 else process_component_status_ptc(msg_end);
656 break;
657 case MSG_CONNECT_LISTEN:
658 process_connect_listen();
659 break;
660 case MSG_CONNECT:
661 process_connect();
662 break;
663 case MSG_CONNECT_ACK:
664 process_connect_ack();
665 break;
666 case MSG_DISCONNECT:
667 process_disconnect();
668 break;
669 case MSG_DISCONNECT_ACK:
670 process_disconnect_ack();
671 break;
672 case MSG_MAP:
673 process_map();
674 break;
675 case MSG_MAP_ACK:
676 process_map_ack();
677 break;
678 case MSG_UNMAP:
679 process_unmap();
680 break;
681 case MSG_UNMAP_ACK:
682 process_unmap_ack();
683 break;
684 case MSG_DEBUG_COMMAND:
685 process_debug_command();
686 break;
687 default:
688 if (TTCN_Runtime::is_mtc()) {
689 // messages: MC -> MTC
690 switch (msg_type) {
691 case MSG_EXECUTE_CONTROL:
692 process_execute_control();
693 break;
694 case MSG_EXECUTE_TESTCASE:
695 process_execute_testcase();
696 break;
697 case MSG_PTC_VERDICT:
698 process_ptc_verdict();
699 break;
700 case MSG_CONTINUE:
701 process_continue();
702 break;
703 case MSG_EXIT_MTC:
704 process_exit_mtc();
705 break;
706 default:
707 process_unsupported_message(msg_type, msg_end);
708 }
709 } else {
710 // messages: MC -> PTC
711 switch (msg_type) {
712 case MSG_START:
713 process_start();
714 break;
715 case MSG_KILL:
716 process_kill();
717 break;
718 default:
719 process_unsupported_message(msg_type, msg_end);
720 }
721 }
722 }
723 }
724 }
725
726 void TTCN_Communication::process_debug_messages()
727 {
728 // receives and processes messages from the MC, while test execution is halted
729 // by the debugger
730 char *buf_ptr;
731 int buf_len;
732 Text_Buf storage_buf;
733 while (ttcn3_debugger.is_halted()) {
734 incoming_buf.get_end(buf_ptr, buf_len);
735
736 int recv_len = recv(mc_fd, buf_ptr, buf_len, 0);
737
738 if (recv_len > 0) {
739 incoming_buf.increase_length(recv_len);
740
741 while (incoming_buf.is_message() && ttcn3_debugger.is_halted()) {
742 int msg_len = incoming_buf.pull_int().get_val();
743 int msg_end = incoming_buf.get_pos() + msg_len;
744 int msg_type = incoming_buf.pull_int().get_val();
745 // process only debug commands and 'stop' messages, store the rest
746 switch (msg_type) {
747 case MSG_DEBUG_COMMAND:
748 process_debug_command();
749 break;
750 case MSG_STOP:
751 process_stop();
752 break;
753 default: {
754 // store all other messages in a different buffer
755 int data_len = msg_end - incoming_buf.get_pos();
756 char* msg_data = new char[data_len];
757 incoming_buf.pull_raw(data_len, msg_data);
758 incoming_buf.cut_message();
759 storage_buf.push_int(msg_type);
760 storage_buf.push_raw(data_len, msg_data);
761 delete [] msg_data;
762 storage_buf.calculate_length();
763 break; }
764 }
765 }
766 }
767 }
768 // append the stored messages to the beginning of the main buffer and
769 // process them
770 if (storage_buf.is_message()) {
771 incoming_buf.push_raw_front(storage_buf.get_len(), storage_buf.get_data());
772 process_all_messages_tc();
773 }
774 }
775
776 void TTCN_Communication::send_version()
777 {
778 Text_Buf text_buf;
779 text_buf.push_int(MSG_VERSION);
780 text_buf.push_int(TTCN3_MAJOR);
781 text_buf.push_int(TTCN3_MINOR);
782 text_buf.push_int(TTCN3_PATCHLEVEL);
783 #ifdef TTCN3_BUILDNUMBER
784 text_buf.push_int(TTCN3_BUILDNUMBER);
785 #else
786 text_buf.push_int((RInt)0);
787 #endif
788 Module_List::push_version(text_buf);
789 struct utsname uts;
790 if (uname(&uts) < 0) TTCN_error("System call uname() failed.");
791 text_buf.push_string(uts.nodename);
792 text_buf.push_string(uts.machine);
793 text_buf.push_string(uts.sysname);
794 text_buf.push_string(uts.release);
795 text_buf.push_string(uts.version);
796 boolean unix_stream_supported = transport_unix_stream_supported();
797
798 // LOCAL (software loop) and INET_STREAM (TCP) transports are always
799 // supported
800 int n_supported_transports = 2;
801
802 if (unix_stream_supported) n_supported_transports++;
803 text_buf.push_int(n_supported_transports);
804 text_buf.push_int(TRANSPORT_LOCAL);
805 text_buf.push_int(TRANSPORT_INET_STREAM);
806 if (unix_stream_supported)
807 text_buf.push_int(TRANSPORT_UNIX_STREAM);
808 send_message(text_buf);
809 }
810
811 void TTCN_Communication::send_configure_ack()
812 {
813 Text_Buf text_buf;
814 text_buf.push_int(MSG_CONFIGURE_ACK);
815 send_message(text_buf);
816 }
817
818 void TTCN_Communication::send_configure_nak()
819 {
820 Text_Buf text_buf;
821 text_buf.push_int(MSG_CONFIGURE_NAK);
822 send_message(text_buf);
823 }
824
825 void TTCN_Communication::send_create_nak(component component_reference,
826 const char *fmt_str, ...)
827 {
828 va_list ap;
829 va_start(ap, fmt_str);
830 char *error_str = mprintf_va_list(fmt_str, ap);
831 va_end(ap);
832 Text_Buf text_buf;
833 text_buf.push_int(MSG_CREATE_NAK);
834 text_buf.push_int(component_reference);
835 text_buf.push_string(error_str);
836 Free(error_str);
837 send_message(text_buf);
838 }
839
840 void TTCN_Communication::send_hc_ready()
841 {
842 Text_Buf text_buf;
843 text_buf.push_int(MSG_HC_READY);
844 send_message(text_buf);
845 }
846
847 void TTCN_Communication::send_create_req(const char *component_type_module,
848 const char *component_type_name, const char *component_name,
849 const char *component_location, boolean is_alive)
850 {
851 Text_Buf text_buf;
852 text_buf.push_int(MSG_CREATE_REQ);
853 text_buf.push_string(component_type_module);
854 text_buf.push_string(component_type_name);
855 text_buf.push_string(component_name);
856 text_buf.push_string(component_location);
857 text_buf.push_int(is_alive ? 1 : 0);
858 send_message(text_buf);
859 }
860
861 void TTCN_Communication::prepare_start_req(Text_Buf& text_buf,
862 component component_reference, const char *module_name,
863 const char *function_name)
864 {
865 text_buf.push_int(MSG_START_REQ);
866 text_buf.push_int(component_reference);
867 text_buf.push_string(module_name);
868 text_buf.push_string(function_name);
869 }
870
871 void TTCN_Communication::send_stop_req(component component_reference)
872 {
873 Text_Buf text_buf;
874 text_buf.push_int(MSG_STOP_REQ);
875 text_buf.push_int(component_reference);
876 send_message(text_buf);
877 }
878
879 void TTCN_Communication::send_kill_req(component component_reference)
880 {
881 Text_Buf text_buf;
882 text_buf.push_int(MSG_KILL_REQ);
883 text_buf.push_int(component_reference);
884 send_message(text_buf);
885 }
886
887 void TTCN_Communication::send_is_running(component component_reference)
888 {
889 Text_Buf text_buf;
890 text_buf.push_int(MSG_IS_RUNNING);
891 text_buf.push_int(component_reference);
892 send_message(text_buf);
893 }
894
895 void TTCN_Communication::send_is_alive(component component_reference)
896 {
897 Text_Buf text_buf;
898 text_buf.push_int(MSG_IS_ALIVE);
899 text_buf.push_int(component_reference);
900 send_message(text_buf);
901 }
902
903 void TTCN_Communication::send_done_req(component component_reference)
904 {
905 Text_Buf text_buf;
906 text_buf.push_int(MSG_DONE_REQ);
907 text_buf.push_int(component_reference);
908 send_message(text_buf);
909 }
910
911 void TTCN_Communication::send_killed_req(component component_reference)
912 {
913 Text_Buf text_buf;
914 text_buf.push_int(MSG_KILLED_REQ);
915 text_buf.push_int(component_reference);
916 send_message(text_buf);
917 }
918
919 void TTCN_Communication::send_cancel_done_ack(component component_reference)
920 {
921 Text_Buf text_buf;
922 text_buf.push_int(MSG_CANCEL_DONE_ACK);
923 text_buf.push_int(component_reference);
924 send_message(text_buf);
925 }
926
927 void TTCN_Communication::send_connect_req(component src_component,
928 const char *src_port, component dst_component, const char *dst_port)
929 {
930 Text_Buf text_buf;
931 text_buf.push_int(MSG_CONNECT_REQ);
932 text_buf.push_int(src_component);
933 text_buf.push_string(src_port);
934 text_buf.push_int(dst_component);
935 text_buf.push_string(dst_port);
936 send_message(text_buf);
937 }
938
939 void TTCN_Communication::send_connect_listen_ack_inet_stream(
940 const char *local_port, component remote_component,
941 const char *remote_port, const IPAddress *local_address)
942 {
943 Text_Buf text_buf;
944 text_buf.push_int(MSG_CONNECT_LISTEN_ACK);
945 text_buf.push_string(local_port);
946 text_buf.push_int(remote_component);
947 text_buf.push_string(remote_port);
948 text_buf.push_int(TRANSPORT_INET_STREAM);
949 local_address->push_raw(text_buf);
950 send_message(text_buf);
951 }
952
953 void TTCN_Communication::send_connect_listen_ack_unix_stream(
954 const char *local_port, component remote_component,
955 const char *remote_port, const struct sockaddr_un *local_address)
956 {
957 Text_Buf text_buf;
958 text_buf.push_int(MSG_CONNECT_LISTEN_ACK);
959 text_buf.push_string(local_port);
960 text_buf.push_int(remote_component);
961 text_buf.push_string(remote_port);
962 text_buf.push_int(TRANSPORT_UNIX_STREAM);
963 text_buf.push_string(local_address->sun_path);
964 send_message(text_buf);
965 }
966
967 void TTCN_Communication::send_connected(const char *local_port,
968 component remote_component, const char *remote_port)
969 {
970 Text_Buf text_buf;
971 text_buf.push_int(MSG_CONNECTED);
972 text_buf.push_string(local_port);
973 text_buf.push_int(remote_component);
974 text_buf.push_string(remote_port);
975 send_message(text_buf);
976 }
977
978 void TTCN_Communication::send_connect_error(const char *local_port,
979 component remote_component, const char *remote_port,
980 const char *fmt_str, ...)
981 {
982 va_list ap;
983 va_start(ap, fmt_str);
984 char *error_str = mprintf_va_list(fmt_str, ap);
985 va_end(ap);
986 Text_Buf text_buf;
987 text_buf.push_int(MSG_CONNECT_ERROR);
988 text_buf.push_string(local_port);
989 text_buf.push_int(remote_component);
990 text_buf.push_string(remote_port);
991 text_buf.push_string(error_str);
992 Free(error_str);
993 send_message(text_buf);
994 }
995
996 void TTCN_Communication::send_disconnect_req(component src_component,
997 const char *src_port, component dst_component, const char *dst_port)
998 {
999 Text_Buf text_buf;
1000 text_buf.push_int(MSG_DISCONNECT_REQ);
1001 text_buf.push_int(src_component);
1002 text_buf.push_string(src_port);
1003 text_buf.push_int(dst_component);
1004 text_buf.push_string(dst_port);
1005 send_message(text_buf);
1006 }
1007
1008 void TTCN_Communication::send_disconnected(const char *local_port,
1009 component remote_component, const char *remote_port)
1010 {
1011 Text_Buf text_buf;
1012 text_buf.push_int(MSG_DISCONNECTED);
1013 text_buf.push_string(local_port);
1014 text_buf.push_int(remote_component);
1015 text_buf.push_string(remote_port);
1016 send_message(text_buf);
1017 }
1018
1019 void TTCN_Communication::send_map_req(component src_component,
1020 const char *src_port, const char *system_port)
1021 {
1022 Text_Buf text_buf;
1023 text_buf.push_int(MSG_MAP_REQ);
1024 text_buf.push_int(src_component);
1025 text_buf.push_string(src_port);
1026 text_buf.push_string(system_port);
1027 send_message(text_buf);
1028 }
1029
1030 void TTCN_Communication::send_mapped(const char *local_port,
1031 const char *system_port)
1032 {
1033 Text_Buf text_buf;
1034 text_buf.push_int(MSG_MAPPED);
1035 text_buf.push_string(local_port);
1036 text_buf.push_string(system_port);
1037 send_message(text_buf);
1038 }
1039
1040 void TTCN_Communication::send_unmap_req(component src_component,
1041 const char *src_port, const char *system_port)
1042 {
1043 Text_Buf text_buf;
1044 text_buf.push_int(MSG_UNMAP_REQ);
1045 text_buf.push_int(src_component);
1046 text_buf.push_string(src_port);
1047 text_buf.push_string(system_port);
1048 send_message(text_buf);
1049 }
1050
1051 void TTCN_Communication::send_unmapped(const char *local_port,
1052 const char *system_port)
1053 {
1054 Text_Buf text_buf;
1055 text_buf.push_int(MSG_UNMAPPED);
1056 text_buf.push_string(local_port);
1057 text_buf.push_string(system_port);
1058 send_message(text_buf);
1059 }
1060
1061 void TTCN_Communication::send_mtc_created()
1062 {
1063 Text_Buf text_buf;
1064 text_buf.push_int(MSG_MTC_CREATED);
1065 send_message(text_buf);
1066 }
1067
1068 void TTCN_Communication::send_testcase_started(const char *testcase_module,
1069 const char *testcase_name, const char *mtc_comptype_module,
1070 const char *mtc_comptype_name, const char *system_comptype_module,
1071 const char *system_comptype_name)
1072 {
1073 Text_Buf text_buf;
1074 text_buf.push_int(MSG_TESTCASE_STARTED);
1075 text_buf.push_string(testcase_module);
1076 text_buf.push_string(testcase_name);
1077 text_buf.push_string(mtc_comptype_module);
1078 text_buf.push_string(mtc_comptype_name);
1079 text_buf.push_string(system_comptype_module);
1080 text_buf.push_string(system_comptype_name);
1081 send_message(text_buf);
1082 }
1083
1084 void TTCN_Communication::send_testcase_finished(verdicttype final_verdict,
1085 const char* reason)
1086 {
1087 Text_Buf text_buf;
1088 text_buf.push_int(MSG_TESTCASE_FINISHED);
1089 text_buf.push_int(final_verdict);
1090 text_buf.push_string(reason);
1091 send_message(text_buf);
1092 }
1093
1094 void TTCN_Communication::send_mtc_ready()
1095 {
1096 Text_Buf text_buf;
1097 text_buf.push_int(MSG_MTC_READY);
1098 send_message(text_buf);
1099 }
1100
1101 void TTCN_Communication::send_ptc_created(component component_reference)
1102 {
1103 Text_Buf text_buf;
1104 text_buf.push_int(MSG_PTC_CREATED);
1105 text_buf.push_int(component_reference);
1106 send_message(text_buf);
1107 }
1108
1109 void TTCN_Communication::prepare_stopped(Text_Buf& text_buf,
1110 const char *return_type)
1111 {
1112 text_buf.push_int(MSG_STOPPED);
1113 text_buf.push_string(return_type);
1114 }
1115
1116 void TTCN_Communication::send_stopped()
1117 {
1118 Text_Buf text_buf;
1119 text_buf.push_int(MSG_STOPPED);
1120 // add an empty return type
1121 text_buf.push_string(NULL);
1122 send_message(text_buf);
1123 }
1124
1125 void TTCN_Communication::prepare_stopped_killed(Text_Buf& text_buf,
1126 verdicttype final_verdict, const char *return_type, const char* reason)
1127 {
1128 text_buf.push_int(MSG_STOPPED_KILLED);
1129 text_buf.push_int(final_verdict);
1130 text_buf.push_string(reason);
1131 text_buf.push_string(return_type);
1132 }
1133
1134 void TTCN_Communication::send_stopped_killed(verdicttype final_verdict,
1135 const char* reason)
1136 {
1137 Text_Buf text_buf;
1138 text_buf.push_int(MSG_STOPPED_KILLED);
1139 text_buf.push_int(final_verdict);
1140 text_buf.push_string(reason);
1141 // add an empty return type
1142 text_buf.push_string(NULL);
1143 send_message(text_buf);
1144 }
1145
1146 void TTCN_Communication::send_killed(verdicttype final_verdict,
1147 const char* reason)
1148 {
1149 Text_Buf text_buf;
1150 text_buf.push_int(MSG_KILLED);
1151 text_buf.push_int(final_verdict);
1152 text_buf.push_string(reason);
1153 send_message(text_buf);
1154 }
1155
1156 void TTCN_Communication::send_debug_return_value(int return_type, const char* message)
1157 {
1158 Text_Buf text_buf;
1159 text_buf.push_int(MSG_DEBUG_RETURN_VALUE);
1160 text_buf.push_int(return_type);
1161 timeval tv;
1162 gettimeofday(&tv, NULL);
1163 text_buf.push_int(tv.tv_sec);
1164 text_buf.push_int(tv.tv_usec);
1165 text_buf.push_string(message);
1166 send_message(text_buf);
1167 }
1168
1169 void TTCN_Communication::send_debug_halt_req()
1170 {
1171 Text_Buf text_buf;
1172 text_buf.push_int(MSG_DEBUG_HALT_REQ);
1173 send_message(text_buf);
1174 }
1175
1176 boolean TTCN_Communication::send_log(time_t timestamp_sec, long timestamp_usec,
1177 unsigned int event_severity, size_t message_text_len,
1178 const char *message_text)
1179 {
1180 if (is_connected) {
1181 Text_Buf text_buf;
1182 text_buf.push_int(MSG_LOG);
1183 text_buf.push_int(timestamp_sec);
1184 text_buf.push_int(timestamp_usec);
1185 text_buf.push_int(event_severity);
1186 text_buf.push_int(message_text_len);
1187 text_buf.push_raw(message_text_len, message_text);
1188 send_message(text_buf);
1189 /* If an ERROR message (indicating a version mismatch) arrives from MC
1190 in state HC_IDLE (i.e. before CONFIGURE) it shall be
1191 printed to the console as well. */
1192 if (TTCN_Runtime::get_state() == TTCN_Runtime::HC_IDLE) return FALSE;
1193 else return TRUE;
1194 } else {
1195 switch (TTCN_Runtime::get_state()) {
1196 case TTCN_Runtime::HC_EXIT:
1197 case TTCN_Runtime::MTC_INITIAL:
1198 case TTCN_Runtime::MTC_EXIT:
1199 case TTCN_Runtime::PTC_INITIAL:
1200 case TTCN_Runtime::PTC_EXIT:
1201 /* Do not print the first/last few lines of logs to the console
1202 even if ConsoleMask is set to LOG_ALL */
1203 return TRUE;
1204 default:
1205 return FALSE;
1206 }
1207 }
1208 }
1209
1210 void TTCN_Communication::send_error(const char *fmt_str, ...)
1211 {
1212 va_list ap;
1213 va_start(ap, fmt_str);
1214 char *error_str = mprintf_va_list(fmt_str, ap);
1215 va_end(ap);
1216 Text_Buf text_buf;
1217 text_buf.push_int((RInt)MSG_ERROR);
1218 text_buf.push_string(error_str);
1219 Free(error_str);
1220 send_message(text_buf);
1221 }
1222
1223 void TTCN_Communication::send_message(Text_Buf& text_buf)
1224 {
1225 if (!is_connected) TTCN_error("Trying to send a message to MC, but the "
1226 "control connection is down.");
1227 text_buf.calculate_length();
1228 const char *msg_ptr = text_buf.get_data();
1229 size_t msg_len = text_buf.get_len(), sent_len = 0;
1230 while (sent_len < msg_len) {
1231 int ret_val = send(mc_fd, msg_ptr + sent_len, msg_len - sent_len, 0);
1232 if (ret_val > 0) sent_len += ret_val;
1233 else {
1234 switch (errno) {
1235 case EINTR:
1236 // a signal occurred: do nothing, just try again
1237 errno = 0;
1238 break;
1239 default:
1240 close_mc_connection();
1241 TTCN_error("Sending data on the control connection to MC "
1242 "failed.");
1243 }
1244 }
1245 }
1246 }
1247
1248 void TTCN_Communication::process_configure(int msg_end)
1249 {
1250 switch (TTCN_Runtime::get_state()) {
1251 case TTCN_Runtime::HC_IDLE:
1252 case TTCN_Runtime::HC_ACTIVE:
1253 case TTCN_Runtime::HC_OVERLOADED:
1254 break;
1255 default:
1256 incoming_buf.cut_message();
1257 send_error("Message CONFIGURE arrived in invalid state.");
1258 return;
1259 }
1260
1261 TTCN_Runtime::set_state(TTCN_Runtime::HC_CONFIGURING);
1262 TTCN_Logger::log_configdata(TitanLoggerApiSimple::ExecutorConfigdata_reason::received__from__mc);
1263
1264 // take the config string directly from the buffer for efficiency reasons
1265 int config_str_len = incoming_buf.pull_int().get_val();
1266 int config_str_begin = incoming_buf.get_pos();
1267 if (config_str_begin + config_str_len != msg_end) {
1268 incoming_buf.cut_message();
1269 send_error("Malformed message CONFIGURE was received.");
1270 return;
1271 }
1272 const char *config_str = incoming_buf.get_data() + config_str_begin;
1273 boolean success = process_config_string(config_str, config_str_len);
1274
1275 // Only non component specific settings will be applied. The plug-ins need
1276 // to be loaded due to resetting.
1277 TTCN_Logger::load_plugins(NULL_COMPREF, "");
1278 TTCN_Logger::set_plugin_parameters(NULL_COMPREF, "");
1279 TTCN_Logger::open_file();
1280 if (success) {
1281 try {
1282 Module_List::log_param();
1283 Module_List::post_init_modules();
1284 } catch (const TC_Error& TC_error) {
1285 TTCN_Logger::log_executor_runtime(
1286 TitanLoggerApiSimple::ExecutorRuntime_reason::initialization__of__modules__failed);
1287 success = FALSE;
1288 }
1289 } else {
1290 TTCN_Logger::log_configdata(
1291 TitanLoggerApiSimple::ExecutorConfigdata_reason::processing__failed, NULL);
1292 }
1293
1294 if (success) {
1295 send_configure_ack();
1296 TTCN_Runtime::set_state(TTCN_Runtime::HC_ACTIVE);
1297 TTCN_Logger::log_configdata(
1298 TitanLoggerApiSimple::ExecutorConfigdata_reason::processing__succeeded);
1299 } else {
1300 send_configure_nak();
1301 TTCN_Runtime::set_state(TTCN_Runtime::HC_IDLE);
1302 }
1303
1304 incoming_buf.cut_message();
1305 }
1306
1307 void TTCN_Communication::process_create_mtc()
1308 {
1309 incoming_buf.cut_message();
1310 TTCN_Runtime::process_create_mtc();
1311 }
1312
1313 void TTCN_Communication::process_create_ptc()
1314 {
1315 component component_reference = (component)incoming_buf.pull_int().get_val();
1316 if (component_reference < FIRST_PTC_COMPREF) {
1317 incoming_buf.cut_message();
1318 send_error("Message CREATE_PTC refers to invalid "
1319 "component reference %d.", component_reference);
1320 return;
1321 }
1322 qualified_name component_type;
1323 incoming_buf.pull_qualified_name(component_type);
1324 if (component_type.module_name == NULL ||
1325 component_type.definition_name == NULL) {
1326 incoming_buf.cut_message();
1327 delete [] component_type.module_name;
1328 delete [] component_type.definition_name;
1329 send_error("Message CREATE_PTC with component reference %d contains "
1330 "an invalid component type.", component_reference);
1331 return;
1332 }
1333 char *component_name = incoming_buf.pull_string();
1334 boolean is_alive = incoming_buf.pull_int().get_val();
1335 qualified_name current_testcase;
1336 incoming_buf.pull_qualified_name(current_testcase);
1337 incoming_buf.cut_message();
1338
1339 try {
1340 TTCN_Runtime::process_create_ptc(component_reference,
1341 component_type.module_name, component_type.definition_name,
1342 component_name, is_alive, current_testcase.module_name,
1343 current_testcase.definition_name);
1344 } catch (...) {
1345 // to prevent from memory leaks
1346 delete [] component_type.module_name;
1347 delete [] component_type.definition_name;
1348 delete [] component_name;
1349 delete [] current_testcase.module_name;
1350 delete [] current_testcase.definition_name;
1351 throw;
1352 }
1353
1354 delete [] component_type.module_name;
1355 delete [] component_type.definition_name;
1356 delete [] component_name;
1357 delete [] current_testcase.module_name;
1358 delete [] current_testcase.definition_name;
1359 }
1360
1361 void TTCN_Communication::process_kill_process()
1362 {
1363 component component_reference = (component)incoming_buf.pull_int().get_val();
1364 incoming_buf.cut_message();
1365 TTCN_Runtime::process_kill_process(component_reference);
1366 }
1367
1368 void TTCN_Communication::process_exit_hc()
1369 {
1370 incoming_buf.cut_message();
1371 TTCN_Logger::log_executor_runtime(
1372 TitanLoggerApiSimple::ExecutorRuntime_reason::exit__requested__from__mc__hc);
1373 TTCN_Runtime::set_state(TTCN_Runtime::HC_EXIT);
1374 }
1375
1376 void TTCN_Communication::process_create_ack()
1377 {
1378 component component_reference = incoming_buf.pull_int().get_val();
1379 incoming_buf.cut_message();
1380 TTCN_Runtime::process_create_ack(component_reference);
1381 }
1382
1383 void TTCN_Communication::process_start_ack()
1384 {
1385 incoming_buf.cut_message();
1386
1387 switch (TTCN_Runtime::get_state()) {
1388 case TTCN_Runtime::MTC_START:
1389 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE);
1390 case TTCN_Runtime::MTC_TERMINATING_TESTCASE:
1391 break;
1392 case TTCN_Runtime::PTC_START:
1393 TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION);
1394 break;
1395 default:
1396 TTCN_error("Internal error: Message START_ACK arrived in invalid "
1397 "state.");
1398 }
1399 }
1400
1401 void TTCN_Communication::process_stop()
1402 {
1403 incoming_buf.cut_message();
1404 switch (TTCN_Runtime::get_state()) {
1405 case TTCN_Runtime::MTC_IDLE:
1406 TTCN_Logger::log_executor_runtime(
1407 TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc__ignored__on__idle__mtc);
1408 break;
1409 case TTCN_Runtime::MTC_PAUSED:
1410 TTCN_Logger::log_executor_runtime(
1411 TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc);
1412 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TERMINATING_EXECUTION);
1413 break;
1414 case TTCN_Runtime::PTC_IDLE:
1415 case TTCN_Runtime::PTC_STOPPED:
1416 TTCN_Logger::log_executor_runtime(
1417 TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc__ignored__on__idle__ptc);
1418 break;
1419 case TTCN_Runtime::PTC_EXIT:
1420 // silently ignore
1421 break;
1422 default:
1423 TTCN_Logger::log_executor_runtime(
1424 TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc);
1425 TTCN_Runtime::stop_execution();
1426 break;
1427 }
1428 }
1429
1430 void TTCN_Communication::process_stop_ack()
1431 {
1432 incoming_buf.cut_message();
1433 switch (TTCN_Runtime::get_state()) {
1434 case TTCN_Runtime::MTC_STOP:
1435 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE);
1436 case TTCN_Runtime::MTC_TERMINATING_TESTCASE:
1437 break;
1438 case TTCN_Runtime::PTC_STOP:
1439 TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION);
1440 break;
1441 default:
1442 TTCN_error("Internal error: Message STOP_ACK arrived in invalid "
1443 "state.");
1444 }
1445 }
1446
1447 void TTCN_Communication::process_kill_ack()
1448 {
1449 incoming_buf.cut_message();
1450 switch (TTCN_Runtime::get_state()) {
1451 case TTCN_Runtime::MTC_KILL:
1452 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE);
1453 case TTCN_Runtime::MTC_TERMINATING_TESTCASE:
1454 break;
1455 case TTCN_Runtime::PTC_KILL:
1456 TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION);
1457 break;
1458 default:
1459 TTCN_error("Internal error: Message KILL_ACK arrived in invalid "
1460 "state.");
1461 }
1462 }
1463
1464 void TTCN_Communication::process_running()
1465 {
1466 boolean answer = incoming_buf.pull_int().get_val();
1467 incoming_buf.cut_message();
1468 TTCN_Runtime::process_running(answer);
1469 }
1470
1471 void TTCN_Communication::process_alive()
1472 {
1473 boolean answer = incoming_buf.pull_int().get_val();
1474 incoming_buf.cut_message();
1475 TTCN_Runtime::process_alive(answer);
1476 }
1477
1478 void TTCN_Communication::process_done_ack(int msg_end)
1479 {
1480 // decoding the mandatory attributes
1481 boolean answer = incoming_buf.pull_int().get_val();
1482 char *return_type = incoming_buf.pull_string();
1483 // the return value starts here
1484 int return_value_begin = incoming_buf.get_pos();
1485
1486 try {
1487 TTCN_Runtime::process_done_ack(answer, return_type,
1488 msg_end - return_value_begin,
1489 incoming_buf.get_data() + return_value_begin);
1490 } catch (...) {
1491 // avoid memory leaks in case of error
1492 incoming_buf.cut_message();
1493 delete [] return_type;
1494 throw;
1495 }
1496
1497 incoming_buf.cut_message();
1498 delete [] return_type;
1499 }
1500
1501 void TTCN_Communication::process_killed_ack()
1502 {
1503 boolean answer = incoming_buf.pull_int().get_val();
1504 incoming_buf.cut_message();
1505 TTCN_Runtime::process_killed_ack(answer);
1506 }
1507
1508 void TTCN_Communication::process_cancel_done_mtc()
1509 {
1510 component component_reference = incoming_buf.pull_int().get_val();
1511 boolean cancel_any = incoming_buf.pull_int().get_val();
1512 incoming_buf.cut_message();
1513 TTCN_Runtime::cancel_component_done(component_reference);
1514 if (cancel_any) TTCN_Runtime::cancel_component_done(ANY_COMPREF);
1515 send_cancel_done_ack(component_reference);
1516 }
1517
1518 void TTCN_Communication::process_cancel_done_ptc()
1519 {
1520 component component_reference = incoming_buf.pull_int().get_val();
1521 incoming_buf.cut_message();
1522 TTCN_Runtime::cancel_component_done(component_reference);
1523 send_cancel_done_ack(component_reference);
1524 }
1525
1526 void TTCN_Communication::process_component_status_mtc(int msg_end)
1527 {
1528 // decoding the mandatory attributes
1529 component component_reference = incoming_buf.pull_int().get_val();
1530 boolean is_done = incoming_buf.pull_int().get_val();
1531 boolean is_killed = incoming_buf.pull_int().get_val();
1532 boolean is_any_done = incoming_buf.pull_int().get_val();
1533 boolean is_all_done = incoming_buf.pull_int().get_val();
1534 boolean is_any_killed = incoming_buf.pull_int().get_val();
1535 boolean is_all_killed = incoming_buf.pull_int().get_val();
1536 if (is_done) {
1537 // the return type and value is valid
1538 char *return_type = incoming_buf.pull_string();
1539 int return_value_begin = incoming_buf.get_pos();
1540 try {
1541 TTCN_Runtime::set_component_done(component_reference, return_type,
1542 msg_end - return_value_begin,
1543 incoming_buf.get_data() + return_value_begin);
1544 } catch (...) {
1545 // avoid memory leaks
1546 incoming_buf.cut_message();
1547 delete [] return_type;
1548 throw;
1549 }
1550 delete [] return_type;
1551 }
1552 if (is_killed) TTCN_Runtime::set_component_killed(component_reference);
1553 if (is_any_done)
1554 TTCN_Runtime::set_component_done(ANY_COMPREF, NULL, 0, NULL);
1555 if (is_all_done)
1556 TTCN_Runtime::set_component_done(ALL_COMPREF, NULL, 0, NULL);
1557 if (is_any_killed) TTCN_Runtime::set_component_killed(ANY_COMPREF);
1558 if (is_all_killed) TTCN_Runtime::set_component_killed(ALL_COMPREF);
1559 incoming_buf.cut_message();
1560 if (!is_done && !is_killed && (component_reference != NULL_COMPREF ||
1561 (!is_any_done && !is_all_done && !is_any_killed && !is_all_killed)))
1562 TTCN_error("Internal error: Malformed COMPONENT_STATUS message was "
1563 "received.");
1564 }
1565
1566 void TTCN_Communication::process_component_status_ptc(int msg_end)
1567 {
1568 // decoding the mandatory attributes
1569 component component_reference = incoming_buf.pull_int().get_val();
1570 boolean is_done = incoming_buf.pull_int().get_val();
1571 boolean is_killed = incoming_buf.pull_int().get_val();
1572 if (is_done) {
1573 // the return type and value is valid
1574 char *return_type = incoming_buf.pull_string();
1575 int return_value_begin = incoming_buf.get_pos();
1576 try {
1577 TTCN_Runtime::set_component_done(component_reference, return_type,
1578 msg_end - return_value_begin,
1579 incoming_buf.get_data() + return_value_begin);
1580 } catch (...) {
1581 // avoid memory leaks
1582 incoming_buf.cut_message();
1583 delete [] return_type;
1584 throw;
1585 }
1586 delete [] return_type;
1587 }
1588 if (is_killed) TTCN_Runtime::set_component_killed(component_reference);
1589 incoming_buf.cut_message();
1590 if (!is_done && !is_killed) TTCN_error("Internal error: Malformed "
1591 "COMPONENT_STATUS message was received.");
1592 }
1593
1594 void TTCN_Communication::process_connect_listen()
1595 {
1596 char *local_port = incoming_buf.pull_string();
1597 component remote_component = incoming_buf.pull_int().get_val();
1598 char *remote_component_name = incoming_buf.pull_string();
1599 char *remote_port = incoming_buf.pull_string();
1600 transport_type_enum transport_type =
1601 (transport_type_enum)incoming_buf.pull_int().get_val();
1602 incoming_buf.cut_message();
1603
1604 try {
1605 if (remote_component != MTC_COMPREF && self != remote_component)
1606 COMPONENT::register_component_name(remote_component,
1607 remote_component_name);
1608 PORT::process_connect_listen(local_port, remote_component, remote_port,
1609 transport_type);
1610 } catch (...) {
1611 delete [] local_port;
1612 delete [] remote_component_name;
1613 delete [] remote_port;
1614 throw;
1615 }
1616
1617 delete [] local_port;
1618 delete [] remote_component_name;
1619 delete [] remote_port;
1620 }
1621
1622 void TTCN_Communication::process_connect()
1623 {
1624 char *local_port = incoming_buf.pull_string();
1625 component remote_component = incoming_buf.pull_int().get_val();
1626 char *remote_component_name = incoming_buf.pull_string();
1627 char *remote_port = incoming_buf.pull_string();
1628 transport_type_enum transport_type =
1629 (transport_type_enum)incoming_buf.pull_int().get_val();
1630
1631 try {
1632 if (remote_component != MTC_COMPREF && self != remote_component)
1633 COMPONENT::register_component_name(remote_component,
1634 remote_component_name);
1635 PORT::process_connect(local_port, remote_component, remote_port,
1636 transport_type, incoming_buf);
1637 } catch (...) {
1638 incoming_buf.cut_message();
1639 delete [] local_port;
1640 delete [] remote_component_name;
1641 delete [] remote_port;
1642 throw;
1643 }
1644
1645 incoming_buf.cut_message();
1646 delete [] local_port;
1647 delete [] remote_component_name;
1648 delete [] remote_port;
1649 }
1650
1651 void TTCN_Communication::process_connect_ack()
1652 {
1653 incoming_buf.cut_message();
1654
1655 switch (TTCN_Runtime::get_state()) {
1656 case TTCN_Runtime::MTC_CONNECT:
1657 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE);
1658 case TTCN_Runtime::MTC_TERMINATING_TESTCASE:
1659 break;
1660 case TTCN_Runtime::PTC_CONNECT:
1661 TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION);
1662 break;
1663 default:
1664 TTCN_error("Internal error: Message CONNECT_ACK arrived in invalid "
1665 "state.");
1666 }
1667 }
1668
1669 void TTCN_Communication::process_disconnect()
1670 {
1671 char *local_port = incoming_buf.pull_string();
1672 component remote_component = incoming_buf.pull_int().get_val();
1673 char *remote_port = incoming_buf.pull_string();
1674 incoming_buf.cut_message();
1675
1676 try {
1677 PORT::process_disconnect(local_port, remote_component, remote_port);
1678 } catch (...) {
1679 delete [] local_port;
1680 delete [] remote_port;
1681 throw;
1682 }
1683
1684 delete [] local_port;
1685 delete [] remote_port;
1686 }
1687
1688 void TTCN_Communication::process_disconnect_ack()
1689 {
1690 incoming_buf.cut_message();
1691
1692 switch (TTCN_Runtime::get_state()) {
1693 case TTCN_Runtime::MTC_DISCONNECT:
1694 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE);
1695 case TTCN_Runtime::MTC_TERMINATING_TESTCASE:
1696 break;
1697 case TTCN_Runtime::PTC_DISCONNECT:
1698 TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION);
1699 break;
1700 default:
1701 TTCN_error("Internal error: Message DISCONNECT_ACK arrived in invalid "
1702 "state.");
1703 }
1704 }
1705
1706 void TTCN_Communication::process_map()
1707 {
1708 char *local_port = incoming_buf.pull_string();
1709 char *system_port = incoming_buf.pull_string();
1710 incoming_buf.cut_message();
1711
1712 try {
1713 PORT::map_port(local_port, system_port);
1714 } catch (...) {
1715 delete [] local_port;
1716 delete [] system_port;
1717 throw;
1718 }
1719
1720 delete [] local_port;
1721 delete [] system_port;
1722 }
1723
1724 void TTCN_Communication::process_map_ack()
1725 {
1726 incoming_buf.cut_message();
1727
1728 switch (TTCN_Runtime::get_state()) {
1729 case TTCN_Runtime::MTC_MAP:
1730 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE);
1731 case TTCN_Runtime::MTC_TERMINATING_TESTCASE:
1732 break;
1733 case TTCN_Runtime::PTC_MAP:
1734 TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION);
1735 break;
1736 default:
1737 TTCN_error("Internal error: Message MAP_ACK arrived in invalid state.");
1738 }
1739 }
1740
1741 void TTCN_Communication::process_unmap()
1742 {
1743 char *local_port = incoming_buf.pull_string();
1744 char *system_port = incoming_buf.pull_string();
1745 incoming_buf.cut_message();
1746
1747 try {
1748 PORT::unmap_port(local_port, system_port);
1749 } catch (...) {
1750 delete [] local_port;
1751 delete [] system_port;
1752 throw;
1753 }
1754
1755 delete [] local_port;
1756 delete [] system_port;
1757 }
1758
1759 void TTCN_Communication::process_unmap_ack()
1760 {
1761 incoming_buf.cut_message();
1762
1763 switch(TTCN_Runtime::get_state()){
1764 case TTCN_Runtime::MTC_UNMAP:
1765 TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE);
1766 case TTCN_Runtime::MTC_TERMINATING_TESTCASE:
1767 break;
1768 case TTCN_Runtime::PTC_UNMAP:
1769 TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION);
1770 break;
1771 default:
1772 TTCN_error("Internal error: Message UNMAP_ACK arrived in invalid "
1773 "state.");
1774 }
1775 }
1776
1777 void TTCN_Communication::process_execute_control()
1778 {
1779 char *module_name = incoming_buf.pull_string();
1780 incoming_buf.cut_message();
1781
1782 if (TTCN_Runtime::get_state() != TTCN_Runtime::MTC_IDLE) {
1783 delete [] module_name;
1784 TTCN_error("Internal error: Message EXECUTE_CONTROL arrived in "
1785 "invalid state.");
1786 }
1787
1788 TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED,
1789 "Executing control part of module %s.", module_name);
1790
1791 TTCN_Runtime::set_state(TTCN_Runtime::MTC_CONTROLPART);
1792
1793 try {
1794 Module_List::execute_control(module_name);
1795 } catch (const TC_End& TC_end) {
1796 } catch (const TC_Error& TC_error) {
1797 }
1798
1799 delete [] module_name;
1800
1801 if (is_connected) {
1802 send_mtc_ready();
1803 TTCN_Runtime::set_state(TTCN_Runtime::MTC_IDLE);
1804 } else TTCN_Runtime::set_state(TTCN_Runtime::MTC_EXIT);
1805 }
1806
1807 void TTCN_Communication::process_execute_testcase()
1808 {
1809 char *module_name = incoming_buf.pull_string();
1810 char *testcase_name = incoming_buf.pull_string();
1811 incoming_buf.cut_message();
1812
1813 if (TTCN_Runtime::get_state() != TTCN_Runtime::MTC_IDLE) {
1814 delete [] module_name;
1815 delete [] testcase_name;
1816 TTCN_error("Internal error: Message EXECUTE_TESTCASE arrived in "
1817 "invalid state.");
1818 }
1819
1820 TTCN_Logger::log_testcase_exec(testcase_name, module_name);
1821
1822 TTCN_Runtime::set_state(TTCN_Runtime::MTC_CONTROLPART);
1823
1824 try {
1825 if (testcase_name != NULL && testcase_name[0] != '\0')
1826 Module_List::execute_testcase(module_name, testcase_name);
1827 else Module_List::execute_all_testcases(module_name);
1828 } catch (const TC_End& TC_end) {
1829 } catch (const TC_Error& TC_error) {
1830 }
1831
1832 if (is_connected) {
1833 send_mtc_ready();
1834 TTCN_Runtime::set_state(TTCN_Runtime::MTC_IDLE);
1835 } else TTCN_Runtime::set_state(TTCN_Runtime::MTC_EXIT);
1836
1837 delete [] module_name;
1838 delete [] testcase_name;
1839 }
1840
1841 void TTCN_Communication::process_ptc_verdict()
1842 {
1843 TTCN_Runtime::process_ptc_verdict(incoming_buf);
1844 incoming_buf.cut_message();
1845 }
1846
1847 void TTCN_Communication::process_continue()
1848 {
1849 incoming_buf.cut_message();
1850
1851 if (TTCN_Runtime::get_state() != TTCN_Runtime::MTC_PAUSED)
1852 TTCN_error("Internal error: Message CONTINUE arrived in invalid "
1853 "state.");
1854
1855 TTCN_Runtime::set_state(TTCN_Runtime::MTC_CONTROLPART);
1856 }
1857
1858 void TTCN_Communication::process_exit_mtc()
1859 {
1860 incoming_buf.cut_message();
1861 TTCN_Runtime::log_verdict_statistics();
1862 TTCN_Logger::log_executor_runtime(
1863 TitanLoggerApiSimple::ExecutorRuntime_reason::exit__requested__from__mc__mtc);
1864 TTCN_Runtime::set_state(TTCN_Runtime::MTC_EXIT);
1865 }
1866
1867 void TTCN_Communication::process_start()
1868 {
1869 qualified_name function_name;
1870 incoming_buf.pull_qualified_name(function_name);
1871 if (function_name.module_name == NULL ||
1872 function_name.definition_name == NULL) {
1873 incoming_buf.cut_message();
1874 delete [] function_name.module_name;
1875 delete [] function_name.definition_name;
1876 TTCN_error("Internal error: Message START contains an invalid "
1877 "function name.");
1878 }
1879
1880 try {
1881 TTCN_Runtime::start_function(function_name.module_name,
1882 function_name.definition_name, incoming_buf);
1883 } catch (...) {
1884 // avoid memory leaks
1885 delete [] function_name.module_name;
1886 delete [] function_name.definition_name;
1887 throw;
1888 }
1889
1890 delete [] function_name.module_name;
1891 delete [] function_name.definition_name;
1892 }
1893
1894 void TTCN_Communication::process_kill()
1895 {
1896 incoming_buf.cut_message();
1897 TTCN_Runtime::process_kill();
1898 }
1899
1900 void TTCN_Communication::process_error()
1901 {
1902 char *error_string = incoming_buf.pull_string();
1903 incoming_buf.cut_message();
1904
1905 try {
1906 TTCN_error("Error message was received from MC: %s", error_string);
1907 } catch (...) {
1908 delete [] error_string;
1909 throw;
1910 }
1911 }
1912
1913 void TTCN_Communication::process_unsupported_message(int msg_type, int msg_end)
1914 {
1915 TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED);
1916 TTCN_Logger::log_event("Unsupported message was received from MC: "
1917 "type (decimal): %d, data (hexadecimal): ", msg_type);
1918 const unsigned char *msg_ptr =
1919 (const unsigned char*)incoming_buf.get_data();
1920 for (int i = incoming_buf.get_pos(); i < msg_end; i++)
1921 TTCN_Logger::log_octet(msg_ptr[i]);
1922 TTCN_Logger::end_event();
1923 incoming_buf.cut_message();
1924 }
1925
1926 void TTCN_Communication::process_debug_command()
1927 {
1928 int command = incoming_buf.pull_int().get_val();
1929 int argument_count = incoming_buf.pull_int().get_val();
1930 char** arguments = NULL;
1931 if (argument_count > 0) {
1932 arguments = new char*[argument_count];
1933 for (int i = 0; i < argument_count; ++i) {
1934 arguments[i] = incoming_buf.pull_string();
1935 }
1936 }
1937 incoming_buf.cut_message();
1938 ttcn3_debugger.execute_command(command, argument_count, arguments);
1939 if (argument_count > 0) {
1940 for (int i = 0; i < argument_count; ++i) {
1941 delete [] arguments[i];
1942 }
1943 delete [] arguments;
1944 }
1945 }
1946
1947 /* * * * Temporary squatting place because it includes version.h * * * */
1948
1949 const struct runtime_version current_runtime_version = {
1950 TTCN3_MAJOR, TTCN3_MINOR, TTCN3_PATCHLEVEL, TITAN_RUNTIME_NR
1951 };
1952
1953 static const char *runtime_name[] = { 0, "load", "function " };
1954
1955 RuntimeVersionChecker::RuntimeVersionChecker(
1956 int ver_major, int ver_minor, int patch_level, int rt)
1957 {
1958 if ( TTCN3_MAJOR != ver_major
1959 || TTCN3_MINOR != ver_minor
1960 || TTCN3_PATCHLEVEL != patch_level)
1961 {
1962 TTCN_error(
1963 "Version mismatch detected: generated code %d.%d.pl%d, "
1964 "runtime is %d.%d.pl%d",
1965 ver_major, ver_minor, patch_level,
1966 TTCN3_MAJOR, TTCN3_MINOR, TTCN3_PATCHLEVEL);
1967 }
1968
1969 if (TITAN_RUNTIME_NR != rt) {
1970 TTCN_error("Runtime mismatch detected: files compiled for the %stest"
1971 " runtime cannot be linked to %stest library",
1972 runtime_name[TITAN_RUNTIME_NR], runtime_name[rt]);
1973 }
1974 }
1975
1976 reffer::reffer(const char*) {}
1977
This page took 0.134911 seconds and 5 git commands to generate.