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: | |
575 | process_configure(msg_end); | |
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; | |
707 | default: | |
708 | process_unsupported_message(msg_type, msg_end); | |
709 | } | |
710 | } else { | |
711 | // messages: MC -> PTC | |
712 | switch (msg_type) { | |
713 | case MSG_START: | |
714 | process_start(); | |
715 | break; | |
716 | case MSG_KILL: | |
717 | process_kill(); | |
718 | break; | |
719 | default: | |
720 | process_unsupported_message(msg_type, msg_end); | |
721 | } | |
722 | } | |
723 | } | |
724 | } | |
725 | } | |
726 | ||
016a1a93 BB |
727 | void TTCN_Communication::process_debug_messages() |
728 | { | |
729 | // receives and processes messages from the MC, while test execution is halted | |
730 | // by the debugger | |
731 | char *buf_ptr; | |
732 | int buf_len; | |
733 | Text_Buf storage_buf; | |
734 | while (ttcn3_debugger.is_halted()) { | |
735 | incoming_buf.get_end(buf_ptr, buf_len); | |
736 | ||
737 | int recv_len = recv(mc_fd, buf_ptr, buf_len, 0); | |
738 | ||
739 | if (recv_len > 0) { | |
740 | incoming_buf.increase_length(recv_len); | |
741 | ||
742 | while (incoming_buf.is_message() && ttcn3_debugger.is_halted()) { | |
743 | int msg_len = incoming_buf.pull_int().get_val(); | |
744 | int msg_end = incoming_buf.get_pos() + msg_len; | |
745 | int msg_type = incoming_buf.pull_int().get_val(); | |
746 | // process only debug commands and 'stop' messages, store the rest | |
747 | switch (msg_type) { | |
748 | case MSG_DEBUG_COMMAND: | |
749 | process_debug_command(); | |
750 | break; | |
751 | case MSG_STOP: | |
752 | process_stop(); | |
753 | break; | |
754 | default: { | |
755 | // store all other messages in a different buffer | |
756 | int data_len = msg_end - incoming_buf.get_pos(); | |
757 | char* msg_data = new char[data_len]; | |
758 | incoming_buf.pull_raw(data_len, msg_data); | |
759 | incoming_buf.cut_message(); | |
760 | storage_buf.push_int(msg_type); | |
761 | storage_buf.push_raw(data_len, msg_data); | |
762 | delete [] msg_data; | |
763 | storage_buf.calculate_length(); | |
764 | break; } | |
765 | } | |
766 | } | |
767 | } | |
768 | } | |
769 | // append the stored messages to the beginning of the main buffer and | |
770 | // process them | |
771 | if (storage_buf.is_message()) { | |
772 | incoming_buf.push_raw_front(storage_buf.get_len(), storage_buf.get_data()); | |
773 | process_all_messages_tc(); | |
774 | } | |
775 | } | |
776 | ||
970ed795 EL |
777 | void TTCN_Communication::send_version() |
778 | { | |
779 | Text_Buf text_buf; | |
780 | text_buf.push_int(MSG_VERSION); | |
781 | text_buf.push_int(TTCN3_MAJOR); | |
782 | text_buf.push_int(TTCN3_MINOR); | |
783 | text_buf.push_int(TTCN3_PATCHLEVEL); | |
784 | #ifdef TTCN3_BUILDNUMBER | |
785 | text_buf.push_int(TTCN3_BUILDNUMBER); | |
786 | #else | |
787 | text_buf.push_int((RInt)0); | |
788 | #endif | |
789 | Module_List::push_version(text_buf); | |
790 | struct utsname uts; | |
791 | if (uname(&uts) < 0) TTCN_error("System call uname() failed."); | |
792 | text_buf.push_string(uts.nodename); | |
793 | text_buf.push_string(uts.machine); | |
794 | text_buf.push_string(uts.sysname); | |
795 | text_buf.push_string(uts.release); | |
796 | text_buf.push_string(uts.version); | |
797 | boolean unix_stream_supported = transport_unix_stream_supported(); | |
798 | ||
799 | // LOCAL (software loop) and INET_STREAM (TCP) transports are always | |
800 | // supported | |
801 | int n_supported_transports = 2; | |
802 | ||
803 | if (unix_stream_supported) n_supported_transports++; | |
804 | text_buf.push_int(n_supported_transports); | |
805 | text_buf.push_int(TRANSPORT_LOCAL); | |
806 | text_buf.push_int(TRANSPORT_INET_STREAM); | |
807 | if (unix_stream_supported) | |
808 | text_buf.push_int(TRANSPORT_UNIX_STREAM); | |
809 | send_message(text_buf); | |
810 | } | |
811 | ||
812 | void TTCN_Communication::send_configure_ack() | |
813 | { | |
814 | Text_Buf text_buf; | |
815 | text_buf.push_int(MSG_CONFIGURE_ACK); | |
816 | send_message(text_buf); | |
817 | } | |
818 | ||
819 | void TTCN_Communication::send_configure_nak() | |
820 | { | |
821 | Text_Buf text_buf; | |
822 | text_buf.push_int(MSG_CONFIGURE_NAK); | |
823 | send_message(text_buf); | |
824 | } | |
825 | ||
826 | void TTCN_Communication::send_create_nak(component component_reference, | |
827 | const char *fmt_str, ...) | |
828 | { | |
829 | va_list ap; | |
830 | va_start(ap, fmt_str); | |
831 | char *error_str = mprintf_va_list(fmt_str, ap); | |
832 | va_end(ap); | |
833 | Text_Buf text_buf; | |
834 | text_buf.push_int(MSG_CREATE_NAK); | |
835 | text_buf.push_int(component_reference); | |
836 | text_buf.push_string(error_str); | |
837 | Free(error_str); | |
838 | send_message(text_buf); | |
839 | } | |
840 | ||
841 | void TTCN_Communication::send_hc_ready() | |
842 | { | |
843 | Text_Buf text_buf; | |
844 | text_buf.push_int(MSG_HC_READY); | |
845 | send_message(text_buf); | |
846 | } | |
847 | ||
848 | void TTCN_Communication::send_create_req(const char *component_type_module, | |
849 | const char *component_type_name, const char *component_name, | |
850 | const char *component_location, boolean is_alive) | |
851 | { | |
852 | Text_Buf text_buf; | |
853 | text_buf.push_int(MSG_CREATE_REQ); | |
854 | text_buf.push_string(component_type_module); | |
855 | text_buf.push_string(component_type_name); | |
856 | text_buf.push_string(component_name); | |
857 | text_buf.push_string(component_location); | |
858 | text_buf.push_int(is_alive ? 1 : 0); | |
859 | send_message(text_buf); | |
860 | } | |
861 | ||
862 | void TTCN_Communication::prepare_start_req(Text_Buf& text_buf, | |
863 | component component_reference, const char *module_name, | |
864 | const char *function_name) | |
865 | { | |
866 | text_buf.push_int(MSG_START_REQ); | |
867 | text_buf.push_int(component_reference); | |
868 | text_buf.push_string(module_name); | |
869 | text_buf.push_string(function_name); | |
870 | } | |
871 | ||
872 | void TTCN_Communication::send_stop_req(component component_reference) | |
873 | { | |
874 | Text_Buf text_buf; | |
875 | text_buf.push_int(MSG_STOP_REQ); | |
876 | text_buf.push_int(component_reference); | |
877 | send_message(text_buf); | |
878 | } | |
879 | ||
880 | void TTCN_Communication::send_kill_req(component component_reference) | |
881 | { | |
882 | Text_Buf text_buf; | |
883 | text_buf.push_int(MSG_KILL_REQ); | |
884 | text_buf.push_int(component_reference); | |
885 | send_message(text_buf); | |
886 | } | |
887 | ||
888 | void TTCN_Communication::send_is_running(component component_reference) | |
889 | { | |
890 | Text_Buf text_buf; | |
891 | text_buf.push_int(MSG_IS_RUNNING); | |
892 | text_buf.push_int(component_reference); | |
893 | send_message(text_buf); | |
894 | } | |
895 | ||
896 | void TTCN_Communication::send_is_alive(component component_reference) | |
897 | { | |
898 | Text_Buf text_buf; | |
899 | text_buf.push_int(MSG_IS_ALIVE); | |
900 | text_buf.push_int(component_reference); | |
901 | send_message(text_buf); | |
902 | } | |
903 | ||
904 | void TTCN_Communication::send_done_req(component component_reference) | |
905 | { | |
906 | Text_Buf text_buf; | |
907 | text_buf.push_int(MSG_DONE_REQ); | |
908 | text_buf.push_int(component_reference); | |
909 | send_message(text_buf); | |
910 | } | |
911 | ||
912 | void TTCN_Communication::send_killed_req(component component_reference) | |
913 | { | |
914 | Text_Buf text_buf; | |
915 | text_buf.push_int(MSG_KILLED_REQ); | |
916 | text_buf.push_int(component_reference); | |
917 | send_message(text_buf); | |
918 | } | |
919 | ||
920 | void TTCN_Communication::send_cancel_done_ack(component component_reference) | |
921 | { | |
922 | Text_Buf text_buf; | |
923 | text_buf.push_int(MSG_CANCEL_DONE_ACK); | |
924 | text_buf.push_int(component_reference); | |
925 | send_message(text_buf); | |
926 | } | |
927 | ||
928 | void TTCN_Communication::send_connect_req(component src_component, | |
929 | const char *src_port, component dst_component, const char *dst_port) | |
930 | { | |
931 | Text_Buf text_buf; | |
932 | text_buf.push_int(MSG_CONNECT_REQ); | |
933 | text_buf.push_int(src_component); | |
934 | text_buf.push_string(src_port); | |
935 | text_buf.push_int(dst_component); | |
936 | text_buf.push_string(dst_port); | |
937 | send_message(text_buf); | |
938 | } | |
939 | ||
940 | void TTCN_Communication::send_connect_listen_ack_inet_stream( | |
941 | const char *local_port, component remote_component, | |
942 | const char *remote_port, const IPAddress *local_address) | |
943 | { | |
944 | Text_Buf text_buf; | |
945 | text_buf.push_int(MSG_CONNECT_LISTEN_ACK); | |
946 | text_buf.push_string(local_port); | |
947 | text_buf.push_int(remote_component); | |
948 | text_buf.push_string(remote_port); | |
949 | text_buf.push_int(TRANSPORT_INET_STREAM); | |
950 | local_address->push_raw(text_buf); | |
951 | send_message(text_buf); | |
952 | } | |
953 | ||
954 | void TTCN_Communication::send_connect_listen_ack_unix_stream( | |
955 | const char *local_port, component remote_component, | |
956 | const char *remote_port, const struct sockaddr_un *local_address) | |
957 | { | |
958 | Text_Buf text_buf; | |
959 | text_buf.push_int(MSG_CONNECT_LISTEN_ACK); | |
960 | text_buf.push_string(local_port); | |
961 | text_buf.push_int(remote_component); | |
962 | text_buf.push_string(remote_port); | |
963 | text_buf.push_int(TRANSPORT_UNIX_STREAM); | |
964 | text_buf.push_string(local_address->sun_path); | |
965 | send_message(text_buf); | |
966 | } | |
967 | ||
968 | void TTCN_Communication::send_connected(const char *local_port, | |
969 | component remote_component, const char *remote_port) | |
970 | { | |
971 | Text_Buf text_buf; | |
972 | text_buf.push_int(MSG_CONNECTED); | |
973 | text_buf.push_string(local_port); | |
974 | text_buf.push_int(remote_component); | |
975 | text_buf.push_string(remote_port); | |
976 | send_message(text_buf); | |
977 | } | |
978 | ||
979 | void TTCN_Communication::send_connect_error(const char *local_port, | |
980 | component remote_component, const char *remote_port, | |
981 | const char *fmt_str, ...) | |
982 | { | |
983 | va_list ap; | |
984 | va_start(ap, fmt_str); | |
985 | char *error_str = mprintf_va_list(fmt_str, ap); | |
986 | va_end(ap); | |
987 | Text_Buf text_buf; | |
988 | text_buf.push_int(MSG_CONNECT_ERROR); | |
989 | text_buf.push_string(local_port); | |
990 | text_buf.push_int(remote_component); | |
991 | text_buf.push_string(remote_port); | |
992 | text_buf.push_string(error_str); | |
993 | Free(error_str); | |
994 | send_message(text_buf); | |
995 | } | |
996 | ||
997 | void TTCN_Communication::send_disconnect_req(component src_component, | |
998 | const char *src_port, component dst_component, const char *dst_port) | |
999 | { | |
1000 | Text_Buf text_buf; | |
1001 | text_buf.push_int(MSG_DISCONNECT_REQ); | |
1002 | text_buf.push_int(src_component); | |
1003 | text_buf.push_string(src_port); | |
1004 | text_buf.push_int(dst_component); | |
1005 | text_buf.push_string(dst_port); | |
1006 | send_message(text_buf); | |
1007 | } | |
1008 | ||
1009 | void TTCN_Communication::send_disconnected(const char *local_port, | |
1010 | component remote_component, const char *remote_port) | |
1011 | { | |
1012 | Text_Buf text_buf; | |
1013 | text_buf.push_int(MSG_DISCONNECTED); | |
1014 | text_buf.push_string(local_port); | |
1015 | text_buf.push_int(remote_component); | |
1016 | text_buf.push_string(remote_port); | |
1017 | send_message(text_buf); | |
1018 | } | |
1019 | ||
1020 | void TTCN_Communication::send_map_req(component src_component, | |
1021 | const char *src_port, const char *system_port) | |
1022 | { | |
1023 | Text_Buf text_buf; | |
1024 | text_buf.push_int(MSG_MAP_REQ); | |
1025 | text_buf.push_int(src_component); | |
1026 | text_buf.push_string(src_port); | |
1027 | text_buf.push_string(system_port); | |
1028 | send_message(text_buf); | |
1029 | } | |
1030 | ||
1031 | void TTCN_Communication::send_mapped(const char *local_port, | |
1032 | const char *system_port) | |
1033 | { | |
1034 | Text_Buf text_buf; | |
1035 | text_buf.push_int(MSG_MAPPED); | |
1036 | text_buf.push_string(local_port); | |
1037 | text_buf.push_string(system_port); | |
1038 | send_message(text_buf); | |
1039 | } | |
1040 | ||
1041 | void TTCN_Communication::send_unmap_req(component src_component, | |
1042 | const char *src_port, const char *system_port) | |
1043 | { | |
1044 | Text_Buf text_buf; | |
1045 | text_buf.push_int(MSG_UNMAP_REQ); | |
1046 | text_buf.push_int(src_component); | |
1047 | text_buf.push_string(src_port); | |
1048 | text_buf.push_string(system_port); | |
1049 | send_message(text_buf); | |
1050 | } | |
1051 | ||
1052 | void TTCN_Communication::send_unmapped(const char *local_port, | |
1053 | const char *system_port) | |
1054 | { | |
1055 | Text_Buf text_buf; | |
1056 | text_buf.push_int(MSG_UNMAPPED); | |
1057 | text_buf.push_string(local_port); | |
1058 | text_buf.push_string(system_port); | |
1059 | send_message(text_buf); | |
1060 | } | |
1061 | ||
1062 | void TTCN_Communication::send_mtc_created() | |
1063 | { | |
1064 | Text_Buf text_buf; | |
1065 | text_buf.push_int(MSG_MTC_CREATED); | |
1066 | send_message(text_buf); | |
1067 | } | |
1068 | ||
1069 | void TTCN_Communication::send_testcase_started(const char *testcase_module, | |
1070 | const char *testcase_name, const char *mtc_comptype_module, | |
1071 | const char *mtc_comptype_name, const char *system_comptype_module, | |
1072 | const char *system_comptype_name) | |
1073 | { | |
1074 | Text_Buf text_buf; | |
1075 | text_buf.push_int(MSG_TESTCASE_STARTED); | |
1076 | text_buf.push_string(testcase_module); | |
1077 | text_buf.push_string(testcase_name); | |
1078 | text_buf.push_string(mtc_comptype_module); | |
1079 | text_buf.push_string(mtc_comptype_name); | |
1080 | text_buf.push_string(system_comptype_module); | |
1081 | text_buf.push_string(system_comptype_name); | |
1082 | send_message(text_buf); | |
1083 | } | |
1084 | ||
1085 | void TTCN_Communication::send_testcase_finished(verdicttype final_verdict, | |
1086 | const char* reason) | |
1087 | { | |
1088 | Text_Buf text_buf; | |
1089 | text_buf.push_int(MSG_TESTCASE_FINISHED); | |
1090 | text_buf.push_int(final_verdict); | |
1091 | text_buf.push_string(reason); | |
1092 | send_message(text_buf); | |
1093 | } | |
1094 | ||
1095 | void TTCN_Communication::send_mtc_ready() | |
1096 | { | |
1097 | Text_Buf text_buf; | |
1098 | text_buf.push_int(MSG_MTC_READY); | |
1099 | send_message(text_buf); | |
1100 | } | |
1101 | ||
1102 | void TTCN_Communication::send_ptc_created(component component_reference) | |
1103 | { | |
1104 | Text_Buf text_buf; | |
1105 | text_buf.push_int(MSG_PTC_CREATED); | |
1106 | text_buf.push_int(component_reference); | |
1107 | send_message(text_buf); | |
1108 | } | |
1109 | ||
1110 | void TTCN_Communication::prepare_stopped(Text_Buf& text_buf, | |
1111 | const char *return_type) | |
1112 | { | |
1113 | text_buf.push_int(MSG_STOPPED); | |
1114 | text_buf.push_string(return_type); | |
1115 | } | |
1116 | ||
1117 | void TTCN_Communication::send_stopped() | |
1118 | { | |
1119 | Text_Buf text_buf; | |
1120 | text_buf.push_int(MSG_STOPPED); | |
1121 | // add an empty return type | |
1122 | text_buf.push_string(NULL); | |
1123 | send_message(text_buf); | |
1124 | } | |
1125 | ||
1126 | void TTCN_Communication::prepare_stopped_killed(Text_Buf& text_buf, | |
1127 | verdicttype final_verdict, const char *return_type, const char* reason) | |
1128 | { | |
1129 | text_buf.push_int(MSG_STOPPED_KILLED); | |
1130 | text_buf.push_int(final_verdict); | |
1131 | text_buf.push_string(reason); | |
1132 | text_buf.push_string(return_type); | |
1133 | } | |
1134 | ||
1135 | void TTCN_Communication::send_stopped_killed(verdicttype final_verdict, | |
1136 | const char* reason) | |
1137 | { | |
1138 | Text_Buf text_buf; | |
1139 | text_buf.push_int(MSG_STOPPED_KILLED); | |
1140 | text_buf.push_int(final_verdict); | |
1141 | text_buf.push_string(reason); | |
1142 | // add an empty return type | |
1143 | text_buf.push_string(NULL); | |
1144 | send_message(text_buf); | |
1145 | } | |
1146 | ||
1147 | void TTCN_Communication::send_killed(verdicttype final_verdict, | |
1148 | const char* reason) | |
1149 | { | |
1150 | Text_Buf text_buf; | |
1151 | text_buf.push_int(MSG_KILLED); | |
1152 | text_buf.push_int(final_verdict); | |
1153 | text_buf.push_string(reason); | |
1154 | send_message(text_buf); | |
1155 | } | |
1156 | ||
016a1a93 BB |
1157 | void TTCN_Communication::send_debug_return_value(int return_type, const char* message) |
1158 | { | |
1159 | Text_Buf text_buf; | |
1160 | text_buf.push_int(MSG_DEBUG_RETURN_VALUE); | |
1161 | text_buf.push_int(return_type); | |
f08ff9ca BB |
1162 | if (message != NULL) { |
1163 | timeval tv; | |
1164 | gettimeofday(&tv, NULL); | |
1165 | text_buf.push_int(tv.tv_sec); | |
1166 | text_buf.push_int(tv.tv_usec); | |
1167 | text_buf.push_string(message); | |
1168 | } | |
016a1a93 BB |
1169 | send_message(text_buf); |
1170 | } | |
1171 | ||
1172 | void TTCN_Communication::send_debug_halt_req() | |
1173 | { | |
1174 | Text_Buf text_buf; | |
1175 | text_buf.push_int(MSG_DEBUG_HALT_REQ); | |
1176 | send_message(text_buf); | |
1177 | } | |
1178 | ||
f08ff9ca BB |
1179 | void TTCN_Communication::send_debug_continue_req() |
1180 | { | |
1181 | Text_Buf text_buf; | |
1182 | text_buf.push_int(MSG_DEBUG_CONTINUE_REQ); | |
1183 | send_message(text_buf); | |
1184 | } | |
1185 | ||
1186 | void TTCN_Communication::send_debug_batch(const char* batch_file) | |
1187 | { | |
1188 | Text_Buf text_buf; | |
1189 | text_buf.push_int(MSG_DEBUG_BATCH); | |
1190 | text_buf.push_string(batch_file); | |
1191 | send_message(text_buf); | |
1192 | } | |
1193 | ||
970ed795 EL |
1194 | boolean TTCN_Communication::send_log(time_t timestamp_sec, long timestamp_usec, |
1195 | unsigned int event_severity, size_t message_text_len, | |
1196 | const char *message_text) | |
1197 | { | |
1198 | if (is_connected) { | |
1199 | Text_Buf text_buf; | |
1200 | text_buf.push_int(MSG_LOG); | |
1201 | text_buf.push_int(timestamp_sec); | |
1202 | text_buf.push_int(timestamp_usec); | |
1203 | text_buf.push_int(event_severity); | |
1204 | text_buf.push_int(message_text_len); | |
1205 | text_buf.push_raw(message_text_len, message_text); | |
1206 | send_message(text_buf); | |
1207 | /* If an ERROR message (indicating a version mismatch) arrives from MC | |
1208 | in state HC_IDLE (i.e. before CONFIGURE) it shall be | |
1209 | printed to the console as well. */ | |
1210 | if (TTCN_Runtime::get_state() == TTCN_Runtime::HC_IDLE) return FALSE; | |
1211 | else return TRUE; | |
1212 | } else { | |
1213 | switch (TTCN_Runtime::get_state()) { | |
1214 | case TTCN_Runtime::HC_EXIT: | |
1215 | case TTCN_Runtime::MTC_INITIAL: | |
1216 | case TTCN_Runtime::MTC_EXIT: | |
1217 | case TTCN_Runtime::PTC_INITIAL: | |
1218 | case TTCN_Runtime::PTC_EXIT: | |
1219 | /* Do not print the first/last few lines of logs to the console | |
1220 | even if ConsoleMask is set to LOG_ALL */ | |
1221 | return TRUE; | |
1222 | default: | |
1223 | return FALSE; | |
1224 | } | |
1225 | } | |
1226 | } | |
1227 | ||
1228 | void TTCN_Communication::send_error(const char *fmt_str, ...) | |
1229 | { | |
1230 | va_list ap; | |
1231 | va_start(ap, fmt_str); | |
1232 | char *error_str = mprintf_va_list(fmt_str, ap); | |
1233 | va_end(ap); | |
1234 | Text_Buf text_buf; | |
1235 | text_buf.push_int((RInt)MSG_ERROR); | |
1236 | text_buf.push_string(error_str); | |
1237 | Free(error_str); | |
1238 | send_message(text_buf); | |
1239 | } | |
1240 | ||
1241 | void TTCN_Communication::send_message(Text_Buf& text_buf) | |
1242 | { | |
1243 | if (!is_connected) TTCN_error("Trying to send a message to MC, but the " | |
1244 | "control connection is down."); | |
1245 | text_buf.calculate_length(); | |
1246 | const char *msg_ptr = text_buf.get_data(); | |
1247 | size_t msg_len = text_buf.get_len(), sent_len = 0; | |
1248 | while (sent_len < msg_len) { | |
1249 | int ret_val = send(mc_fd, msg_ptr + sent_len, msg_len - sent_len, 0); | |
1250 | if (ret_val > 0) sent_len += ret_val; | |
1251 | else { | |
1252 | switch (errno) { | |
1253 | case EINTR: | |
1254 | // a signal occurred: do nothing, just try again | |
1255 | errno = 0; | |
1256 | break; | |
1257 | default: | |
1258 | close_mc_connection(); | |
1259 | TTCN_error("Sending data on the control connection to MC " | |
1260 | "failed."); | |
1261 | } | |
1262 | } | |
1263 | } | |
1264 | } | |
1265 | ||
1266 | void TTCN_Communication::process_configure(int msg_end) | |
1267 | { | |
1268 | switch (TTCN_Runtime::get_state()) { | |
1269 | case TTCN_Runtime::HC_IDLE: | |
1270 | case TTCN_Runtime::HC_ACTIVE: | |
1271 | case TTCN_Runtime::HC_OVERLOADED: | |
1272 | break; | |
1273 | default: | |
1274 | incoming_buf.cut_message(); | |
1275 | send_error("Message CONFIGURE arrived in invalid state."); | |
1276 | return; | |
1277 | } | |
1278 | ||
1279 | TTCN_Runtime::set_state(TTCN_Runtime::HC_CONFIGURING); | |
1280 | TTCN_Logger::log_configdata(TitanLoggerApiSimple::ExecutorConfigdata_reason::received__from__mc); | |
1281 | ||
1282 | // take the config string directly from the buffer for efficiency reasons | |
1283 | int config_str_len = incoming_buf.pull_int().get_val(); | |
1284 | int config_str_begin = incoming_buf.get_pos(); | |
1285 | if (config_str_begin + config_str_len != msg_end) { | |
1286 | incoming_buf.cut_message(); | |
1287 | send_error("Malformed message CONFIGURE was received."); | |
1288 | return; | |
1289 | } | |
1290 | const char *config_str = incoming_buf.get_data() + config_str_begin; | |
1291 | boolean success = process_config_string(config_str, config_str_len); | |
1292 | ||
1293 | // Only non component specific settings will be applied. The plug-ins need | |
1294 | // to be loaded due to resetting. | |
1295 | TTCN_Logger::load_plugins(NULL_COMPREF, ""); | |
1296 | TTCN_Logger::set_plugin_parameters(NULL_COMPREF, ""); | |
1297 | TTCN_Logger::open_file(); | |
1298 | if (success) { | |
1299 | try { | |
1300 | Module_List::log_param(); | |
1301 | Module_List::post_init_modules(); | |
1302 | } catch (const TC_Error& TC_error) { | |
1303 | TTCN_Logger::log_executor_runtime( | |
1304 | TitanLoggerApiSimple::ExecutorRuntime_reason::initialization__of__modules__failed); | |
1305 | success = FALSE; | |
1306 | } | |
1307 | } else { | |
1308 | TTCN_Logger::log_configdata( | |
1309 | TitanLoggerApiSimple::ExecutorConfigdata_reason::processing__failed, NULL); | |
1310 | } | |
1311 | ||
1312 | if (success) { | |
1313 | send_configure_ack(); | |
1314 | TTCN_Runtime::set_state(TTCN_Runtime::HC_ACTIVE); | |
1315 | TTCN_Logger::log_configdata( | |
1316 | TitanLoggerApiSimple::ExecutorConfigdata_reason::processing__succeeded); | |
1317 | } else { | |
1318 | send_configure_nak(); | |
1319 | TTCN_Runtime::set_state(TTCN_Runtime::HC_IDLE); | |
1320 | } | |
1321 | ||
1322 | incoming_buf.cut_message(); | |
1323 | } | |
1324 | ||
1325 | void TTCN_Communication::process_create_mtc() | |
1326 | { | |
1327 | incoming_buf.cut_message(); | |
1328 | TTCN_Runtime::process_create_mtc(); | |
1329 | } | |
1330 | ||
1331 | void TTCN_Communication::process_create_ptc() | |
1332 | { | |
1333 | component component_reference = (component)incoming_buf.pull_int().get_val(); | |
1334 | if (component_reference < FIRST_PTC_COMPREF) { | |
1335 | incoming_buf.cut_message(); | |
1336 | send_error("Message CREATE_PTC refers to invalid " | |
1337 | "component reference %d.", component_reference); | |
1338 | return; | |
1339 | } | |
1340 | qualified_name component_type; | |
1341 | incoming_buf.pull_qualified_name(component_type); | |
1342 | if (component_type.module_name == NULL || | |
1343 | component_type.definition_name == NULL) { | |
1344 | incoming_buf.cut_message(); | |
1345 | delete [] component_type.module_name; | |
1346 | delete [] component_type.definition_name; | |
1347 | send_error("Message CREATE_PTC with component reference %d contains " | |
1348 | "an invalid component type.", component_reference); | |
1349 | return; | |
1350 | } | |
1351 | char *component_name = incoming_buf.pull_string(); | |
1352 | boolean is_alive = incoming_buf.pull_int().get_val(); | |
1353 | qualified_name current_testcase; | |
1354 | incoming_buf.pull_qualified_name(current_testcase); | |
1355 | incoming_buf.cut_message(); | |
1356 | ||
1357 | try { | |
1358 | TTCN_Runtime::process_create_ptc(component_reference, | |
1359 | component_type.module_name, component_type.definition_name, | |
1360 | component_name, is_alive, current_testcase.module_name, | |
1361 | current_testcase.definition_name); | |
1362 | } catch (...) { | |
1363 | // to prevent from memory leaks | |
1364 | delete [] component_type.module_name; | |
1365 | delete [] component_type.definition_name; | |
1366 | delete [] component_name; | |
1367 | delete [] current_testcase.module_name; | |
1368 | delete [] current_testcase.definition_name; | |
1369 | throw; | |
1370 | } | |
1371 | ||
1372 | delete [] component_type.module_name; | |
1373 | delete [] component_type.definition_name; | |
1374 | delete [] component_name; | |
1375 | delete [] current_testcase.module_name; | |
1376 | delete [] current_testcase.definition_name; | |
1377 | } | |
1378 | ||
1379 | void TTCN_Communication::process_kill_process() | |
1380 | { | |
1381 | component component_reference = (component)incoming_buf.pull_int().get_val(); | |
1382 | incoming_buf.cut_message(); | |
1383 | TTCN_Runtime::process_kill_process(component_reference); | |
1384 | } | |
1385 | ||
1386 | void TTCN_Communication::process_exit_hc() | |
1387 | { | |
1388 | incoming_buf.cut_message(); | |
1389 | TTCN_Logger::log_executor_runtime( | |
1390 | TitanLoggerApiSimple::ExecutorRuntime_reason::exit__requested__from__mc__hc); | |
1391 | TTCN_Runtime::set_state(TTCN_Runtime::HC_EXIT); | |
1392 | } | |
1393 | ||
1394 | void TTCN_Communication::process_create_ack() | |
1395 | { | |
1396 | component component_reference = incoming_buf.pull_int().get_val(); | |
1397 | incoming_buf.cut_message(); | |
1398 | TTCN_Runtime::process_create_ack(component_reference); | |
1399 | } | |
1400 | ||
1401 | void TTCN_Communication::process_start_ack() | |
1402 | { | |
1403 | incoming_buf.cut_message(); | |
1404 | ||
1405 | switch (TTCN_Runtime::get_state()) { | |
1406 | case TTCN_Runtime::MTC_START: | |
1407 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE); | |
1408 | case TTCN_Runtime::MTC_TERMINATING_TESTCASE: | |
1409 | break; | |
1410 | case TTCN_Runtime::PTC_START: | |
1411 | TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION); | |
1412 | break; | |
1413 | default: | |
1414 | TTCN_error("Internal error: Message START_ACK arrived in invalid " | |
1415 | "state."); | |
1416 | } | |
1417 | } | |
1418 | ||
1419 | void TTCN_Communication::process_stop() | |
1420 | { | |
1421 | incoming_buf.cut_message(); | |
1422 | switch (TTCN_Runtime::get_state()) { | |
1423 | case TTCN_Runtime::MTC_IDLE: | |
1424 | TTCN_Logger::log_executor_runtime( | |
1425 | TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc__ignored__on__idle__mtc); | |
1426 | break; | |
1427 | case TTCN_Runtime::MTC_PAUSED: | |
1428 | TTCN_Logger::log_executor_runtime( | |
1429 | TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc); | |
1430 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TERMINATING_EXECUTION); | |
1431 | break; | |
1432 | case TTCN_Runtime::PTC_IDLE: | |
1433 | case TTCN_Runtime::PTC_STOPPED: | |
1434 | TTCN_Logger::log_executor_runtime( | |
1435 | TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc__ignored__on__idle__ptc); | |
1436 | break; | |
1437 | case TTCN_Runtime::PTC_EXIT: | |
1438 | // silently ignore | |
1439 | break; | |
1440 | default: | |
1441 | TTCN_Logger::log_executor_runtime( | |
1442 | TitanLoggerApiSimple::ExecutorRuntime_reason::stop__was__requested__from__mc); | |
1443 | TTCN_Runtime::stop_execution(); | |
1444 | break; | |
1445 | } | |
1446 | } | |
1447 | ||
1448 | void TTCN_Communication::process_stop_ack() | |
1449 | { | |
1450 | incoming_buf.cut_message(); | |
1451 | switch (TTCN_Runtime::get_state()) { | |
1452 | case TTCN_Runtime::MTC_STOP: | |
1453 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE); | |
1454 | case TTCN_Runtime::MTC_TERMINATING_TESTCASE: | |
1455 | break; | |
1456 | case TTCN_Runtime::PTC_STOP: | |
1457 | TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION); | |
1458 | break; | |
1459 | default: | |
1460 | TTCN_error("Internal error: Message STOP_ACK arrived in invalid " | |
1461 | "state."); | |
1462 | } | |
1463 | } | |
1464 | ||
1465 | void TTCN_Communication::process_kill_ack() | |
1466 | { | |
1467 | incoming_buf.cut_message(); | |
1468 | switch (TTCN_Runtime::get_state()) { | |
1469 | case TTCN_Runtime::MTC_KILL: | |
1470 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE); | |
1471 | case TTCN_Runtime::MTC_TERMINATING_TESTCASE: | |
1472 | break; | |
1473 | case TTCN_Runtime::PTC_KILL: | |
1474 | TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION); | |
1475 | break; | |
1476 | default: | |
1477 | TTCN_error("Internal error: Message KILL_ACK arrived in invalid " | |
1478 | "state."); | |
1479 | } | |
1480 | } | |
1481 | ||
1482 | void TTCN_Communication::process_running() | |
1483 | { | |
1484 | boolean answer = incoming_buf.pull_int().get_val(); | |
1485 | incoming_buf.cut_message(); | |
1486 | TTCN_Runtime::process_running(answer); | |
1487 | } | |
1488 | ||
1489 | void TTCN_Communication::process_alive() | |
1490 | { | |
1491 | boolean answer = incoming_buf.pull_int().get_val(); | |
1492 | incoming_buf.cut_message(); | |
1493 | TTCN_Runtime::process_alive(answer); | |
1494 | } | |
1495 | ||
1496 | void TTCN_Communication::process_done_ack(int msg_end) | |
1497 | { | |
1498 | // decoding the mandatory attributes | |
1499 | boolean answer = incoming_buf.pull_int().get_val(); | |
1500 | char *return_type = incoming_buf.pull_string(); | |
1501 | // the return value starts here | |
1502 | int return_value_begin = incoming_buf.get_pos(); | |
1503 | ||
1504 | try { | |
1505 | TTCN_Runtime::process_done_ack(answer, return_type, | |
1506 | msg_end - return_value_begin, | |
1507 | incoming_buf.get_data() + return_value_begin); | |
1508 | } catch (...) { | |
1509 | // avoid memory leaks in case of error | |
1510 | incoming_buf.cut_message(); | |
1511 | delete [] return_type; | |
1512 | throw; | |
1513 | } | |
1514 | ||
1515 | incoming_buf.cut_message(); | |
1516 | delete [] return_type; | |
1517 | } | |
1518 | ||
1519 | void TTCN_Communication::process_killed_ack() | |
1520 | { | |
1521 | boolean answer = incoming_buf.pull_int().get_val(); | |
1522 | incoming_buf.cut_message(); | |
1523 | TTCN_Runtime::process_killed_ack(answer); | |
1524 | } | |
1525 | ||
1526 | void TTCN_Communication::process_cancel_done_mtc() | |
1527 | { | |
1528 | component component_reference = incoming_buf.pull_int().get_val(); | |
1529 | boolean cancel_any = incoming_buf.pull_int().get_val(); | |
1530 | incoming_buf.cut_message(); | |
1531 | TTCN_Runtime::cancel_component_done(component_reference); | |
1532 | if (cancel_any) TTCN_Runtime::cancel_component_done(ANY_COMPREF); | |
1533 | send_cancel_done_ack(component_reference); | |
1534 | } | |
1535 | ||
1536 | void TTCN_Communication::process_cancel_done_ptc() | |
1537 | { | |
1538 | component component_reference = incoming_buf.pull_int().get_val(); | |
1539 | incoming_buf.cut_message(); | |
1540 | TTCN_Runtime::cancel_component_done(component_reference); | |
1541 | send_cancel_done_ack(component_reference); | |
1542 | } | |
1543 | ||
1544 | void TTCN_Communication::process_component_status_mtc(int msg_end) | |
1545 | { | |
1546 | // decoding the mandatory attributes | |
1547 | component component_reference = incoming_buf.pull_int().get_val(); | |
1548 | boolean is_done = incoming_buf.pull_int().get_val(); | |
1549 | boolean is_killed = incoming_buf.pull_int().get_val(); | |
1550 | boolean is_any_done = incoming_buf.pull_int().get_val(); | |
1551 | boolean is_all_done = incoming_buf.pull_int().get_val(); | |
1552 | boolean is_any_killed = incoming_buf.pull_int().get_val(); | |
1553 | boolean is_all_killed = incoming_buf.pull_int().get_val(); | |
1554 | if (is_done) { | |
1555 | // the return type and value is valid | |
1556 | char *return_type = incoming_buf.pull_string(); | |
1557 | int return_value_begin = incoming_buf.get_pos(); | |
1558 | try { | |
1559 | TTCN_Runtime::set_component_done(component_reference, return_type, | |
1560 | msg_end - return_value_begin, | |
1561 | incoming_buf.get_data() + return_value_begin); | |
1562 | } catch (...) { | |
1563 | // avoid memory leaks | |
1564 | incoming_buf.cut_message(); | |
1565 | delete [] return_type; | |
1566 | throw; | |
1567 | } | |
1568 | delete [] return_type; | |
1569 | } | |
1570 | if (is_killed) TTCN_Runtime::set_component_killed(component_reference); | |
1571 | if (is_any_done) | |
1572 | TTCN_Runtime::set_component_done(ANY_COMPREF, NULL, 0, NULL); | |
1573 | if (is_all_done) | |
1574 | TTCN_Runtime::set_component_done(ALL_COMPREF, NULL, 0, NULL); | |
1575 | if (is_any_killed) TTCN_Runtime::set_component_killed(ANY_COMPREF); | |
1576 | if (is_all_killed) TTCN_Runtime::set_component_killed(ALL_COMPREF); | |
1577 | incoming_buf.cut_message(); | |
1578 | if (!is_done && !is_killed && (component_reference != NULL_COMPREF || | |
1579 | (!is_any_done && !is_all_done && !is_any_killed && !is_all_killed))) | |
1580 | TTCN_error("Internal error: Malformed COMPONENT_STATUS message was " | |
1581 | "received."); | |
1582 | } | |
1583 | ||
1584 | void TTCN_Communication::process_component_status_ptc(int msg_end) | |
1585 | { | |
1586 | // decoding the mandatory attributes | |
1587 | component component_reference = incoming_buf.pull_int().get_val(); | |
1588 | boolean is_done = incoming_buf.pull_int().get_val(); | |
1589 | boolean is_killed = incoming_buf.pull_int().get_val(); | |
1590 | if (is_done) { | |
1591 | // the return type and value is valid | |
1592 | char *return_type = incoming_buf.pull_string(); | |
1593 | int return_value_begin = incoming_buf.get_pos(); | |
1594 | try { | |
1595 | TTCN_Runtime::set_component_done(component_reference, return_type, | |
1596 | msg_end - return_value_begin, | |
1597 | incoming_buf.get_data() + return_value_begin); | |
1598 | } catch (...) { | |
1599 | // avoid memory leaks | |
1600 | incoming_buf.cut_message(); | |
1601 | delete [] return_type; | |
1602 | throw; | |
1603 | } | |
1604 | delete [] return_type; | |
1605 | } | |
1606 | if (is_killed) TTCN_Runtime::set_component_killed(component_reference); | |
1607 | incoming_buf.cut_message(); | |
1608 | if (!is_done && !is_killed) TTCN_error("Internal error: Malformed " | |
1609 | "COMPONENT_STATUS message was received."); | |
1610 | } | |
1611 | ||
1612 | void TTCN_Communication::process_connect_listen() | |
1613 | { | |
1614 | char *local_port = incoming_buf.pull_string(); | |
1615 | component remote_component = incoming_buf.pull_int().get_val(); | |
1616 | char *remote_component_name = incoming_buf.pull_string(); | |
1617 | char *remote_port = incoming_buf.pull_string(); | |
1618 | transport_type_enum transport_type = | |
1619 | (transport_type_enum)incoming_buf.pull_int().get_val(); | |
1620 | incoming_buf.cut_message(); | |
1621 | ||
1622 | try { | |
1623 | if (remote_component != MTC_COMPREF && self != remote_component) | |
1624 | COMPONENT::register_component_name(remote_component, | |
1625 | remote_component_name); | |
1626 | PORT::process_connect_listen(local_port, remote_component, remote_port, | |
1627 | transport_type); | |
1628 | } catch (...) { | |
1629 | delete [] local_port; | |
1630 | delete [] remote_component_name; | |
1631 | delete [] remote_port; | |
1632 | throw; | |
1633 | } | |
1634 | ||
1635 | delete [] local_port; | |
1636 | delete [] remote_component_name; | |
1637 | delete [] remote_port; | |
1638 | } | |
1639 | ||
1640 | void TTCN_Communication::process_connect() | |
1641 | { | |
1642 | char *local_port = incoming_buf.pull_string(); | |
1643 | component remote_component = incoming_buf.pull_int().get_val(); | |
1644 | char *remote_component_name = incoming_buf.pull_string(); | |
1645 | char *remote_port = incoming_buf.pull_string(); | |
1646 | transport_type_enum transport_type = | |
1647 | (transport_type_enum)incoming_buf.pull_int().get_val(); | |
1648 | ||
1649 | try { | |
1650 | if (remote_component != MTC_COMPREF && self != remote_component) | |
1651 | COMPONENT::register_component_name(remote_component, | |
1652 | remote_component_name); | |
1653 | PORT::process_connect(local_port, remote_component, remote_port, | |
1654 | transport_type, incoming_buf); | |
1655 | } catch (...) { | |
1656 | incoming_buf.cut_message(); | |
1657 | delete [] local_port; | |
1658 | delete [] remote_component_name; | |
1659 | delete [] remote_port; | |
1660 | throw; | |
1661 | } | |
1662 | ||
1663 | incoming_buf.cut_message(); | |
1664 | delete [] local_port; | |
1665 | delete [] remote_component_name; | |
1666 | delete [] remote_port; | |
1667 | } | |
1668 | ||
1669 | void TTCN_Communication::process_connect_ack() | |
1670 | { | |
1671 | incoming_buf.cut_message(); | |
1672 | ||
1673 | switch (TTCN_Runtime::get_state()) { | |
1674 | case TTCN_Runtime::MTC_CONNECT: | |
1675 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE); | |
1676 | case TTCN_Runtime::MTC_TERMINATING_TESTCASE: | |
1677 | break; | |
1678 | case TTCN_Runtime::PTC_CONNECT: | |
1679 | TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION); | |
1680 | break; | |
1681 | default: | |
1682 | TTCN_error("Internal error: Message CONNECT_ACK arrived in invalid " | |
1683 | "state."); | |
1684 | } | |
1685 | } | |
1686 | ||
1687 | void TTCN_Communication::process_disconnect() | |
1688 | { | |
1689 | char *local_port = incoming_buf.pull_string(); | |
1690 | component remote_component = incoming_buf.pull_int().get_val(); | |
1691 | char *remote_port = incoming_buf.pull_string(); | |
1692 | incoming_buf.cut_message(); | |
1693 | ||
1694 | try { | |
1695 | PORT::process_disconnect(local_port, remote_component, remote_port); | |
1696 | } catch (...) { | |
1697 | delete [] local_port; | |
1698 | delete [] remote_port; | |
1699 | throw; | |
1700 | } | |
1701 | ||
1702 | delete [] local_port; | |
1703 | delete [] remote_port; | |
1704 | } | |
1705 | ||
1706 | void TTCN_Communication::process_disconnect_ack() | |
1707 | { | |
1708 | incoming_buf.cut_message(); | |
1709 | ||
1710 | switch (TTCN_Runtime::get_state()) { | |
1711 | case TTCN_Runtime::MTC_DISCONNECT: | |
1712 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE); | |
1713 | case TTCN_Runtime::MTC_TERMINATING_TESTCASE: | |
1714 | break; | |
1715 | case TTCN_Runtime::PTC_DISCONNECT: | |
1716 | TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION); | |
1717 | break; | |
1718 | default: | |
1719 | TTCN_error("Internal error: Message DISCONNECT_ACK arrived in invalid " | |
1720 | "state."); | |
1721 | } | |
1722 | } | |
1723 | ||
1724 | void TTCN_Communication::process_map() | |
1725 | { | |
1726 | char *local_port = incoming_buf.pull_string(); | |
1727 | char *system_port = incoming_buf.pull_string(); | |
1728 | incoming_buf.cut_message(); | |
1729 | ||
1730 | try { | |
1731 | PORT::map_port(local_port, system_port); | |
1732 | } catch (...) { | |
1733 | delete [] local_port; | |
1734 | delete [] system_port; | |
1735 | throw; | |
1736 | } | |
1737 | ||
1738 | delete [] local_port; | |
1739 | delete [] system_port; | |
1740 | } | |
1741 | ||
1742 | void TTCN_Communication::process_map_ack() | |
1743 | { | |
1744 | incoming_buf.cut_message(); | |
1745 | ||
1746 | switch (TTCN_Runtime::get_state()) { | |
1747 | case TTCN_Runtime::MTC_MAP: | |
1748 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE); | |
1749 | case TTCN_Runtime::MTC_TERMINATING_TESTCASE: | |
1750 | break; | |
1751 | case TTCN_Runtime::PTC_MAP: | |
1752 | TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION); | |
1753 | break; | |
1754 | default: | |
1755 | TTCN_error("Internal error: Message MAP_ACK arrived in invalid state."); | |
1756 | } | |
1757 | } | |
1758 | ||
1759 | void TTCN_Communication::process_unmap() | |
1760 | { | |
1761 | char *local_port = incoming_buf.pull_string(); | |
1762 | char *system_port = incoming_buf.pull_string(); | |
1763 | incoming_buf.cut_message(); | |
1764 | ||
1765 | try { | |
1766 | PORT::unmap_port(local_port, system_port); | |
1767 | } catch (...) { | |
1768 | delete [] local_port; | |
1769 | delete [] system_port; | |
1770 | throw; | |
1771 | } | |
1772 | ||
1773 | delete [] local_port; | |
1774 | delete [] system_port; | |
1775 | } | |
1776 | ||
1777 | void TTCN_Communication::process_unmap_ack() | |
1778 | { | |
1779 | incoming_buf.cut_message(); | |
1780 | ||
1781 | switch(TTCN_Runtime::get_state()){ | |
1782 | case TTCN_Runtime::MTC_UNMAP: | |
1783 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_TESTCASE); | |
1784 | case TTCN_Runtime::MTC_TERMINATING_TESTCASE: | |
1785 | break; | |
1786 | case TTCN_Runtime::PTC_UNMAP: | |
1787 | TTCN_Runtime::set_state(TTCN_Runtime::PTC_FUNCTION); | |
1788 | break; | |
1789 | default: | |
1790 | TTCN_error("Internal error: Message UNMAP_ACK arrived in invalid " | |
1791 | "state."); | |
1792 | } | |
1793 | } | |
1794 | ||
1795 | void TTCN_Communication::process_execute_control() | |
1796 | { | |
1797 | char *module_name = incoming_buf.pull_string(); | |
1798 | incoming_buf.cut_message(); | |
1799 | ||
1800 | if (TTCN_Runtime::get_state() != TTCN_Runtime::MTC_IDLE) { | |
1801 | delete [] module_name; | |
1802 | TTCN_error("Internal error: Message EXECUTE_CONTROL arrived in " | |
1803 | "invalid state."); | |
1804 | } | |
1805 | ||
1806 | TTCN_Logger::log(TTCN_Logger::PARALLEL_UNQUALIFIED, | |
1807 | "Executing control part of module %s.", module_name); | |
1808 | ||
1809 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_CONTROLPART); | |
1810 | ||
1811 | try { | |
1812 | Module_List::execute_control(module_name); | |
1813 | } catch (const TC_End& TC_end) { | |
1814 | } catch (const TC_Error& TC_error) { | |
1815 | } | |
1816 | ||
1817 | delete [] module_name; | |
1818 | ||
1819 | if (is_connected) { | |
1820 | send_mtc_ready(); | |
1821 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_IDLE); | |
1822 | } else TTCN_Runtime::set_state(TTCN_Runtime::MTC_EXIT); | |
1823 | } | |
1824 | ||
1825 | void TTCN_Communication::process_execute_testcase() | |
1826 | { | |
1827 | char *module_name = incoming_buf.pull_string(); | |
1828 | char *testcase_name = incoming_buf.pull_string(); | |
1829 | incoming_buf.cut_message(); | |
1830 | ||
1831 | if (TTCN_Runtime::get_state() != TTCN_Runtime::MTC_IDLE) { | |
1832 | delete [] module_name; | |
1833 | delete [] testcase_name; | |
1834 | TTCN_error("Internal error: Message EXECUTE_TESTCASE arrived in " | |
1835 | "invalid state."); | |
1836 | } | |
1837 | ||
1838 | TTCN_Logger::log_testcase_exec(testcase_name, module_name); | |
1839 | ||
1840 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_CONTROLPART); | |
1841 | ||
1842 | try { | |
1843 | if (testcase_name != NULL && testcase_name[0] != '\0') | |
1844 | Module_List::execute_testcase(module_name, testcase_name); | |
1845 | else Module_List::execute_all_testcases(module_name); | |
1846 | } catch (const TC_End& TC_end) { | |
1847 | } catch (const TC_Error& TC_error) { | |
1848 | } | |
1849 | ||
1850 | if (is_connected) { | |
1851 | send_mtc_ready(); | |
1852 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_IDLE); | |
1853 | } else TTCN_Runtime::set_state(TTCN_Runtime::MTC_EXIT); | |
1854 | ||
1855 | delete [] module_name; | |
1856 | delete [] testcase_name; | |
1857 | } | |
1858 | ||
1859 | void TTCN_Communication::process_ptc_verdict() | |
1860 | { | |
1861 | TTCN_Runtime::process_ptc_verdict(incoming_buf); | |
1862 | incoming_buf.cut_message(); | |
1863 | } | |
1864 | ||
1865 | void TTCN_Communication::process_continue() | |
1866 | { | |
1867 | incoming_buf.cut_message(); | |
1868 | ||
1869 | if (TTCN_Runtime::get_state() != TTCN_Runtime::MTC_PAUSED) | |
1870 | TTCN_error("Internal error: Message CONTINUE arrived in invalid " | |
1871 | "state."); | |
1872 | ||
1873 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_CONTROLPART); | |
1874 | } | |
1875 | ||
1876 | void TTCN_Communication::process_exit_mtc() | |
1877 | { | |
1878 | incoming_buf.cut_message(); | |
1879 | TTCN_Runtime::log_verdict_statistics(); | |
1880 | TTCN_Logger::log_executor_runtime( | |
1881 | TitanLoggerApiSimple::ExecutorRuntime_reason::exit__requested__from__mc__mtc); | |
1882 | TTCN_Runtime::set_state(TTCN_Runtime::MTC_EXIT); | |
1883 | } | |
1884 | ||
1885 | void TTCN_Communication::process_start() | |
1886 | { | |
1887 | qualified_name function_name; | |
1888 | incoming_buf.pull_qualified_name(function_name); | |
1889 | if (function_name.module_name == NULL || | |
1890 | function_name.definition_name == NULL) { | |
1891 | incoming_buf.cut_message(); | |
1892 | delete [] function_name.module_name; | |
1893 | delete [] function_name.definition_name; | |
1894 | TTCN_error("Internal error: Message START contains an invalid " | |
1895 | "function name."); | |
1896 | } | |
1897 | ||
1898 | try { | |
1899 | TTCN_Runtime::start_function(function_name.module_name, | |
1900 | function_name.definition_name, incoming_buf); | |
1901 | } catch (...) { | |
1902 | // avoid memory leaks | |
1903 | delete [] function_name.module_name; | |
1904 | delete [] function_name.definition_name; | |
1905 | throw; | |
1906 | } | |
1907 | ||
1908 | delete [] function_name.module_name; | |
1909 | delete [] function_name.definition_name; | |
1910 | } | |
1911 | ||
1912 | void TTCN_Communication::process_kill() | |
1913 | { | |
1914 | incoming_buf.cut_message(); | |
1915 | TTCN_Runtime::process_kill(); | |
1916 | } | |
1917 | ||
1918 | void TTCN_Communication::process_error() | |
1919 | { | |
1920 | char *error_string = incoming_buf.pull_string(); | |
1921 | incoming_buf.cut_message(); | |
1922 | ||
1923 | try { | |
1924 | TTCN_error("Error message was received from MC: %s", error_string); | |
1925 | } catch (...) { | |
1926 | delete [] error_string; | |
1927 | throw; | |
1928 | } | |
1929 | } | |
1930 | ||
1931 | void TTCN_Communication::process_unsupported_message(int msg_type, int msg_end) | |
1932 | { | |
1933 | TTCN_Logger::begin_event(TTCN_Logger::WARNING_UNQUALIFIED); | |
1934 | TTCN_Logger::log_event("Unsupported message was received from MC: " | |
1935 | "type (decimal): %d, data (hexadecimal): ", msg_type); | |
1936 | const unsigned char *msg_ptr = | |
1937 | (const unsigned char*)incoming_buf.get_data(); | |
1938 | for (int i = incoming_buf.get_pos(); i < msg_end; i++) | |
1939 | TTCN_Logger::log_octet(msg_ptr[i]); | |
1940 | TTCN_Logger::end_event(); | |
1941 | incoming_buf.cut_message(); | |
1942 | } | |
1943 | ||
016a1a93 BB |
1944 | void TTCN_Communication::process_debug_command() |
1945 | { | |
1946 | int command = incoming_buf.pull_int().get_val(); | |
1947 | int argument_count = incoming_buf.pull_int().get_val(); | |
1948 | char** arguments = NULL; | |
1949 | if (argument_count > 0) { | |
1950 | arguments = new char*[argument_count]; | |
1951 | for (int i = 0; i < argument_count; ++i) { | |
1952 | arguments[i] = incoming_buf.pull_string(); | |
1953 | } | |
1954 | } | |
1955 | incoming_buf.cut_message(); | |
1956 | ttcn3_debugger.execute_command(command, argument_count, arguments); | |
1957 | if (argument_count > 0) { | |
1958 | for (int i = 0; i < argument_count; ++i) { | |
1959 | delete [] arguments[i]; | |
1960 | } | |
1961 | delete [] arguments; | |
1962 | } | |
1963 | } | |
1964 | ||
970ed795 EL |
1965 | /* * * * Temporary squatting place because it includes version.h * * * */ |
1966 | ||
1967 | const struct runtime_version current_runtime_version = { | |
1968 | TTCN3_MAJOR, TTCN3_MINOR, TTCN3_PATCHLEVEL, TITAN_RUNTIME_NR | |
1969 | }; | |
1970 | ||
1971 | static const char *runtime_name[] = { 0, "load", "function " }; | |
1972 | ||
1973 | RuntimeVersionChecker::RuntimeVersionChecker( | |
1974 | int ver_major, int ver_minor, int patch_level, int rt) | |
1975 | { | |
1976 | if ( TTCN3_MAJOR != ver_major | |
1977 | || TTCN3_MINOR != ver_minor | |
1978 | || TTCN3_PATCHLEVEL != patch_level) | |
1979 | { | |
1980 | TTCN_error( | |
1981 | "Version mismatch detected: generated code %d.%d.pl%d, " | |
1982 | "runtime is %d.%d.pl%d", | |
1983 | ver_major, ver_minor, patch_level, | |
1984 | TTCN3_MAJOR, TTCN3_MINOR, TTCN3_PATCHLEVEL); | |
1985 | } | |
1986 | ||
1987 | if (TITAN_RUNTIME_NR != rt) { | |
1988 | TTCN_error("Runtime mismatch detected: files compiled for the %stest" | |
1989 | " runtime cannot be linked to %stest library", | |
1990 | runtime_name[TITAN_RUNTIME_NR], runtime_name[rt]); | |
1991 | } | |
1992 | } | |
1993 | ||
1994 | reffer::reffer(const char*) {} | |
1995 |