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