Debugger - Stage 3 (artf511247)
[deliverable/titan.core.git] / mctr2 / mctr / MainController.cc
CommitLineData
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 * Bene, Tamas
13 * Feher, Csaba
14 * Forstner, Matyas
15 * Gecse, Roland
16 * Kovacs, Ferenc
17 * Lovassy, Arpad
18 * Raduly, Csaba
19 * Szabados, Kristof
20 * Szabo, Janos Zoltan – initial implementation
21 * Szalai, Gabor
22 * Zalanyi, Balazs Andor
23 *
24 ******************************************************************************/
970ed795
EL
25//
26// Description: Implementation file for MainController
27// Author: Janos Zoltan Szabo
28// mail: tmpjsz@eth.ericsson.se
29//
3abe9331 30// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
31//
32//----------------------------------------------------------------------------
33
34#include "MainController.h"
35#include "UserInterface.h"
36
37#include "../../common/memory.h"
38#include "../../common/version.h"
39#include "../../common/version_internal.h"
40#include "../../core/Message_types.hh"
41#include "../../core/Error.hh"
42#include "../../core/Textbuf.hh"
43#include "../../core/Logger.hh"
016a1a93 44#include "DebugCommands.hh"
970ed795
EL
45
46#include <stdio.h>
47#include <string.h>
48#include <ctype.h>
49#include <stdarg.h>
50#include <unistd.h>
51#include <errno.h>
52#include <pthread.h>
53#include <fcntl.h>
54#include <sys/types.h>
55#include <sys/socket.h>
56#include <sys/time.h>
57#ifdef USE_EPOLL
58#include <sys/epoll.h>
59#else
60#include <sys/poll.h>
61#endif
62#include <sys/utsname.h>
63#include <netinet/in.h>
64#include <netinet/tcp.h>
65#include <arpa/inet.h>
66#include <netdb.h>
67#include <sys/un.h>
68#include <signal.h>
69
70reffer::reffer(const char*) {}
71
72//----------------------------------------------------------------------------
73
74namespace mctr {
75
76//----------------------------------------------------------------------------
77
78/* Static variables */
79
80UserInterface *MainController::ui;
81NetworkHandler MainController::nh;
82
83mc_state_enum MainController::mc_state;
84char *MainController::mc_hostname;
85
86struct sigaction MainController::new_action, MainController::old_action;
87
88int MainController::server_fd;
89int MainController::server_fd_unix = -1;
90boolean MainController::server_fd_disabled;
91
016a1a93
BB
92debugger_settings_struct MainController::debugger_settings;
93debug_command_struct MainController::last_debug_command;
94
970ed795
EL
95void MainController::disable_server_fd()
96{
97 if (!server_fd_disabled) {
98 remove_poll_fd(server_fd);
99 server_fd_disabled = TRUE;
100 }
101}
102
103void MainController::enable_server_fd()
104{
105 if (server_fd_disabled) {
106 add_poll_fd(server_fd);
107 server_fd_disabled = FALSE;
108 }
109}
110
111pthread_mutex_t MainController::mutex;
112
113void MainController::lock()
114{
115 int result = pthread_mutex_lock(&mutex);
116 if (result > 0) {
117 fatal_error("MainController::lock: "
118 "pthread_mutex_lock failed with code %d.", result);
119 }
120}
121
122void MainController::unlock()
123{
124 int result = pthread_mutex_unlock(&mutex);
125 if (result > 0) {
126 fatal_error("MainController::unlock: "
127 "pthread_mutex_unlock failed with code %d.", result);
128 }
129}
130
131#ifdef USE_EPOLL
132epoll_event *MainController::epoll_events;
133int MainController::epfd;
134#else
135unsigned int MainController::nfds, MainController::new_nfds;
136struct pollfd *MainController::ufds, *MainController::new_ufds;
137boolean MainController::pollfds_modified;
138#endif //USE_EPOLL
139
140#ifdef USE_EPOLL
141void MainController::add_poll_fd(int fd)
142{
143 if (fd < 0) return;
144 epoll_event event;
a38c6d4c 145 memset(&event,0,sizeof(event));
970ed795
EL
146 event.events = EPOLLIN;
147 event.data.fd = fd;
148 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) < 0)
149 fatal_error("MainController::add_poll_fd: system call epoll_ctl"
150 " failed on file descriptor %d.", fd);
151}
152
153void MainController::remove_poll_fd(int fd)
154{
155 if (fd < 0) return;
156 epoll_event event;
a38c6d4c 157 memset(&event,0,sizeof(event));
970ed795
EL
158 event.events = EPOLLIN;
159 event.data.fd = fd;
160 if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &event) < 0)
161 fatal_error("MainController::remove_poll_fd: system call epoll_ctl"
162 " failed on file descriptor %d.", fd);
163}
164#else // ! defined USE_EPOLL
165void MainController::add_poll_fd(int fd)
166{
167 if (fd < 0) return;
168 if (pollfds_modified) {
169 int i;
170 for (i = new_nfds - 1; i >= 0; i--) {
171 if (new_ufds[i].fd < fd) break;
172 else if (new_ufds[i].fd == fd) return;
173 }
174 i++;
175 new_ufds = (struct pollfd*)Realloc(new_ufds, (new_nfds + 1) *
176 sizeof(struct pollfd));
177 memmove(new_ufds + i + 1, new_ufds + i, (new_nfds - i) *
178 sizeof(struct pollfd));
179 new_ufds[i].fd = fd;
180 new_ufds[i].events = POLLIN;
181 new_ufds[i].revents = 0;
182 new_nfds++;
183 } else {
184 int i;
185 for (i = nfds - 1; i >= 0; i--) {
186 if (ufds[i].fd < fd) break;
187 else if (ufds[i].fd == fd) return;
188 }
189 i++;
190 new_nfds = nfds + 1;
191 new_ufds = (struct pollfd*)Malloc(new_nfds * sizeof(struct pollfd));
192 memcpy(new_ufds, ufds, i * sizeof(struct pollfd));
193 new_ufds[i].fd = fd;
194 new_ufds[i].events = POLLIN;
195 new_ufds[i].revents = 0;
196 memcpy(new_ufds + i + 1, ufds + i, (nfds - i) * sizeof(struct pollfd));
197 pollfds_modified = TRUE;
198 }
199}
200
201void MainController::remove_poll_fd(int fd)
202{
203 if (fd < 0) return;
204 if (pollfds_modified) {
205 int i;
206 for (i = new_nfds - 1; i >= 0; i--) {
207 if (new_ufds[i].fd == fd) break;
208 else if (new_ufds[i].fd < fd) return;
209 }
210 if (i < 0) return;
211 new_nfds--;
212 memmove(new_ufds + i, new_ufds + i + 1, (new_nfds - i) *
213 sizeof(struct pollfd));
214 new_ufds = (struct pollfd*)Realloc(new_ufds, new_nfds *
215 sizeof(struct pollfd));
216 } else {
217 int i;
218 for (i = nfds - 1; i >= 0; i--) {
219 if (ufds[i].fd == fd) break;
220 else if (ufds[i].fd < fd) return;
221 }
222 if (i < 0) return;
223 new_nfds = nfds - 1;
224 new_ufds = (struct pollfd*)Malloc(new_nfds * sizeof(struct pollfd));
225 memcpy(new_ufds, ufds, i * sizeof(struct pollfd));
226 memcpy(new_ufds + i, ufds + i + 1, (new_nfds - i) *
227 sizeof(struct pollfd));
228 pollfds_modified = TRUE;
229 }
230}
231
232void MainController::update_pollfds()
233{
234 if (pollfds_modified) {
235 nfds = new_nfds;
236 new_nfds = 0;
237 Free(ufds);
238 ufds = new_ufds;
239 new_ufds = NULL;
240 pollfds_modified = FALSE;
241 }
242}
243#endif //USE_EPOLL
244
245int MainController::fd_table_size;
246fd_table_struct *MainController::fd_table;
247
248void MainController::add_fd_to_table(int fd)
249{
250 if (fd >= fd_table_size) {
251 fd_table = (fd_table_struct *)Realloc(fd_table, (fd + 1) *
252 sizeof(fd_table_struct));
253 for (int i = fd_table_size; i <= fd; i++) {
254 fd_table[i].fd_type = FD_UNUSED;
255 fd_table[i].dummy_ptr = NULL;
256 }
257 fd_table_size = fd + 1;
258 }
259}
260
261void MainController::remove_fd_from_table(int fd)
262{
263 if (fd < fd_table_size) {
264 fd_table[fd].fd_type = FD_UNUSED;
265 int i;
266 for (i = fd_table_size - 1; i >= 0 ; i--) {
267 if (fd_table[i].fd_type != FD_UNUSED) break;
268 }
269 if (i < fd_table_size - 1) {
270 fd_table_size = i + 1;
271 fd_table = (fd_table_struct *)Realloc(fd_table, fd_table_size *
272 sizeof(fd_table_struct));
273 }
274 }
275}
276
277void MainController::set_close_on_exec(int fd)
278{
279 int flags = fcntl(fd, F_GETFD);
280 if (flags < 0) fatal_error("MainController::set_close_on_exec: system call "
281 "fcntl(F_GETFD) failed on file descriptor %d.", fd);
282
283 flags |= FD_CLOEXEC;
284
285 if (fcntl(fd, F_SETFD, flags) == -1)
286 fatal_error("MainController::set_close_on_exec: system call "
287 "fcntl(F_SETFD) failed on file descriptor %d.", fd);
288}
289
290unknown_connection *MainController::unknown_head, *MainController::unknown_tail;
291
292unknown_connection *MainController::new_unknown_connection(
293 bool unix_socket)
294{
295 unknown_connection *conn = new unknown_connection;
296 conn->unix_socket = unix_socket;
297 conn->prev = unknown_tail;
298 conn->next = NULL;
299 if (unknown_tail != NULL) unknown_tail->next = conn;
300 else unknown_head = conn;
301 unknown_tail = conn;
302 return conn;
303}
304
305void MainController::delete_unknown_connection(unknown_connection *conn)
306{
307 if (conn->prev != NULL) conn->prev->next = conn->next;
308 else unknown_head = conn->next;
309 if (conn->next != NULL) conn->next->prev = conn->prev;
310 else unknown_tail = conn->prev;
311 delete conn;
312}
313
314void MainController::close_unknown_connection(unknown_connection *conn)
315{
316 remove_poll_fd(conn->fd);
317 close(conn->fd);
318 remove_fd_from_table(conn->fd);
319 delete conn->text_buf;
320 delete_unknown_connection(conn);
321 enable_server_fd();
322}
323
324void MainController::init_string_set(string_set *set)
325{
326 set->n_elements = 0;
327 set->elements = NULL;
328}
329
330void MainController::free_string_set(string_set *set)
331{
332 for (int i = 0; i < set->n_elements; i++) Free(set->elements[i]);
333 Free(set->elements);
334 set->n_elements = 0;
335 set->elements = NULL;
336}
337
338void MainController::add_string_to_set(string_set *set, const char *str)
339{
340 int i;
341 for (i = 0; i < set->n_elements; i++) {
342 int result = strcmp(set->elements[i], str);
343 if (result > 0) break;
344 else if (result == 0) return;
345 }
346 set->elements = (char**)Realloc(set->elements,
347 (set->n_elements + 1) * sizeof(*set->elements));
348 memmove(set->elements + i + 1, set->elements + i,
349 (set->n_elements - i) * sizeof(*set->elements));
350 set->elements[i] = mcopystr(str);
351 set->n_elements++;
352}
353
354void MainController::remove_string_from_set(string_set *set,
355 const char *str)
356{
357 for (int i = 0; i < set->n_elements; i++) {
358 int result = strcmp(set->elements[i], str);
359 if (result < 0) continue;
360 else if (result == 0) {
361 Free(set->elements[i]);
362 set->n_elements--;
363 memmove(set->elements + i, set->elements + i + 1,
364 (set->n_elements - i) * sizeof(*set->elements));
365 set->elements = (char**)Realloc(set->elements,
366 set->n_elements * sizeof(*set->elements));
367 }
368 return;
369 }
370}
371
372boolean MainController::set_has_string(const string_set *set,
373 const char *str)
374{
375 if(str == NULL) return FALSE;
376 for (int i = 0; i < set->n_elements; i++) {
377 int result = strcmp(set->elements[i], str);
378 if (result == 0) return TRUE;
379 else if (result > 0) break;
380 }
381 return FALSE;
382}
383
384const char *MainController::get_string_from_set(const string_set *set,
385 int index)
386{
387 if (index >= 0 && index < set->n_elements) return set->elements[index];
388 else return NULL;
389}
390
391int MainController::n_host_groups;
392host_group_struct *MainController::host_groups;
393string_set MainController::assigned_components;
394boolean MainController::all_components_assigned;
395
396host_group_struct *MainController::add_host_group(const char *group_name)
397{
398 int i;
399 for (i = 0 ; i < n_host_groups; i++) {
400 host_group_struct *group = host_groups + i;
401 int result = strcmp(group->group_name, group_name);
402 if (result > 0) break;
403 else if (result == 0) return group;
404 }
405 host_groups = (host_group_struct*)Realloc(host_groups,
406 (n_host_groups + 1) * sizeof(*host_groups));
407 host_group_struct *new_group = host_groups + i;
408 memmove(new_group + 1, new_group,
409 (n_host_groups - i) * sizeof(*host_groups));
410 new_group->group_name = mcopystr(group_name);
411 new_group->has_all_hosts = FALSE;
412 new_group->has_all_components = FALSE;
413 init_string_set(&new_group->host_members);
414 init_string_set(&new_group->assigned_components);
415 n_host_groups++;
416 return new_group;
417}
418
419host_group_struct *MainController::lookup_host_group(const char *group_name)
420{
421 for (int i = 0; i < n_host_groups; i++) {
422 host_group_struct *group = host_groups + i;
423 int result = strcmp(group->group_name, group_name);
424 if (result == 0) return group;
425 else if (result > 0) break;
426 }
427 return NULL;
428}
429
430boolean MainController::is_similar_hostname(const char *host1,
431 const char *host2)
432{
433 for (size_t i = 0; ; i++) {
434 unsigned char c1 = host1[i], c2 = host2[i];
435 if (c1 == '\0') {
436 // if host2 is the longer one it may contain an additional domain
437 // name with a leading dot (e.g. "foo" is similar to "foo.bar.com")
438 // note: empty string is similar with empty string only
439 if (c2 == '\0' || (i > 0 && c2 == '.')) return TRUE;
440 else return FALSE;
441 } else if (c2 == '\0') {
442 // or vice versa
443 if (c1 == '\0' || (i > 0 && c1 == '.')) return TRUE;
444 else return FALSE;
445 } else {
446 // case insensitive comparison of the characters
447 if (tolower(c1) != tolower(c2)) return FALSE;
448 // continue the evaluation if they are matching
449 }
450 }
451}
452
453boolean MainController::host_has_name(const host_struct *host, const char *name)
454{
455 // name might resemble to host->hostname
456 if (is_similar_hostname(host->hostname, name)) return TRUE;
457 // to avoid returning true in situations when name is "foo.bar.com", but
458 // host->hostname is "foo.other.com" and host->hostname_local is "foo"
459 // name might resemble to host->hostname_local
460 if (host->local_hostname_different &&
461 is_similar_hostname(host->hostname_local, name)) return TRUE;
462 // name might be an IP address or a DNS alias
463 IPAddress *ip_addr = IPAddress::create_addr(nh.get_family());
464 if (ip_addr->set_addr(name)) {
465 // check if IP addresses match
466 if (*ip_addr == *(host->ip_addr)) {
467 delete ip_addr;
468 return TRUE;
469 }
470 // try to handle such strange situations when the local hostname is
471 // mapped to a loopback address by /etc/hosts
472 // (i.e. host->ip_addr contains 127.x.y.z)
473 // but the given name contains the real IP address of the host
474 const char *canonical_name = ip_addr->get_host_str();
475 if (is_similar_hostname(host->hostname, canonical_name)) {
476 delete ip_addr;
477 return TRUE;
478 }
479 if (host->local_hostname_different &&
480 is_similar_hostname(host->hostname_local, canonical_name)) {
481 delete ip_addr;
482 return TRUE;
483 }
484 }
485 delete ip_addr;
486 return FALSE;
487}
488
489boolean MainController::member_of_group(const host_struct *host,
490 const host_group_struct *group)
491{
492 if (group->has_all_hosts) return TRUE;
493 for (int i = 0; ; i++) {
494 const char *member_name = get_string_from_set(&group->host_members, i);
495 if (member_name != NULL) {
496 if (host_has_name(host, member_name)) return TRUE;
497 } else if (i == 0) {
498 // empty group: the group name is considered as a hostname
499 return host_has_name(host, group->group_name);
500 } else {
501 // no more members
502 break;
503 }
504 }
505 return FALSE;
506}
507
508void MainController::add_allowed_components(host_struct *host)
509{
510 init_string_set(&host->allowed_components);
511 host->all_components_allowed = FALSE;
512 for (int i = 0; i < n_host_groups; i++) {
513 host_group_struct *group = host_groups + i;
514 if (!member_of_group(host, group)) continue;
515 for (int j = 0; ; j++) {
516 const char *component_id =
517 get_string_from_set(&group->assigned_components, j);
518 if (component_id == NULL) break;
519 add_string_to_set(&host->allowed_components, component_id);
520 }
521 if (group->has_all_components) host->all_components_allowed = TRUE;
522 }
523}
524
525host_struct *MainController::choose_ptc_location(const char *component_type,
526 const char *component_name, const char *component_location)
527{
528 host_struct *best_candidate = NULL;
529 int load_on_best_candidate = 0;
530 boolean has_constraint =
531 set_has_string(&assigned_components, component_type) ||
532 set_has_string(&assigned_components, component_name);
533 host_group_struct *group;
534 if (component_location != NULL)
535 group = lookup_host_group(component_location);
536 else group = NULL;
537 for (int i = 0; i < n_hosts; i++) {
538 host_struct *host = hosts[i];
539 if (host->hc_state != HC_ACTIVE) continue;
540 if (best_candidate != NULL &&
541 host->n_active_components >= load_on_best_candidate) continue;
542 if (component_location != NULL) {
543 // the explicit location has precedence over the constraints
544 if (group != NULL) {
545 if (!member_of_group(host, group)) continue;
546 } else {
547 if (!host_has_name(host, component_location)) continue;
548 }
549 } else if (has_constraint) {
550 if (!set_has_string(&host->allowed_components, component_type) &&
551 !set_has_string(&host->allowed_components, component_name))
552 continue;
553 } else if (all_components_assigned) {
554 if (!host->all_components_allowed) continue;
555 }
556 best_candidate = host;
557 load_on_best_candidate = host->n_active_components;
558 }
559 return best_candidate;
560}
561
562int MainController::n_hosts;
563host_struct **MainController::hosts;
564
565host_struct *MainController::add_new_host(unknown_connection *conn)
566{
567 Text_Buf *text_buf = conn->text_buf;
568 int fd = conn->fd;
569
570 host_struct *new_host = new host_struct;
571
572 new_host->ip_addr = conn->ip_addr;
573 new_host->hostname = mcopystr(new_host->ip_addr->get_host_str());
574 new_host->hostname_local = text_buf->pull_string();
575 new_host->machine_type = text_buf->pull_string();
576 new_host->system_name = text_buf->pull_string();
577 new_host->system_release = text_buf->pull_string();
578 new_host->system_version = text_buf->pull_string();
579 for (int i = 0; i < TRANSPORT_NUM; i++)
580 new_host->transport_supported[i] = FALSE;
581 int n_supported_transports = text_buf->pull_int().get_val();
582 for (int i = 0; i < n_supported_transports; i++) {
583 int transport_type = text_buf->pull_int().get_val();
584 if (transport_type >= 0 && transport_type < TRANSPORT_NUM) {
585 if (new_host->transport_supported[transport_type]) {
586 send_error(fd, "Malformed VERSION message was received: "
587 "Transport type %s was specified more than once.",
588 get_transport_name((transport_type_enum)transport_type));
589 } else new_host->transport_supported[transport_type] = TRUE;
590 } else {
591 send_error(fd, "Malformed VERSION message was received: "
592 "Transport type code %d is invalid.", transport_type);
593 }
594 }
595 if (!new_host->transport_supported[TRANSPORT_LOCAL]) {
596 send_error(fd, "Malformed VERSION message was received: "
597 "Transport type %s must be supported anyway.",
598 get_transport_name(TRANSPORT_LOCAL));
599 }
600 if (!new_host->transport_supported[TRANSPORT_INET_STREAM]) {
601 send_error(fd, "Malformed VERSION message was received: "
602 "Transport type %s must be supported anyway.",
603 get_transport_name(TRANSPORT_INET_STREAM));
604 }
605 new_host->log_source = mprintf("HC@%s", new_host->hostname_local);
606 new_host->hc_state = HC_IDLE;
607 new_host->hc_fd = fd;
608 new_host->text_buf = text_buf;
609 new_host->n_components = 0;
610 new_host->components = NULL;
611 // in most cases hostname and hostname_local are similar ("foo.bar.com" vs.
612 // "foo") and it is enough to compare only the (fully qualified) hostname
613 // when evaluating PTC location constraints
614 new_host->local_hostname_different =
615 !is_similar_hostname(new_host->hostname, new_host->hostname_local);
616 add_allowed_components(new_host);
617 new_host->n_active_components = 0;
618
619 text_buf->cut_message();
620
621 delete_unknown_connection(conn);
622
623 n_hosts++;
624 hosts = (host_struct**)Realloc(hosts, n_hosts * sizeof(*hosts));
625 hosts[n_hosts - 1] = new_host;
626
627 fd_table[fd].fd_type = FD_HC;
628 fd_table[fd].host_ptr = new_host;
629
630 notify("New HC connected from %s [%s]. %s: %s %s on %s.",
631 new_host->hostname, new_host->ip_addr->get_addr_str(),
632 new_host->hostname_local, new_host->system_name,
633 new_host->system_release, new_host->machine_type);
634
635 return new_host;
636}
637
638void MainController::close_hc_connection(host_struct *hc)
639{
640 if (hc->hc_state != HC_DOWN) {
641 remove_poll_fd(hc->hc_fd);
642 close(hc->hc_fd);
643 remove_fd_from_table(hc->hc_fd);
644 hc->hc_fd = -1;
645 delete hc->text_buf;
646 hc->text_buf = NULL;
647 hc->hc_state = HC_DOWN;
648 enable_server_fd();
649 }
650}
651
652boolean MainController::is_hc_in_state(hc_state_enum checked_state)
653{
654 for (int i = 0; i < n_hosts; i++)
655 if (hosts[i]->hc_state == checked_state) return TRUE;
656 return FALSE;
657}
658
659boolean MainController::all_hc_in_state(hc_state_enum checked_state)
660{
661 for (int i = 0; i < n_hosts; i++)
662 if (hosts[i]->hc_state != checked_state) return FALSE;
663 return TRUE;
664}
665
666void MainController::configure_host(host_struct *host, boolean should_notify)
667{
668 if(config_str == NULL)
669 fatal_error("MainController::configure_host: no config file");
670 hc_state_enum next_state = HC_CONFIGURING;
671 switch(host->hc_state) {
672 case HC_CONFIGURING:
673 case HC_CONFIGURING_OVERLOADED:
674 case HC_EXITING:
675 fatal_error("MainController::configure_host:"
676 " host %s is in wrong state.",
677 host->hostname);
678 break;
679 case HC_DOWN:
680 break;
681 case HC_OVERLOADED:
682 next_state = HC_CONFIGURING_OVERLOADED;
683 // no break
684 default:
685 host->hc_state = next_state;
686 if (should_notify) {
687 notify("Downloading configuration file to HC on host %s.",
688 host->hostname);
689 }
690 send_configure(host, config_str);
016a1a93 691 send_debug_setup(host);
970ed795
EL
692 }
693}
694
695void MainController::check_all_hc_configured()
696{
697 if (is_hc_in_state(HC_CONFIGURING) ||
698 is_hc_in_state(HC_CONFIGURING_OVERLOADED)) return;
699 if (is_hc_in_state(HC_IDLE)) {
700 error("There were errors during configuring HCs.");
701 mc_state = MC_HC_CONNECTED;
702 } else if (is_hc_in_state(HC_ACTIVE) || is_hc_in_state(HC_OVERLOADED)) {
703 notify("Configuration file was processed on all HCs.");
704 mc_state = MC_ACTIVE;
705 } else {
706 error("There is no HC connection after processing the configuration "
707 "file.");
708 mc_state = MC_LISTENING;
709 }
710}
711
712void MainController::add_component_to_host(host_struct *host,
713 component_struct *comp)
714{
715 if (comp->comp_ref == MTC_COMPREF)
716 comp->log_source = mprintf("MTC@%s", host->hostname_local);
717 else if (comp->comp_name != NULL)
718 comp->log_source = mprintf("%s(%d)@%s", comp->comp_name,
719 comp->comp_ref, host->hostname_local);
720 else comp->log_source = mprintf("%d@%s", comp->comp_ref,
721 host->hostname_local);
722 comp->comp_location = host;
723 int i;
724 for (i = host->n_components; i > 0; i--) {
725 if (host->components[i - 1] < comp->comp_ref) break;
726 else if (host->components[i - 1] == comp->comp_ref) return;
727 }
728 host->components = (component*)Realloc(host->components,
729 (host->n_components + 1) * sizeof(component));
730 memmove(host->components + i + 1, host->components + i,
731 (host->n_components - i) * sizeof(component));
732 host->components[i] = comp->comp_ref;
733 host->n_components++;
734}
735
736void MainController::remove_component_from_host(component_struct *comp)
737{
738 Free(comp->log_source);
739 comp->log_source = NULL;
740 host_struct *host = comp->comp_location;
741 if (host != NULL) {
742 component comp_ref = comp->comp_ref;
743 int i;
744 for (i = host->n_components - 1; i >= 0; i--) {
745 if (host->components[i] == comp_ref) break;
746 else if (host->components[i] < comp_ref) return;
747 }
748 if (i < 0) return;
749 host->n_components--;
750 memmove(host->components + i, host->components + i + 1,
751 (host->n_components - i) * sizeof(component));
752 host->components = (component*)Realloc(host->components,
753 host->n_components * sizeof(component));
754 }
755}
756
757boolean MainController::version_known;
758int MainController::n_modules;
759module_version_info *MainController::modules;
760
761#ifdef TTCN3_BUILDNUMBER
762#define TTCN3_BUILDNUMBER_SAFE TTCN3_BUILDNUMBER
763#else
764#define TTCN3_BUILDNUMBER_SAFE 0
765#endif
766
767
768boolean MainController::check_version(unknown_connection *conn)
769{
770 Text_Buf& text_buf = *conn->text_buf;
771 int version_major = text_buf.pull_int().get_val();
772 int version_minor = text_buf.pull_int().get_val();
773 int version_patchlevel = text_buf.pull_int().get_val();
774 if (version_major != TTCN3_MAJOR || version_minor != TTCN3_MINOR ||
775 version_patchlevel != TTCN3_PATCHLEVEL) {
776 send_error(conn->fd, "Version mismatch: The TTCN-3 Main Controller has "
777 "version " PRODUCT_NUMBER ", but the ETS was built with version "
778 "%d.%d.pl%d.", version_major, version_minor, version_patchlevel);
779 return TRUE;
780 }
781 int version_buildnumber = text_buf.pull_int().get_val();
782 if (version_buildnumber != TTCN3_BUILDNUMBER_SAFE) {
783 if (version_buildnumber > 0) send_error(conn->fd, "Build number "
784 "mismatch: The TTCN-3 Main Controller has version " PRODUCT_NUMBER
785 ", but the ETS was built with %d.%d.pre%d build %d.",
786 version_major, version_minor, version_patchlevel,
787 version_buildnumber);
788 else send_error(conn->fd, "Build number mismatch: The TTCN-3 Main "
789 "Controller has version " PRODUCT_NUMBER ", but the ETS was built "
790 "with %d.%d.pl%d.", version_major, version_minor,
791 version_patchlevel);
792 return TRUE;
793 }
794 if (version_known) {
795 int new_n_modules = text_buf.pull_int().get_val();
796 if (n_modules != new_n_modules) {
797 send_error(conn->fd, "The number of modules in this ETS (%d) "
798 "differs from the number of modules in the firstly connected "
799 "ETS (%d).", new_n_modules, n_modules);
800 return TRUE;
801 }
802 for (int i = 0; i < n_modules; i++) {
803 char *module_name = text_buf.pull_string();
804 if (strcmp(module_name, modules[i].module_name)) {
805 send_error(conn->fd, "The module number %d in this ETS (%s) "
806 "has different name than in the firstly connected ETS (%s).",
807 i, module_name, modules[i].module_name);
808 delete [] module_name;
809 return TRUE;
810 }
811 boolean checksum_differs = FALSE;
812 int checksum_length = text_buf.pull_int().get_val();
813 unsigned char *module_checksum;
814 if (checksum_length != 0) {
815 module_checksum = new unsigned char[checksum_length];
816 text_buf.pull_raw(checksum_length, module_checksum);
817 } else module_checksum = NULL;
818 if (checksum_length != modules[i].checksum_length ||
819 memcmp(module_checksum, modules[i].module_checksum,
820 checksum_length)) checksum_differs = TRUE;
821 delete [] module_checksum;
822 if (checksum_differs) {
823 send_error(conn->fd, "The checksum of module %s in this ETS "
824 "is different than that of the firstly connected ETS.",
825 module_name);
826 }
827 delete [] module_name;
828 if (checksum_differs) return TRUE;
829 }
830 } else {
831 n_modules = text_buf.pull_int().get_val();
832 modules = new module_version_info[n_modules];
833 for (int i = 0; i < n_modules; i++) {
834 modules[i].module_name = text_buf.pull_string();
835 modules[i].checksum_length = text_buf.pull_int().get_val();
836 if (modules[i].checksum_length > 0) {
837 modules[i].module_checksum =
838 new unsigned char[modules[i].checksum_length];
839 text_buf.pull_raw(modules[i].checksum_length,
840 modules[i].module_checksum);
841 } else modules[i].module_checksum = NULL;
842 }
843 version_known = TRUE;
844 }
845 return FALSE;
846}
847
848int MainController::n_components, MainController::n_active_ptcs,
849 MainController::max_ptcs;
850component_struct **MainController::components;
851component_struct *MainController::mtc, *MainController::system;
016a1a93 852const component_struct* MainController::debugger_active_tc;
970ed795
EL
853component MainController::next_comp_ref, MainController::tc_first_comp_ref;
854
855boolean MainController::any_component_done_requested,
856 MainController::any_component_done_sent,
857 MainController::all_component_done_requested,
858 MainController::any_component_killed_requested,
859 MainController::all_component_killed_requested;
860
861void MainController::add_component(component_struct *comp)
862{
863 component comp_ref = comp->comp_ref;
864 if (lookup_component(comp_ref) != NULL)
865 fatal_error("MainController::add_component: duplicate "
866 "component reference %d.", comp_ref);
867 if (n_components <= comp_ref) {
868 components = (component_struct**)Realloc(components, (comp_ref + 1) *
869 sizeof(component_struct*));
870 for (int i = n_components; i < comp_ref; i++) components[i] = NULL;
871 n_components = comp_ref + 1;
872 }
873 components[comp_ref] = comp;
874}
875
876component_struct *MainController::lookup_component(component comp_ref)
877{
878 if (comp_ref >= 0 && comp_ref < n_components) return components[comp_ref];
879 else return NULL;
880}
881
882void MainController::destroy_all_components()
883{
884 for (component i = 0; i < n_components; i++) {
885 component_struct *comp = components[i];
886 if (comp != NULL) {
887 close_tc_connection(comp);
888 remove_component_from_host(comp);
889 free_qualified_name(&comp->comp_type);
890 delete [] comp->comp_name;
891 free_qualified_name(&comp->tc_fn_name);
892 delete [] comp->return_type;
893 Free(comp->return_value);
894 if (comp->verdict_reason != NULL) {
895 delete [] comp->verdict_reason;
896 comp->verdict_reason = NULL;
897 }
898 switch (comp->tc_state) {
899 case TC_INITIAL:
900 delete [] comp->initial.location_str;
901 break;
902 case PTC_STARTING:
903 Free(comp->starting.arguments_ptr);
904 free_requestors(&comp->starting.cancel_done_sent_to);
905 break;
906 case TC_STOPPING:
907 case PTC_STOPPING_KILLING:
908 case PTC_KILLING:
909 free_requestors(&comp->stopping_killing.stop_requestors);
910 free_requestors(&comp->stopping_killing.kill_requestors);
911 default:
912 break;
913 }
914 free_requestors(&comp->done_requestors);
915 free_requestors(&comp->killed_requestors);
916 free_requestors(&comp->cancel_done_sent_for);
917 remove_all_connections(i);
918 delete comp;
919 }
920 }
921 Free(components);
922 components = NULL;
923 n_components = 0;
924 n_active_ptcs = 0;
925 mtc = NULL;
926 system = NULL;
927
928 for (int i = 0; i < n_hosts; i++) hosts[i]->n_active_components = 0;
929
930 next_comp_ref = FIRST_PTC_COMPREF;
931
932 any_component_done_requested = FALSE;
933 any_component_done_sent = FALSE;
934 all_component_done_requested = FALSE;
935 any_component_killed_requested = FALSE;
936 all_component_killed_requested = FALSE;
937}
938
939void MainController::close_tc_connection(component_struct *comp)
940{
941 if (comp->tc_fd >= 0) {
942 remove_poll_fd(comp->tc_fd);
943 close(comp->tc_fd);
944 remove_fd_from_table(comp->tc_fd);
945 comp->tc_fd = -1;
946 delete comp->text_buf;
947 comp->text_buf = NULL;
948 enable_server_fd();
949 }
950 if (comp->kill_timer != NULL) {
951 cancel_timer(comp->kill_timer);
952 comp->kill_timer = NULL;
953 }
954}
955
956boolean MainController::stop_after_tc, MainController::stop_requested;
957
958boolean MainController::ready_to_finish_testcase()
959{
960 for (component i = tc_first_comp_ref; i < n_components; i++) {
961 switch (components[i]->tc_state) {
962 case TC_EXITED:
963 case PTC_STALE:
964 break;
965 default:
966 return FALSE;
967 }
968 }
969 return TRUE;
970}
971
972void MainController::finish_testcase()
973{
974 if (stop_requested) {
975 send_ptc_verdict(FALSE);
976 send_stop(mtc);
977 mtc->tc_state = MTC_CONTROLPART;
978 mtc->stop_requested = TRUE;
979 start_kill_timer(mtc);
980 mc_state = MC_EXECUTING_CONTROL;
981 } else if (stop_after_tc) {
982 send_ptc_verdict(FALSE);
983 mtc->tc_state = MTC_PAUSED;
984 mc_state = MC_PAUSED;
985 notify("Execution has been paused.");
986 } else {
987 send_ptc_verdict(TRUE);
988 mtc->tc_state = MTC_CONTROLPART;
989 mc_state = MC_EXECUTING_CONTROL;
990 }
991
992 for (component i = tc_first_comp_ref; i < n_components; i++) {
993 components[i]->tc_state = PTC_STALE;
994 }
995 mtc->local_verdict = NONE;
996 free_qualified_name(&mtc->comp_type);
997 free_qualified_name(&mtc->tc_fn_name);
998 free_qualified_name(&system->comp_type);
999}
1000
1001boolean MainController::message_expected(component_struct *from,
1002 const char *message_name)
1003{
1004 switch (mc_state) {
1005 case MC_EXECUTING_TESTCASE:
1006 switch (mtc->tc_state) {
1007 case MTC_ALL_COMPONENT_STOP:
1008 case MTC_ALL_COMPONENT_KILL:
1009 // silently ignore
1010 return FALSE;
1011 default:
1012 return TRUE;
1013 }
1014 case MC_TERMINATING_TESTCASE:
1015 // silently ignore
1016 return FALSE;
1017 default:
1018 send_error(from->tc_fd, "Unexpected message %s was received.",
1019 message_name);
1020 return FALSE;
1021 }
1022}
1023
1024boolean MainController::request_allowed(component_struct *from,
1025 const char *message_name)
1026{
1027 if (!message_expected(from, message_name)) return FALSE;
1028
1029 switch (from->tc_state) {
1030 case MTC_TESTCASE:
1031 if (from == mtc) return TRUE;
1032 else break;
1033 case PTC_FUNCTION:
1034 if (from != mtc) return TRUE;
1035 else break;
1036 case TC_STOPPING:
1037 case PTC_STOPPING_KILLING:
1038 case PTC_KILLING:
1039 // silently ignore
1040 return FALSE;
1041 default:
1042 break;
1043 }
1044 send_error(from->tc_fd, "The sender of message %s is in "
1045 "unexpected state.", message_name);
1046 return FALSE;
1047}
1048
1049boolean MainController::valid_endpoint(component component_reference,
1050 boolean new_connection, component_struct *requestor, const char *operation)
1051{
1052 switch (component_reference) {
1053 case NULL_COMPREF:
1054 send_error(requestor->tc_fd, "The %s operation refers to the null "
1055 "component reference.", operation);
1056 return FALSE;
1057 case SYSTEM_COMPREF:
1058 send_error(requestor->tc_fd, "The %s operation refers to the system "
1059 "component reference.", operation);
1060 return FALSE;
1061 case ANY_COMPREF:
1062 send_error(requestor->tc_fd, "The %s operation refers to "
1063 "'any component'.", operation);
1064 return FALSE;
1065 case ALL_COMPREF:
1066 send_error(requestor->tc_fd, "The %s operation refers to "
1067 "'all component'.", operation);
1068 return FALSE;
1069 default:
1070 break;
1071 }
1072 component_struct *comp = lookup_component(component_reference);
1073 if (comp == NULL) {
1074 send_error(requestor->tc_fd, "The %s operation refers to "
1075 "invalid component reference %d.", operation,
1076 component_reference);
1077 return FALSE;
1078 }
1079 switch (comp->tc_state) {
1080 case TC_IDLE:
1081 case TC_CREATE:
1082 case TC_START:
1083 case TC_STOP:
1084 case TC_KILL:
1085 case TC_CONNECT:
1086 case TC_DISCONNECT:
1087 case TC_MAP:
1088 case TC_UNMAP:
1089 case TC_STOPPING:
1090 case MTC_TESTCASE:
1091 case PTC_FUNCTION:
1092 case PTC_STARTING:
1093 case PTC_STOPPED:
1094 return TRUE;
1095 case PTC_KILLING:
1096 case PTC_STOPPING_KILLING:
1097 if (new_connection) {
1098 send_error(requestor->tc_fd, "The %s operation refers to test "
1099 "component with component reference %d, which is currently "
1100 "being terminated.", operation, component_reference);
1101 return FALSE;
1102 } else return TRUE;
1103 case TC_EXITING:
1104 case TC_EXITED:
1105 if (new_connection) {
1106 send_error(requestor->tc_fd, "The %s operation refers to test "
1107 "component with component reference %d, which has already "
1108 "terminated.", operation, component_reference);
1109 return FALSE;
1110 } else return TRUE;
1111 case PTC_STALE:
1112 send_error(requestor->tc_fd, "The %s operation refers to component "
1113 "reference %d, which belongs to an earlier test case.",
1114 operation, component_reference);
1115 return FALSE;
1116 default:
1117 send_error(requestor->tc_fd, "The %s operation refers to component "
1118 "reference %d, which is in invalid state.",
1119 operation, component_reference);
1120 error("Test component with component reference %d is in invalid state "
1121 "when a %s operation was requested on a port of it.",
1122 component_reference, operation);
1123 return FALSE;
1124 }
1125}
1126
1127void MainController::destroy_connection(port_connection *conn,
1128 component_struct *tc)
1129{
1130 switch (conn->conn_state) {
1131 case CONN_LISTENING:
1132 case CONN_CONNECTING:
1133 if (conn->transport_type != TRANSPORT_LOCAL &&
1134 conn->head.comp_ref != tc->comp_ref) {
1135 // shut down the server side if the client has terminated
1136 send_disconnect_to_server(conn);
1137 }
1138 send_error_to_connect_requestors(conn, "test component %d has "
1139 "terminated during connection setup.", tc->comp_ref);
1140 break;
1141 case CONN_CONNECTED:
1142 break;
1143 case CONN_DISCONNECTING:
1144 send_disconnect_ack_to_requestors(conn);
1145 break;
1146 default:
1147 error("The port connection %d:%s - %d:%s is in invalid state when "
1148 "test component %d has terminated.", conn->head.comp_ref,
1149 conn->head.port_name, conn->tail.comp_ref, conn->tail.port_name,
1150 tc->comp_ref);
1151 }
1152 remove_connection(conn);
1153}
1154
1155void MainController::destroy_mapping(port_connection *conn)
1156{
1157 component tc_compref;
1158 const char *tc_port, *system_port;
1159 if (conn->head.comp_ref == SYSTEM_COMPREF) {
1160 tc_compref = conn->tail.comp_ref;
1161 tc_port = conn->tail.port_name;
1162 system_port = conn->head.port_name;
1163 } else {
1164 tc_compref = conn->head.comp_ref;
1165 tc_port = conn->head.port_name;
1166 system_port = conn->tail.port_name;
1167 }
1168 switch (conn->conn_state) {
1169 case CONN_UNMAPPING:
1170 for (int i = 0; ; i++) {
1171 component_struct *comp = get_requestor(&conn->requestors, i);
1172 if (comp == NULL) break;
1173 if (comp->tc_state == TC_UNMAP) {
1174 send_unmap_ack(comp);
1175 if (comp == mtc) comp->tc_state = MTC_TESTCASE;
1176 else comp->tc_state = PTC_FUNCTION;
1177 }
1178 }
1179 break;
1180 case CONN_MAPPING:
1181 for (int i = 0; ; i++) {
1182 component_struct *comp = get_requestor(&conn->requestors, i);
1183 if (comp == NULL) break;
1184 if (comp->tc_state == TC_MAP) {
1185 send_error(comp->tc_fd, "Establishment of port mapping "
1186 "%d:%s - system:%s failed because the test component "
1187 "endpoint has terminated.", tc_compref, tc_port,
1188 system_port);
1189 if (comp == mtc) comp->tc_state = MTC_TESTCASE;
1190 else comp->tc_state = PTC_FUNCTION;
1191 }
1192 }
1193 default:
1194 break;
1195 }
1196 remove_connection(conn);
1197}
1198
1199boolean MainController::stop_all_components()
1200{
1201 boolean ready_for_ack = TRUE;
1202 for (component i = tc_first_comp_ref; i < n_components; i++) {
1203 component_struct *tc = components[i];
1204 switch (tc->tc_state) {
1205 case TC_INITIAL:
1206 // we do not have to termiate the PTC (and wait for the control
1207 // connection) if it is alive
1208 if (!tc->is_alive) ready_for_ack = FALSE;
1209 break;
1210 case TC_IDLE:
1211 // do nothing if the component is alive
1212 if (!tc->is_alive) {
1213 send_kill(tc);
1214 tc->tc_state = PTC_KILLING;
1215 tc->stop_requested = TRUE;
1216 init_requestors(&tc->stopping_killing.stop_requestors, NULL);
1217 init_requestors(&tc->stopping_killing.kill_requestors, NULL);
1218 start_kill_timer(tc);
1219 ready_for_ack = FALSE;
1220 }
1221 break;
1222 case TC_CREATE:
1223 case TC_START:
1224 case TC_STOP:
1225 case TC_KILL:
1226 case TC_CONNECT:
1227 case TC_DISCONNECT:
1228 case TC_MAP:
1229 case TC_UNMAP:
1230 case PTC_FUNCTION:
1231 // the PTC is executing behaviour
1232 if (tc->is_alive) {
1233 send_stop(tc);
1234 tc->tc_state = TC_STOPPING;
1235 } else {
1236 // STOP is never sent to non-alive PTCs
1237 send_kill(tc);
1238 tc->tc_state = PTC_STOPPING_KILLING;
1239 }
1240 tc->stop_requested = TRUE;
1241 init_requestors(&tc->stopping_killing.stop_requestors, NULL);
1242 init_requestors(&tc->stopping_killing.kill_requestors, NULL);
1243 start_kill_timer(tc);
1244 ready_for_ack = FALSE;
1245 break;
1246 case PTC_STARTING:
1247 // do nothing, just put it back to STOPPED state
1248 free_qualified_name(&tc->tc_fn_name);
1249 Free(tc->starting.arguments_ptr);
1250 free_requestors(&tc->starting.cancel_done_sent_to);
1251 tc->tc_state = PTC_STOPPED;
1252 break;
1253 case TC_STOPPING:
1254 case PTC_STOPPING_KILLING:
1255 free_requestors(&tc->stopping_killing.stop_requestors);
1256 free_requestors(&tc->stopping_killing.kill_requestors);
1257 ready_for_ack = FALSE;
1258 break;
1259 case PTC_KILLING:
1260 free_requestors(&tc->stopping_killing.stop_requestors);
1261 free_requestors(&tc->stopping_killing.kill_requestors);
1262 // we have to wait only if the PTC is non-alive
1263 if (!tc->is_alive) ready_for_ack = FALSE;
1264 break;
1265 case PTC_STOPPED:
1266 case TC_EXITING:
1267 case TC_EXITED:
1268 case PTC_STALE:
1269 break;
1270 default:
1271 error("Test Component %d is in invalid state when stopping all "
1272 "components.", tc->comp_ref);
1273 }
1274 // only mtc is preserved in done_requestors and killed_requestors
1275 boolean mtc_requested_done = has_requestor(&tc->done_requestors, mtc);
1276 free_requestors(&tc->done_requestors);
1277 if (mtc_requested_done) add_requestor(&tc->done_requestors, mtc);
1278 boolean mtc_requested_killed = has_requestor(&tc->killed_requestors,
1279 mtc);
1280 free_requestors(&tc->killed_requestors);
1281 if (mtc_requested_killed) add_requestor(&tc->killed_requestors, mtc);
1282 free_requestors(&tc->cancel_done_sent_for);
1283 }
1284 return ready_for_ack;
1285
1286}
1287
1288void MainController::check_all_component_stop()
1289{
1290 // MTC has requested 'all component.stop'
1291 // we have to send acknowledgement to MTC only
1292 boolean ready_for_ack = TRUE;
1293 for (component i = tc_first_comp_ref; i < n_components; i++) {
1294 component_struct *comp = components[i];
1295 switch (comp->tc_state) {
1296 case TC_INITIAL:
1297 case PTC_KILLING:
1298 if (!comp->is_alive) ready_for_ack = FALSE;
1299 break;
1300 case TC_STOPPING:
1301 case PTC_STOPPING_KILLING:
1302 ready_for_ack = FALSE;
1303 break;
1304 case TC_EXITING:
1305 case TC_EXITED:
1306 case PTC_STOPPED:
1307 case PTC_STALE:
1308 break;
1309 case TC_IDLE:
1310 // only alive components can be in idle state
1311 if (comp->is_alive) break;
1312 default:
1313 error("PTC %d is in invalid state when performing "
1314 "'all component.stop' operation.", comp->comp_ref);
1315 }
1316 if (!ready_for_ack) break;
1317 }
1318 if (ready_for_ack) {
1319 send_stop_ack(mtc);
1320 mtc->tc_state = MTC_TESTCASE;
1321 }
1322}
1323
1324void MainController::send_stop_ack_to_requestors(component_struct *tc)
1325{
1326 for (int i = 0; ; i++) {
1327 component_struct *requestor =
1328 get_requestor(&tc->stopping_killing.stop_requestors, i);
1329 if (requestor == NULL) break;
1330 if (requestor->tc_state == TC_STOP) {
1331 send_stop_ack(requestor);
1332 if (requestor == mtc) requestor->tc_state = MTC_TESTCASE;
1333 else requestor->tc_state = PTC_FUNCTION;
1334 }
1335 }
1336 free_requestors(&tc->stopping_killing.stop_requestors);
1337}
1338
1339boolean MainController::kill_all_components(boolean testcase_ends)
1340{
1341 boolean ready_for_ack = TRUE;
1342 for (component i = tc_first_comp_ref; i < n_components; i++) {
1343 component_struct *tc = components[i];
1344 boolean is_inactive = FALSE;
1345 switch (tc->tc_state) {
1346 case TC_INITIAL:
1347 // the PTC does not have an identified control connection yet
1348 ready_for_ack = FALSE;
1349 break;
1350 case PTC_STARTING:
1351 free_qualified_name(&tc->tc_fn_name);
1352 Free(tc->starting.arguments_ptr);
1353 free_requestors(&tc->starting.cancel_done_sent_to);
1354 // no break
1355 case TC_IDLE:
1356 case PTC_STOPPED:
1357 is_inactive = TRUE;
1358 // no break
1359 case TC_CREATE:
1360 case TC_START:
1361 case TC_STOP:
1362 case TC_KILL:
1363 case TC_CONNECT:
1364 case TC_DISCONNECT:
1365 case TC_MAP:
1366 case TC_UNMAP:
1367 case PTC_FUNCTION:
1368 send_kill(tc);
1369 if (is_inactive) {
1370 // the PTC was inactive
1371 tc->tc_state = PTC_KILLING;
1372 if (!tc->is_alive) tc->stop_requested = TRUE;
1373 } else {
1374 // the PTC was active
1375 tc->tc_state = PTC_STOPPING_KILLING;
1376 tc->stop_requested = TRUE;
1377 }
1378 init_requestors(&tc->stopping_killing.stop_requestors, NULL);
1379 init_requestors(&tc->stopping_killing.kill_requestors, NULL);
1380 start_kill_timer(tc);
1381 ready_for_ack = FALSE;
1382 break;
1383 case TC_STOPPING:
1384 send_kill(tc);
1385 tc->tc_state = PTC_STOPPING_KILLING;
1386 if (tc->kill_timer != NULL) cancel_timer(tc->kill_timer);
1387 start_kill_timer(tc);
1388 // no break
1389 case PTC_KILLING:
1390 case PTC_STOPPING_KILLING:
1391 free_requestors(&tc->stopping_killing.stop_requestors);
1392 free_requestors(&tc->stopping_killing.kill_requestors);
1393 ready_for_ack = FALSE;
1394 break;
1395 case TC_EXITING:
1396 if (testcase_ends) ready_for_ack = FALSE;
1397 case TC_EXITED:
1398 case PTC_STALE:
1399 break;
1400 default:
1401 error("Test Component %d is in invalid state when killing all "
1402 "components.", tc->comp_ref);
1403 }
1404 if (testcase_ends) {
1405 free_requestors(&tc->done_requestors);
1406 free_requestors(&tc->killed_requestors);
1407 } else {
1408 // only mtc is preserved in done_requestors and killed_requestors
1409 boolean mtc_requested_done = has_requestor(&tc->done_requestors,
1410 mtc);
1411 free_requestors(&tc->done_requestors);
1412 if (mtc_requested_done) add_requestor(&tc->done_requestors, mtc);
1413 boolean mtc_requested_killed = has_requestor(&tc->killed_requestors,
1414 mtc);
1415 free_requestors(&tc->killed_requestors);
1416 if (mtc_requested_killed)
1417 add_requestor(&tc->killed_requestors, mtc);
1418 }
1419 free_requestors(&tc->cancel_done_sent_for);
1420 }
1421 return ready_for_ack;
1422}
1423
1424void MainController::check_all_component_kill()
1425{
1426 // MTC has requested 'all component.kill'
1427 // we have to send acknowledgement to MTC only
1428 boolean ready_for_ack = TRUE;
1429 for (component i = tc_first_comp_ref; i < n_components; i++) {
1430 component_struct *comp = components[i];
1431 switch (comp->tc_state) {
1432 case TC_INITIAL:
1433 case PTC_STOPPING_KILLING:
1434 case PTC_KILLING:
1435 ready_for_ack = FALSE;
1436 case TC_EXITING:
1437 case TC_EXITED:
1438 case PTC_STALE:
1439 break;
1440 default:
1441 error("PTC %d is in invalid state when performing "
1442 "'all component.kill' operation.", comp->comp_ref);
1443 }
1444 if (!ready_for_ack) break;
1445 }
1446 if (ready_for_ack) {
1447 send_kill_ack(mtc);
1448 mtc->tc_state = MTC_TESTCASE;
1449 }
1450}
1451
1452void MainController::send_kill_ack_to_requestors(component_struct *tc)
1453{
1454 for (int i = 0; ; i++) {
1455 component_struct *requestor =
1456 get_requestor(&tc->stopping_killing.kill_requestors, i);
1457 if (requestor == NULL) break;
1458 if (requestor->tc_state == TC_KILL) {
1459 send_kill_ack(requestor);
1460 if (requestor == mtc) requestor->tc_state = MTC_TESTCASE;
1461 else requestor->tc_state = PTC_FUNCTION;
1462 }
1463 }
1464 free_requestors(&tc->stopping_killing.kill_requestors);
1465}
1466
1467void MainController::send_component_status_to_requestor(component_struct *tc,
1468 component_struct *requestor, boolean done_status, boolean killed_status)
1469{
1470 switch (requestor->tc_state) {
1471 case PTC_FUNCTION:
1472 case TC_CREATE:
1473 case TC_START:
1474 case TC_STOP:
1475 case TC_KILL:
1476 case TC_CONNECT:
1477 case TC_DISCONNECT:
1478 case TC_MAP:
1479 case TC_UNMAP:
1480 case TC_STOPPING:
1481 case PTC_STOPPED:
1482 case PTC_STARTING:
1483 if (done_status) {
1484 send_component_status_ptc(requestor, tc->comp_ref, TRUE,
1485 killed_status, tc->return_type, tc->return_value_len,
1486 tc->return_value);
1487 } else {
1488 send_component_status_ptc(requestor, tc->comp_ref, FALSE,
1489 killed_status, NULL, 0, NULL);
1490 }
1491 break;
1492 case PTC_STOPPING_KILLING:
1493 case PTC_KILLING:
1494 case TC_EXITING:
1495 case TC_EXITED:
1496 // the PTC requestor is not interested in the component status anymore
1497 break;
1498 default:
1499 error("PTC %d is in invalid state when sending out COMPONENT_STATUS "
1500 "message about PTC %d.", requestor->comp_ref, tc->comp_ref);
1501 }
1502}
1503
1504void MainController::component_stopped(component_struct *tc)
1505{
1506 // checking and updating the state of tc
1507 tc_state_enum old_state = tc->tc_state;
1508 if (old_state == PTC_STOPPING_KILLING) tc->tc_state = PTC_KILLING;
1509 else {
1510 tc->tc_state = PTC_STOPPED;
1511 if (tc->kill_timer != NULL) {
1512 cancel_timer(tc->kill_timer);
1513 tc->kill_timer = NULL;
1514 }
1515 }
1516 switch (mc_state) {
1517 case MC_EXECUTING_TESTCASE:
1518 // this is the correct state
1519 break;
1520 case MC_TERMINATING_TESTCASE:
1521 // do nothing, we are waiting for the end of all PTC connections
1522 return;
1523 default:
1524 error("PTC %d stopped in invalid MC state.", tc->comp_ref);
1525 return;
1526 }
1527 if (!tc->is_alive) {
1528 send_error_str(tc->tc_fd, "Message STOPPED can only be sent by "
1529 "alive PTCs.");
1530 return;
1531 }
1532 // Note: the COMPONENT_STATUS message must be sent before STOP_ACK because
1533 // the latter may update the component status cache table to an inconsistent
1534 // state
1535 boolean send_status_to_mtc = FALSE, send_done_to_mtc = FALSE;
1536 // sending out COMPONENT_STATUS messages to PTCs
1537 for (int i = 0; ; i++) {
1538 component_struct *requestor = get_requestor(&tc->done_requestors, i);
1539 if (requestor == NULL) break;
1540 else if (requestor == mtc) {
1541 send_status_to_mtc = TRUE;
1542 send_done_to_mtc = TRUE;
1543 } else send_component_status_to_requestor(tc, requestor, TRUE, FALSE);
1544 }
1545 // do not send unsolicited 'any component.done' status
1546 if (any_component_done_requested) send_status_to_mtc = TRUE;
1547 boolean all_done_checked = FALSE, all_done_result = FALSE;
1548 if (all_component_done_requested) {
1549 all_done_checked = TRUE;
1550 all_done_result = !is_any_component_running();
1551 if (all_done_result) send_status_to_mtc = TRUE;
1552 }
1553 if (send_status_to_mtc) {
1554 if (!all_done_checked) all_done_result = !is_any_component_running();
1555 if (send_done_to_mtc) {
1556 // the return value was requested
1557 send_component_status_mtc(tc->comp_ref, TRUE, FALSE,
1558 any_component_done_requested, all_done_result, FALSE, FALSE,
1559 tc->return_type, tc->return_value_len, tc->return_value);
1560 } else {
1561 // the return value was not requested
1562 send_component_status_mtc(NULL_COMPREF, FALSE, FALSE,
1563 any_component_done_requested, all_done_result, FALSE, FALSE,
1564 NULL, 0, NULL);
1565 }
1566 if (any_component_done_requested) {
1567 any_component_done_requested = FALSE;
1568 any_component_done_sent = TRUE;
1569 }
1570 if (all_done_result) all_component_done_requested = FALSE;
1571 }
1572 // sending out STOP_ACK messages
1573 if (old_state != PTC_FUNCTION) {
1574 // the PTC was explicitly stopped and/or killed
1575 if (mtc->tc_state == MTC_ALL_COMPONENT_KILL) {
1576 // do nothing
1577 } else if (mtc->tc_state == MTC_ALL_COMPONENT_STOP) {
1578 check_all_component_stop();
1579 } else {
1580 send_stop_ack_to_requestors(tc);
1581 }
1582 }
1583}
1584
1585void MainController::component_terminated(component_struct *tc)
1586{
1587 // the state variable of the PTC has to be updated first
1588 // because in case of 'all component.kill' or 'all component.stop'
1589 // we are walking through the states of all PTCs
1590 tc_state_enum old_state = tc->tc_state;
1591 tc->tc_state = TC_EXITING;
1592 n_active_ptcs--;
1593 tc->comp_location->n_active_components--;
1594 switch (mc_state) {
1595 case MC_EXECUTING_TESTCASE:
1596 // this is the correct state
1597 break;
1598 case MC_TERMINATING_TESTCASE:
1599 // do nothing, we are waiting for the end of all PTC connections
1600 return;
1601 default:
1602 error("PTC %d terminated in invalid MC state.", tc->comp_ref);
1603 return;
1604 }
1605 // sending out COMPONENT_STATUS messages
1606 // Notes:
1607 // - the COMPONENT_STATUS message must be sent before STOP_ACK and KILL_ACK
1608 // because the latter may update the component status cache table to an
1609 // inconsistent state
1610 // - unsolicited 'done' status and return value is never sent out
1611 // the flags below indicate whether a COMPONENT_STATUS message
1612 // (with or without the return value) has to be sent to the MTC
1613 boolean send_status_to_mtc = FALSE, send_done_to_mtc = TRUE;
1614 // first send out the COMPONENT_STATUS messages to PTCs
1615 for (int i = 0; ; i++) {
1616 component_struct *requestor = get_requestor(&tc->done_requestors, i);
1617 if (requestor == NULL) break;
1618 else if (requestor == mtc) {
1619 send_status_to_mtc = TRUE;
1620 send_done_to_mtc = TRUE;
1621 } else send_component_status_to_requestor(tc, requestor, TRUE, TRUE);
1622 }
1623 for (int i = 0; ; i++) {
1624 component_struct *requestor = get_requestor(&tc->killed_requestors, i);
1625 if (requestor == NULL) break;
1626 else if (requestor == mtc) send_status_to_mtc = TRUE;
1627 else if (!has_requestor(&tc->done_requestors, requestor)) {
1628 // do not send COMPONENT_STATUS twice to the same PTC
1629 send_component_status_to_requestor(tc, requestor, FALSE, TRUE);
1630 }
1631 }
1632 free_requestors(&tc->done_requestors);
1633 free_requestors(&tc->killed_requestors);
1634 // deciding whether to send a COMPONENT_STATUS message to MTC
1635 // 'any component.done' status can be safely sent out
1636 // it will not be cancelled later
1637 if (any_component_done_requested || any_component_killed_requested)
1638 send_status_to_mtc = TRUE;
1639 boolean all_done_checked = FALSE, all_done_result = FALSE;
1640 if (all_component_done_requested) {
1641 all_done_checked = TRUE;
1642 all_done_result = !is_any_component_running();
1643 if (all_done_result) send_status_to_mtc = TRUE;
1644 }
1645 boolean all_killed_checked = FALSE, all_killed_result = FALSE;
1646 if (all_component_killed_requested) {
1647 all_killed_checked = TRUE;
1648 all_killed_result = !is_any_component_alive();
1649 if (all_killed_result) send_status_to_mtc = TRUE;
1650 }
1651 // sending the COMPONENT_STATUS message to MTC if necessary
1652 if (send_status_to_mtc) {
1653 if (!all_done_checked) all_done_result = !is_any_component_running();
1654 if (!all_killed_checked) all_killed_result = !is_any_component_alive();
1655 if (send_done_to_mtc) {
1656 // the return value was requested
1657 send_component_status_mtc(tc->comp_ref, TRUE, TRUE, TRUE,
1658 all_done_result, TRUE, all_killed_result, tc->return_type,
1659 tc->return_value_len, tc->return_value);
1660 } else {
1661 // the return value was not requested
1662 send_component_status_mtc(tc->comp_ref, FALSE, TRUE, TRUE,
1663 all_done_result, TRUE, all_killed_result, NULL, 0, NULL);
1664 }
1665 any_component_done_requested = FALSE;
1666 any_component_done_sent = TRUE;
1667 any_component_killed_requested = FALSE;
1668 if (all_done_result) all_component_done_requested = FALSE;
1669 if (all_killed_result) all_component_killed_requested = FALSE;
1670 }
1671 // sending out STOP_ACK and KILL_ACK messages if necessary
1672 switch (old_state) {
1673 case TC_STOPPING:
1674 case PTC_STOPPING_KILLING:
1675 case PTC_KILLING:
1676 // the component was explicitly stopped and/or killed
1677 if (mtc->tc_state == MTC_ALL_COMPONENT_KILL) {
1678 check_all_component_kill();
1679 } else if (mtc->tc_state == MTC_ALL_COMPONENT_STOP) {
1680 check_all_component_stop();
1681 } else {
1682 send_stop_ack_to_requestors(tc);
1683 send_kill_ack_to_requestors(tc);
1684 }
1685 default:
1686 break;
1687 }
1688 // we should behave as we got all pending CANCEL_DONE_ACK messages from tc
1689 for (int i = 0; ; i++) {
1690 component_struct *comp = get_requestor(&tc->cancel_done_sent_for, i);
1691 if (comp == NULL) break;
1692 done_cancelled(tc, comp);
1693 }
1694 free_requestors(&tc->cancel_done_sent_for);
1695 // destroy all connections and mappings of the component
1696 // and send out the related messages
1697 while (tc->conn_head_list != NULL) {
1698 if (tc->conn_head_list->tail.comp_ref == SYSTEM_COMPREF)
1699 destroy_mapping(tc->conn_head_list);
1700 else destroy_connection(tc->conn_head_list, tc);
1701 }
1702 while (tc->conn_tail_list != NULL) {
1703 if (tc->conn_tail_list->head.comp_ref == SYSTEM_COMPREF)
1704 destroy_mapping(tc->conn_tail_list);
1705 else destroy_connection(tc->conn_tail_list, tc);
1706 }
1707 // drop the name of the currently executed function
1708 free_qualified_name(&tc->tc_fn_name);
1709}
1710
1711void MainController::done_cancelled(component_struct *from,
1712 component_struct *started_tc)
1713{
1714 // do nothing if the PTC to be started is not in starting state anymore
1715 if (started_tc->tc_state != PTC_STARTING) return;
1716 remove_requestor(&started_tc->starting.cancel_done_sent_to, from);
1717 // do nothing if we are waiting for more CANCEL_DONE_ACK messages
1718 if (get_requestor(&started_tc->starting.cancel_done_sent_to, 0) != NULL)
1719 return;
1720 send_start(started_tc, started_tc->tc_fn_name,
1721 started_tc->starting.arguments_len, started_tc->starting.arguments_ptr);
1722 component_struct *start_requestor = started_tc->starting.start_requestor;
1723 if (start_requestor->tc_state == TC_START) {
1724 send_start_ack(start_requestor);
1725 if (start_requestor == mtc) start_requestor->tc_state = MTC_TESTCASE;
1726 else start_requestor->tc_state = PTC_FUNCTION;
1727 }
1728 Free(started_tc->starting.arguments_ptr);
1729 free_requestors(&started_tc->starting.cancel_done_sent_to);
1730 started_tc->tc_state = PTC_FUNCTION;
1731 status_change();
1732}
1733
1734boolean MainController::component_is_alive(component_struct *tc)
1735{
1736 switch (tc->tc_state) {
1737 case TC_INITIAL:
1738 case TC_IDLE:
1739 case TC_CREATE:
1740 case TC_START:
1741 case TC_STOP:
1742 case TC_KILL:
1743 case TC_CONNECT:
1744 case TC_DISCONNECT:
1745 case TC_MAP:
1746 case TC_UNMAP:
1747 case TC_STOPPING:
1748 case PTC_FUNCTION:
1749 case PTC_STARTING:
1750 case PTC_STOPPED:
1751 case PTC_KILLING:
1752 case PTC_STOPPING_KILLING:
1753 return TRUE;
1754 case TC_EXITING:
1755 case TC_EXITED:
1756 return FALSE;
1757 default:
1758 error("PTC %d is in invalid state when checking whether it is alive.",
1759 tc->comp_ref);
1760 return FALSE;
1761 }
1762}
1763
1764boolean MainController::component_is_running(component_struct *tc)
1765{
1766 switch (tc->tc_state) {
1767 case TC_CREATE:
1768 case TC_START:
1769 case TC_STOP:
1770 case TC_KILL:
1771 case TC_CONNECT:
1772 case TC_DISCONNECT:
1773 case TC_MAP:
1774 case TC_UNMAP:
1775 case TC_STOPPING:
1776 case PTC_FUNCTION:
1777 case PTC_STARTING:
1778 case PTC_STOPPING_KILLING:
1779 return TRUE;
1780 case TC_INITIAL:
1781 case TC_IDLE:
1782 case TC_EXITING:
1783 case TC_EXITED:
1784 case PTC_STOPPED:
1785 case PTC_KILLING:
1786 return FALSE;
1787 default:
1788 error("PTC %d is in invalid state when checking whether it is running.",
1789 tc->comp_ref);
1790 return FALSE;
1791 }
1792}
1793
1794boolean MainController::component_is_done(component_struct *tc)
1795{
1796 switch (tc->tc_state) {
1797 case TC_EXITING:
1798 case TC_EXITED:
1799 case PTC_STOPPED:
1800 return TRUE;
1801 case TC_INITIAL:
1802 case TC_IDLE:
1803 case TC_CREATE:
1804 case TC_START:
1805 case TC_STOP:
1806 case TC_KILL:
1807 case TC_CONNECT:
1808 case TC_DISCONNECT:
1809 case TC_MAP:
1810 case TC_UNMAP:
1811 case TC_STOPPING:
1812 case PTC_FUNCTION:
1813 case PTC_STARTING:
1814 case PTC_KILLING:
1815 case PTC_STOPPING_KILLING:
1816 return FALSE;
1817 default:
1818 error("PTC %d is in invalid state when checking whether it is done.",
1819 tc->comp_ref);
1820 return FALSE;
1821 }
1822}
1823
1824boolean MainController::is_any_component_alive()
1825{
1826 for (component i = tc_first_comp_ref; i < n_components; i++)
1827 if (component_is_alive(components[i])) return TRUE;
1828 return FALSE;
1829}
1830
1831boolean MainController::is_all_component_alive()
1832{
1833 for (component i = tc_first_comp_ref; i < n_components; i++)
1834 if (!component_is_alive(components[i])) return FALSE;
1835 return TRUE;
1836}
1837
1838boolean MainController::is_any_component_running()
1839{
1840 for (component i = tc_first_comp_ref; i < n_components; i++)
1841 if (component_is_running(components[i])) return TRUE;
1842 return FALSE;
1843}
1844
1845boolean MainController::is_all_component_running()
1846{
1847 for (component i = tc_first_comp_ref; i < n_components; i++) {
1848 component_struct *tc = components[i];
1849 if (tc->stop_requested) continue;
1850 switch (tc->tc_state) {
1851 case TC_EXITING:
1852 case TC_EXITED:
1853 case PTC_STOPPED:
1854 return FALSE;
1855 default:
1856 break;
1857 }
1858 }
1859 return TRUE;
1860}
1861
1862boolean MainController::is_any_component_done()
1863{
1864 for (component i = tc_first_comp_ref; i < n_components; i++)
1865 if (component_is_done(components[i])) return TRUE;
1866 return FALSE;
1867}
1868
1869void MainController::start_kill_timer(component_struct *tc)
1870{
1871 if (kill_timer > 0.0) {
1872 timer_struct *timer = new timer_struct;
1873 timer->expiration = time_now() + kill_timer;
1874 timer->timer_argument.component_ptr = tc;
1875 tc->kill_timer = timer;
1876 register_timer(timer);
1877 } else tc->kill_timer = NULL;
1878}
1879
1880void MainController::init_connections(component_struct *tc)
1881{
1882 tc->conn_head_list = NULL;
1883 tc->conn_tail_list = NULL;
1884 tc->conn_head_count = 0;
1885 tc->conn_tail_count = 0;
1886}
1887
1888void MainController::add_connection(port_connection *c)
1889{
1890 // Canonical ordering of endpoints so that head <= tail
1891 if (c->head.comp_ref > c->tail.comp_ref) {
1892 component tmp_comp = c->head.comp_ref;
1893 c->head.comp_ref = c->tail.comp_ref;
1894 c->tail.comp_ref = tmp_comp;
1895 char *tmp_port = c->head.port_name;
1896 c->head.port_name = c->tail.port_name;
1897 c->tail.port_name = tmp_port;
1898 } else if (c->head.comp_ref == c->tail.comp_ref &&
1899 strcmp(c->head.port_name, c->tail.port_name) > 0) {
1900 char *tmp_port = c->head.port_name;
1901 c->head.port_name = c->tail.port_name;
1902 c->tail.port_name = tmp_port;
1903 }
1904 // Double-chain in according to c->head
1905 component_struct *head_component = lookup_component(c->head.comp_ref);
1906 port_connection *head_connection = head_component->conn_head_list;
1907 if (head_connection == NULL) {
1908 c->head.next = c;
1909 c->head.prev = c;
1910 } else {
1911 c->head.prev = head_connection->head.prev;
1912 head_connection->head.prev = c;
1913 c->head.next = head_connection;
1914 c->head.prev->head.next = c;
1915 }
1916 head_component->conn_head_list = c;
1917 head_component->conn_head_count++;
1918 // Double-chain in according to c->tail
1919 component_struct *tail_component = lookup_component(c->tail.comp_ref);
1920 port_connection *tail_connection = tail_component->conn_tail_list;
1921 if (tail_connection == NULL) {
1922 c->tail.next = c;
1923 c->tail.prev = c;
1924 } else {
1925 c->tail.prev = tail_connection->tail.prev;
1926 tail_connection->tail.prev = c;
1927 c->tail.next = tail_connection;
1928 c->tail.prev->tail.next = c;
1929 }
1930 tail_component->conn_tail_list = c;
1931 tail_component->conn_tail_count++;
1932}
1933
1934void MainController::remove_connection(port_connection *c)
1935{
1936 // Remove from conn_head_list
1937 component_struct *head_component = lookup_component(c->head.comp_ref);
1938 if (c->head.next == c) {
1939 head_component->conn_head_list = NULL;
1940 head_component->conn_head_count = 0;
1941 } else {
1942 c->head.prev->head.next = c->head.next;
1943 c->head.next->head.prev = c->head.prev;
1944 head_component->conn_head_list = c->head.next;
1945 head_component->conn_head_count--;
1946 }
1947 // Remove from conn_tail_list
1948 component_struct *tail_component = lookup_component(c->tail.comp_ref);
1949 if (c->tail.next == c) {
1950 tail_component->conn_tail_list = NULL;
1951 tail_component->conn_tail_count = 0;
1952 } else {
1953 c->tail.prev->tail.next = c->tail.next;
1954 c->tail.next->tail.prev = c->tail.prev;
1955 tail_component->conn_tail_list = c->tail.next;
1956 tail_component->conn_tail_count--;
1957 }
1958 // Delete the data members
1959 delete [] c->head.port_name;
1960 delete [] c->tail.port_name;
1961 free_requestors(&c->requestors);
1962 delete c;
1963}
1964
1965port_connection *MainController::find_connection(component head_comp,
1966 const char *head_port, component tail_comp, const char *tail_port)
1967{
1968 // Canonical ordering of parameters so that head <= tail
1969 if (head_comp > tail_comp) {
1970 component tmp_comp = head_comp;
1971 head_comp = tail_comp;
1972 tail_comp = tmp_comp;
1973 const char *tmp_port = head_port;
1974 head_port = tail_port;
1975 tail_port = tmp_port;
1976 } else if (head_comp == tail_comp && strcmp(head_port, tail_port) > 0) {
1977 const char *tmp_port = head_port;
1978 head_port = tail_port;
1979 tail_port = tmp_port;
1980 }
1981 // Check whether one of the endpoints' list is empty
1982 component_struct *head_component = lookup_component(head_comp);
1983 port_connection *head_connection = head_component->conn_head_list;
1984 if (head_connection == NULL) return NULL;
1985 component_struct *tail_component = lookup_component(tail_comp);
1986 port_connection *tail_connection = tail_component->conn_tail_list;
1987 if (tail_connection == NULL) return NULL;
1988 // Start searching on the shorter list
1989 if (head_component->conn_head_count <= tail_component->conn_tail_count) {
1990 port_connection *iter = head_connection;
1991 do {
1992 if (iter->tail.comp_ref == tail_comp &&
1993 !strcmp(iter->head.port_name, head_port) &&
1994 !strcmp(iter->tail.port_name, tail_port)) return iter;
1995 iter = iter->head.next;
1996 } while (iter != head_connection);
1997 return NULL;
1998 } else {
1999 port_connection *iter = tail_connection;
2000 do {
2001 if (iter->head.comp_ref == head_comp &&
2002 !strcmp(iter->head.port_name, head_port) &&
2003 !strcmp(iter->tail.port_name, tail_port)) return iter;
2004 iter = iter->tail.next;
2005 } while (iter != tail_connection);
2006 return NULL;
2007 }
2008}
2009
2010void MainController::remove_all_connections(component head_or_tail)
2011{
2012 component_struct *comp = lookup_component(head_or_tail);
2013 while (comp->conn_head_list != NULL)
2014 remove_connection(comp->conn_head_list);
2015 while (comp->conn_tail_list != NULL)
2016 remove_connection(comp->conn_tail_list);
2017}
2018
2019transport_type_enum MainController::choose_port_connection_transport(
2020 component head_comp, component tail_comp)
2021{
2022 host_struct *head_location = components[head_comp]->comp_location;
2023 // use the most efficient software loop if the two endpoints are in the
2024 // same component and the host supports it
2025 if (head_comp == tail_comp &&
2026 head_location->transport_supported[TRANSPORT_LOCAL])
2027 return TRANSPORT_LOCAL;
2028 host_struct *tail_location = components[tail_comp]->comp_location;
2029 // use the efficient UNIX domain socket if the two endpoints are on the
2030 // same host and it is supported by the host
2031 if (head_location == tail_location &&
2032 head_location->transport_supported[TRANSPORT_UNIX_STREAM])
2033 return TRANSPORT_UNIX_STREAM;
2034 // use TCP if it is supported by the host of both endpoints
2035 if (head_location->transport_supported[TRANSPORT_INET_STREAM] &&
2036 tail_location->transport_supported[TRANSPORT_INET_STREAM])
2037 return TRANSPORT_INET_STREAM;
2038 // no suitable transport was found, return an erroneous type
2039 return TRANSPORT_NUM;
2040}
2041
2042void MainController::send_connect_ack_to_requestors(port_connection *conn)
2043{
2044 for (int i = 0; ; i++) {
2045 component_struct *comp = get_requestor(&conn->requestors, i);
2046 if (comp == NULL) break;
2047 else if (comp->tc_state == TC_CONNECT) {
2048 send_connect_ack(comp);
2049 if (comp == mtc) comp->tc_state = MTC_TESTCASE;
2050 else comp->tc_state = PTC_FUNCTION;
2051 }
2052 }
2053 free_requestors(&conn->requestors);
2054}
2055
2056void MainController::send_error_to_connect_requestors(port_connection *conn,
2057 const char *fmt, ...)
2058{
2059 char *reason = mprintf("Establishment of port connection %d:%s - %d:%s "
2060 "failed because ", conn->head.comp_ref, conn->head.port_name,
2061 conn->tail.comp_ref, conn->tail.port_name);
2062 va_list ap;
2063 va_start(ap, fmt);
2064 reason = mputprintf_va_list(reason, fmt, ap);
2065 va_end(ap);
2066 for (int i = 0; ; i++) {
2067 component_struct *comp = get_requestor(&conn->requestors, i);
2068 if (comp == NULL) break;
2069 else if (comp->tc_state == TC_CONNECT) {
2070 send_error_str(comp->tc_fd, reason);
2071 if (comp == mtc) comp->tc_state = MTC_TESTCASE;
2072 else comp->tc_state = PTC_FUNCTION;
2073 }
2074 }
2075 Free(reason);
2076 free_requestors(&conn->requestors);
2077}
2078
2079void MainController::send_disconnect_to_server(port_connection *conn)
2080{
2081 component_struct *comp = components[conn->head.comp_ref];
2082 switch (comp->tc_state) {
2083 case TC_IDLE:
2084 case TC_CREATE:
2085 case TC_START:
2086 case TC_STOP:
2087 case TC_KILL:
2088 case TC_CONNECT:
2089 case TC_DISCONNECT:
2090 case TC_MAP:
2091 case TC_UNMAP:
2092 case TC_STOPPING:
2093 case MTC_TESTCASE:
2094 case PTC_FUNCTION:
2095 case PTC_STARTING:
2096 case PTC_STOPPED:
2097 send_disconnect(comp, conn->head.port_name, conn->tail.comp_ref,
2098 conn->tail.port_name);
2099 default:
2100 break;
2101 }
2102}
2103
2104void MainController::send_disconnect_ack_to_requestors(port_connection *conn)
2105{
2106 for (int i = 0; ; i++) {
2107 component_struct *comp = get_requestor(&conn->requestors, i);
2108 if (comp == NULL) break;
2109 else if (comp->tc_state == TC_DISCONNECT) {
2110 send_disconnect_ack(comp);
2111 if (comp == mtc) comp->tc_state = MTC_TESTCASE;
2112 else comp->tc_state = PTC_FUNCTION;
2113 }
2114 }
2115 free_requestors(&conn->requestors);
2116}
2117
2118void MainController::init_requestors(requestor_struct *reqs,
2119 component_struct *tc)
2120{
2121 if (tc != NULL) {
2122 reqs->n_components = 1;
2123 reqs->the_component = tc;
2124 } else reqs->n_components = 0;
2125}
2126
2127void MainController::add_requestor(requestor_struct *reqs, component_struct *tc)
2128{
2129 switch (reqs->n_components) {
2130 case 0:
2131 reqs->n_components = 1;
2132 reqs->the_component = tc;
2133 break;
2134 case 1:
2135 if (reqs->the_component != tc) {
2136 reqs->n_components = 2;
2137 component_struct *tmp = reqs->the_component;
2138 reqs->components =
2139 (component_struct**)Malloc(2 * sizeof(*reqs->components));
2140 reqs->components[0] = tmp;
2141 reqs->components[1] = tc;
2142 }
2143 break;
2144 default:
2145 for (int i = 0; i < reqs->n_components; i++)
2146 if (reqs->components[i] == tc) return;
2147 reqs->n_components++;
2148 reqs->components = (component_struct**)Realloc(reqs->components,
2149 reqs->n_components * sizeof(*reqs->components));
2150 reqs->components[reqs->n_components - 1] = tc;
2151 }
2152}
2153
2154void MainController::remove_requestor(requestor_struct *reqs,
2155 component_struct *tc)
2156{
2157 switch (reqs->n_components) {
2158 case 0:
2159 break;
2160 case 1:
2161 if (reqs->the_component == tc) reqs->n_components = 0;
2162 break;
2163 case 2: {
2164 component_struct *tmp = NULL;
2165 if (reqs->components[0] == tc) tmp = reqs->components[1];
2166 else if (reqs->components[1] == tc) tmp = reqs->components[0];
2167 if (tmp != NULL) {
2168 Free(reqs->components);
2169 reqs->n_components = 1;
2170 reqs->the_component = tmp;
2171 }
2172 break; }
2173 default:
2174 for (int i = 0; i < reqs->n_components; i++)
2175 if (reqs->components[i] == tc) {
2176 reqs->n_components--;
2177 memmove(reqs->components + i, reqs->components + i + 1,
2178 (reqs->n_components - i) * sizeof(*reqs->components));
2179 reqs->components = (component_struct**)Realloc(reqs->components,
2180 reqs->n_components * sizeof(*reqs->components));
2181 break;
2182 }
2183 }
2184}
2185
2186boolean MainController::has_requestor(const requestor_struct *reqs,
2187 component_struct *tc)
2188{
2189 switch (reqs->n_components) {
2190 case 0:
2191 return FALSE;
2192 case 1:
2193 return reqs->the_component == tc;
2194 default:
2195 for (int i = 0; i < reqs->n_components; i++)
2196 if (reqs->components[i] == tc) return TRUE;
2197 return FALSE;
2198 }
2199}
2200
2201component_struct *MainController::get_requestor(const requestor_struct *reqs,
2202 int index)
2203{
2204 if (index >= 0 && index < reqs->n_components) {
2205 if (reqs->n_components == 1) return reqs->the_component;
2206 else return reqs->components[index];
2207 } else return NULL;
2208}
2209
2210void MainController::free_requestors(requestor_struct *reqs)
2211{
2212 if (reqs->n_components > 1) Free(reqs->components);
2213 reqs->n_components = 0;
2214}
2215
2216void MainController::init_qualified_name(qualified_name *name)
2217{
2218 name->module_name = NULL;
2219 name->definition_name = NULL;
2220}
2221
2222void MainController::free_qualified_name(qualified_name *name)
2223{
2224 delete [] name->module_name;
2225 name->module_name = NULL;
2226 delete [] name->definition_name;
2227 name->definition_name = NULL;
2228}
2229
2230double MainController::kill_timer;
2231
2232double MainController::time_now()
2233{
2234 static boolean first_call = TRUE;
2235 static struct timeval first_time;
2236 if (first_call) {
2237 first_call = FALSE;
2238 if (gettimeofday(&first_time, NULL) < 0)
2239 fatal_error("MainController::time_now: gettimeofday() system call "
2240 "failed.");
2241 return 0.0;
2242 } else {
2243 struct timeval tv;
2244 if (gettimeofday(&tv, NULL) < 0)
2245 fatal_error("MainController::time_now: gettimeofday() system call "
2246 "failed.");
2247 return (tv.tv_sec - first_time.tv_sec) +
2248 1.0e-6 * (tv.tv_usec - first_time.tv_usec);
2249 }
2250}
2251
2252timer_struct *MainController::timer_head, *MainController::timer_tail;
2253
2254void MainController::register_timer(timer_struct *timer)
2255{
2256 timer_struct *iter;
2257 for (iter = timer_tail; iter != NULL; iter = iter->prev)
2258 if (iter->expiration <= timer->expiration) break;
2259 if (iter != NULL) {
2260 // inserting after iter
2261 timer->prev = iter;
2262 timer->next = iter->next;
2263 if (iter->next != NULL) iter->next->prev = timer;
2264 else timer_tail = timer;
2265 iter->next = timer;
2266 } else {
2267 // inserting at the beginning of list
2268 timer->prev = NULL;
2269 timer->next = timer_head;
2270 if (timer_head != NULL) timer_head->prev = timer;
2271 else timer_tail = timer;
2272 timer_head = timer;
2273 }
2274}
2275
2276void MainController::cancel_timer(timer_struct *timer)
2277{
2278 if (timer->next != NULL) timer->next->prev = timer->prev;
2279 else timer_tail = timer->prev;
2280 if (timer->prev != NULL) timer->prev->next = timer->next;
2281 else timer_head = timer->next;
2282 delete timer;
2283}
2284
2285int MainController::get_poll_timeout()
2286{
2287 if (timer_head != NULL) {
2288 double offset = timer_head->expiration - time_now();
2289 if (offset > 0.0) return (int)(1000.0 * offset);
2290 else return 0;
2291 } else return -1;
2292}
2293
2294void MainController::handle_expired_timers()
2295{
2296 if (timer_head != NULL) {
2297 timer_struct *iter = timer_head;
2298 double now = time_now();
2299 do {
2300 if (iter->expiration > now) break;
2301 timer_struct *next = iter->next;
2302 handle_kill_timer(iter);
2303 iter = next;
2304 } while (iter != NULL);
2305 }
2306}
2307
2308void MainController::handle_kill_timer(timer_struct *timer)
2309{
2310 component_struct *tc = timer->timer_argument.component_ptr;
2311 host_struct *host = tc->comp_location;
2312 boolean kill_process = FALSE;
2313 switch (tc->tc_state) {
2314 case TC_EXITED:
2315 // do nothing
2316 break;
2317 case TC_EXITING:
2318 if (tc == mtc) {
2319 error("MTC on host %s did not close its control connection in "
2320 "time. Trying to kill it using its HC.", host->hostname);
2321 } else {
2322 notify("PTC %d on host %s did not close its control connection in "
2323 "time. Trying to kill it using its HC.", tc->comp_ref,
2324 host->hostname);
2325 }
2326 kill_process = TRUE;
2327 break;
2328 case TC_STOPPING:
2329 case PTC_STOPPING_KILLING:
2330 case PTC_KILLING:
2331 // active PTCs with kill timer can be only in these states
2332 if (tc != mtc) {
2333 notify("PTC %d on host %s is not responding. Trying to kill it "
2334 "using its HC.", tc->comp_ref, host->hostname);
2335 kill_process = TRUE;
2336 break;
2337 }
2338 // no break
2339 default:
2340 // MTC can be in any state
2341 if (tc == mtc) {
2342 error("MTC on host %s is not responding. Trying to kill it using "
2343 "its HC. This will abort test execution.", host->hostname);
2344 kill_process = TRUE;
2345 } else {
2346 error("PTC %d is in invalid state when its kill timer expired.",
2347 tc->comp_ref);
2348 }
2349 }
2350 if (kill_process) {
2351 if (host->hc_state == HC_ACTIVE) {
2352 send_kill_process(host, tc->comp_ref);
2353 tc->process_killed = TRUE;
2354 } else {
2355 error("Test Component %d cannot be killed because the HC on host "
2356 "%s is not in active state. Kill the process manually or the "
2357 "test system may get into a deadlock.", tc->comp_ref,
2358 host->hostname);
2359 }
2360 }
2361 cancel_timer(timer);
2362 tc->kill_timer = NULL;
2363}
2364
2365void MainController::register_termination_handlers()
2366{
2367 new_action.sa_handler = termination_handler;
2368 sigemptyset(&new_action.sa_mask);
2369 new_action.sa_flags = 0;
2370
2371 sigaction(SIGINT, NULL, &old_action);
2372 if (old_action.sa_handler != SIG_IGN)
2373 sigaction (SIGINT, &new_action, NULL);
2374 sigaction(SIGHUP, NULL, &old_action);
2375 if (old_action.sa_handler != SIG_IGN)
2376 sigaction (SIGHUP, &new_action, NULL);
2377 sigaction(SIGTERM, NULL, &old_action);
2378 if (old_action.sa_handler != SIG_IGN)
2379 sigaction(SIGTERM, &new_action, NULL);
2380 sigaction(SIGQUIT, NULL, &old_action);
2381 if (old_action.sa_handler != SIG_IGN)
2382 sigaction(SIGQUIT, &new_action, NULL);
2383 sigaction(SIGKILL, NULL, &old_action);
2384 if (old_action.sa_handler != SIG_IGN)
2385 sigaction(SIGKILL, &new_action, NULL);
2386}
2387
2388void MainController::termination_handler(int signum)
2389{
2390 // Call shutdown_server() and reset handlers and re-raise the signal.
2391 // clean_up() or perform_shutdown() is state dependent and cannot be used
2392 // here... Related to HP67376.
2393 shutdown_server();
2394
2395 new_action.sa_handler = SIG_DFL;
2396 sigemptyset(&new_action.sa_mask);
2397 new_action.sa_flags = 0;
2398
2399 sigaction(SIGINT, &new_action, NULL);
2400 sigaction(SIGHUP, &new_action, NULL);
2401 sigaction(SIGTERM, &new_action, NULL);
2402 sigaction(SIGQUIT, &new_action, NULL);
2403 sigaction(SIGKILL, &new_action, NULL);
2404
2405 raise(signum);
2406}
2407
2408void MainController::error(const char *fmt, ...)
2409{
2410 va_list ap;
2411 va_start(ap, fmt);
2412 char *str = mprintf_va_list(fmt, ap);
2413 va_end(ap);
2414 unlock();
2415 ui->error(/*severity*/ 0, str);
2416 lock();
2417 Free(str);
2418}
2419
2420void MainController::notify(const char *fmt, ...)
2421{
2422 va_list ap;
2423 va_start(ap, fmt);
2424 char *str = mprintf_va_list(fmt, ap);
2425 va_end(ap);
2426 struct timeval tv;
2427 if (gettimeofday(&tv, NULL) < 0) fatal_error("MainController::notify: "
2428 "gettimeofday() system call failed.");
2429 notify(&tv, mc_hostname, TTCN_EXECUTOR, str);
2430 Free(str);
2431}
2432
2433void MainController::notify(const struct timeval *timestamp,
2434 const char *source, int severity, const char *message)
2435{
2436 unlock();
2437 ui->notify(timestamp, source, severity, message);
2438 lock();
2439}
2440
2441void MainController::status_change()
2442{
2443 unlock();
2444 ui->status_change();
2445 lock();
2446}
2447
2448void MainController::fatal_error(const char *fmt, ...)
2449{
2450 va_list ap;
2451 va_start(ap, fmt);
2452 vfprintf(stderr, fmt, ap);
2453 va_end(ap);
2454 if (errno != 0) fprintf(stderr, " (%s)", strerror(errno));
2455 putc('\n', stderr);
2456 exit(EXIT_FAILURE);
2457}
2458
2459void *MainController::thread_main(void *)
2460{
2461 lock();
2462 while (mc_state != MC_INACTIVE) {
2463 int fds_selected;
2464 for ( ; ; ) {
2465 int maxDtInMs = 0;
2466#ifdef USE_EPOLL
2467 int timeout = get_poll_timeout();
2468 if (maxDtInMs != 0 && (timeout < 0 || maxDtInMs < timeout))
2469 timeout = maxDtInMs;
2470 unlock();
2471 fds_selected = epoll_wait(epfd, epoll_events, EPOLL_MAX_EVENTS,
2472 timeout);
2473 lock();
2474 if (fds_selected >= 0) break;
2475 if (errno != EINTR) fatal_error("epoll_wait() system call failed.");
2476#else // ! defined USE_EPOLL
2477 update_pollfds();
2478 int timeout = get_poll_timeout();
2479 if (maxDtInMs != 0 && (timeout < 0 || maxDtInMs < timeout))
2480 timeout = maxDtInMs;
2481 unlock();
2482 fds_selected = poll(ufds, nfds, timeout);
2483 lock();
2484 if (fds_selected >= 0) break;
2485 if (errno != EINTR) fatal_error("poll() system call failed.");
2486#endif //USE_EPOLL
2487 errno = 0;
2488 }
2489 switch (wakeup_reason) {
2490 case REASON_NOTHING:
2491 case REASON_MTC_KILL_TIMER:
2492 break;
2493 case REASON_SHUTDOWN:
2494 wakeup_reason = REASON_NOTHING;
2495 perform_shutdown();
2496 continue;
2497 default:
2498 error("Invalid wakeup reason (%d) was set.", wakeup_reason);
2499 wakeup_reason = REASON_NOTHING;
2500 }
2501 if (fds_selected == 0) {
2502 handle_expired_timers();
2503 continue;
2504 }
2505#ifdef USE_EPOLL
2506 for (int i = 0; i < fds_selected; i++) {
2507 int fd = epoll_events[i].data.fd;
2508 if (epoll_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) {
2509 dispatch_socket_event(fd);
2510 }
2511 }
2512#else // ! defined USE_EPOLL
2513 for (unsigned int i = 0; i < nfds; i++) {
2514 int fd = ufds[i].fd;
2515 if (ufds[i].revents & POLLNVAL) {
2516 fatal_error("Invalid file descriptor (%d) was given for "
2517 "poll() system call.", fd);
2518 } else if (ufds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
2519 dispatch_socket_event(fd);
2520 }
2521 }
2522#endif //USE_EPOLL
2523 handle_expired_timers();
2524 }
2525 clean_up();
2526 notify("Shutdown complete.");
2527 unlock();
2528 // don't try to lock the mutex after ui->status_change() is completed
2529 // the main thread might call in turn terminate(), which destroys the mutex
2530 ui->status_change();
2531 return NULL;
2532}
2533
2534void MainController::dispatch_socket_event(int fd)
2535{
2536 // a previous event might have closed the socket
2537 if (fd >= fd_table_size) return;
2538 switch (fd_table[fd].fd_type) {
2539 case FD_PIPE:
2540 handle_pipe();
2541 break;
2542 case FD_SERVER:
2543 handle_incoming_connection(fd);
2544 break;
2545 case FD_UNKNOWN:
2546 handle_unknown_data(fd_table[fd].unknown_ptr);
2547 break;
2548 case FD_HC:
2549 handle_hc_data(fd_table[fd].host_ptr, TRUE);
2550 break;
2551 case FD_TC:
2552 handle_tc_data(fd_table[fd].component_ptr, TRUE);
2553 break;
2554 default:
2555 fatal_error("Invalid file descriptor type (%d) for "
2556 "file descriptor %d.", fd_table[fd].fd_type, fd);
2557 }
2558}
2559
2560int MainController::pipe_fd[2];
2561wakeup_reason_t MainController::wakeup_reason;
2562
2563void MainController::wakeup_thread(wakeup_reason_t reason)
2564{
2565 unsigned char msg = '\0';
2566 if (write(pipe_fd[1], &msg, 1) != 1) {
2567 fatal_error("MainController::wakeup_thread: writing to pipe failed.");
2568 }
2569 wakeup_reason = reason;
2570}
2571
2572void MainController::handle_pipe()
2573{
2574 unsigned char buf;
2575 if (read(pipe_fd[0], &buf, 1) != 1) {
2576 fatal_error("MainController::handle_pipe: reading from pipe failed.");
2577 }
2578}
2579
2580void MainController::handle_incoming_connection(int p_server_fd)
2581{
2582 IPAddress *remote_addr = IPAddress::create_addr(nh.get_family());
2583 int fd = remote_addr->accept(p_server_fd);
2584 if (fd > 0) {
2585 set_close_on_exec(fd);
2586 unknown_connection *new_connection =
2587 new_unknown_connection(p_server_fd != MainController::server_fd);
2588 new_connection->fd = fd;
2589 if (p_server_fd == MainController::server_fd)
2590 new_connection->ip_addr = remote_addr;
2591 else { // in case of unix domain socket connection
2592 delete remote_addr;
2593 new_connection->ip_addr = IPAddress::create_addr("127.0.0.1");
2594 }
2595 new_connection->text_buf = new Text_Buf;
2596 add_poll_fd(fd);
2597 add_fd_to_table(fd);
2598 fd_table[fd].fd_type = FD_UNKNOWN;
2599 fd_table[fd].unknown_ptr = new_connection;
2600 } else {
2601 delete remote_addr;
2602 switch (errno) {
2603 case EINTR:
2604 errno = 0;
2605 break;
2606 case EMFILE:
2607 case ENFILE:
2608 error("New incoming connection cannot be accepted "
2609 "because the maximum number of open files has been reached. "
2610 "Try to increase this limit.");
2611 disable_server_fd();
2612 error("No incoming connections will be accepted until at least "
2613 "one component terminates. This may result in deadlock.");
2614 break;
2615 default:
2616 fatal_error("MainController::handle_incoming_connection: "
2617 "system call accept() failed.");
2618 }
2619 }
2620}
2621
2622int MainController::recv_to_buffer(int fd, Text_Buf& text_buf,
2623 boolean recv_from_socket)
2624{
2625 // if recv_from_socket is false we are checking the messages that are
2626 // already in text_buf so we are emulating that recv() was successful
2627 if (!recv_from_socket) return 1;
2628
2629 char *buf_ptr;
2630 int buf_len;
2631 text_buf.get_end(buf_ptr, buf_len);
2632
2633 int recv_len = recv(fd, buf_ptr, buf_len, 0);
2634
2635 if (recv_len > 0) text_buf.increase_length(recv_len);
2636
2637 return recv_len;
2638}
2639
2640void MainController::handle_unknown_data(unknown_connection *conn)
2641{
2642 Text_Buf& text_buf = *conn->text_buf;
2643 int recv_len = recv_to_buffer(conn->fd, text_buf, TRUE);
2644 boolean error_flag = FALSE;
2645
2646 if (recv_len > 0) {
2647 try {
2648 while (text_buf.is_message()) {
2649 text_buf.pull_int(); // message length
2650 int message_type = text_buf.pull_int().get_val();
2651 // only the first message is processed in this loop
2652 // except when a generic message is received
2653 boolean process_more_messages = FALSE;
2654 switch (message_type) {
2655 case MSG_ERROR:
2656 process_error(conn);
2657 process_more_messages = TRUE;
2658 break;
2659 case MSG_LOG:
2660 process_log(conn);
2661 process_more_messages = TRUE;
2662 break;
2663 case MSG_VERSION:
2664 process_version(conn);
2665 break;
2666 case MSG_MTC_CREATED:
2667 process_mtc_created(conn);
2668 break;
2669 case MSG_PTC_CREATED:
2670 process_ptc_created(conn);
2671 break;
2672 default:
2673 error("Invalid message type (%d) was received on an "
2674 "unknown connection from %s [%s].", message_type,
2675 conn->ip_addr->get_host_str(),
2676 conn->ip_addr->get_addr_str());
2677 error_flag = TRUE;
2678 }
2679 if (process_more_messages) text_buf.cut_message();
2680 else break;
2681 }
2682 } catch (const TC_Error& tc_error) {
2683 error("Maleformed message was received on an unknown connection "
2684 "from %s [%s].", conn->ip_addr->get_host_str(),
2685 conn->ip_addr->get_addr_str());
2686 error_flag = TRUE;
2687 }
2688 if (error_flag) {
2689 send_error_str(conn->fd, "The received message was not understood "
2690 "by the MC.");
2691 }
2692 } else if (recv_len == 0) {
2693 error("Unexpected end of an unknown connection from %s [%s].",
2694 conn->ip_addr->get_host_str(), conn->ip_addr->get_addr_str());
2695 error_flag = TRUE;
2696 } else {
2697 error("Receiving of data failed on an unknown connection from %s [%s].",
2698 conn->ip_addr->get_host_str(), conn->ip_addr->get_addr_str());
2699 error_flag = TRUE;
2700 }
2701 if (error_flag) {
2702 close_unknown_connection(conn);
2703 }
2704}
2705
2706void MainController::handle_hc_data(host_struct *hc, boolean recv_from_socket)
2707{
2708 Text_Buf& text_buf = *hc->text_buf;
2709 boolean error_flag = FALSE;
2710 int recv_len = recv_to_buffer(hc->hc_fd, text_buf, recv_from_socket);
2711
2712 if (recv_len > 0) {
2713 try {
2714 while (text_buf.is_message()) {
f08ff9ca
BB
2715 int msg_len = text_buf.pull_int().get_val();
2716 int msg_end = text_buf.get_pos() + msg_len;
970ed795
EL
2717 int message_type = text_buf.pull_int().get_val();
2718 switch (message_type) {
2719 case MSG_ERROR:
2720 process_error(hc);
2721 break;
2722 case MSG_LOG:
2723 process_log(hc);
2724 break;
2725 case MSG_CONFIGURE_ACK:
2726 process_configure_ack(hc);
2727 break;
2728 case MSG_CONFIGURE_NAK:
2729 process_configure_nak(hc);
2730 break;
2731 case MSG_CREATE_NAK:
2732 process_create_nak(hc);
2733 break;
2734 case MSG_HC_READY:
2735 process_hc_ready(hc);
2736 break;
016a1a93 2737 case MSG_DEBUG_RETURN_VALUE:
f08ff9ca 2738 process_debug_return_value(*hc->text_buf, hc->log_source, msg_end, false);
016a1a93 2739 break;
970ed795
EL
2740 default:
2741 error("Invalid message type (%d) was received on HC "
2742 "connection from %s [%s].", message_type,
2743 hc->hostname, hc->ip_addr->get_addr_str());
2744 error_flag = TRUE;
2745 }
2746 if (error_flag) break;
2747 text_buf.cut_message();
2748 }
2749 } catch (const TC_Error& tc_error) {
2750 error("Malformed message was received on HC connection "
2751 "from %s [%s].", hc->hostname, hc->ip_addr->get_addr_str());
2752 error_flag = TRUE;
2753 }
2754 if (error_flag) {
2755 send_error_str(hc->hc_fd, "The received message was not understood "
2756 "by the MC.");
2757 }
2758 } else if (recv_len == 0) {
2759 if (hc->hc_state == HC_EXITING) {
2760 close_hc_connection(hc);
2761 if (mc_state == MC_SHUTDOWN && all_hc_in_state(HC_DOWN))
2762 mc_state = MC_INACTIVE;
2763 } else {
2764 error("Unexpected end of HC connection from %s [%s].",
2765 hc->hostname, hc->ip_addr->get_addr_str());
2766 error_flag = TRUE;
2767 }
2768 } else {
2769 error("Receiving of data failed on HC connection from %s [%s].",
2770 hc->hostname, hc->ip_addr->get_addr_str());
2771 error_flag = TRUE;
2772 }
2773 if (error_flag) {
2774 close_hc_connection(hc);
2775 switch (mc_state) {
2776 case MC_INACTIVE:
2777 case MC_LISTENING:
2778 case MC_LISTENING_CONFIGURED:
2779 fatal_error("MC is in invalid state when a HC connection "
2780 "terminated.");
2781 case MC_HC_CONNECTED:
2782 if (all_hc_in_state(HC_DOWN)) mc_state = MC_LISTENING;
2783 break;
2784 case MC_CONFIGURING:
2785 check_all_hc_configured();
2786 break;
2787 case MC_ACTIVE:
2788 if (all_hc_in_state(HC_DOWN)) mc_state = MC_LISTENING_CONFIGURED;
2789 else if (!is_hc_in_state(HC_ACTIVE) &&
2790 !is_hc_in_state(HC_OVERLOADED)) mc_state = MC_HC_CONNECTED;
2791 break;
2792 default:
2793 if (!is_hc_in_state(HC_ACTIVE)) notify("There is no active HC "
2794 "connection. Further create operations will fail.");
2795 }
2796 status_change();
2797 }
2798}
2799
2800void MainController::handle_tc_data(component_struct *tc,
2801 boolean recv_from_socket)
2802{
2803 Text_Buf& text_buf = *tc->text_buf;
2804 boolean close_connection = FALSE;
2805 int recv_len = recv_to_buffer(tc->tc_fd, text_buf, recv_from_socket);
2806
2807 if (recv_len > 0) {
2808 try {
2809 while (text_buf.is_message()) {
2810 int message_len = text_buf.pull_int().get_val();
2811 int message_end = text_buf.get_pos() + message_len;
2812 int message_type = text_buf.pull_int().get_val();
2813 // these messages can be received both from MTC and PTCs
2814 switch (message_type) {
2815 case MSG_ERROR:
2816 process_error(tc);
2817 break;
2818 case MSG_LOG:
2819 process_log(tc);
2820 break;
2821 case MSG_CREATE_REQ:
2822 process_create_req(tc);
2823 break;
2824 case MSG_START_REQ:
2825 process_start_req(tc, message_end);
2826 break;
2827 case MSG_STOP_REQ:
2828 process_stop_req(tc);
2829 break;
2830 case MSG_KILL_REQ:
2831 process_kill_req(tc);
2832 break;
2833 case MSG_IS_RUNNING:
2834 process_is_running(tc);
2835 break;
2836 case MSG_IS_ALIVE:
2837 process_is_alive(tc);
2838 break;
2839 case MSG_DONE_REQ:
2840 process_done_req(tc);
2841 break;
2842 case MSG_KILLED_REQ:
2843 process_killed_req(tc);
2844 break;
2845 case MSG_CANCEL_DONE_ACK:
2846 process_cancel_done_ack(tc);
2847 break;
2848 case MSG_CONNECT_REQ:
2849 process_connect_req(tc);
2850 break;
2851 case MSG_CONNECT_LISTEN_ACK:
2852 process_connect_listen_ack(tc, message_end);
2853 break;
2854 case MSG_CONNECTED:
2855 process_connected(tc);
2856 break;
2857 case MSG_CONNECT_ERROR:
2858 process_connect_error(tc);
2859 break;
2860 case MSG_DISCONNECT_REQ:
2861 process_disconnect_req(tc);
2862 break;
2863 case MSG_DISCONNECTED:
2864 process_disconnected(tc);
2865 break;
2866 case MSG_MAP_REQ:
2867 process_map_req(tc);
2868 break;
2869 case MSG_MAPPED:
2870 process_mapped(tc);
2871 break;
2872 case MSG_UNMAP_REQ:
2873 process_unmap_req(tc);
2874 break;
2875 case MSG_UNMAPPED:
2876 process_unmapped(tc);
2877 break;
016a1a93 2878 case MSG_DEBUG_RETURN_VALUE:
f08ff9ca
BB
2879 process_debug_return_value(*tc->text_buf, tc->log_source, message_end,
2880 tc == mtc);
016a1a93
BB
2881 break;
2882 case MSG_DEBUG_HALT_REQ:
f08ff9ca
BB
2883 process_debug_broadcast_req(tc, D_HALT);
2884 break;
2885 case MSG_DEBUG_CONTINUE_REQ:
2886 process_debug_broadcast_req(tc, D_CONTINUE);
2887 break;
2888 case MSG_DEBUG_BATCH:
2889 process_debug_batch(tc);
016a1a93 2890 break;
970ed795
EL
2891 default:
2892 if (tc == mtc) {
2893 // these messages can be received only from the MTC
2894 switch (message_type) {
2895 case MSG_TESTCASE_STARTED:
2896 process_testcase_started();
2897 break;
2898 case MSG_TESTCASE_FINISHED:
2899 process_testcase_finished();
2900 break;
2901 case MSG_MTC_READY:
2902 process_mtc_ready();
2903 break;
2904 default:
2905 error("Invalid message type (%d) was received "
2906 "from the MTC at %s [%s].", message_type,
2907 mtc->comp_location->hostname,
2908 mtc->comp_location->ip_addr->get_addr_str());
2909 close_connection = TRUE;
2910 }
2911 } else {
2912 // these messages can be received only from PTCs
2913 switch (message_type) {
2914 case MSG_STOPPED:
2915 process_stopped(tc, message_end);
2916 break;
2917 case MSG_STOPPED_KILLED:
2918 process_stopped_killed(tc, message_end);
2919 break;
2920 case MSG_KILLED:
2921 process_killed(tc);
2922 break;
2923 default:
2924 notify("Invalid message type (%d) was received from "
2925 "PTC %d at %s [%s].", message_type,
2926 tc->comp_ref, tc->comp_location->hostname,
2927 tc->comp_location->ip_addr->get_addr_str());
2928 close_connection = TRUE;
2929 }
2930 }
2931 }
2932 if (close_connection) break;
2933 text_buf.cut_message();
2934 }
2935 } catch (const TC_Error& tc_error) {
2936 if (tc == mtc) {
2937 error("Malformed message was received from the MTC at %s "
2938 "[%s].", mtc->comp_location->hostname,
2939 mtc->comp_location->ip_addr->get_addr_str());
2940 } else {
2941 notify("Malformed message was received from PTC %d at %s [%s].",
2942 tc->comp_ref, tc->comp_location->hostname,
2943 tc->comp_location->ip_addr->get_addr_str());
2944 }
2945 close_connection = TRUE;
2946 }
2947 if (close_connection) {
2948 send_error_str(tc->tc_fd, "The received message was not understood "
2949 "by the MC.");
2950 }
2951 } else if (recv_len == 0) {
2952 // TCP connection is closed by peer
2953 if (tc->tc_state != TC_EXITING && !tc->process_killed) {
2954 if (tc == mtc) {
2955 error("Unexpected end of MTC connection from %s [%s].",
2956 mtc->comp_location->hostname,
2957 mtc->comp_location->ip_addr->get_addr_str());
2958 } else {
2959 notify("Unexpected end of PTC connection (%d) from %s [%s].",
2960 tc->comp_ref, tc->comp_location->hostname,
2961 tc->comp_location->ip_addr->get_addr_str());
2962 }
2963 }
2964 close_connection = TRUE;
2965 } else {
2966 if (tc->process_killed && errno == ECONNRESET) {
2967 // ignore TCP resets if the process was killed
2968 // because the last STOP or KILL message can stuck in TCP buffers
2969 // if the process did not receive any data
2970 } else {
2971 if (tc == mtc) {
2972 error("Receiving of data failed from the MTC at %s [%s]: %s",
2973 mtc->comp_location->hostname,
2974 mtc->comp_location->ip_addr->get_addr_str(), strerror(errno));
2975 } else {
2976 notify("Receiving of data failed from PTC %d at %s [%s]: %s",
2977 tc->comp_ref, tc->comp_location->hostname,
2978 tc->comp_location->ip_addr->get_addr_str(), strerror(errno));
2979 }
2980 }
2981 close_connection = TRUE;
2982 }
2983 if (close_connection) {
2984 close_tc_connection(tc);
2985 remove_component_from_host(tc);
2986 if (tc == mtc) {
2987 if (mc_state != MC_TERMINATING_MTC) {
2988 notify("The control connection to MTC is lost. "
2989 "Destroying all PTC connections.");
2990 }
2991 destroy_all_components();
2992 notify("MTC terminated.");
2993 if (is_hc_in_state(HC_CONFIGURING)) mc_state = MC_CONFIGURING;
2994 else if (is_hc_in_state(HC_IDLE)) mc_state = MC_HC_CONNECTED;
2995 else if (is_hc_in_state(HC_ACTIVE) ||
2996 is_hc_in_state(HC_OVERLOADED)) mc_state = MC_ACTIVE;
2997 else mc_state = MC_LISTENING_CONFIGURED;
2998 stop_requested = FALSE;
2999 } else {
3000 if (tc->tc_state != TC_EXITING) {
3001 // we have no idea about the final verdict of the PTC
3002 tc->local_verdict = ERROR;
3003 component_terminated(tc);
3004 }
3005 tc->tc_state = TC_EXITED;
3006 if (mc_state == MC_TERMINATING_TESTCASE &&
3007 ready_to_finish_testcase()) finish_testcase();
3008 }
3009 status_change();
3010 }
3011}
3012
3013void MainController::unlink_unix_socket(int socket_fd) {
3014 struct sockaddr_un local_addr;
3015 // querying the local pathname used by socket_fd
3016 socklen_type addr_len = sizeof(local_addr);
3017 if (getsockname(socket_fd, (struct sockaddr*)&local_addr, &addr_len)) {
3018 } else if (local_addr.sun_family != AF_UNIX) {
3019 } else if (unlink(local_addr.sun_path)) {
3020 errno = 0;
3021 }
3022}
3023
3024void MainController::shutdown_server()
3025{
3026 if (server_fd >= 0) {
3027 remove_poll_fd(server_fd);
3028 remove_fd_from_table(server_fd);
3029 close(server_fd);
3030 server_fd = -1;
3031 }
3032
3033 if (server_fd_unix >= 0) {
3034 unlink_unix_socket(server_fd_unix);
3035 remove_poll_fd(server_fd_unix);
3036 remove_fd_from_table(server_fd_unix);
3037 close(server_fd_unix);
3038 server_fd_unix = -1;
3039 }
3040}
3041
3042void MainController::perform_shutdown()
3043{
3044 boolean shutdown_complete = TRUE;
3045 switch (mc_state) {
3046 case MC_HC_CONNECTED:
3047 case MC_ACTIVE:
3048 for (int i = 0; i < n_hosts; i++) {
3049 host_struct *host = hosts[i];
3050 if (host->hc_state != HC_DOWN) {
3051 send_exit_hc(host);
3052 host->hc_state = HC_EXITING;
3053 shutdown_complete = FALSE;
3054 }
3055 }
3056 // no break
3057 case MC_LISTENING:
3058 case MC_LISTENING_CONFIGURED:
3059 shutdown_server();
3060 // don't call status_change() if shutdown is complete
3061 // it will be called from thread_main() later
3062 if (shutdown_complete) mc_state = MC_INACTIVE;
3063 else {
3064 mc_state = MC_SHUTDOWN;
3065 status_change();
3066 }
3067 break;
3068 default:
3069 fatal_error("MainController::perform_shutdown: called in wrong state.");
3070 }
3071}
3072
3073void MainController::clean_up()
3074{
3075 shutdown_server();
3076
3077 while (unknown_head != NULL) close_unknown_connection(unknown_head);
3078
3079 destroy_all_components();
3080
3081 for (int i = 0; i < n_hosts; i++) {
3082 host_struct *host = hosts[i];
3083 close_hc_connection(host);
3084 Free(host->hostname);
3085 delete host->ip_addr;
3086 delete [] host->hostname_local;
3087 delete [] host->machine_type;
3088 delete [] host->system_name;
3089 delete [] host->system_release;
3090 delete [] host->system_version;
3091 Free(host->log_source);
3092 Free(host->components);
3093 free_string_set(&host->allowed_components);
3094 delete host;
3095 }
3096 Free(hosts);
3097 n_hosts = 0;
3098 hosts = NULL;
3099 Free(config_str);
3100 config_str = NULL;
016a1a93
BB
3101
3102 Free(debugger_settings.on_switch);
3103 debugger_settings.on_switch = NULL;
3104 Free(debugger_settings.output_type);
3105 debugger_settings.output_type = NULL;
3106 Free(debugger_settings.output_file);
3107 debugger_settings.output_file = NULL;
3108 Free(debugger_settings.error_behavior);
3109 debugger_settings.error_behavior = NULL;
f08ff9ca
BB
3110 Free(debugger_settings.error_batch_file);
3111 debugger_settings.error_batch_file = NULL;
016a1a93
BB
3112 Free(debugger_settings.fail_behavior);
3113 debugger_settings.fail_behavior = NULL;
f08ff9ca
BB
3114 Free(debugger_settings.fail_batch_file);
3115 debugger_settings.fail_batch_file = NULL;
3116 Free(debugger_settings.global_batch_state);
3117 debugger_settings.global_batch_state = NULL;
3118 Free(debugger_settings.global_batch_file);
3119 debugger_settings.global_batch_file = NULL;
016a1a93
BB
3120 for (int i = 0; i < debugger_settings.nof_breakpoints; ++i) {
3121 Free(debugger_settings.breakpoints[i].module);
3122 Free(debugger_settings.breakpoints[i].line);
f08ff9ca 3123 Free(debugger_settings.breakpoints[i].batch_file);
016a1a93
BB
3124 }
3125 debugger_settings.nof_breakpoints = 0;
3126 Free(debugger_settings.breakpoints);
3127 debugger_settings.breakpoints = NULL;
3128 Free(last_debug_command.arguments);
3129 last_debug_command.arguments = NULL;
970ed795
EL
3130
3131 while (timer_head != NULL) cancel_timer(timer_head);
3132
3133 for (int i = 0; i < n_modules; i++) {
3134 delete [] modules[i].module_name;
3135 delete [] modules[i].module_checksum;
3136 }
3137 delete [] modules;
3138 n_modules = 0;
3139 modules = NULL;
3140 version_known = FALSE;
3141
3142#ifdef USE_EPOLL
3143 if (epfd >= 0) {
3144 if (close(epfd) < 0)
3145 error("MainController::clean_up: Error while closing epoll"
3146 " fd %d", epfd);
3147 epfd = -1;
3148 }
3149 Free(epoll_events);
3150 epoll_events = NULL;
3151#else // ! defined USE_EPOLL
3152 nfds = 0;
3153 Free(ufds);
3154 ufds = NULL;
3155 new_nfds = 0;
3156 Free(new_ufds);
3157 new_ufds = NULL;
3158 pollfds_modified = FALSE;
3159#endif
3160
3161 fd_table_size = 0;
3162 Free(fd_table);
3163 fd_table = NULL;
3164
3165 mc_state = MC_INACTIVE;
3166
3167 if (pipe_fd[1] >= 0) {
3168 close(pipe_fd[1]);
3169 pipe_fd[1] = -1;
3170 }
3171 if (pipe_fd[0] >= 0) {
3172 close(pipe_fd[1]);
3173 pipe_fd[0] = -1;
3174 }
3175}
3176
3177void MainController::send_configure(host_struct *hc, const char *config_file)
3178{
3179 Text_Buf text_buf;
3180 text_buf.push_int(MSG_CONFIGURE);
3181 text_buf.push_string(config_file);
3182 send_message(hc->hc_fd, text_buf);
3183}
3184
3185void MainController::send_exit_hc(host_struct *hc)
3186{
3187 Text_Buf text_buf;
3188 text_buf.push_int(MSG_EXIT_HC);
3189 send_message(hc->hc_fd, text_buf);
3190}
3191
3192void MainController::send_create_mtc(host_struct *hc)
3193{
3194 Text_Buf text_buf;
3195 text_buf.push_int(MSG_CREATE_MTC);
3196 send_message(hc->hc_fd, text_buf);
3197}
3198
3199void MainController::send_create_ptc(host_struct *hc,
3200 component component_reference, const qualified_name& component_type,
3201 const char *component_name, boolean is_alive,
3202 const qualified_name& current_testcase)
3203{
3204 Text_Buf text_buf;
3205 text_buf.push_int(MSG_CREATE_PTC);
3206 text_buf.push_int(component_reference);
3207 text_buf.push_qualified_name(component_type);
3208 text_buf.push_string(component_name);
3209 text_buf.push_int(is_alive ? 1 : 0);
3210 text_buf.push_qualified_name(current_testcase);
3211 send_message(hc->hc_fd, text_buf);
3212}
3213
3214void MainController::send_kill_process(host_struct *hc,
3215 component component_reference)
3216{
3217 Text_Buf text_buf;
3218 text_buf.push_int(MSG_KILL_PROCESS);
3219 text_buf.push_int(component_reference);
3220 send_message(hc->hc_fd, text_buf);
3221}
3222
3223void MainController::send_create_ack(component_struct *tc,
3224 component component_reference)
3225{
3226 Text_Buf text_buf;
3227 text_buf.push_int(MSG_CREATE_ACK);
3228 text_buf.push_int(component_reference);
3229 send_message(tc->tc_fd, text_buf);
3230}
3231
3232void MainController::send_start_ack(component_struct *tc)
3233{
3234 Text_Buf text_buf;
3235 text_buf.push_int(MSG_START_ACK);
3236 send_message(tc->tc_fd, text_buf);
3237}
3238
3239void MainController::send_stop(component_struct *tc)
3240{
3241 Text_Buf text_buf;
3242 text_buf.push_int(MSG_STOP);
3243 send_message(tc->tc_fd, text_buf);
3244}
3245
3246void MainController::send_stop_ack(component_struct *tc)
3247{
3248 Text_Buf text_buf;
3249 text_buf.push_int(MSG_STOP_ACK);
3250 send_message(tc->tc_fd, text_buf);
3251}
3252
3253void MainController::send_kill_ack(component_struct *tc)
3254{
3255 Text_Buf text_buf;
3256 text_buf.push_int(MSG_KILL_ACK);
3257 send_message(tc->tc_fd, text_buf);
3258}
3259
3260void MainController::send_running(component_struct *tc, boolean answer)
3261{
3262 Text_Buf text_buf;
3263 text_buf.push_int(MSG_RUNNING);
3264 text_buf.push_int(answer ? 1 : 0);
3265 send_message(tc->tc_fd, text_buf);
3266}
3267
3268void MainController::send_alive(component_struct *tc, boolean answer)
3269{
3270 Text_Buf text_buf;
3271 text_buf.push_int(MSG_ALIVE);
3272 text_buf.push_int(answer ? 1 : 0);
3273 send_message(tc->tc_fd, text_buf);
3274}
3275
3276void MainController::send_done_ack(component_struct *tc, boolean answer,
3277 const char *return_type, int return_value_len, const void *return_value)
3278{
3279 Text_Buf text_buf;
3280 text_buf.push_int(MSG_DONE_ACK);
3281 text_buf.push_int(answer ? 1 : 0);
3282 text_buf.push_string(return_type);
3283 text_buf.push_raw(return_value_len, return_value);
3284 send_message(tc->tc_fd, text_buf);
3285}
3286
3287void MainController::send_killed_ack(component_struct *tc, boolean answer)
3288{
3289 Text_Buf text_buf;
3290 text_buf.push_int(MSG_KILLED_ACK);
3291 text_buf.push_int(answer ? 1 : 0);
3292 send_message(tc->tc_fd, text_buf);
3293}
3294
3295void MainController::send_connect_listen(component_struct *tc,
3296 const char *local_port, component remote_comp, const char *remote_comp_name,
3297 const char *remote_port, transport_type_enum transport_type)
3298{
3299 Text_Buf text_buf;
3300 text_buf.push_int(MSG_CONNECT_LISTEN);
3301 text_buf.push_string(local_port);
3302 text_buf.push_int(remote_comp);
3303 text_buf.push_string(remote_comp_name);
3304 text_buf.push_string(remote_port);
3305 text_buf.push_int(transport_type);
3306 send_message(tc->tc_fd, text_buf);
3307}
3308
3309void MainController::send_connect(component_struct *tc,
3310 const char *local_port, component remote_comp, const char *remote_comp_name,
3311 const char *remote_port, transport_type_enum transport_type,
3312 int remote_address_len, const void *remote_address)
3313{
3314 Text_Buf text_buf;
3315 text_buf.push_int(MSG_CONNECT);
3316 text_buf.push_string(local_port);
3317 text_buf.push_int(remote_comp);
3318 text_buf.push_string(remote_comp_name);
3319 text_buf.push_string(remote_port);
3320 text_buf.push_int(transport_type);
3321 text_buf.push_raw(remote_address_len, remote_address);
3322 send_message(tc->tc_fd, text_buf);
3323}
3324
3325void MainController::send_connect_ack(component_struct *tc)
3326{
3327 Text_Buf text_buf;
3328 text_buf.push_int(MSG_CONNECT_ACK);
3329 send_message(tc->tc_fd, text_buf);
3330}
3331
3332void MainController::send_disconnect(component_struct *tc,
3333 const char *local_port, component remote_comp, const char *remote_port)
3334{
3335 Text_Buf text_buf;
3336 text_buf.push_int(MSG_DISCONNECT);
3337 text_buf.push_string(local_port);
3338 text_buf.push_int(remote_comp);
3339 text_buf.push_string(remote_port);
3340 send_message(tc->tc_fd, text_buf);
3341}
3342
3343void MainController::send_disconnect_ack(component_struct *tc)
3344{
3345 Text_Buf text_buf;
3346 text_buf.push_int(MSG_DISCONNECT_ACK);
3347 send_message(tc->tc_fd, text_buf);
3348}
3349
3350void MainController::send_map(component_struct *tc,
3351 const char *local_port, const char *system_port)
3352{
3353 Text_Buf text_buf;
3354 text_buf.push_int(MSG_MAP);
3355 text_buf.push_string(local_port);
3356 text_buf.push_string(system_port);
3357 send_message(tc->tc_fd, text_buf);
3358}
3359
3360void MainController::send_map_ack(component_struct *tc)
3361{
3362 Text_Buf text_buf;
3363 text_buf.push_int(MSG_MAP_ACK);
3364 send_message(tc->tc_fd, text_buf);
3365}
3366
3367void MainController::send_unmap(component_struct *tc,
3368 const char *local_port, const char *system_port)
3369{
3370 Text_Buf text_buf;
3371 text_buf.push_int(MSG_UNMAP);
3372 text_buf.push_string(local_port);
3373 text_buf.push_string(system_port);
3374 send_message(tc->tc_fd, text_buf);
3375}
3376
3377void MainController::send_unmap_ack(component_struct *tc)
3378{
3379 Text_Buf text_buf;
3380 text_buf.push_int(MSG_UNMAP_ACK);
3381 send_message(tc->tc_fd, text_buf);
3382}
3383
016a1a93
BB
3384static void get_next_argument_loc(const char* arguments, size_t len, size_t& start, size_t& end)
3385{
3386 while (start < len && isspace(arguments[start])) {
3387 ++start;
3388 }
3389 end = start;
3390 while (end < len && !isspace(arguments[end])) {
3391 ++end;
3392 }
3393}
3394
3395void MainController::send_debug_command(int fd, int commandID, const char* arguments)
3396{
3397 Text_Buf text_buf;
3398 text_buf.push_int(MSG_DEBUG_COMMAND);
3399 text_buf.push_int(commandID);
3400
3401 size_t arg_len = strlen(arguments);
3402 int arg_count = 0;
3403 for (size_t i = 0; i < arg_len; ++i) {
3404 if (isspace(arguments[i]) && (i == 0 || !isspace(arguments[i - 1]))) {
3405 ++arg_count;
3406 }
3407 }
3408 if (arg_len > 0) {
3409 ++arg_count;
3410 }
3411 text_buf.push_int(arg_count);
3412
3413 if (arg_count > 0) {
3414 size_t start = 0;
3415 size_t end = 0;
3416 while (start < arg_len) {
3417 get_next_argument_loc(arguments, arg_len, start, end);
3418 // don't use push_string, as that requires a null-terminated string
3419 text_buf.push_int(end - start);
3420 text_buf.push_raw(end - start, arguments + start);
3421 start = end;
3422 }
3423 }
3424
3425 send_message(fd, text_buf);
3426}
3427
3428void MainController::send_debug_setup(host_struct *hc)
3429{
3430 Text_Buf text_buf;
3431 text_buf.push_int(MSG_DEBUG_COMMAND);
3432 text_buf.push_int(D_SETUP);
f08ff9ca 3433 text_buf.push_int(9 + 3 * debugger_settings.nof_breakpoints);
016a1a93
BB
3434 text_buf.push_string(debugger_settings.on_switch);
3435 text_buf.push_string(debugger_settings.output_file);
3436 text_buf.push_string(debugger_settings.output_type);
3437 text_buf.push_string(debugger_settings.error_behavior);
f08ff9ca 3438 text_buf.push_string(debugger_settings.error_batch_file);
016a1a93 3439 text_buf.push_string(debugger_settings.fail_behavior);
f08ff9ca
BB
3440 text_buf.push_string(debugger_settings.fail_batch_file);
3441 text_buf.push_string(debugger_settings.global_batch_state);
3442 text_buf.push_string(debugger_settings.global_batch_file);
016a1a93
BB
3443 for (int i = 0; i < debugger_settings.nof_breakpoints; ++i) {
3444 text_buf.push_string(debugger_settings.breakpoints[i].module);
3445 text_buf.push_string(debugger_settings.breakpoints[i].line);
f08ff9ca 3446 text_buf.push_string(debugger_settings.breakpoints[i].batch_file);
016a1a93
BB
3447 }
3448 send_message(hc->hc_fd, text_buf);
3449}
3450
970ed795
EL
3451void MainController::send_cancel_done_mtc(component component_reference,
3452 boolean cancel_any)
3453{
3454 Text_Buf text_buf;
3455 text_buf.push_int(MSG_CANCEL_DONE);
3456 text_buf.push_int(component_reference);
3457 text_buf.push_int(cancel_any ? 1 : 0);
3458 send_message(mtc->tc_fd, text_buf);
3459}
3460
3461void MainController::send_component_status_mtc(component component_reference,
3462 boolean is_done, boolean is_killed, boolean is_any_done,
3463 boolean is_all_done, boolean is_any_killed, boolean is_all_killed,
3464 const char *return_type, int return_value_len, const void *return_value)
3465{
3466 Text_Buf text_buf;
3467 text_buf.push_int(MSG_COMPONENT_STATUS);
3468 text_buf.push_int(component_reference);
3469 text_buf.push_int(is_done ? 1 : 0);
3470 text_buf.push_int(is_killed ? 1 : 0);
3471 text_buf.push_int(is_any_done ? 1 : 0);
3472 text_buf.push_int(is_all_done ? 1 : 0);
3473 text_buf.push_int(is_any_killed ? 1 : 0);
3474 text_buf.push_int(is_all_killed ? 1 : 0);
3475 text_buf.push_string(return_type);
3476 text_buf.push_raw(return_value_len, return_value);
3477 send_message(mtc->tc_fd, text_buf);
3478}
3479
3480void MainController::send_execute_control(const char *module_name)
3481{
3482 Text_Buf text_buf;
3483 text_buf.push_int(MSG_EXECUTE_CONTROL);
3484 text_buf.push_string(module_name);
3485 send_message(mtc->tc_fd, text_buf);
3486}
3487
3488void MainController::send_execute_testcase(const char *module_name,
3489 const char *testcase_name)
3490{
3491 Text_Buf text_buf;
3492 text_buf.push_int(MSG_EXECUTE_TESTCASE);
3493 text_buf.push_string(module_name);
3494 text_buf.push_string(testcase_name);
3495 send_message(mtc->tc_fd, text_buf);
3496}
3497
3498void MainController::send_ptc_verdict(boolean continue_execution)
3499{
3500 Text_Buf text_buf;
3501 text_buf.push_int(MSG_PTC_VERDICT);
3502 int n_ptcs = 0;
3503 for (int i = tc_first_comp_ref; i < n_components; i++)
3504 if (components[i]->tc_state != PTC_STALE) n_ptcs++;
3505 text_buf.push_int(n_ptcs);
3506 for (int i = tc_first_comp_ref; i < n_components; i++) {
3507 if (components[i]->tc_state != PTC_STALE) {
3508 text_buf.push_int(components[i]->comp_ref);
3509 text_buf.push_string(components[i]->comp_name);
3510 text_buf.push_int(components[i]->local_verdict);
3511 if (components[i]->verdict_reason != NULL)
3512 text_buf.push_string(components[i]->verdict_reason);
3513 else
3514 text_buf.push_string("");
3515 }
3516 }
3517 text_buf.push_int(continue_execution ? 1 : 0);
3518 send_message(mtc->tc_fd, text_buf);
3519}
3520
3521void MainController::send_continue()
3522{
3523 Text_Buf text_buf;
3524 text_buf.push_int(MSG_CONTINUE);
3525 send_message(mtc->tc_fd, text_buf);
3526}
3527
3528void MainController::send_exit_mtc()
3529{
3530 Text_Buf text_buf;
3531 text_buf.push_int(MSG_EXIT_MTC);
3532 send_message(mtc->tc_fd, text_buf);
3533}
3534
3535void MainController::send_cancel_done_ptc(component_struct *tc,
3536 component component_reference)
3537{
3538 Text_Buf text_buf;
3539 text_buf.push_int(MSG_CANCEL_DONE);
3540 text_buf.push_int(component_reference);
3541 send_message(tc->tc_fd, text_buf);
3542
3543}
3544
3545void MainController::send_component_status_ptc(component_struct *tc,
3546 component component_reference, boolean is_done, boolean is_killed,
3547 const char *return_type, int return_value_len, const void *return_value)
3548{
3549 Text_Buf text_buf;
3550 text_buf.push_int(MSG_COMPONENT_STATUS);
3551 text_buf.push_int(component_reference);
3552 text_buf.push_int(is_done ? 1 : 0);
3553 text_buf.push_int(is_killed ? 1 : 0);
3554 text_buf.push_string(return_type);
3555 text_buf.push_raw(return_value_len, return_value);
3556 send_message(tc->tc_fd, text_buf);
3557}
3558
3559void MainController::send_start(component_struct *tc,
3560 const qualified_name& function_name, int arg_len, const void *arg_ptr)
3561{
3562 Text_Buf text_buf;
3563 text_buf.push_int(MSG_START);
3564 text_buf.push_qualified_name(function_name);
3565 text_buf.push_raw(arg_len, arg_ptr);
3566 send_message(tc->tc_fd, text_buf);
3567}
3568
3569void MainController::send_kill(component_struct *tc)
3570{
3571 Text_Buf text_buf;
3572 text_buf.push_int(MSG_KILL);
3573 send_message(tc->tc_fd, text_buf);
3574}
3575
3576void MainController::send_error(int fd, const char *fmt, ...)
3577{
3578 va_list ap;
3579 va_start(ap, fmt);
3580 char *reason = mprintf_va_list(fmt, ap);
3581 va_end(ap);
3582 send_error_str(fd, reason);
3583 Free(reason);
3584}
3585
3586void MainController::send_error_str(int fd, const char *reason)
3587{
3588 Text_Buf text_buf;
3589 text_buf.push_int((RInt)MSG_ERROR);
3590 text_buf.push_string(reason);
3591 send_message(fd, text_buf);
3592}
3593
3594void MainController::send_message(int fd, Text_Buf& text_buf)
3595{
3596 text_buf.calculate_length();
3597 const char *send_ptr = text_buf.get_data();
3598 int send_len = text_buf.get_len();
3599 int sent_len = send(fd, send_ptr, send_len, 0);
3600 if (send_len != sent_len) {
3601 error("Sending of message failed: %s", strerror(errno));
3602 }
3603}
3604
3605void MainController::process_error(unknown_connection *conn)
3606{
3607 Text_Buf& text_buf = *conn->text_buf;
3608 char *reason = text_buf.pull_string();
3609 error("Error message was received on an unknown connection from %s [%s]: "
3610 "%s.", conn->ip_addr->get_host_str(), conn->ip_addr->get_addr_str(), reason);
3611 delete [] reason;
3612 text_buf.cut_message();
3613 status_change();
3614}
3615
3616void MainController::process_log(unknown_connection *conn)
3617{
3618 Text_Buf& text_buf = *conn->text_buf;
3619 struct timeval tv;
3620 tv.tv_sec = text_buf.pull_int().get_val();
3621 tv.tv_usec = text_buf.pull_int().get_val();
3622 char *source = mprintf("<unknown>@%s", conn->ip_addr->get_host_str());
3623 int severity = text_buf.pull_int().get_val();
3624 char *message = text_buf.pull_string();
3625 notify(&tv, source, severity, message);
3626 Free(source);
3627 delete [] message;
3628}
3629
3630void MainController::process_version(unknown_connection *conn)
3631{
3632 if (check_version(conn)) {
3633 error("HC connection from %s [%s] was refused because of "
3634 "incorrect version.", conn->ip_addr->get_host_str(),
3635 conn->ip_addr->get_addr_str());
3636 close_unknown_connection(conn);
3637 return;
3638 }
3639 host_struct *hc = add_new_host(conn);
3640 switch (mc_state) {
3641 case MC_LISTENING:
3642 mc_state = MC_HC_CONNECTED;
3643 case MC_HC_CONNECTED:
3644 break;
3645 case MC_LISTENING_CONFIGURED:
3646 case MC_ACTIVE:
3647 configure_host(hc, TRUE);
3648 mc_state = MC_CONFIGURING;
3649 break;
3650 case MC_SHUTDOWN:
3651 send_exit_hc(hc);
3652 hc->hc_state = HC_EXITING;
3653 break;
3654 default:
3655 configure_host(hc, TRUE);
3656 }
3657 // handle the remaining messages that are in hc->text_buf
3658 handle_hc_data(hc, FALSE);
3659 status_change();
3660}
3661
3662void MainController::process_mtc_created(unknown_connection *conn)
3663{
3664 int fd = conn->fd;
3665 if (mc_state != MC_CREATING_MTC) {
3666 send_error_str(fd, "Message MTC_CREATED arrived in invalid state.");
3667 close_unknown_connection(conn);
3668 return;
3669 }
3670 if (mtc == NULL || mtc->tc_state != TC_INITIAL)
3671 fatal_error("MainController::process_mtc_created: MTC is in invalid "
3672 "state.");
3673 if (!conn->unix_socket &&
3674 *(mtc->comp_location->ip_addr) != *(conn->ip_addr)) {
3675 send_error(fd, "Message MTC_CREATED arrived from an unexpected "
3676 "IP address. It is accepted only from %s.",
3677 mtc->comp_location->ip_addr->get_addr_str());
3678 close_unknown_connection(conn);
3679 return;
3680 }
3681
3682 mc_state = MC_READY;
3683 mtc->tc_state = TC_IDLE;
3684 mtc->tc_fd = fd;
3685 fd_table[fd].fd_type = FD_TC;
3686 fd_table[fd].component_ptr = mtc;
3687 Text_Buf *text_buf = conn->text_buf;
3688 text_buf->cut_message();
3689 mtc->text_buf = text_buf;
3690 delete [] mtc->initial.location_str;
3691
3692 delete_unknown_connection(conn);
3693
3694 notify("MTC is created.");
3695 // handle the remaining messages that are in text_buf
3696 handle_tc_data(mtc, FALSE);
3697 status_change();
3698}
3699
3700void MainController::process_ptc_created(unknown_connection *conn)
3701{
3702 int fd = conn->fd;
3703
3704 switch (mc_state) {
3705 case MC_EXECUTING_TESTCASE:
3706 case MC_TERMINATING_TESTCASE:
3707 break;
3708 default:
3709 send_error_str(fd, "Message PTC_CREATED arrived in invalid state.");
3710 close_unknown_connection(conn);
3711 return;
3712 }
3713
3714 Text_Buf *text_buf = conn->text_buf;
3715 component component_reference = text_buf->pull_int().get_val();
3716
3717 switch (component_reference) {
3718 case NULL_COMPREF:
3719 send_error_str(fd, "Message PTC_CREATED refers to the null component "
3720 "reference.");
3721 close_unknown_connection(conn);
3722 return;
3723 case MTC_COMPREF:
3724 send_error_str(fd, "Message PTC_CREATED refers to the component "
3725 "reference of the MTC.");
3726 close_unknown_connection(conn);
3727 return;
3728 case SYSTEM_COMPREF:
3729 send_error_str(fd, "Message PTC_CREATED refers to the component "
3730 "reference of the system.");
3731 close_unknown_connection(conn);
3732 return;
3733 case ANY_COMPREF:
3734 send_error_str(fd, "Message PTC_CREATED refers to 'any component'.");
3735 close_unknown_connection(conn);
3736 return;
3737 case ALL_COMPREF:
3738 send_error_str(fd, "Message PTC_CREATED refers to 'all component'.");
3739 close_unknown_connection(conn);
3740 return;
3741 }
3742
3743 component_struct *tc = lookup_component(component_reference);
3744 if (tc == NULL) {
3745 send_error(fd, "Message PTC_CREATED refers to invalid component "
3746 "reference %d.", component_reference);
3747 close_unknown_connection(conn);
3748 return;
3749 } else if (tc->tc_state != TC_INITIAL) {
3750 send_error(fd, "Message PTC_CREATED refers to test component "
3751 "%d, which is not being created.", component_reference);
3752 close_unknown_connection(conn);
3753 return;
3754 } else if (!conn->unix_socket && *(conn->ip_addr) != *(tc->comp_location->ip_addr)) {
3755 char *real_hostname = mprintf("%s [%s]", conn->ip_addr->get_host_str(),
3756 conn->ip_addr->get_addr_str());
3757 char *expected_hostname = mprintf("%s [%s]",
3758 tc->comp_location->hostname, tc->comp_location->ip_addr->get_addr_str());
3759 send_error(fd, "Invalid source host (%s) for the control "
3760 "connection. Expected: %s.", real_hostname, expected_hostname);
3761 error("Connection of PTC %d arrived from an unexpected "
3762 "IP address (%s). Expected: %s.", component_reference,
3763 real_hostname, expected_hostname);
3764 Free(real_hostname);
3765 Free(expected_hostname);
3766 close_unknown_connection(conn);
3767 return;
3768 }
3769
3770 tc->tc_state = TC_IDLE;
3771 tc->tc_fd = fd;
3772 fd_table[fd].fd_type = FD_TC;
3773 fd_table[fd].component_ptr = tc;
3774 text_buf->cut_message();
3775 tc->text_buf = text_buf;
3776 delete [] tc->initial.location_str;
3777
3778 delete_unknown_connection(conn);
3779
3780 if (mc_state == MC_TERMINATING_TESTCASE || mtc->stop_requested ||
3781 mtc->tc_state == MTC_ALL_COMPONENT_KILL ||
3782 (mtc->tc_state == MTC_ALL_COMPONENT_STOP && !tc->is_alive)) {
3783 send_kill(tc);
3784 tc->tc_state = PTC_KILLING;
3785 if (!tc->is_alive) tc->stop_requested = TRUE;
3786 init_requestors(&tc->stopping_killing.stop_requestors, NULL);
3787 init_requestors(&tc->stopping_killing.kill_requestors, NULL);
3788 start_kill_timer(tc);
3789 } else {
3790 component_struct *create_requestor = tc->initial.create_requestor;
3791 if (create_requestor->tc_state == TC_CREATE) {
3792 send_create_ack(create_requestor, component_reference);
3793 if (create_requestor == mtc)
3794 create_requestor->tc_state = MTC_TESTCASE;
3795 else create_requestor->tc_state = PTC_FUNCTION;
3796 }
3797 }
3798 // handle the remaining messages that are in text_buf
3799 handle_tc_data(tc, FALSE);
3800 status_change();
3801}
3802
3803void MainController::process_error(host_struct *hc)
3804{
3805 char *reason = hc->text_buf->pull_string();
3806 error("Error message was received from HC at %s [%s]: %s",
3807 hc->hostname, hc->ip_addr->get_addr_str(), reason);
3808 delete [] reason;
3809}
3810
3811void MainController::process_log(host_struct *hc)
3812{
3813 Text_Buf& text_buf = *hc->text_buf;
3814 struct timeval tv;
3815 tv.tv_sec = text_buf.pull_int().get_val();
3816 tv.tv_usec = text_buf.pull_int().get_val();
3817 int severity = text_buf.pull_int().get_val();
3818 char *message = text_buf.pull_string();
3819 notify(&tv, hc->log_source, severity, message);
3820 delete [] message;
3821}
3822
3823void MainController::process_configure_ack(host_struct *hc)
3824{
3825 switch (hc->hc_state) {
3826 case HC_CONFIGURING:
3827 hc->hc_state = HC_ACTIVE;
3828 break;
3829 case HC_CONFIGURING_OVERLOADED:
3830 hc->hc_state = HC_OVERLOADED;
3831 break;
3832 default:
3833 send_error_str(hc->hc_fd, "Unexpected message CONFIGURE_ACK was "
3834 "received.");
3835 return;
3836 }
3837 if (mc_state == MC_CONFIGURING) check_all_hc_configured();
3838 else notify("Host %s was configured successfully.", hc->hostname);
3839 status_change();
3840}
3841
3842void MainController::process_configure_nak(host_struct *hc)
3843{
3844 switch (hc->hc_state) {
3845 case HC_CONFIGURING:
3846 case HC_CONFIGURING_OVERLOADED:
3847 hc->hc_state = HC_IDLE;
3848 break;
3849 default:
3850 send_error_str(hc->hc_fd, "Unexpected message CONFIGURE_NAK was "
3851 "received.");
3852 return;
3853 }
3854 if (mc_state == MC_CONFIGURING) check_all_hc_configured();
3855 else notify("Processing of configuration file failed on host %s.",
3856 hc->hostname);
3857 status_change();
3858}
3859
3860void MainController::process_create_nak(host_struct *hc)
3861{
3862 switch (mc_state) {
3863 case MC_CREATING_MTC:
3864 case MC_EXECUTING_TESTCASE:
3865 case MC_TERMINATING_TESTCASE:
3866 break;
3867 default:
3868 send_error_str(hc->hc_fd, "Message CREATE_NAK arrived in invalid "
3869 "state.");
3870 return;
3871 }
3872
3873 switch (hc->hc_state) {
3874 case HC_ACTIVE:
3875 notify("Host %s is overloaded. New components will not be created "
3876 "there until further notice.", hc->hostname);
3877 hc->hc_state = HC_OVERLOADED;
3878 // no break
3879 case HC_OVERLOADED:
3880 break;
3881 default:
3882 send_error_str(hc->hc_fd, "Unexpected message CREATE_NAK was received: "
3883 "the sender is in invalid state.");
3884 return;
3885 }
3886
3887 Text_Buf& text_buf = *hc->text_buf;
3888 component component_reference = text_buf.pull_int().get_val();
3889
3890 switch (component_reference) {
3891 case NULL_COMPREF:
3892 send_error_str(hc->hc_fd, "Message CREATE_NAK refers to the null "
3893 "component reference.");
3894 return;
3895 case SYSTEM_COMPREF:
3896 send_error_str(hc->hc_fd, "Message CREATE_NAK refers to the component "
3897 "reference of the system.");
3898 return;
3899 case ANY_COMPREF:
3900 send_error_str(hc->hc_fd, "Message CREATE_NAK refers to "
3901 "'any component'.");
3902 return;
3903 case ALL_COMPREF:
3904 send_error_str(hc->hc_fd, "Message CREATE_NAK refers to "
3905 "'all component'.");
3906 return;
3907 }
3908
3909 component_struct *tc = lookup_component(component_reference);
3910 if (tc == NULL) {
3911 send_error(hc->hc_fd, "Message CREATE_NAK refers to invalid component "
3912 "reference %d.", component_reference);
3913 return;
3914 }
3915 if (tc->tc_state != TC_INITIAL) {
3916 send_error(hc->hc_fd, "Message CREATE_NAK refers to test component "
3917 "%d, which is not being created.", component_reference);
3918 return;
3919 }
3920 if (tc->comp_location != hc) {
3921 send_error(hc->hc_fd, "Message CREATE_NAK refers to test component "
3922 "%d, which was assigned to a different host (%s).",
3923 component_reference, tc->comp_location->hostname);
3924 return;
3925 }
3926
3927 remove_component_from_host(tc);
3928 hc->n_active_components--;
3929
3930 char *reason = text_buf.pull_string();
3931
3932 if (tc == mtc) {
3933 if (mc_state != MC_CREATING_MTC)
3934 fatal_error("MainController::process_create_nak: MC is in "
3935 "unexpected state when CREATE_NAK refers to MTC.");
3936 error("Creation of MTC failed on host %s: %s.", hc->hostname, reason);
3937 destroy_all_components();
3938 mc_state = MC_ACTIVE;
3939 } else {
3940 host_struct *new_host = choose_ptc_location(
3941 tc->comp_type.definition_name, tc->comp_name,
3942 tc->initial.location_str);
3943 if (new_host != NULL) {
3944 send_create_ptc(new_host, component_reference, tc->comp_type,
3945 tc->comp_name, tc->is_alive, mtc->tc_fn_name);
3946 notify("PTC with component reference %d was relocated from host "
3947 "%s to %s because of overload: %s.", component_reference,
3948 hc->hostname, new_host->hostname, reason);
3949 add_component_to_host(new_host, tc);
3950 new_host->n_active_components++;
3951 } else {
3952 char *comp_data = mprintf("component type: %s.%s",
3953 tc->comp_type.module_name, tc->comp_type.definition_name);
3954 if (tc->comp_name != NULL)
3955 comp_data = mputprintf(comp_data, ", name: %s", tc->comp_name);
3956 if (tc->initial.location_str != NULL &&
3957 tc->initial.location_str[0] != '\0')
3958 comp_data = mputprintf(comp_data, ", location: %s",
3959 tc->initial.location_str);
3960 component_struct *create_requestor = tc->initial.create_requestor;
3961 if (create_requestor->tc_state == TC_CREATE) {
3962 send_error(create_requestor->tc_fd, "Creation of the new PTC "
3963 "(%s) failed on host %s: %s. Other suitable hosts to "
3964 "relocate the component are not available.", comp_data,
3965 hc->hostname, reason);
3966 if (create_requestor == mtc)
3967 create_requestor->tc_state = MTC_TESTCASE;
3968 else create_requestor->tc_state = PTC_FUNCTION;
3969 }
3970 delete [] tc->initial.location_str;
3971 tc->tc_state = PTC_STALE;
3972 n_active_ptcs--;
3973 switch (mtc->tc_state) {
3974 case MTC_TERMINATING_TESTCASE:
3975 if (ready_to_finish_testcase()) finish_testcase();
3976 break;
3977 case MTC_ALL_COMPONENT_KILL:
3978 check_all_component_kill();
3979 break;
3980 case MTC_ALL_COMPONENT_STOP:
3981 check_all_component_stop();
3982 break;
3983 default:
3984 break;
3985 }
3986 notify("Creation of a PTC (%s) failed on host %s: %s. "
3987 "Relocation to other suitable host is not possible.",
3988 comp_data, hc->hostname, reason);
3989 Free(comp_data);
3990 }
3991 }
3992
3993 delete [] reason;
3994
3995 status_change();
3996}
3997
3998void MainController::process_hc_ready(host_struct *hc)
3999{
4000 switch(hc->hc_state) {
4001 case HC_OVERLOADED:
4002 hc->hc_state = HC_ACTIVE;
4003 break;
4004 case HC_CONFIGURING_OVERLOADED:
4005 hc->hc_state = HC_CONFIGURING;
4006 break;
4007 default:
4008 send_error_str(hc->hc_fd, "Unexpected message HC_READY was received.");
4009 return;
4010 }
4011 notify("Host %s is no more overloaded.", hc->hostname);
4012 status_change();
4013}
4014
4015void MainController::process_error(component_struct *tc)
4016{
4017 char *reason = tc->text_buf->pull_string();
4018 if (tc == mtc) {
4019 error("Error message was received from the MTC at %s [%s]: %s",
4020 mtc->comp_location->hostname,
4021 mtc->comp_location->ip_addr->get_addr_str(), reason);
4022 } else {
4023 notify("Error message was received from PTC %d at %s [%s]: %s",
4024 tc->comp_ref, tc->comp_location->hostname,
4025 tc->comp_location->ip_addr->get_addr_str(), reason);
4026 }
4027 delete [] reason;
4028}
4029
4030void MainController::process_log(component_struct *tc)
4031{
4032 Text_Buf& text_buf = *tc->text_buf;
4033 struct timeval tv;
4034 tv.tv_sec = text_buf.pull_int().get_val();
4035 tv.tv_usec = text_buf.pull_int().get_val();
4036 int severity = text_buf.pull_int().get_val();
4037 char *message = text_buf.pull_string();
4038 notify(&tv, tc->log_source, severity, message);
4039 delete [] message;
4040}
4041
4042void MainController::process_create_req(component_struct *tc)
4043{
4044 if (!request_allowed(tc, "CREATE_REQ")) return;
4045
4046 if (max_ptcs >= 0 && n_active_ptcs >= max_ptcs) {
4047 send_error(tc->tc_fd, "The license key does not allow more than %d "
4048 "simultaneously active PTCs.", max_ptcs);
4049 return;
4050 }
4051
4052 Text_Buf& text_buf = *tc->text_buf;
4053 qualified_name component_type;
4054 text_buf.pull_qualified_name(component_type);
4055 char *component_name = text_buf.pull_string();
4056 if (component_name[0] == '\0') {
4057 delete [] component_name;
4058 component_name = NULL;
4059 }
4060 char *component_location = text_buf.pull_string();
4061 if (component_location[0] == '\0') {
4062 delete [] component_location;
4063 component_location = NULL;
4064 }
4065 boolean is_alive = text_buf.pull_int().get_val();
4066
4067 host_struct *host = choose_ptc_location(component_type.definition_name,
4068 component_name, component_location);
4069
4070 if (host == NULL) {
4071 if (!is_hc_in_state(HC_ACTIVE)) {
4072 send_error_str(tc->tc_fd, "There is no active HC connection. "
4073 "Create operation cannot be performed.");
4074 } else {
4075 char *comp_data = mprintf("component type: %s.%s",
4076 component_type.module_name, component_type.definition_name);
4077 if (component_name != NULL)
4078 comp_data = mputprintf(comp_data, ", name: %s", component_name);
4079 if (component_location != NULL)
4080 comp_data = mputprintf(comp_data, ", location: %s",
4081 component_location);
4082 send_error(tc->tc_fd, "No suitable host was found to create a "
4083 "new PTC (%s).", comp_data);
4084 Free(comp_data);
4085 }
4086 free_qualified_name(&component_type);
4087 delete [] component_name;
4088 delete [] component_location;
4089 return;
4090 }
4091
4092 component comp_ref = next_comp_ref++;
4093 send_create_ptc(host, comp_ref, component_type, component_name, is_alive,
4094 mtc->tc_fn_name);
4095
4096 tc->tc_state = TC_CREATE;
4097
4098 component_struct *new_ptc = new component_struct;
4099 new_ptc->comp_ref = comp_ref;
4100 new_ptc->comp_type = component_type;
4101 new_ptc->comp_name = component_name;
4102 new_ptc->tc_state = TC_INITIAL;
4103 new_ptc->local_verdict = NONE;
4104 new_ptc->verdict_reason = NULL;
4105 new_ptc->tc_fd = -1;
4106 new_ptc->text_buf = NULL;
4107 init_qualified_name(&new_ptc->tc_fn_name);
4108 new_ptc->return_type = NULL;
4109 new_ptc->return_value_len = 0;
4110 new_ptc->return_value = NULL;
4111 new_ptc->is_alive = is_alive;
4112 new_ptc->stop_requested = FALSE;
4113 new_ptc->process_killed = FALSE;
4114 new_ptc->initial.create_requestor = tc;
4115 new_ptc->initial.location_str = component_location;
4116 init_requestors(&new_ptc->done_requestors, NULL);
4117 init_requestors(&new_ptc->killed_requestors, NULL);
4118 init_requestors(&new_ptc->cancel_done_sent_for, NULL);
4119 new_ptc->kill_timer = NULL;
4120 init_connections(new_ptc);
4121
4122 add_component(new_ptc);
4123 add_component_to_host(host, new_ptc);
4124 host->n_active_components++;
4125 n_active_ptcs++;
4126
4127 status_change();
4128}
4129
4130void MainController::process_start_req(component_struct *tc, int message_end)
4131{
4132 if (!request_allowed(tc, "START_REQ")) return;
4133
4134 Text_Buf& text_buf = *tc->text_buf;
4135 component component_reference = text_buf.pull_int().get_val();
4136 switch (component_reference) {
4137 case NULL_COMPREF:
4138 send_error_str(tc->tc_fd, "Start operation was requested on the null "
4139 "component reference.");
4140 return;
4141 case MTC_COMPREF:
4142 send_error_str(tc->tc_fd, "Start operation was requested on the "
4143 "component reference of the MTC.");
4144 return;
4145 case SYSTEM_COMPREF:
4146 send_error_str(tc->tc_fd, "Start operation was requested on the "
4147 "component reference of the system.");
4148 return;
4149 case ANY_COMPREF:
4150 send_error_str(tc->tc_fd, "Start operation was requested on "
4151 "'any component'.");
4152 return;
4153 case ALL_COMPREF:
4154 send_error_str(tc->tc_fd, "Start operation was requested on "
4155 "'all component'.");
4156 return;
4157 }
4158 component_struct *target = lookup_component(component_reference);
4159 if (target == NULL) {
4160 send_error(tc->tc_fd, "Start operation was requested on invalid "
4161 "component reference: %d.", component_reference);
4162 return;
4163 }
4164 switch (target->tc_state) {
4165 case TC_IDLE:
4166 case PTC_STOPPED:
4167 // these states are correct
4168 break;
4169 case TC_CREATE:
4170 case TC_START:
4171 case TC_STOP:
4172 case TC_KILL:
4173 case TC_CONNECT:
4174 case TC_DISCONNECT:
4175 case TC_MAP:
4176 case TC_UNMAP:
4177 case PTC_FUNCTION:
4178 case PTC_STARTING:
4179 send_error(tc->tc_fd, "PTC with component reference %d cannot be "
4180 "started because it is already executing function %s.%s.",
4181 component_reference, target->tc_fn_name.module_name,
4182 target->tc_fn_name.definition_name);
4183 return;
4184 case TC_STOPPING:
4185 send_error(tc->tc_fd, "PTC with component reference %d cannot be "
4186 "started because it function %s.%s is currently being stopped on "
4187 "it.", component_reference, target->tc_fn_name.module_name,
4188 target->tc_fn_name.definition_name);
4189 return;
4190 case PTC_KILLING:
4191 case PTC_STOPPING_KILLING:
4192 send_error(tc->tc_fd, "PTC with component reference %d cannot be "
4193 "started because it is currently being killed.",
4194 component_reference);
4195 return;
4196 case TC_EXITING:
4197 case TC_EXITED:
4198 send_error(tc->tc_fd, "PTC with component reference %d cannot be "
4199 "started because it is not alive anymore.", component_reference);
4200 return;
4201 case PTC_STALE:
4202 send_error(tc->tc_fd, "The argument of start operation (%d) is a "
4203 "component reference that belongs to an earlier testcase.",
4204 component_reference);
4205 return;
4206 default:
4207 send_error(tc->tc_fd, "Start operation was requested on component "
4208 "reference %d, which is in invalid state.",
4209 component_reference);
4210 return;
4211 }
4212 text_buf.pull_qualified_name(target->tc_fn_name);
4213 target->stop_requested = FALSE;
4214 int arg_begin = text_buf.get_pos();
4215 int arg_len = message_end - arg_begin;
4216 const void *arg_ptr = text_buf.get_data() + arg_begin;
4217 boolean send_cancel_done = FALSE, cancel_any_component_done = FALSE;
4218 if (target->tc_state == PTC_STOPPED) {
4219 // updating the state of target because 'any component.done' cannot
4220 // consider this component anymore
4221 target->tc_state = PTC_STARTING;
4222 // cleaning up the previous return value
4223 delete [] target->return_type;
4224 target->return_type = NULL;
4225 target->return_value_len = 0;
4226 Free(target->return_value);
4227 target->return_value = NULL;
4228 // determining which components we need to send CANCEL_DONE to
4229 init_requestors(&target->starting.cancel_done_sent_to, NULL);
4230 for (int i = 0; ; i++) {
4231 component_struct *comp = get_requestor(&target->done_requestors, i);
4232 if (comp == NULL) break;
4233 else if (comp == tc) {
4234 // the start requestor shall cancel the done status locally
4235 // ignore it
4236 continue;
4237 }
4238 switch (comp->tc_state) {
4239 case TC_CREATE:
4240 case TC_START:
4241 case TC_STOP:
4242 case TC_KILL:
4243 case TC_CONNECT:
4244 case TC_DISCONNECT:
4245 case TC_MAP:
4246 case TC_UNMAP:
4247 case TC_STOPPING:
4248 case MTC_TESTCASE:
4249 case PTC_FUNCTION:
4250 case PTC_STARTING:
4251 case PTC_STOPPED:
4252 // a CANCEL_DONE message shall be sent to comp
4253 send_cancel_done = TRUE;
4254 add_requestor(&target->starting.cancel_done_sent_to, comp);
4255 break;
4256 case TC_EXITING:
4257 case TC_EXITED:
4258 case PTC_KILLING:
4259 case PTC_STOPPING_KILLING:
4260 // CANCEL_DONE will not be sent to comp
4261 break;
4262 default:
4263 error("Test Component %d is in invalid state when starting "
4264 "PTC %d.", comp->comp_ref, component_reference);
4265 }
4266 }
4267 // check whether 'any component.done' needs to be cancelled
4268 if (any_component_done_sent && !is_any_component_done()) {
4269 send_cancel_done = TRUE;
4270 cancel_any_component_done = TRUE;
4271 any_component_done_sent = FALSE;
4272 add_requestor(&target->starting.cancel_done_sent_to, mtc);
4273 }
4274 free_requestors(&target->done_requestors);
4275 }
4276 if (send_cancel_done) {
4277 for (int i = 0; ; i++) {
4278 component_struct *comp =
4279 get_requestor(&target->starting.cancel_done_sent_to, i);
4280 if (comp == NULL) break;
4281 else if (comp == mtc) send_cancel_done_mtc(component_reference,
4282 cancel_any_component_done);
4283 else send_cancel_done_ptc(comp, component_reference);
4284 add_requestor(&comp->cancel_done_sent_for, target);
4285 }
4286 target->starting.start_requestor = tc;
4287 target->starting.arguments_len = arg_len;
4288 target->starting.arguments_ptr = Malloc(arg_len);
4289 memcpy(target->starting.arguments_ptr, arg_ptr, arg_len);
4290 tc->tc_state = TC_START;
4291 } else {
4292 send_start(target, target->tc_fn_name, arg_len, arg_ptr);
4293 send_start_ack(tc);
4294 target->tc_state = PTC_FUNCTION;
4295 }
4296 status_change();
4297}
4298
4299void MainController::process_stop_req(component_struct *tc)
4300{
4301 if (!request_allowed(tc, "STOP_REQ")) return;
4302
4303 component component_reference = tc->text_buf->pull_int().get_val();
4304 switch (component_reference) {
4305 case NULL_COMPREF:
4306 send_error_str(tc->tc_fd, "Stop operation was requested on the null "
4307 "component reference.");
4308 return;
4309 case MTC_COMPREF:
4310 // 'mtc.stop' initiated by a PTC terminates the current testcase
4311 if (tc != mtc) {
4312 if (!mtc->stop_requested) {
4313 send_stop(mtc);
4314 kill_all_components(TRUE);
4315 mtc->stop_requested = TRUE;
4316 start_kill_timer(mtc);
4317 notify("Test Component %d has requested to stop MTC. "
4318 "Terminating current testcase execution.", tc->comp_ref);
4319 status_change();
4320 }
4321 } else send_error_str(tc->tc_fd, "MTC has requested to stop itself.");
4322 return;
4323 case SYSTEM_COMPREF:
4324 send_error_str(tc->tc_fd, "Stop operation was requested on the "
4325 "component reference of the system.");
4326 return;
4327 case ANY_COMPREF:
4328 send_error_str(tc->tc_fd, "Stop operation was requested on "
4329 "'any component'.");
4330 return;
4331 case ALL_COMPREF:
4332 if (tc == mtc) {
4333 if (stop_all_components()) send_stop_ack(mtc);
4334 else {
4335 mtc->tc_state = MTC_ALL_COMPONENT_STOP;
4336 status_change();
4337 }
4338 } else send_error_str(tc->tc_fd, "Operation 'all component.stop' can "
4339 "only be performed on the MTC.");
4340 return;
4341 default:
4342 break;
4343 }
4344 // the operation refers to a specific PTC
4345 component_struct *target = lookup_component(component_reference);
4346 if (target == NULL) {
4347 send_error(tc->tc_fd, "The argument of stop operation is an "
4348 "invalid component reference: %d.", component_reference);
4349 return;
4350 } else if (target == tc) {
4351 send_error_str(tc->tc_fd, "Stop operation was requested on the "
4352 "requestor component itself.");
4353 return;
4354 }
4355 boolean target_inactive = FALSE;
4356 switch (target->tc_state) {
4357 case PTC_STOPPED:
4358 if (!target->is_alive) error("PTC %d cannot be in state STOPPED "
4359 "because it is not an alive type PTC.", component_reference);
4360 // no break
4361 case TC_IDLE:
4362 target_inactive = TRUE;
4363 // no break
4364 case TC_CREATE:
4365 case TC_START:
4366 case TC_STOP:
4367 case TC_KILL:
4368 case TC_CONNECT:
4369 case TC_DISCONNECT:
4370 case TC_MAP:
4371 case TC_UNMAP:
4372 case PTC_FUNCTION:
4373 if (target->is_alive) {
4374 if (target_inactive) {
4375 // do nothing, just send a STOP_ACK to tc
4376 send_stop_ack(tc);
4377 break;
4378 } else {
4379 send_stop(target);
4380 target->tc_state = TC_STOPPING;
4381 }
4382 } else {
4383 // the target is not an alive type PTC: stop operation means kill
4384 send_kill(target);
4385 if (target_inactive) target->tc_state = PTC_KILLING;
4386 else target->tc_state = PTC_STOPPING_KILLING;
4387 }
4388 // a STOP or KILL message was sent out
4389 target->stop_requested = TRUE;
4390 init_requestors(&target->stopping_killing.stop_requestors, tc);
4391 init_requestors(&target->stopping_killing.kill_requestors, NULL);
4392 start_kill_timer(target);
4393 tc->tc_state = TC_STOP;
4394 status_change();
4395 break;
4396 case PTC_KILLING:
4397 if (target->is_alive) {
4398 // do nothing if the PTC is alive
4399 send_stop_ack(tc);
4400 break;
4401 }
4402 // no break
4403 case TC_STOPPING:
4404 case PTC_STOPPING_KILLING:
4405 // the PTC is currently being stopped
4406 add_requestor(&target->stopping_killing.stop_requestors, tc);
4407 tc->tc_state = TC_STOP;
4408 status_change();
4409 break;
4410 case TC_EXITING:
4411 case TC_EXITED:
4412 // the PTC is already terminated, do nothing
4413 send_stop_ack(tc);
4414 break;
4415 case PTC_STARTING:
4416 send_error(tc->tc_fd, "PTC with component reference %d cannot be "
4417 "stopped because it is currently being started.",
4418 component_reference);
4419 break;
4420 case PTC_STALE:
4421 send_error(tc->tc_fd, "The argument of stop operation (%d) is a "
4422 "component reference that belongs to an earlier testcase.",
4423 component_reference);
4424 break;
4425 default:
4426 send_error(tc->tc_fd, "The test component that the stop operation "
4427 "refers to (%d) is in invalid state.", component_reference);
4428 }
4429}
4430
4431void MainController::process_kill_req(component_struct *tc)
4432{
4433 if (!request_allowed(tc, "KILL_REQ")) return;
4434
4435 component component_reference = tc->text_buf->pull_int().get_val();
4436 switch (component_reference) {
4437 case NULL_COMPREF:
4438 send_error_str(tc->tc_fd, "Kill operation was requested on the null "
4439 "component reference.");
4440 return;
4441 case MTC_COMPREF:
4442 send_error_str(tc->tc_fd, "Kill operation was requested on the "
4443 "component reference of the MTC.");
4444 return;
4445 case SYSTEM_COMPREF:
4446 send_error_str(tc->tc_fd, "Kill operation was requested on the "
4447 "component reference of the system.");
4448 return;
4449 case ANY_COMPREF:
4450 send_error_str(tc->tc_fd, "Kill operation was requested on "
4451 "'any component'.");
4452 return;
4453 case ALL_COMPREF:
4454 if (tc == mtc) {
4455 if (kill_all_components(FALSE)) send_kill_ack(mtc);
4456 else {
4457 mtc->tc_state = MTC_ALL_COMPONENT_KILL;
4458 status_change();
4459 }
4460 } else send_error_str(tc->tc_fd, "Operation 'all component.kill' can "
4461 "only be performed on the MTC.");
4462 return;
4463 default:
4464 break;
4465 }
4466 // the operation refers to a specific PTC
4467 component_struct *target = lookup_component(component_reference);
4468 if (target == NULL) {
4469 send_error(tc->tc_fd, "The argument of kill operation is an "
4470 "invalid component reference: %d.", component_reference);
4471 return;
4472 } else if (target == tc) {
4473 send_error_str(tc->tc_fd, "Kill operation was requested on the "
4474 "requestor component itself.");
4475 return;
4476 }
4477 boolean target_inactive = FALSE;
4478 switch (target->tc_state) {
4479 case PTC_STOPPED:
4480 // the done status of this PTC is already sent out
4481 // and it will not be cancelled in the future
4482 free_requestors(&target->done_requestors);
4483 // no break
4484 case TC_IDLE:
4485 target_inactive = TRUE;
4486 // no break
4487 case TC_CREATE:
4488 case TC_START:
4489 case TC_STOP:
4490 case TC_KILL:
4491 case TC_CONNECT:
4492 case TC_DISCONNECT:
4493 case TC_MAP:
4494 case TC_UNMAP:
4495 case PTC_FUNCTION:
4496 send_kill(target);
4497 if (target_inactive) {
4498 // the PTC was inactive
4499 target->tc_state = PTC_KILLING;
4500 if (!target->is_alive) target->stop_requested = TRUE;
4501 } else {
4502 // the PTC was active
4503 target->tc_state = PTC_STOPPING_KILLING;
4504 target->stop_requested = TRUE;
4505 }
4506 init_requestors(&target->stopping_killing.stop_requestors, NULL);
4507 init_requestors(&target->stopping_killing.kill_requestors, tc);
4508 start_kill_timer(target);
4509 tc->tc_state = TC_KILL;
4510 status_change();
4511 break;
4512 case TC_STOPPING:
4513 // the PTC is currently being stopped
4514 send_kill(target);
4515 target->tc_state = PTC_STOPPING_KILLING;
4516 if (target->kill_timer != NULL) cancel_timer(target->kill_timer);
4517 start_kill_timer(target);
4518 // no break
4519 case PTC_KILLING:
4520 case PTC_STOPPING_KILLING:
4521 // the PTC is currently being terminated
4522 add_requestor(&target->stopping_killing.kill_requestors, tc);
4523 tc->tc_state = TC_KILL;
4524 status_change();
4525 break;
4526 case TC_EXITING:
4527 case TC_EXITED:
4528 // the PTC is already terminated
4529 send_kill_ack(tc);
4530 break;
4531 case PTC_STARTING:
4532 send_error(tc->tc_fd, "PTC with component reference %d cannot be "
4533 "killed because it is currently being started.",
4534 component_reference);
4535 break;
4536 case PTC_STALE:
4537 send_error(tc->tc_fd, "The argument of kill operation (%d) is a "
4538 "component reference that belongs to an earlier testcase.",
4539 component_reference);
4540 break;
4541 default:
4542 send_error(tc->tc_fd, "The test component that the kill operation "
4543 "refers to (%d) is in invalid state.", component_reference);
4544 }
4545}
4546
4547void MainController::process_is_running(component_struct *tc)
4548{
4549 if (!request_allowed(tc, "IS_RUNNING")) return;
4550
4551 component component_reference = tc->text_buf->pull_int().get_val();
4552 switch (component_reference) {
4553 case NULL_COMPREF:
4554 send_error_str(tc->tc_fd, "Running operation was requested on the "
4555 "null component reference.");
4556 return;
4557 case MTC_COMPREF:
4558 send_error_str(tc->tc_fd, "Running operation was requested on the "
4559 "component reference of the MTC.");
4560 return;
4561 case SYSTEM_COMPREF:
4562 send_error_str(tc->tc_fd, "Running operation was requested on the "
4563 "component reference of the system.");
4564 return;
4565 case ANY_COMPREF:
4566 if (tc == mtc) send_running(mtc, is_any_component_running());
4567 else send_error_str(tc->tc_fd, "Operation 'any component.running' "
4568 "can only be performed on the MTC.");
4569 return;
4570 case ALL_COMPREF:
4571 if (tc == mtc) send_running(mtc, is_all_component_running());
4572 else send_error_str(tc->tc_fd, "Operation 'all component.running' "
4573 "can only be performed on the MTC.");
4574 return;
4575 default:
4576 break;
4577 }
4578 // the operation refers to a specific PTC
4579 component_struct *comp = lookup_component(component_reference);
4580 if (comp == NULL) {
4581 send_error(tc->tc_fd, "The argument of running operation is an "
4582 "invalid component reference: %d.", component_reference);
4583 return;
4584 }
4585 switch (comp->tc_state) {
4586 case TC_CREATE:
4587 case TC_START:
4588 case TC_STOP:
4589 case TC_KILL:
4590 case TC_CONNECT:
4591 case TC_DISCONNECT:
4592 case TC_MAP:
4593 case TC_UNMAP:
4594 case TC_STOPPING:
4595 case PTC_FUNCTION:
4596 case PTC_STARTING:
4597 case PTC_STOPPING_KILLING:
4598 send_running(tc, TRUE);
4599 break;
4600 case TC_IDLE:
4601 case TC_EXITING:
4602 case TC_EXITED:
4603 case PTC_STOPPED:
4604 case PTC_KILLING:
4605 send_running(tc, FALSE);
4606 break;
4607 case PTC_STALE:
4608 send_error(tc->tc_fd, "The argument of running operation (%d) is a "
4609 "component reference that belongs to an earlier testcase.",
4610 component_reference);
4611 break;
4612 default:
4613 send_error(tc->tc_fd, "The test component that the running operation "
4614 "refers to (%d) is in invalid state.", component_reference);
4615 }
4616}
4617
4618void MainController::process_is_alive(component_struct *tc)
4619{
4620 if (!request_allowed(tc, "IS_ALIVE")) return;
4621
4622 component component_reference = tc->text_buf->pull_int().get_val();
4623 switch (component_reference) {
4624 case NULL_COMPREF:
4625 send_error_str(tc->tc_fd, "Alive operation was requested on the "
4626 "null component reference.");
4627 return;
4628 case MTC_COMPREF:
4629 send_error_str(tc->tc_fd, "Alive operation was requested on the "
4630 "component reference of the MTC.");
4631 return;
4632 case SYSTEM_COMPREF:
4633 send_error_str(tc->tc_fd, "Alive operation was requested on the "
4634 "component reference of the system.");
4635 return;
4636 case ANY_COMPREF:
4637 if (tc == mtc) send_alive(mtc, is_any_component_alive());
4638 else send_error_str(tc->tc_fd, "Operation 'any component.alive' "
4639 "can only be performed on the MTC.");
4640 return;
4641 case ALL_COMPREF:
4642 if (tc == mtc) send_alive(mtc, is_all_component_alive());
4643 else send_error_str(tc->tc_fd, "Operation 'all component.alive' "
4644 "can only be performed on the MTC.");
4645 return;
4646 default:
4647 break;
4648 }
4649 // the operation refers to a specific PTC
4650 component_struct *comp = lookup_component(component_reference);
4651 if (comp == NULL) {
4652 send_error(tc->tc_fd, "The argument of alive operation is an "
4653 "invalid component reference: %d.", component_reference);
4654 return;
4655 }
4656 switch (comp->tc_state) {
4657 case TC_IDLE:
4658 case TC_CREATE:
4659 case TC_START:
4660 case TC_STOP:
4661 case TC_KILL:
4662 case TC_CONNECT:
4663 case TC_DISCONNECT:
4664 case TC_MAP:
4665 case TC_UNMAP:
4666 case TC_STOPPING:
4667 case PTC_FUNCTION:
4668 case PTC_STARTING:
4669 case PTC_STOPPED:
4670 case PTC_KILLING:
4671 case PTC_STOPPING_KILLING:
4672 send_alive(tc, TRUE);
4673 break;
4674 case TC_EXITING:
4675 case TC_EXITED:
4676 send_alive(tc, FALSE);
4677 break;
4678 case PTC_STALE:
4679 send_error(tc->tc_fd, "The argument of alive operation (%d) is a "
4680 "component reference that belongs to an earlier testcase.",
4681 component_reference);
4682 break;
4683 default:
4684 send_error(tc->tc_fd, "The test component that the alive operation "
4685 "refers to (%d) is in invalid state.", component_reference);
4686 }
4687}
4688
4689void MainController::process_done_req(component_struct *tc)
4690{
4691 if (!request_allowed(tc, "DONE_REQ")) return;
4692
4693 component component_reference = tc->text_buf->pull_int().get_val();
4694 switch (component_reference) {
4695 case NULL_COMPREF:
4696 send_error_str(tc->tc_fd, "Done operation was requested on the null "
4697 "component reference.");
4698 return;
4699 case MTC_COMPREF:
4700 send_error_str(tc->tc_fd, "Done operation was requested on the "
4701 "component reference of the MTC.");
4702 return;
4703 case SYSTEM_COMPREF:
4704 send_error_str(tc->tc_fd, "Done operation was requested on the "
4705 "component reference of the system.");
4706 return;
4707 case ANY_COMPREF:
4708 if (tc == mtc) {
4709 boolean answer = is_any_component_done();
4710 send_done_ack(mtc, answer, NULL, 0, NULL);
4711 if (answer) any_component_done_sent = TRUE;
4712 else any_component_done_requested = TRUE;
4713 } else send_error_str(tc->tc_fd, "Operation 'any component.done' can "
4714 "only be performed on the MTC.");
4715 return;
4716 case ALL_COMPREF:
4717 if (tc == mtc) {
4718 boolean answer = !is_any_component_running();
4719 send_done_ack(mtc, answer, NULL, 0, NULL);
4720 if (!answer) all_component_done_requested = TRUE;
4721 } else send_error_str(tc->tc_fd, "Operation 'all component.done' can "
4722 "only be performed on the MTC.");
4723 return;
4724 default:
4725 break;
4726 }
4727 // the operation refers to a specific PTC
4728 component_struct *comp = lookup_component(component_reference);
4729 if (comp == NULL) {
4730 send_error(tc->tc_fd, "The argument of done operation is an "
4731 "invalid component reference: %d.", component_reference);
4732 return;
4733 }
4734 switch (comp->tc_state) {
4735 case PTC_STOPPED:
4736 // this answer has to be cancelled when the component is re-started
4737 add_requestor(&comp->done_requestors, tc);
4738 // no break
4739 case TC_EXITING:
4740 case TC_EXITED:
4741 case PTC_KILLING:
4742 send_done_ack(tc, TRUE, comp->return_type, comp->return_value_len,
4743 comp->return_value);
4744 break;
4745 case TC_IDLE:
4746 case TC_CREATE:
4747 case TC_START:
4748 case TC_STOP:
4749 case TC_KILL:
4750 case TC_CONNECT:
4751 case TC_DISCONNECT:
4752 case TC_MAP:
4753 case TC_UNMAP:
4754 case TC_STOPPING:
4755 case PTC_FUNCTION:
4756 case PTC_STARTING:
4757 case PTC_STOPPING_KILLING:
4758 send_done_ack(tc, FALSE, NULL, 0, NULL);
4759 add_requestor(&comp->done_requestors, tc);
4760 break;
4761 case PTC_STALE:
4762 send_error(tc->tc_fd, "The argument of done operation (%d) is a "
4763 "component reference that belongs to an earlier testcase.",
4764 component_reference);
4765 break;
4766 default:
4767 send_error(tc->tc_fd, "The test component that the done operation "
4768 "refers to (%d) is in invalid state.", component_reference);
4769 }
4770}
4771
4772void MainController::process_killed_req(component_struct *tc)
4773{
4774 if (!request_allowed(tc, "KILLED_REQ")) return;
4775
4776 component component_reference = tc->text_buf->pull_int().get_val();
4777 switch (component_reference) {
4778 case NULL_COMPREF:
4779 send_error_str(tc->tc_fd, "Killed operation was requested on the null "
4780 "component reference.");
4781 return;
4782 case MTC_COMPREF:
4783 send_error_str(tc->tc_fd, "Killed operation was requested on the "
4784 "component reference of the MTC.");
4785 return;
4786 case SYSTEM_COMPREF:
4787 send_error_str(tc->tc_fd, "Killed operation was requested on the "
4788 "component reference of the system.");
4789 return;
4790 case ANY_COMPREF:
4791 if (tc == mtc) {
4792 boolean answer = !is_all_component_alive();
4793 send_killed_ack(mtc, answer);
4794 if (!answer) any_component_killed_requested = TRUE;
4795 } else send_error_str(tc->tc_fd, "Operation 'any component.killed' can "
4796 "only be performed on the MTC.");
4797 return;
4798 case ALL_COMPREF:
4799 if (tc == mtc) {
4800 boolean answer = !is_any_component_alive();
4801 send_killed_ack(mtc, answer);
4802 if (!answer) all_component_killed_requested = TRUE;
4803 } else send_error_str(tc->tc_fd, "Operation 'all component.killed' can "
4804 "only be performed on the MTC.");
4805 return;
4806 default:
4807 break;
4808 }
4809 // the operation refers to a specific PTC
4810 component_struct *comp = lookup_component(component_reference);
4811 if (comp == NULL) {
4812 send_error(tc->tc_fd, "The argument of killed operation is an "
4813 "invalid component reference: %d.", component_reference);
4814 return;
4815 }
4816 switch (comp->tc_state) {
4817 case TC_EXITING:
4818 case TC_EXITED:
4819 send_killed_ack(tc, TRUE);
4820 break;
4821 case TC_IDLE:
4822 case TC_CREATE:
4823 case TC_START:
4824 case TC_STOP:
4825 case TC_KILL:
4826 case TC_CONNECT:
4827 case TC_DISCONNECT:
4828 case TC_MAP:
4829 case TC_UNMAP:
4830 case TC_STOPPING:
4831 case PTC_FUNCTION:
4832 case PTC_STARTING:
4833 case PTC_STOPPED:
4834 case PTC_KILLING:
4835 case PTC_STOPPING_KILLING:
4836 send_killed_ack(tc, FALSE);
4837 add_requestor(&comp->killed_requestors, tc);
4838 break;
4839 case PTC_STALE:
4840 send_error(tc->tc_fd, "The argument of killed operation (%d) is a "
4841 "component reference that belongs to an earlier testcase.",
4842 component_reference);
4843 break;
4844 default:
4845 send_error(tc->tc_fd, "The test component that the killed operation "
4846 "refers to (%d) is in invalid state.", component_reference);
4847 }
4848}
4849
4850void MainController::process_cancel_done_ack(component_struct *tc)
4851{
4852 component component_reference = tc->text_buf->pull_int().get_val();
4853 switch (component_reference) {
4854 case NULL_COMPREF:
4855 send_error_str(tc->tc_fd, "Message CANCEL_DONE_ACK refers to the null "
4856 "component reference.");
4857 return;
4858 case MTC_COMPREF:
4859 send_error_str(tc->tc_fd, "Message CANCEL_DONE_ACK refers to the "
4860 "component reference of the MTC.");
4861 return;
4862 case SYSTEM_COMPREF:
4863 send_error_str(tc->tc_fd, "Message CANCEL_DONE_ACK refers to the "
4864 "component reference of the system.");
4865 return;
4866 case ANY_COMPREF:
4867 send_error_str(tc->tc_fd, "Message CANCEL_DONE_ACK refers to "
4868 "'any component'.");
4869 return;
4870 case ALL_COMPREF:
4871 send_error_str(tc->tc_fd, "Message CANCEL_DONE_ACK refers to "
4872 "'all component'.");
4873 return;
4874 default:
4875 break;
4876 }
4877 component_struct *started_tc = lookup_component(component_reference);
4878 if (started_tc == NULL) {
4879 send_error(tc->tc_fd, "Message CANCEL_DONE_ACK refers to an invalid "
4880 "component reference: %d.", component_reference);
4881 return;
4882 }
4883 done_cancelled(tc, started_tc);
4884 remove_requestor(&tc->cancel_done_sent_for, started_tc);
4885}
4886
4887void MainController::process_connect_req(component_struct *tc)
4888{
4889 if (!request_allowed(tc, "CONNECT_REQ")) return;
4890
4891 Text_Buf& text_buf = *tc->text_buf;
4892 component src_compref = text_buf.pull_int().get_val();
4893 char *src_port = text_buf.pull_string();
4894 component dst_compref = text_buf.pull_int().get_val();
4895 char *dst_port = text_buf.pull_string();
4896
4897 if (!valid_endpoint(src_compref, TRUE, tc, "connect") ||
4898 !valid_endpoint(dst_compref, TRUE, tc, "connect")) {
4899 delete [] src_port;
4900 delete [] dst_port;
4901 return;
4902 }
4903
4904 port_connection *conn = find_connection(src_compref, src_port, dst_compref,
4905 dst_port);
4906 if (conn == NULL) {
4907 conn = new port_connection;
4908 conn->transport_type =
4909 choose_port_connection_transport(src_compref, dst_compref);
4910 conn->head.comp_ref = src_compref;
4911 conn->head.port_name = src_port;
4912 conn->tail.comp_ref = dst_compref;
4913 conn->tail.port_name = dst_port;
4914 init_requestors(&conn->requestors, tc);
4915 add_connection(conn);
4916 // conn->head and tail is now in canonical order
4917 switch (conn->transport_type) {
4918 case TRANSPORT_LOCAL:
4919 // send an empty string instead of component name
4920 // the component should already know its own name
4921 send_connect(components[conn->head.comp_ref], conn->head.port_name,
4922 conn->tail.comp_ref, NULL, conn->tail.port_name,
4923 conn->transport_type, 0, NULL);
4924 conn->conn_state = CONN_CONNECTING;
4925 break;
4926 case TRANSPORT_UNIX_STREAM:
4927 case TRANSPORT_INET_STREAM:
4928 // conn->head will be the server side
4929 if (conn->tail.comp_ref != MTC_COMPREF &&
4930 conn->tail.comp_ref != conn->head.comp_ref) {
4931 // send the name of conn->tail
4932 send_connect_listen(components[conn->head.comp_ref],
4933 conn->head.port_name, conn->tail.comp_ref,
4934 components[conn->tail.comp_ref]->comp_name,
4935 conn->tail.port_name, conn->transport_type);
4936 } else {
4937 // send an empty string instead of the name of conn->tail if
4938 // it is known by conn->head
4939 send_connect_listen(components[conn->head.comp_ref],
4940 conn->head.port_name, conn->tail.comp_ref, NULL,
4941 conn->tail.port_name, conn->transport_type);
4942 }
4943 conn->conn_state = CONN_LISTENING;
4944 break;
4945 default:
4946 send_error(tc->tc_fd, "The port connection %d:%s - %d:%s cannot "
4947 "be established because no suitable transport mechanism is "
4948 "available on the corresponding host(s).", src_compref,
4949 src_port, dst_compref, dst_port);
4950 remove_connection(conn);
4951 return;
4952 }
4953 tc->tc_state = TC_CONNECT;
4954 status_change();
4955 } else {
4956 switch (conn->conn_state) {
4957 case CONN_LISTENING:
4958 case CONN_CONNECTING:
4959 add_requestor(&conn->requestors, tc);
4960 tc->tc_state = TC_CONNECT;
4961 status_change();
4962 break;
4963 case CONN_CONNECTED:
4964 send_connect_ack(tc);
4965 break;
4966 case CONN_DISCONNECTING:
4967 send_error(tc->tc_fd, "The port connection %d:%s - %d:%s cannot "
4968 "be established because a disconnect operation is in progress "
4969 "on it.", src_compref, src_port, dst_compref, dst_port);
4970 break;
4971 default:
4972 send_error(tc->tc_fd, "The port connection %d:%s - %d:%s cannot "
4973 "be established due to an internal error in the MC.",
4974 src_compref, src_port, dst_compref, dst_port);
4975 error("The port connection %d:%s - %d:%s is in invalid state "
4976 "when a connect operation was requested on it.", src_compref,
4977 src_port, dst_compref, dst_port);
4978 }
4979 delete [] src_port;
4980 delete [] dst_port;
4981 }
4982}
4983
4984void MainController::process_connect_listen_ack(component_struct *tc,
4985 int message_end)
4986{
4987 if (!message_expected(tc, "CONNECT_LISTEN_ACK")) return;
4988
4989 Text_Buf& text_buf = *tc->text_buf;
4990 component src_compref = tc->comp_ref;
4991 char *src_port = text_buf.pull_string();
4992 component dst_compref = text_buf.pull_int().get_val();
4993 char *dst_port = text_buf.pull_string();
4994 transport_type_enum transport_type =
4995 (transport_type_enum)text_buf.pull_int().get_val();
4996 int local_addr_begin = text_buf.get_pos();
4997 int local_addr_len = message_end - local_addr_begin;
4998 const void *local_addr_ptr = text_buf.get_data() + local_addr_begin;
4999
5000 port_connection *conn = find_connection(src_compref, src_port, dst_compref,
5001 dst_port);
5002 if (conn != NULL) {
5003 // this message must arrive in the right state
5004 // and from the server side (head)
5005 if (conn->conn_state != CONN_LISTENING ||
5006 conn->head.comp_ref != src_compref ||
5007 strcmp(conn->head.port_name, src_port)) {
5008 send_error(tc->tc_fd, "Unexpected message CONNECT_LISTEN_ACK was "
5009 "received for port connection %d:%s - %d:%s.",
5010 src_compref, src_port, dst_compref, dst_port);
5011 delete [] src_port;
5012 delete [] dst_port;
5013 return;
5014 } else if (conn->transport_type != transport_type) {
5015 send_error(tc->tc_fd, "Message CONNECT_LISTEN_ACK for port "
5016 "connection %d:%s - %d:%s contains wrong transport type: %s "
5017 "was expected instead of %s.", src_compref, src_port,
5018 dst_compref, dst_port, get_transport_name(conn->transport_type),
5019 get_transport_name(transport_type));
5020 delete [] src_port;
5021 delete [] dst_port;
5022 return;
5023 }
5024 component_struct *dst_comp = components[dst_compref];
5025 switch (dst_comp->tc_state) {
5026 case TC_IDLE:
5027 case TC_CREATE:
5028 case TC_START:
5029 case TC_STOP:
5030 case TC_KILL:
5031 case TC_CONNECT:
5032 case TC_DISCONNECT:
5033 case TC_MAP:
5034 case TC_UNMAP:
5035 case TC_STOPPING:
5036 case MTC_TESTCASE:
5037 case PTC_FUNCTION:
5038 case PTC_STARTING:
5039 case PTC_STOPPED:
5040 if (src_compref != MTC_COMPREF && src_compref != dst_compref) {
5041 // send the name of tc
5042 send_connect(dst_comp, dst_port, src_compref, tc->comp_name,
5043 src_port, transport_type, local_addr_len, local_addr_ptr);
5044 } else {
5045 // send an empty string instead of the name of tc if it is
5046 // known by dst_comp
5047 send_connect(dst_comp, dst_port, src_compref, NULL, src_port,
5048 transport_type, local_addr_len, local_addr_ptr);
5049 }
5050 conn->conn_state = CONN_CONNECTING;
5051 break;
5052 default:
5053 send_disconnect_to_server(conn);
5054 send_error_to_connect_requestors(conn, "test component %d has "
5055 "terminated during connection setup.", dst_compref);
5056 remove_connection(conn);
5057 }
5058 status_change();
5059 } else {
5060 // the connection does not exist anymore
5061 // check whether the transport type is valid
5062 switch (transport_type) {
5063 case TRANSPORT_LOCAL:
5064 send_error(tc->tc_fd, "Message CONNECT_LISTEN_ACK for port "
5065 "connection %d:%s - %d:%s cannot refer to transport type %s.",
5066 src_compref, src_port, dst_compref, dst_port,
5067 get_transport_name(transport_type));
5068 break;
5069 case TRANSPORT_INET_STREAM:
5070 case TRANSPORT_UNIX_STREAM:
5071 break;
5072 default:
5073 send_error(tc->tc_fd, "Message CONNECT_LISTEN_ACK for port "
5074 "connection %d:%s - %d:%s refers to invalid transport type %d.",
5075 src_compref, src_port, dst_compref, dst_port, transport_type);
5076 }
5077 }
5078
5079 delete [] src_port;
5080 delete [] dst_port;
5081}
5082
5083void MainController::process_connected(component_struct *tc)
5084{
5085 if (!message_expected(tc, "CONNECTED")) return;
5086
5087 Text_Buf& text_buf = *tc->text_buf;
5088 component src_compref = tc->comp_ref;
5089 char *src_port = text_buf.pull_string();
5090 component dst_compref = text_buf.pull_int().get_val();
5091 char *dst_port = text_buf.pull_string();
5092
5093 port_connection *conn = find_connection(src_compref, src_port, dst_compref,
5094 dst_port);
5095 if (conn != NULL) {
5096 // this message must arrive in the right state
5097 // and from the server side (head)
5098 if (conn->conn_state == CONN_CONNECTING &&
5099 conn->head.comp_ref == src_compref &&
5100 !strcmp(conn->head.port_name, src_port)) {
5101 send_connect_ack_to_requestors(conn);
5102 conn->conn_state = CONN_CONNECTED;
5103 status_change();
5104 } else {
5105 send_error(tc->tc_fd, "Unexpected CONNECTED message was "
5106 "received for port connection %d:%s - %d:%s.",
5107 src_compref, src_port, dst_compref, dst_port);
5108 }
5109 }
5110 // do nothing if the connection does not exist anymore
5111
5112 delete [] src_port;
5113 delete [] dst_port;
5114}
5115
5116void MainController::process_connect_error(component_struct *tc)
5117{
5118 if (!message_expected(tc, "CONNECT_ERROR")) return;
5119
5120 Text_Buf& text_buf = *tc->text_buf;
5121 component src_compref = tc->comp_ref;
5122 char *src_port = text_buf.pull_string();
5123 component dst_compref = text_buf.pull_int().get_val();
5124 char *dst_port = text_buf.pull_string();
5125 char *reason = text_buf.pull_string();
5126
5127 port_connection *conn = find_connection(src_compref, src_port, dst_compref,
5128 dst_port);
5129 if (conn != NULL) {
5130 switch (conn->conn_state) {
5131 case CONN_CONNECTING:
5132 // in this state both endpoints can report error
5133 if (conn->transport_type != TRANSPORT_LOCAL &&
5134 conn->tail.comp_ref == src_compref &&
5135 !strcmp(conn->tail.port_name, src_port)) {
5136 // shut down the server side (head) only if the error was reported
5137 // by the client side (tail)
5138 send_disconnect_to_server(conn);
5139 }
5140 break;
5141 case CONN_LISTENING:
5142 // in this state only the server side (head) can report the error
5143 if (conn->head.comp_ref == src_compref &&
5144 !strcmp(conn->head.port_name, src_port)) break;
5145 default:
5146 send_error(tc->tc_fd, "Unexpected message CONNECT_ERROR was "
5147 "received for port connection %d:%s - %d:%s.",
5148 src_compref, src_port, dst_compref, dst_port);
5149 delete [] src_port;
5150 delete [] dst_port;
5151 delete [] reason;
5152 return;
5153 }
5154 send_error_to_connect_requestors(conn, "test component %d reported "
5155 "error: %s", src_compref, reason);
5156 remove_connection(conn);
5157 status_change();
5158 }
5159 // do nothing if the connection does not exist anymore
5160
5161 delete [] src_port;
5162 delete [] dst_port;
5163 delete [] reason;
5164}
5165
5166void MainController::process_disconnect_req(component_struct *tc)
5167{
5168 if (!request_allowed(tc, "DISCONNECT_REQ")) return;
5169
5170 Text_Buf& text_buf = *tc->text_buf;
5171 component src_compref = text_buf.pull_int().get_val();
5172 char *src_port = text_buf.pull_string();
5173 component dst_compref = text_buf.pull_int().get_val();
5174 char *dst_port = text_buf.pull_string();
5175
5176 if (!valid_endpoint(src_compref, FALSE, tc, "disconnect") ||
5177 !valid_endpoint(dst_compref, FALSE, tc, "disconnect")) {
5178 delete [] src_port;
5179 delete [] dst_port;
5180 return;
5181 }
5182
5183 port_connection *conn = find_connection(src_compref, src_port, dst_compref,
5184 dst_port);
5185 if (conn != NULL) {
5186 switch (conn->conn_state) {
5187 case CONN_LISTENING:
5188 case CONN_CONNECTING:
5189 send_error(tc->tc_fd, "The port connection %d:%s - %d:%s cannot "
5190 "be destroyed because a connect operation is in progress "
5191 "on it.", src_compref, src_port, dst_compref, dst_port);
5192 break;
5193 case CONN_CONNECTED:
5194 send_disconnect(components[conn->tail.comp_ref],
5195 conn->tail.port_name, conn->head.comp_ref,
5196 conn->head.port_name);
5197 conn->conn_state = CONN_DISCONNECTING;
5198 // no break
5199 case CONN_DISCONNECTING:
5200 add_requestor(&conn->requestors, tc);
5201 tc->tc_state = TC_DISCONNECT;
5202 status_change();
5203 break;
5204 default:
5205 send_error(tc->tc_fd, "The port connection %d:%s - %d:%s cannot "
5206 "be destroyed due to an internal error in the MC.",
5207 src_compref, src_port, dst_compref, dst_port);
5208 error("The port connection %d:%s - %d:%s is in invalid state when "
5209 "a disconnect operation was requested on it.", src_compref,
5210 src_port, dst_compref, dst_port);
5211 }
5212 } else {
5213 // the connection is already terminated
5214 // send the acknowledgement immediately
5215 send_disconnect_ack(tc);
5216 }
5217
5218 delete [] src_port;
5219 delete [] dst_port;
5220}
5221
5222void MainController::process_disconnected(component_struct *tc)
5223{
5224 if (!message_expected(tc, "DISCONNECTED")) return;
5225
5226 Text_Buf& text_buf = *tc->text_buf;
5227 component src_compref = tc->comp_ref;
5228 char *src_port = text_buf.pull_string();
5229 component dst_compref = text_buf.pull_int().get_val();
5230 char *dst_port = text_buf.pull_string();
5231
5232 port_connection *conn = find_connection(src_compref, src_port, dst_compref,
5233 dst_port);
5234 if (conn != NULL) {
5235 switch (conn->conn_state) {
5236 case CONN_LISTENING:
5237 // in this state only the server side (head) can report the end of
5238 // the connection
5239 if (conn->head.comp_ref != src_compref ||
5240 strcmp(conn->head.port_name, src_port)) {
5241 send_error(tc->tc_fd, "Unexpected message DISCONNECTED was "
5242 "received for port connection %d:%s - %d:%s.",
5243 src_compref, src_port, dst_compref, dst_port);
5244 break;
5245 }
5246 // no break
5247 case CONN_CONNECTING:
5248 // in this state both ends can report the end of the connection
5249 send_error_to_connect_requestors(conn, "test component %d "
5250 "reported end of the connection during connection setup.",
5251 src_compref);
5252 remove_connection(conn);
5253 status_change();
5254 break;
5255 case CONN_CONNECTED:
5256 remove_connection(conn);
5257 status_change();
5258 break;
5259 case CONN_DISCONNECTING:
5260 send_disconnect_ack_to_requestors(conn);
5261 remove_connection(conn);
5262 status_change();
5263 break;
5264 default:
5265 error("The port connection %d:%s - %d:%s is in invalid state when "
5266 "MC was notified about its termination.", src_compref, src_port,
5267 dst_compref, dst_port);
5268 }
5269 }
5270
5271 delete [] src_port;
5272 delete [] dst_port;
5273 status_change();
5274}
5275
5276void MainController::process_map_req(component_struct *tc)
5277{
5278 if (!request_allowed(tc, "MAP_REQ")) return;
5279
5280 Text_Buf& text_buf = *tc->text_buf;
5281 component src_compref = text_buf.pull_int().get_val();
5282 char *src_port = text_buf.pull_string();
5283 char *system_port = text_buf.pull_string();
5284
5285 if (!valid_endpoint(src_compref, TRUE, tc, "map")) {
5286 delete [] src_port;
5287 delete [] system_port;
5288 return;
5289 }
5290
5291 port_connection *conn = find_connection(src_compref, src_port,
5292 SYSTEM_COMPREF, system_port);
5293 if (conn == NULL) {
5294 send_map(components[src_compref], src_port, system_port);
5295 conn = new port_connection;
5296 conn->head.comp_ref = src_compref;
5297 conn->head.port_name = src_port;
5298 conn->tail.comp_ref = SYSTEM_COMPREF;
5299 conn->tail.port_name = system_port;
5300 conn->conn_state = CONN_MAPPING;
5301 init_requestors(&conn->requestors, tc);
5302 add_connection(conn);
5303 tc->tc_state = TC_MAP;
5304 status_change();
5305 } else {
5306 switch (conn->conn_state) {
5307 case CONN_MAPPING:
5308 add_requestor(&conn->requestors, tc);
5309 tc->tc_state = TC_MAP;
5310 status_change();
5311 break;
5312 case CONN_MAPPED:
5313 send_map_ack(tc);
5314 break;
5315 case CONN_UNMAPPING:
5316 send_error(tc->tc_fd, "The port mapping %d:%s - system:%s cannot "
5317 "be established because an unmap operation is in progress "
5318 "on it.", src_compref, src_port, system_port);
5319 break;
5320 default:
5321 send_error(tc->tc_fd, "The port mapping %d:%s - system:%s is in "
5322 "invalid state.", src_compref, src_port, system_port);
5323 }
5324 delete [] src_port;
5325 delete [] system_port;
5326 }
5327}
5328
5329void MainController::process_mapped(component_struct *tc)
5330{
5331 if (!message_expected(tc, "MAPPED")) return;
5332
5333 Text_Buf& text_buf = *tc->text_buf;
5334 component src_compref = tc->comp_ref;
5335 char *src_port = text_buf.pull_string();
5336 char *system_port = text_buf.pull_string();
5337
5338 port_connection *conn = find_connection(src_compref, src_port,
5339 SYSTEM_COMPREF, system_port);
5340 if (conn == NULL) {
5341 send_error(tc->tc_fd, "The MAPPED message refers to a "
5342 "non-existent port mapping %d:%s - system:%s.",
5343 src_compref, src_port, system_port);
5344 } else if (conn->conn_state != CONN_MAPPING) {
5345 send_error(tc->tc_fd, "Unexpected MAPPED message was "
5346 "received for port mapping %d:%s - system:%s.",
5347 src_compref, src_port, system_port);
5348 } else {
5349 for (int i = 0; ; i++) {
5350 component_struct *comp = get_requestor(&conn->requestors, i);
5351 if (comp == NULL) break;
5352 if (comp->tc_state == TC_MAP) {
5353 send_map_ack(comp);
5354 if (comp == mtc) comp->tc_state = MTC_TESTCASE;
5355 else comp->tc_state = PTC_FUNCTION;
5356 }
5357 }
5358 free_requestors(&conn->requestors);
5359 conn->conn_state = CONN_MAPPED;
5360 status_change();
5361 }
5362
5363 delete [] src_port;
5364 delete [] system_port;
5365}
5366
5367void MainController::process_unmap_req(component_struct *tc)
5368{
5369 if (!request_allowed(tc, "UNMAP_REQ")) return;
5370
5371 Text_Buf& text_buf = *tc->text_buf;
5372 component src_compref = text_buf.pull_int().get_val();
5373 char *src_port = text_buf.pull_string();
5374 char *system_port = text_buf.pull_string();
5375
5376 if (!valid_endpoint(src_compref, FALSE, tc, "unmap")) {
5377 delete [] src_port;
5378 delete [] system_port;
5379 return;
5380 }
5381
5382 port_connection *conn = find_connection(src_compref, src_port,
5383 SYSTEM_COMPREF, system_port);
5384 if (conn == NULL) {
5385 send_unmap_ack(tc);
5386 } else {
5387 switch (conn->conn_state) {
5388 case CONN_MAPPED:
5389 send_unmap(components[src_compref], src_port, system_port);
5390 conn->conn_state = CONN_UNMAPPING;
5391 case CONN_UNMAPPING:
5392 add_requestor(&conn->requestors, tc);
5393 tc->tc_state = TC_UNMAP;
5394 status_change();
5395 break;
5396 case CONN_MAPPING:
5397 send_error(tc->tc_fd, "The port mapping %d:%s - system:%s cannot "
5398 "be destroyed because a map operation is in progress "
5399 "on it.", src_compref, src_port, system_port);
5400 break;
5401 default:
5402 send_error(tc->tc_fd, "The port mapping %d:%s - system:%s is in "
5403 "invalid state.", src_compref, src_port, system_port);
5404 }
5405 }
5406
5407 delete [] src_port;
5408 delete [] system_port;
5409}
5410
5411void MainController::process_unmapped(component_struct *tc)
5412{
5413 if (!message_expected(tc, "UNMAPPED")) return;
5414
5415 Text_Buf& text_buf = *tc->text_buf;
5416 component src_compref = tc->comp_ref;
5417 char *src_port = text_buf.pull_string();
5418 char *system_port = text_buf.pull_string();
5419
5420 port_connection *conn = find_connection(src_compref, src_port,
5421 SYSTEM_COMPREF, system_port);
5422 if (conn != NULL) {
5423 switch (conn->conn_state) {
5424 case CONN_MAPPING:
5425 case CONN_MAPPED:
5426 case CONN_UNMAPPING:
5427 destroy_mapping(conn);
5428 break;
5429 default:
5430 send_error(tc->tc_fd, "Unexpected UNMAPPED message was "
5431 "received for port mapping %d:%s - system:%s.",
5432 src_compref, src_port, system_port);
5433 }
5434 }
5435
5436 delete [] src_port;
5437 delete [] system_port;
5438 status_change();
5439}
5440
f08ff9ca
BB
5441void MainController::process_debug_return_value(Text_Buf& text_buf, char* log_source,
5442 int msg_end, bool from_mtc)
016a1a93
BB
5443{
5444 int return_type = text_buf.pull_int().get_val();
f08ff9ca
BB
5445 if (text_buf.get_pos() != msg_end) {
5446 timeval tv;
5447 tv.tv_sec = text_buf.pull_int().get_val();
5448 tv.tv_usec = text_buf.pull_int().get_val();
5449 char* message = text_buf.pull_string();
5450 if (return_type == DRET_DATA) {
5451 char* result = mprintf("\n%s", message);
5452 notify(&tv, log_source, TTCN_Logger::DEBUG_UNQUALIFIED, result);
5453 Free(result);
5454 }
5455 else {
5456 notify(&tv, log_source, TTCN_Logger::DEBUG_UNQUALIFIED, message);
5457 }
5458 delete [] message;
5459 }
5460 if (from_mtc) {
5461 if (return_type == DRET_SETTING_CHANGE) {
5462 switch (last_debug_command.command) {
5463 case D_SWITCH:
5464 Free(debugger_settings.on_switch);
5465 debugger_settings.on_switch = mcopystr(last_debug_command.arguments);
5466 break;
5467 case D_SET_OUTPUT: {
5468 Free(debugger_settings.output_type);
5469 Free(debugger_settings.output_file);
5470 debugger_settings.output_file = NULL;
5471 size_t args_len = mstrlen(last_debug_command.arguments);
5472 size_t start = 0;
5473 size_t end = 0;
5474 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5475 debugger_settings.output_type = mcopystrn(last_debug_command.arguments + start, end - start);
5476 if (end < args_len) {
5477 start = end;
5478 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5479 debugger_settings.output_file = mcopystrn(last_debug_command.arguments + start, end - start);
5480 }
5481 break; }
5482 case D_SET_AUTOMATIC_BREAKPOINT: {
5483 size_t args_len = mstrlen(last_debug_command.arguments);
5484 size_t start = 0;
5485 size_t end = 0;
5486 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5487 char* event_str = mcopystrn(last_debug_command.arguments + start, end - start);
5488 char** event_behavior;
5489 char** event_batch_file;
5490 if (!strcmp(event_str, "error")) {
5491 event_behavior = &debugger_settings.error_behavior;
5492 event_batch_file = &debugger_settings.error_batch_file;
5493 }
5494 else if (!strcmp(event_str, "fail")) {
5495 event_behavior = &debugger_settings.fail_behavior;
5496 event_batch_file = &debugger_settings.fail_batch_file;
5497 }
5498 else { // should never happen
5499 Free(event_str);
016a1a93 5500 break;
f08ff9ca
BB
5501 }
5502 Free(event_str);
5503 Free(*event_behavior);
5504 Free(*event_batch_file);
5505 *event_batch_file = NULL;
5506 start = end;
5507 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5508 *event_behavior = mcopystrn(last_debug_command.arguments + start, end - start);
5509 if (end < args_len) {
5510 start = end;
5511 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5512 *event_batch_file = mcopystrn(last_debug_command.arguments + start, end - start);
5513 }
5514 break; }
5515 case D_SET_GLOBAL_BATCH_FILE: {
5516 Free(debugger_settings.global_batch_state);
5517 Free(debugger_settings.global_batch_file);
5518 debugger_settings.global_batch_file = NULL;
5519 size_t args_len = mstrlen(last_debug_command.arguments);
5520 size_t start = 0;
5521 size_t end = 0;
5522 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5523 debugger_settings.global_batch_state = mcopystrn(last_debug_command.arguments + start, end - start);
5524 if (end < args_len) {
5525 start = end;
016a1a93 5526 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
f08ff9ca
BB
5527 debugger_settings.global_batch_file = mcopystrn(last_debug_command.arguments + start, end - start);
5528 }
5529 break; }
5530 case D_SET_BREAKPOINT: {
5531 size_t args_len = mstrlen(last_debug_command.arguments);
5532 size_t start = 0;
5533 size_t end = 0;
5534 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5535 char* module = mcopystrn(last_debug_command.arguments + start, end - start);
5536 start = end;
5537 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5538 char* line = mcopystrn(last_debug_command.arguments + start, end - start);
5539 char* batch_file = NULL;
5540 if (end < args_len) {
5541 start = end;
5542 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5543 batch_file = mcopystrn(last_debug_command.arguments + start, end - start);
5544 }
5545 int pos;
5546 for (pos = 0; pos < debugger_settings.nof_breakpoints; ++pos) {
5547 if (!strcmp(debugger_settings.breakpoints[pos].module, module) &&
5548 !strcmp(debugger_settings.breakpoints[pos].line, line)) {
5549 break;
016a1a93 5550 }
f08ff9ca
BB
5551 }
5552 if (pos == debugger_settings.nof_breakpoints) {
5553 // not found, add a new one
016a1a93
BB
5554 debugger_settings.breakpoints = (debugger_settings_struct::breakpoint_struct*)
5555 Realloc(debugger_settings.breakpoints, (debugger_settings.nof_breakpoints + 1) *
5556 sizeof(debugger_settings_struct::breakpoint_struct));
016a1a93 5557 ++debugger_settings.nof_breakpoints;
f08ff9ca
BB
5558 debugger_settings.breakpoints[pos].module = module;
5559 debugger_settings.breakpoints[pos].line = line;
5560 }
5561 else {
5562 Free(debugger_settings.breakpoints[pos].batch_file);
5563 Free(module);
5564 Free(line);
5565 }
5566 debugger_settings.breakpoints[pos].batch_file = batch_file;
5567 break; }
5568 case D_REMOVE_BREAKPOINT:
5569 if (!strcmp(last_debug_command.arguments, "all")) {
5570 for (int i = 0; i < debugger_settings.nof_breakpoints; ++i) {
5571 Free(debugger_settings.breakpoints[i].module);
5572 Free(debugger_settings.breakpoints[i].line);
5573 Free(debugger_settings.breakpoints[i].batch_file);
5574 }
5575 Free(debugger_settings.breakpoints);
5576 debugger_settings.breakpoints = NULL;
5577 debugger_settings.nof_breakpoints = 0;
5578 }
5579 else {
016a1a93
BB
5580 size_t args_len = mstrlen(last_debug_command.arguments);
5581 size_t start = 0;
5582 size_t end = 0;
5583 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5584 char* module = mcopystrn(last_debug_command.arguments + start, end - start);
5585 start = end;
5586 get_next_argument_loc(last_debug_command.arguments, args_len, start, end);
5587 char* line = mcopystrn(last_debug_command.arguments + start, end - start);
f08ff9ca 5588 bool all_in_module = !strcmp(line, "all");
016a1a93
BB
5589 for (int i = 0; i < debugger_settings.nof_breakpoints; ++i) {
5590 if (!strcmp(debugger_settings.breakpoints[i].module, module) &&
f08ff9ca 5591 (all_in_module || !strcmp(debugger_settings.breakpoints[i].line, line))) {
016a1a93
BB
5592 Free(debugger_settings.breakpoints[i].module);
5593 Free(debugger_settings.breakpoints[i].line);
f08ff9ca 5594 Free(debugger_settings.breakpoints[i].batch_file);
016a1a93
BB
5595 for (int j = i; j < debugger_settings.nof_breakpoints - 1; ++j) {
5596 debugger_settings.breakpoints[j] = debugger_settings.breakpoints[j + 1];
5597 }
016a1a93 5598 --debugger_settings.nof_breakpoints;
f08ff9ca
BB
5599 if (!all_in_module) {
5600 break;
5601 }
016a1a93
BB
5602 }
5603 }
f08ff9ca
BB
5604 debugger_settings.breakpoints = (debugger_settings_struct::breakpoint_struct*)
5605 Realloc(debugger_settings.breakpoints, debugger_settings.nof_breakpoints *
5606 sizeof(debugger_settings_struct::breakpoint_struct));
016a1a93
BB
5607 Free(module);
5608 Free(line);
016a1a93 5609 }
f08ff9ca
BB
5610 break;
5611 default:
5612 break;
016a1a93 5613 }
016a1a93 5614 }
f08ff9ca
BB
5615 else if (return_type == DRET_EXIT_ALL) {
5616 stop_requested = TRUE;
5617 }
016a1a93 5618 }
016a1a93
BB
5619}
5620
f08ff9ca 5621void MainController::process_debug_broadcast_req(component_struct* tc, int commandID)
016a1a93 5622{
f08ff9ca 5623 // don't send the command back to the requesting component
016a1a93 5624 if (tc != mtc) {
f08ff9ca 5625 send_debug_command(mtc->tc_fd, commandID, "");
016a1a93
BB
5626 }
5627 for (component i = tc_first_comp_ref; i < n_components; ++i) {
5628 component_struct* comp = components[i];
5629 if (tc != comp && comp->tc_state != PTC_STALE && comp->tc_state != TC_EXITED) {
f08ff9ca 5630 send_debug_command(comp->tc_fd, commandID, "");
016a1a93
BB
5631 }
5632 }
5633 debugger_active_tc = tc;
f08ff9ca
BB
5634 for (int i = 0; i < n_hosts; i++) {
5635 host_struct* host = hosts[i];
5636 if (host->hc_state != HC_DOWN) {
5637 send_debug_command(hosts[i]->hc_fd, commandID, "");
5638 }
5639 }
5640}
5641
5642void MainController::process_debug_batch(component_struct* tc)
5643{
5644 Text_Buf& text_buf = *tc->text_buf;
5645 const char* batch_file = text_buf.pull_string();
5646 unlock();
5647 ui->executeBatchFile(batch_file);
5648 lock();
5649 delete [] batch_file;
016a1a93
BB
5650}
5651
970ed795
EL
5652void MainController::process_testcase_started()
5653{
5654 if (mc_state != MC_EXECUTING_CONTROL) {
5655 send_error_str(mtc->tc_fd, "Unexpected message TESTCASE_STARTED "
5656 "was received.");
5657 return;
5658 }
5659
5660 Text_Buf& text_buf = *mtc->text_buf;
5661 text_buf.pull_qualified_name(mtc->tc_fn_name);
5662 text_buf.pull_qualified_name(mtc->comp_type);
5663 text_buf.pull_qualified_name(system->comp_type);
5664
5665 mtc->tc_state = MTC_TESTCASE;
5666 mc_state = MC_EXECUTING_TESTCASE;
5667 tc_first_comp_ref = next_comp_ref;
5668 any_component_done_requested = FALSE;
5669 any_component_done_sent = FALSE;
5670 all_component_done_requested = FALSE;
5671 any_component_killed_requested = FALSE;
5672 all_component_killed_requested = FALSE;
5673
5674 status_change();
5675}
5676
5677void MainController::process_testcase_finished()
5678{
5679 if (mc_state != MC_EXECUTING_TESTCASE) {
5680 send_error_str(mtc->tc_fd, "Unexpected message TESTCASE_FINISHED "
5681 "was received.");
5682 return;
5683 }
5684
5685 boolean ready_to_finish = kill_all_components(TRUE);
5686
5687 mc_state = MC_TERMINATING_TESTCASE;
5688 mtc->tc_state = MTC_TERMINATING_TESTCASE;
5689 mtc->local_verdict = (verdicttype)mtc->text_buf->pull_int().get_val();
5690 mtc->verdict_reason = mtc->text_buf->pull_string();
5691 mtc->stop_requested = FALSE;
5692 if (mtc->kill_timer != NULL) {
5693 cancel_timer(mtc->kill_timer);
5694 mtc->kill_timer = NULL;
5695 }
5696 any_component_done_requested = FALSE;
5697 any_component_done_sent = FALSE;
5698 all_component_done_requested = FALSE;
5699 any_component_killed_requested = FALSE;
5700 all_component_killed_requested = FALSE;
5701
5702 if (ready_to_finish) finish_testcase();
5703
5704 status_change();
5705}
5706
5707void MainController::process_mtc_ready()
5708{
5709 if (mc_state != MC_EXECUTING_CONTROL || mtc->tc_state != MTC_CONTROLPART) {
5710 send_error_str(mtc->tc_fd, "Unexpected message MTC_READY was "
5711 "received.");
5712 return;
5713 }
5714 mc_state = MC_READY;
5715 mtc->tc_state = TC_IDLE;
5716 mtc->stop_requested = FALSE;
5717 if (mtc->kill_timer != NULL) {
5718 cancel_timer(mtc->kill_timer);
5719 mtc->kill_timer = NULL;
5720 }
5721 stop_requested = FALSE;
5722 notify("Test execution finished.");
5723 status_change();
5724}
5725
5726void MainController::process_stopped(component_struct *tc, int message_end)
5727{
5728 switch (tc->tc_state) {
5729 case TC_STOPPING:
5730 case PTC_FUNCTION:
5731 case PTC_STOPPING_KILLING:
5732 // only alive PTCs are allowed to send STOPPED
5733 if (tc->is_alive) break;
5734 default:
5735 send_error_str(tc->tc_fd, "Unexpected message STOPPED was received.");
5736 return;
5737 }
5738 Text_Buf& text_buf = *tc->text_buf;
5739 delete [] tc->return_type;
5740 tc->return_type = text_buf.pull_string();
5741 tc->return_value_len = message_end - text_buf.get_pos();
5742 Free(tc->return_value);
5743 tc->return_value = Malloc(tc->return_value_len);
5744 text_buf.pull_raw(tc->return_value_len, tc->return_value);
5745 free_qualified_name(&tc->tc_fn_name);
5746 component_stopped(tc);
5747 status_change();
5748}
5749
5750void MainController::process_stopped_killed(component_struct *tc,
5751 int message_end)
5752{
5753 switch (tc->tc_state) {
5754 case TC_CREATE:
5755 case TC_START:
5756 case TC_STOP:
5757 case TC_KILL:
5758 case TC_CONNECT:
5759 case TC_DISCONNECT:
5760 case TC_MAP:
5761 case TC_UNMAP:
5762 case TC_STOPPING:
5763 case PTC_FUNCTION:
5764 case PTC_STOPPING_KILLING:
5765 break;
5766 default:
5767 send_error_str(tc->tc_fd, "Unexpected message STOPPED_KILLED was "
5768 "received.");
5769 // also notify the user because the above message may get lost
5770 notify("Unexpected message STOPPED_KILLED was received from PTC %d.",
5771 tc->comp_ref);
5772 return;
5773 }
5774 Text_Buf& text_buf = *tc->text_buf;
5775 tc->local_verdict = (verdicttype)text_buf.pull_int().get_val();
5776 tc->verdict_reason = text_buf.pull_string();
5777 tc->return_type = text_buf.pull_string();
5778 tc->return_value_len = message_end - text_buf.get_pos();
5779 tc->return_value = Malloc(tc->return_value_len);
5780 text_buf.pull_raw(tc->return_value_len, tc->return_value);
5781 // start a guard timer to detect whether the control connection is closed
5782 // in time
5783 if (tc->tc_state != PTC_STOPPING_KILLING) start_kill_timer(tc);
5784 component_terminated(tc);
5785 status_change();
5786}
5787
5788void MainController::process_killed(component_struct *tc)
5789{
5790 switch (tc->tc_state) {
5791 case TC_IDLE:
5792 case PTC_STOPPED:
5793 case PTC_KILLING:
5794 break;
5795 default:
5796 send_error_str(tc->tc_fd, "Unexpected message KILLED was received.");
5797 // also notify the user because the above message may get lost
5798 notify("Unexpected message KILLED was received from PTC %d.",
5799 tc->comp_ref);
5800 return;
5801 }
5802 tc->local_verdict = (verdicttype)tc->text_buf->pull_int().get_val();
5803 tc->verdict_reason = tc->text_buf->pull_string();
5804 // start a guard timer to detect whether the control connection is closed
5805 // in time
5806 if (tc->tc_state != PTC_KILLING) start_kill_timer(tc);
5807 component_terminated(tc);
5808 status_change();
5809}
5810
5811void MainController::initialize(UserInterface& par_ui, int par_max_ptcs)
5812{
5813 ui = &par_ui;
5814
5815 max_ptcs = par_max_ptcs;
5816
5817 mc_state = MC_INACTIVE;
5818
5819 struct utsname buf;
5820 if (uname(&buf) < 0) fatal_error("MainController::initialize: "
5821 "uname() system call failed.");
5822 mc_hostname = mprintf("MC@%s", buf.nodename);
5823
5824 server_fd = -1;
5825
5826 if (pthread_mutex_init(&mutex, NULL))
5827 fatal_error("MainController::initialize: pthread_mutex_init failed.");
5828
5829#ifdef USE_EPOLL
5830 epoll_events = NULL;
5831 epfd = -1;
5832#else
5833 nfds = 0;
5834 ufds = NULL;
5835 new_nfds = 0;
5836 new_ufds = NULL;
5837 pollfds_modified = FALSE;
5838#endif
5839
5840 fd_table_size = 0;
5841 fd_table = NULL;
5842
5843 unknown_head = NULL;
5844 unknown_tail = NULL;
5845
5846 n_host_groups = 0;
5847 host_groups = NULL;
5848 init_string_set(&assigned_components);
5849 all_components_assigned = FALSE;
5850
5851 n_hosts = 0;
5852 hosts = NULL;
5853 config_str = NULL;
016a1a93
BB
5854
5855 debugger_settings.on_switch = NULL;
5856 debugger_settings.output_type = NULL;
5857 debugger_settings.output_file = NULL;
5858 debugger_settings.error_behavior = NULL;
f08ff9ca 5859 debugger_settings.error_batch_file = NULL;
016a1a93 5860 debugger_settings.fail_behavior = NULL;
f08ff9ca
BB
5861 debugger_settings.fail_batch_file = NULL;
5862 debugger_settings.global_batch_state = NULL;
5863 debugger_settings.global_batch_file = NULL;
016a1a93
BB
5864 debugger_settings.nof_breakpoints = 0;
5865 debugger_settings.breakpoints = NULL;
5866 last_debug_command.command = D_ERROR;
5867 last_debug_command.arguments = NULL;
970ed795
EL
5868
5869 version_known = FALSE;
5870 n_modules = 0;
5871 modules = NULL;
5872
5873 n_components = 0;
5874 n_active_ptcs = 0;
5875 components = NULL;
5876 mtc = NULL;
5877 system = NULL;
016a1a93 5878 debugger_active_tc = NULL;
970ed795
EL
5879 next_comp_ref = FIRST_PTC_COMPREF;
5880
5881 stop_after_tc = FALSE;
5882 stop_requested = FALSE;
5883
5884 kill_timer = 10.0;
5885
5886 timer_head = NULL;
5887 timer_tail = NULL;
5888
5889 pipe_fd[0] = -1;
5890 pipe_fd[1] = -1;
5891 wakeup_reason = REASON_NOTHING;
5892
5893 register_termination_handlers();
5894}
5895
5896void MainController::terminate()
5897{
5898 clean_up();
5899 destroy_host_groups();
5900 Free(mc_hostname);
5901 pthread_mutex_destroy(&mutex);
5902}
5903
5904void MainController::add_host(const char *group_name, const char *host_name)
5905{
5906 lock();
5907 if (mc_state != MC_INACTIVE) {
5908 error("MainController::add_host: called in wrong state.");
5909 unlock();
5910 return;
5911 }
5912 host_group_struct *group = add_host_group(group_name);
5913 if (host_name != NULL) {
5914 if (group->has_all_hosts) error("Redundant member `%s' was ignored in "
5915 "host group `%s'. All hosts (`*') are already the members of the "
5916 "group.", host_name, group_name);
5917 else {
5918 if (set_has_string(&group->host_members, host_name)) {
5919 error("Duplicate member `%s' was ignored in host group "
5920 "`%s'.", host_name, group_name);
5921 } else add_string_to_set(&group->host_members, host_name);
5922 }
5923 } else {
5924 if (group->has_all_hosts) error("Duplicate member `*' was ignored in "
5925 "host group `%s'.", group_name);
5926 else {
5927 for (int i = 0; ; i++) {
5928 const char *group_member =
5929 get_string_from_set(&group->host_members, i);
5930 if (group_member == NULL) break;
5931 error("Redundant member `%s' was ignored in host group `%s'. "
5932 "All hosts (`*') are already the members of the group.",
5933 group_member, group_name);
5934 }
5935 free_string_set(&group->host_members);
5936 group->has_all_hosts = TRUE;
5937 }
5938 }
5939 unlock();
5940}
5941
5942void MainController::assign_component(const char *host_or_group,
5943 const char *component_id)
5944{
5945 lock();
5946 if (mc_state != MC_INACTIVE) {
5947 error("MainController::assign_component: called in wrong state.");
5948 unlock();
5949 return;
5950 }
5951 host_group_struct *group = add_host_group(host_or_group);
5952 if (component_id == NULL) {
5953 if (all_components_assigned) {
5954 for (int i = 0; i < n_host_groups; i++) {
5955 if (host_groups[i].has_all_components) {
5956 error("Duplicate assignment of all components (*) to host "
5957 "group `%s'. Previous assignment to group `%s' is "
5958 "ignored.", host_or_group, host_groups[i].group_name);
5959 host_groups[i].has_all_components = FALSE;
5960 }
5961 }
5962 } else all_components_assigned = TRUE;
5963 group->has_all_components = TRUE;
5964 } else {
5965 if (set_has_string(&assigned_components, component_id)) {
5966 for (int i = 0; i < n_host_groups; i++) {
5967 if (set_has_string(&host_groups[i].assigned_components,
5968 component_id)) {
5969 error("Duplicate assignment of component `%s' to host "
5970 "group `%s'. Previous assignment to group `%s' is "
5971 "ignored.", component_id, host_or_group,
5972 host_groups[i].group_name);
5973 remove_string_from_set(&host_groups[i].assigned_components,
5974 component_id);
5975 }
5976 }
5977 } else add_string_to_set(&assigned_components, component_id);
5978 add_string_to_set(&group->assigned_components, component_id);
5979 }
5980 unlock();
5981}
5982
5983void MainController::destroy_host_groups()
5984{
5985 lock();
5986 if (mc_state != MC_INACTIVE)
5987 error("MainController::destroy_host_groups: called in wrong state.");
5988 else {
5989 for (int i = 0; i < n_host_groups; i++) {
5990 host_group_struct *group = host_groups + i;
5991 Free(group->group_name);
5992 free_string_set(&group->host_members);
5993 free_string_set(&group->assigned_components);
5994 }
5995 Free(host_groups);
5996 n_host_groups = 0;
5997 host_groups = NULL;
5998 free_string_set(&assigned_components);
5999 all_components_assigned = FALSE;
6000 }
6001 unlock();
6002}
6003
6004void MainController::set_kill_timer(double timer_val)
6005{
6006 lock();
6007 if (mc_state != MC_INACTIVE)
6008 error("MainController::set_kill_timer: called in wrong state.");
6009 else if (timer_val < 0.0)
6010 error("MainController::set_kill_timer: setting a negative kill timer "
6011 "value.");
6012 else kill_timer = timer_val;
6013 unlock();
6014}
6015
6016unsigned short MainController::start_session(const char *local_address,
6017 unsigned short tcp_port, bool unix_sockets_enabled)
6018{
6019 lock();
6020
6021 if (mc_state != MC_INACTIVE) {
6022 error("MainController::start_session: called in wrong state.");
6023 unlock();
6024 return 0;
6025 }
6026
6027#ifdef USE_EPOLL
6028 epoll_events = (epoll_event *)Malloc(EPOLL_MAX_EVENTS * sizeof(*epoll_events));
6029 epfd = epoll_create(EPOLL_SIZE_HINT);
6030 if (epfd < 0) {
6031 error("System call epoll_create failed: %s", strerror(errno));
6032 clean_up();
6033 unlock();
6034 return 0;
6035 }
6036 set_close_on_exec(epfd);
6037#endif //USE_EPOLL
6038
6039 nh.set_family(local_address);
6040 server_fd = nh.socket();
6041 if (server_fd < 0) {
6042 error("Server socket creation failed: %s", strerror(errno));
6043 clean_up();
6044 unlock();
6045 return 0;
6046 }
6047
6048 const int on = 1;
6049 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on,
6050 sizeof(on))) {
6051 error("System call setsockopt (SO_REUSEADDR) failed on server socket: "
6052 "%s", strerror(errno));
6053 clean_up();
6054 unlock();
6055 return 0;
6056 }
6057
6058 if (setsockopt(server_fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&on,
6059 sizeof(on))) {
6060 error("System call setsockopt (TCP_NODELAY) failed on server socket: "
6061 "%s", strerror(errno));
6062 clean_up();
6063 unlock();
6064 return 0;
6065 }
6066
6067 IPAddress *localaddr = IPAddress::create_addr(nh.get_family());
6068 if (localaddr) localaddr->set_port(tcp_port);
6069
6070 if (local_address != NULL) {
6071 if (!localaddr || !localaddr->set_addr(local_address, tcp_port)) {
6072 error("Cannot resolve host name `%s' to a local IP address: "
6073 "Host name lookup failure", local_address);
6074 clean_up();
6075 unlock();
6076 delete localaddr;
6077 return 0;
6078 }
6079 }
6080
6081 if (bind(server_fd, localaddr->get_addr(), localaddr->get_addr_len())) {
6082 if (local_address != NULL) {
6083 if (tcp_port != 0) error("Binding server socket to IP address "
6084 "%s and TCP port %d failed: %s", localaddr->get_addr_str(),
6085 tcp_port, strerror(errno));
6086 else error("Binding server socket to IP address %s failed: %s",
6087 localaddr->get_addr_str(), strerror(errno));
6088 } else {
6089 if (tcp_port != 0) error("Binding server socket to TCP port %d "
6090 "failed: %s", tcp_port, strerror(errno));
6091 else error("Binding server socket to an ephemeral TCP port "
6092 "failed: %s", strerror(errno));
6093 }
6094 clean_up();
6095 unlock();
6096 delete localaddr;
6097 return 0;
6098 }
6099
6100 if (listen(server_fd, 10)) {
6101 if (local_address != NULL) {
6102 if (tcp_port != 0) error("Listening on IP address %s and TCP port "
6103 "%d failed: %s", localaddr->get_addr_str(), tcp_port,
6104 strerror(errno));
6105 else error("Listening on IP address %s failed: %s",
6106 localaddr->get_addr_str(), strerror(errno));
6107 } else {
6108 if (tcp_port != 0) error("Listening on TCP port %d failed: %s",
6109 tcp_port, strerror(errno));
6110 else error("Listening on an ephemeral TCP port failed: %s",
6111 strerror(errno));
6112 }
6113 clean_up();
6114 unlock();
6115 delete localaddr;
6116 return 0;
6117 }
6118
6119 if (localaddr->getsockname(server_fd)) {
6120 error("System call getsockname() failed on server socket: %s",
6121 strerror(errno));
6122 clean_up();
6123 unlock();
6124 delete localaddr;
6125 return 0;
6126 }
6127 tcp_port = localaddr->get_port();
6128
6129 set_close_on_exec(server_fd);
6130
6131 // Trying to open a unix socket for local communication
6132 if (unix_sockets_enabled) {
6133
6134 server_fd_unix = socket(PF_UNIX, SOCK_STREAM, 0);
6135 if (server_fd_unix < 0) {
6136 notify("Unix server socket creation failed: %s", strerror(errno));
6137 errno = 0;
6138 goto unix_end;
6139 }
6140
6141 struct sockaddr_un localaddr_unix;
6142 memset(&localaddr_unix, 0, sizeof(localaddr_unix));
6143 localaddr_unix.sun_family = AF_UNIX;
6144 snprintf(localaddr_unix.sun_path, sizeof(localaddr_unix.sun_path),
6145 "/tmp/ttcn3-mctr-%u", tcp_port);
6146 if (unlink(localaddr_unix.sun_path))
6147 errno = 0; // silently ignore, error handling below
6148
6149 if (bind(server_fd_unix, (struct sockaddr *)&localaddr_unix,
6150 sizeof(localaddr_unix)) != 0) {
6151 if (errno == EADDRINUSE) {
6152 // the temporary file name is already used by someone else
6153 close(server_fd_unix);
6154 notify("Could not create Unix server socket: '%s' is already existed "
6155 "and cannot be removed.", localaddr_unix.sun_path);
6156 errno = 0;
6157 goto unix_end;
6158 } else {
6159 close(server_fd_unix);
6160 notify("Binding of Unix server socket to pathname %s failed. (%s)",
6161 localaddr_unix.sun_path, strerror(errno));
6162 errno = 0;
6163 goto unix_end;
6164 }
6165 }
6166
6167 if (listen(server_fd_unix, 10)) {
6168 notify("Could not listen on the given socket. Unix domain socket "
6169 "communication will not be used.");
6170 close(server_fd_unix);
6171 errno = 0;
6172 goto unix_end;
6173 }
6174
6175 set_close_on_exec(server_fd_unix);
6176
6177 add_fd_to_table(server_fd_unix);
6178 fd_table[server_fd_unix].fd_type = FD_SERVER;
6179 add_poll_fd(server_fd_unix);
6180
6181 notify("Unix server socket created successfully.");
6182 }
6183 unix_end:
6184
6185 if (pipe(pipe_fd) < 0) {
6186 error("System call pipe failed: %s", strerror(errno));
6187 clean_up();
6188 unlock();
6189 delete localaddr;
6190 return 0;
6191 }
6192 set_close_on_exec(pipe_fd[0]);
6193 set_close_on_exec(pipe_fd[1]);
6194
6195 wakeup_reason = REASON_NOTHING;
6196
6197 mc_state = MC_LISTENING;
6198
6199 add_fd_to_table(server_fd);
6200 fd_table[server_fd].fd_type = FD_SERVER;
6201 add_poll_fd(server_fd);
6202 server_fd_disabled = FALSE;
6203
6204 add_fd_to_table(pipe_fd[0]);
6205 fd_table[pipe_fd[0]].fd_type = FD_PIPE;
6206 add_poll_fd(pipe_fd[0]);
6207
6208 pthread_attr_t attr;
6209 if (pthread_attr_init(&attr))
6210 fatal_error("MainController::start_session: pthread_attr_init failed.");
6211 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
6212 fatal_error("MainController::start_session: "
6213 "pthread_attr_setdetachstate failed.");
6214
6215 pthread_t thread;
6216 if (pthread_create(&thread, &attr, thread_main, NULL))
6217 fatal_error("MainController::start_session: pthread_create failed.");
6218
6219 if (pthread_attr_destroy(&attr))
6220 fatal_error("MainController::start_session: pthread_attr_destroy "
6221 "failed.");
6222 if (local_address != NULL)
6223 notify("Listening on IP address %s and TCP port %d.", localaddr->get_addr_str(), tcp_port);
6224 else notify("Listening on TCP port %d.", tcp_port);
6225 delete localaddr;
6226 status_change();
6227 unlock();
6228 return tcp_port;
6229}
6230
6231void MainController::shutdown_session()
6232{
6233 lock();
6234 switch (mc_state) {
6235 case MC_INACTIVE:
6236 status_change();
6237 break;
6238 case MC_SHUTDOWN:
6239 break;
6240 case MC_LISTENING:
6241 case MC_LISTENING_CONFIGURED:
6242 case MC_HC_CONNECTED:
6243 case MC_ACTIVE:
6244 notify("Shutting down session.");
6245 wakeup_thread(REASON_SHUTDOWN);
6246 break;
6247 default:
6248 error("MainController::shutdown_session: called in wrong state.");
6249 }
6250 unlock();
6251}
6252
6253char *MainController::config_str;
6254
6255void MainController::configure(const char *config_file)
6256{
6257 lock();
6258 switch (mc_state) {
6259 case MC_HC_CONNECTED:
6260 case MC_ACTIVE:
6261 mc_state = MC_CONFIGURING;
6262 break;
6263 case MC_LISTENING:
6264 case MC_LISTENING_CONFIGURED:
6265 mc_state = MC_LISTENING_CONFIGURED;
6266 break;
6267 default:
6268 error("MainController::configure: called in wrong state.");
6269 unlock();
6270 return;
6271 }
6272 Free(config_str);
6273 config_str = mcopystr(config_file);
6274 if(mc_state == MC_CONFIGURING) {
6275 notify("Downloading configuration file to all HCs.");
6276 for (int i = 0; i < n_hosts; i++) configure_host(hosts[i], FALSE);
6277 }
6278 status_change();
6279 unlock();
6280}
6281
6282void MainController::create_mtc(int host_index)
6283{
6284 lock();
6285 if (mc_state != MC_ACTIVE) {
6286 error("MainController::create_mtc: called in wrong state.");
6287 unlock();
6288 return;
6289 }
6290 if (host_index < 0 || host_index >= n_hosts) {
6291 error("MainController::create_mtc: host index (%d) is out of range.",
6292 host_index);
6293 unlock();
6294 return;
6295 }
6296 host_struct *host = hosts[host_index];
6297 switch (host->hc_state) {
6298 case HC_OVERLOADED:
6299 notify("HC on host %s reported overload. Trying to create MTC there "
6300 "anyway.", host->hostname);
6301 case HC_ACTIVE:
6302 break;
6303 default:
6304 error("MTC cannot be created on %s: HC is not active.", host->hostname);
6305 unlock();
6306 return;
6307 }
6308 notify("Creating MTC on host %s.", host->hostname);
6309 send_create_mtc(host);
6310
6311 mtc = new component_struct;
6312 mtc->comp_ref = MTC_COMPREF;
6313 init_qualified_name(&mtc->comp_type);
6314 mtc->comp_name = new char[4];
6315 strcpy(mtc->comp_name, "MTC");
6316 mtc->tc_state = TC_INITIAL;
6317 mtc->local_verdict = NONE;
6318 mtc->verdict_reason = NULL;
6319 mtc->tc_fd = -1;
6320 mtc->text_buf = NULL;
6321 init_qualified_name(&mtc->tc_fn_name);
6322 mtc->return_type = NULL;
6323 mtc->return_value_len = 0;
6324 mtc->return_value = NULL;
6325 mtc->is_alive = FALSE;
6326 mtc->stop_requested = FALSE;
6327 mtc->process_killed = FALSE;
6328 mtc->initial.create_requestor = NULL;
6329 mtc->initial.location_str = NULL;
6330 init_requestors(&mtc->done_requestors, NULL);
6331 init_requestors(&mtc->killed_requestors, NULL);
6332 init_requestors(&mtc->cancel_done_sent_for, NULL);
6333 mtc->kill_timer = NULL;
6334 init_connections(mtc);
6335 add_component(mtc);
6336 add_component_to_host(host, mtc);
6337 host->n_active_components++;
6338
6339 system = new component_struct;
6340 system->comp_ref = SYSTEM_COMPREF;
6341 init_qualified_name(&system->comp_type);
6342 system->comp_name = new char[7];
6343 strcpy(system->comp_name, "SYSTEM");
6344 system->log_source = NULL;
6345 system->comp_location = NULL;
6346 system->tc_state = TC_SYSTEM;
6347 system->local_verdict = NONE;
6348 system->verdict_reason = NULL;
6349 system->tc_fd = -1;
6350 system->text_buf = NULL;
6351 init_qualified_name(&system->tc_fn_name);
6352 system->return_type = NULL;
6353 system->return_value_len = 0;
6354 system->return_value = NULL;
6355 system->is_alive = FALSE;
6356 system->stop_requested = FALSE;
6357 system->process_killed = FALSE;
6358 init_requestors(&system->done_requestors, NULL);
6359 init_requestors(&system->killed_requestors, NULL);
6360 init_requestors(&system->cancel_done_sent_for, NULL);
6361 system->kill_timer = NULL;
6362 init_connections(system);
6363 add_component(system);
6364
6365 mc_state = MC_CREATING_MTC;
6366 status_change();
6367 unlock();
6368}
6369
6370void MainController::exit_mtc()
6371{
6372 lock();
6373 if (mc_state != MC_READY) {
6374 error("MainController::exit_mtc: called in wrong state.");
6375 unlock();
6376 return;
6377 }
6378 notify("Terminating MTC.");
6379 send_exit_mtc();
6380 mtc->tc_state = TC_EXITING;
6381 mtc->comp_location->n_active_components--;
6382 mc_state = MC_TERMINATING_MTC;
6383 start_kill_timer(mtc);
6384 status_change();
6385 unlock();
6386}
6387
6388void MainController::execute_control(const char *module_name)
6389{
6390 lock();
6391 if (mc_state != MC_READY) {
6392 error("MainController::execute_control: called in wrong state.");
6393 unlock();
6394 return;
6395 }
6396 send_execute_control(module_name);
6397 mtc->tc_state = MTC_CONTROLPART;
6398 mc_state = MC_EXECUTING_CONTROL;
6399 status_change();
6400 unlock();
6401}
6402
6403void MainController::execute_testcase(const char *module_name,
6404 const char *testcase_name)
6405{
6406 lock();
6407 if (mc_state != MC_READY) {
6408 error("MainController::execute_testcase: called in wrong state.");
6409 unlock();
6410 return;
6411 }
6412 send_execute_testcase(module_name, testcase_name);
6413 mtc->tc_state = MTC_CONTROLPART;
6414 mc_state = MC_EXECUTING_CONTROL;
6415 status_change();
6416 unlock();
6417}
6418
6419void MainController::stop_after_testcase(boolean new_state)
6420{
6421 lock();
6422 stop_after_tc = new_state;
6423 if (mc_state == MC_PAUSED && !stop_after_tc) {
6424 unlock();
6425 continue_testcase();
6426 } else unlock();
6427}
6428
6429void MainController::continue_testcase()
6430{
6431 lock();
6432 if (mc_state == MC_PAUSED) {
6433 notify("Resuming execution.");
6434 send_continue();
6435 mtc->tc_state = MTC_CONTROLPART;
6436 mc_state = MC_EXECUTING_CONTROL;
6437 status_change();
6438 } else error("MainController::continue_testcase: called in wrong state.");
6439 unlock();
6440}
6441
6442void MainController::stop_execution()
6443{
6444 lock();
6445 if (!stop_requested) {
6446 notify("Stopping execution.");
6447 switch (mc_state) {
6448 case MC_PAUSED:
6449 mc_state = MC_EXECUTING_CONTROL;
6450 mtc->tc_state = MTC_CONTROLPART;
6451 case MC_EXECUTING_CONTROL:
6452 send_stop(mtc);
6453 mtc->stop_requested = TRUE;
6454 start_kill_timer(mtc);
6455 wakeup_thread(REASON_MTC_KILL_TIMER);
6456 break;
6457 case MC_EXECUTING_TESTCASE:
6458 if (!mtc->stop_requested) {
6459 send_stop(mtc);
6460 kill_all_components(TRUE);
6461 mtc->stop_requested = TRUE;
6462 start_kill_timer(mtc);
6463 wakeup_thread(REASON_MTC_KILL_TIMER);
6464 }
6465 case MC_TERMINATING_TESTCASE:
6466 // MTC will be stopped later in finish_testcase()
6467 case MC_READY:
6468 // do nothing
6469 break;
6470 default:
6471 error("MainController::stop_execution: called in wrong state.");
6472 unlock();
6473 return;
6474 }
6475 stop_requested = TRUE;
6476 status_change();
6477 } else notify("Stop was already requested. Operation ignored.");
6478 unlock();
6479}
6480
016a1a93
BB
6481void MainController::debug_command(int commandID, char* arguments)
6482{
6483 lock();
6484 if (mtc != NULL) {
6485 switch (commandID) {
6486 case D_SET_COMPONENT: // handled by the MC
6487 if (!strcmp(arguments, "mtc")) {
6488 notify("Debugger %sset to print data from the MTC.",
6489 debugger_active_tc == mtc ? "was already " : "");
6490 debugger_active_tc = mtc;
6491 }
6492 else {
6493 size_t len = strlen(arguments);
6494 for (size_t i = 0; i < len; ++i) {
6495 if (arguments[i] < '0' || arguments[i] > '9') {
6496 notify("Argument 1 is invalid. Expected 'mtc' or integer value "
6497 "(component reference).");
6498 unlock();
6499 return;
6500 }
6501 }
6502 const component_struct* tc = lookup_component(strtol(arguments, NULL, 10));
6503 if (tc == NULL || tc->tc_state == PTC_STALE || tc->tc_state == TC_EXITED) {
6504 notify("Invalid component reference %s.", arguments);
6505 }
6506 else {
6507 notify("Debugger %sset to print data from PTC %s%s%d%s.",
6508 debugger_active_tc == tc ? "was already " : "",
6509 tc->comp_name != NULL ? tc->comp_name : "",
6510 tc->comp_name != NULL ? "(" : "", tc->comp_ref,
6511 tc->comp_name != NULL ? ")" : "");
6512 debugger_active_tc = tc;
6513 }
6514 }
6515 break;
6516 case D_PRINT_CALL_STACK:
6517 case D_SET_STACK_LEVEL:
6518 case D_LIST_VARIABLES:
6519 case D_PRINT_VARIABLE:
6520 case D_OVERWRITE_VARIABLE:
6521 case D_PRINT_SNAPSHOTS:
6522 case D_STEP_OVER:
6523 case D_STEP_INTO:
6524 case D_STEP_OUT:
016a1a93
BB
6525 // it's a data printing or stepping command, needs to be sent to the
6526 // active component
f08ff9ca
BB
6527 if (debugger_active_tc == NULL ||
6528 debugger_active_tc->tc_state == PTC_STALE ||
6529 debugger_active_tc->tc_state == TC_EXITED) {
6530 // set the MTC as active in the beginning or if the active PTC has
6531 // finished executing
016a1a93
BB
6532 debugger_active_tc = mtc;
6533 }
6534 send_debug_command(debugger_active_tc->tc_fd, commandID, arguments);
6535 break;
6536 case D_SWITCH:
6537 case D_SET_OUTPUT:
f08ff9ca
BB
6538 case D_SET_AUTOMATIC_BREAKPOINT:
6539 case D_SET_GLOBAL_BATCH_FILE:
6540 case D_SET_BREAKPOINT:
016a1a93 6541 case D_REMOVE_BREAKPOINT:
f08ff9ca
BB
6542 // it's a global setting, store it, the next MSG_DEBUG_RETURN_VALUE message
6543 // might need it
016a1a93
BB
6544 last_debug_command.command = commandID;
6545 Free(last_debug_command.arguments);
6546 last_debug_command.arguments = mcopystr(arguments);
f08ff9ca
BB
6547 // no break
6548 case D_RUN_TO_CURSOR:
016a1a93
BB
6549 case D_HALT:
6550 case D_CONTINUE:
6551 case D_EXIT:
f08ff9ca
BB
6552 // it's a global setting, a 'run to' command or a command related to the
6553 // halted state, needs to be sent to all HCs and TCs
016a1a93
BB
6554 send_debug_command(mtc->tc_fd, commandID, arguments);
6555 for (component i = FIRST_PTC_COMPREF; i < n_components; ++i) {
f08ff9ca 6556 component_struct* comp = components[i];
016a1a93
BB
6557 if (comp != NULL && comp->tc_state != PTC_STALE && comp->tc_state != TC_EXITED) {
6558 send_debug_command(comp->tc_fd, commandID, arguments);
6559 }
6560 }
f08ff9ca
BB
6561 for (int i = 0; i < n_hosts; i++) {
6562 host_struct* host = hosts[i];
6563 if (host->hc_state != HC_DOWN) {
6564 send_debug_command(host->hc_fd, commandID, arguments);
6565 }
6566 }
016a1a93
BB
6567 break;
6568 default:
6569 break;
6570 }
6571 }
6572 else {
6573 notify("Cannot execute debug commands before the MTC is created.");
6574 }
016a1a93
BB
6575 unlock();
6576}
6577
970ed795
EL
6578mc_state_enum MainController::get_state()
6579{
6580 lock();
6581 mc_state_enum ret_val = mc_state;
6582 unlock();
6583 return ret_val;
6584}
6585
6586boolean MainController::get_stop_after_testcase()
6587{
6588 lock();
6589 boolean ret_val = stop_after_tc;
6590 unlock();
6591 return ret_val;
6592}
6593
6594int MainController::get_nof_hosts()
6595{
6596 lock();
6597 int ret_val = n_hosts;
6598 unlock();
6599 return ret_val;
6600}
6601
6602host_struct *MainController::get_host_data(int host_index)
6603{
6604 lock();
6605 if (host_index >= 0 && host_index < n_hosts) return hosts[host_index];
6606 else return NULL;
6607}
6608
6609component_struct *MainController::get_component_data(int component_reference)
6610{
6611 lock();
6612 return lookup_component(component_reference);
6613}
6614
6615void MainController::release_data()
6616{
6617 unlock();
6618}
6619
6620const char *MainController::get_mc_state_name(mc_state_enum state)
6621{
6622 switch (state) {
6623 case MC_INACTIVE:
6624 return "inactive";
6625 case MC_LISTENING:
6626 return "listening";
6627 case MC_LISTENING_CONFIGURED:
6628 return "listening (configured)";
6629 case MC_HC_CONNECTED:
6630 return "HC connected";
6631 case MC_CONFIGURING:
6632 return "configuring...";
6633 case MC_ACTIVE:
6634 return "active";
6635 case MC_CREATING_MTC:
6636 return "creating MTC...";
6637 case MC_TERMINATING_MTC:
6638 return "terminating MTC...";
6639 case MC_READY:
6640 return "ready";
6641 case MC_EXECUTING_CONTROL:
6642 return "executing control part";
6643 case MC_EXECUTING_TESTCASE:
6644 return "executing testcase";
6645 case MC_TERMINATING_TESTCASE:
6646 return "terminating testcase...";
6647 case MC_PAUSED:
6648 return "paused after testcase";
6649 case MC_SHUTDOWN:
6650 return "shutting down...";
6651 default:
6652 return "unknown/transient";
6653 }
6654}
6655
6656const char *MainController::get_hc_state_name(hc_state_enum state)
6657{
6658 switch (state) {
6659 case HC_IDLE:
6660 return "not configured";
6661 case HC_CONFIGURING:
6662 case HC_CONFIGURING_OVERLOADED:
6663 return "being configured";
6664 case HC_ACTIVE:
6665 return "ready";
6666 case HC_OVERLOADED:
6667 return "overloaded";
6668 case HC_DOWN:
6669 return "down";
6670 default:
6671 return "unknown/transient";
6672 }
6673}
6674
6675const char *MainController::get_tc_state_name(tc_state_enum state)
6676{
6677 switch (state) {
6678 case TC_INITIAL:
6679 return "being created";
6680 case TC_IDLE:
6681 return "inactive - waiting for start";
6682 case TC_CREATE:
6683 return "executing create operation";
6684 case TC_START:
6685 return "executing component start operation";
6686 case TC_STOP:
6687 case MTC_ALL_COMPONENT_STOP:
6688 return "executing component stop operation";
6689 case TC_KILL:
6690 case MTC_ALL_COMPONENT_KILL:
6691 return "executing kill operation";
6692 case TC_CONNECT:
6693 return "executing connect operation";
6694 case TC_DISCONNECT:
6695 return "executing disconnect operation";
6696 case TC_MAP:
6697 return "executing map operation";
6698 case TC_UNMAP:
6699 return "executing unmap operation";
6700 case TC_STOPPING:
6701 return "being stopped";
6702 case TC_EXITING:
6703 return "terminated";
6704 case TC_EXITED:
6705 return "exited";
6706 case MTC_CONTROLPART:
6707 return "executing control part";
6708 case MTC_TESTCASE:
6709 return "executing testcase";
6710 case MTC_TERMINATING_TESTCASE:
6711 return "terminating testcase";
6712 case MTC_PAUSED:
6713 return "paused";
6714 case PTC_FUNCTION:
6715 return "executing function";
6716 case PTC_STARTING:
6717 return "being started";
6718 case PTC_STOPPED:
6719 return "stopped - waiting for re-start";
6720 case PTC_KILLING:
6721 case PTC_STOPPING_KILLING:
6722 return "being killed";
6723 default:
6724 return "unknown/transient";
6725 }
6726}
6727
6728const char *MainController::get_transport_name(transport_type_enum transport)
6729{
6730 switch (transport) {
6731 case TRANSPORT_LOCAL:
6732 return "LOCAL (software loop)";
6733 case TRANSPORT_INET_STREAM:
6734 return "INET_STREAM (TCP over IPv4)";
6735 case TRANSPORT_UNIX_STREAM:
6736 return "UNIX_STREAM (UNIX domain socket)";
6737 default:
6738 return "unknown";
6739 }
6740}
6741
6742//----------------------------------------------------------------------------
6743
6744} /* namespace mctr */
6745
6746//----------------------------------------------------------------------------
6747
6748// Local Variables:
6749// mode: C++
6750// indent-tabs-mode: nil
6751// c-basic-offset: 2
6752// End:
This page took 0.29519 seconds and 5 git commands to generate.