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