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