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