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
19 * Szabo, Janos Zoltan – initial implementation
21 * Zalanyi, Balazs Andor
23 ******************************************************************************/
25 // Description: Implementation file for MainController
26 // Author: Janos Zoltan Szabo
27 // mail: tmpjsz@eth.ericsson.se
29 // Copyright (c) 2000-2015 Ericsson Telecom AB
31 //----------------------------------------------------------------------------
33 #include "MainController.h"
34 #include "UserInterface.h"
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"
52 #include <sys/types.h>
53 #include <sys/socket.h>
56 #include <sys/epoll.h>
60 #include <sys/utsname.h>
61 #include <netinet/in.h>
62 #include <netinet/tcp.h>
63 #include <arpa/inet.h>
68 reffer::reffer(const char*) {}
70 //----------------------------------------------------------------------------
74 //----------------------------------------------------------------------------
76 /* Static variables */
78 UserInterface
*MainController::ui
;
79 NetworkHandler
MainController::nh
;
81 mc_state_enum
MainController::mc_state
;
82 char *MainController::mc_hostname
;
84 struct sigaction
MainController::new_action
, MainController::old_action
;
86 int MainController::server_fd
;
87 int MainController::server_fd_unix
= -1;
88 boolean
MainController::server_fd_disabled
;
90 void MainController::disable_server_fd()
92 if (!server_fd_disabled
) {
93 remove_poll_fd(server_fd
);
94 server_fd_disabled
= TRUE
;
98 void MainController::enable_server_fd()
100 if (server_fd_disabled
) {
101 add_poll_fd(server_fd
);
102 server_fd_disabled
= FALSE
;
106 pthread_mutex_t
MainController::mutex
;
108 void MainController::lock()
110 int result
= pthread_mutex_lock(&mutex
);
112 fatal_error("MainController::lock: "
113 "pthread_mutex_lock failed with code %d.", result
);
117 void MainController::unlock()
119 int result
= pthread_mutex_unlock(&mutex
);
121 fatal_error("MainController::unlock: "
122 "pthread_mutex_unlock failed with code %d.", result
);
127 epoll_event
*MainController::epoll_events
;
128 int MainController::epfd
;
130 unsigned int MainController::nfds
, MainController::new_nfds
;
131 struct pollfd
*MainController::ufds
, *MainController::new_ufds
;
132 boolean
MainController::pollfds_modified
;
136 void MainController::add_poll_fd(int fd
)
140 memset(&event
,0,sizeof(event
));
141 event
.events
= EPOLLIN
;
143 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, fd
, &event
) < 0)
144 fatal_error("MainController::add_poll_fd: system call epoll_ctl"
145 " failed on file descriptor %d.", fd
);
148 void MainController::remove_poll_fd(int fd
)
152 memset(&event
,0,sizeof(event
));
153 event
.events
= EPOLLIN
;
155 if (epoll_ctl(epfd
, EPOLL_CTL_DEL
, fd
, &event
) < 0)
156 fatal_error("MainController::remove_poll_fd: system call epoll_ctl"
157 " failed on file descriptor %d.", fd
);
159 #else // ! defined USE_EPOLL
160 void MainController::add_poll_fd(int fd
)
163 if (pollfds_modified
) {
165 for (i
= new_nfds
- 1; i
>= 0; i
--) {
166 if (new_ufds
[i
].fd
< fd
) break;
167 else if (new_ufds
[i
].fd
== fd
) return;
170 new_ufds
= (struct pollfd
*)Realloc(new_ufds
, (new_nfds
+ 1) *
171 sizeof(struct pollfd
));
172 memmove(new_ufds
+ i
+ 1, new_ufds
+ i
, (new_nfds
- i
) *
173 sizeof(struct pollfd
));
175 new_ufds
[i
].events
= POLLIN
;
176 new_ufds
[i
].revents
= 0;
180 for (i
= nfds
- 1; i
>= 0; i
--) {
181 if (ufds
[i
].fd
< fd
) break;
182 else if (ufds
[i
].fd
== fd
) return;
186 new_ufds
= (struct pollfd
*)Malloc(new_nfds
* sizeof(struct pollfd
));
187 memcpy(new_ufds
, ufds
, i
* sizeof(struct pollfd
));
189 new_ufds
[i
].events
= POLLIN
;
190 new_ufds
[i
].revents
= 0;
191 memcpy(new_ufds
+ i
+ 1, ufds
+ i
, (nfds
- i
) * sizeof(struct pollfd
));
192 pollfds_modified
= TRUE
;
196 void MainController::remove_poll_fd(int fd
)
199 if (pollfds_modified
) {
201 for (i
= new_nfds
- 1; i
>= 0; i
--) {
202 if (new_ufds
[i
].fd
== fd
) break;
203 else if (new_ufds
[i
].fd
< fd
) return;
207 memmove(new_ufds
+ i
, new_ufds
+ i
+ 1, (new_nfds
- i
) *
208 sizeof(struct pollfd
));
209 new_ufds
= (struct pollfd
*)Realloc(new_ufds
, new_nfds
*
210 sizeof(struct pollfd
));
213 for (i
= nfds
- 1; i
>= 0; i
--) {
214 if (ufds
[i
].fd
== fd
) break;
215 else if (ufds
[i
].fd
< fd
) return;
219 new_ufds
= (struct pollfd
*)Malloc(new_nfds
* sizeof(struct pollfd
));
220 memcpy(new_ufds
, ufds
, i
* sizeof(struct pollfd
));
221 memcpy(new_ufds
+ i
, ufds
+ i
+ 1, (new_nfds
- i
) *
222 sizeof(struct pollfd
));
223 pollfds_modified
= TRUE
;
227 void MainController::update_pollfds()
229 if (pollfds_modified
) {
235 pollfds_modified
= FALSE
;
240 int MainController::fd_table_size
;
241 fd_table_struct
*MainController::fd_table
;
243 void MainController::add_fd_to_table(int fd
)
245 if (fd
>= fd_table_size
) {
246 fd_table
= (fd_table_struct
*)Realloc(fd_table
, (fd
+ 1) *
247 sizeof(fd_table_struct
));
248 for (int i
= fd_table_size
; i
<= fd
; i
++) {
249 fd_table
[i
].fd_type
= FD_UNUSED
;
250 fd_table
[i
].dummy_ptr
= NULL
;
252 fd_table_size
= fd
+ 1;
256 void MainController::remove_fd_from_table(int fd
)
258 if (fd
< fd_table_size
) {
259 fd_table
[fd
].fd_type
= FD_UNUSED
;
261 for (i
= fd_table_size
- 1; i
>= 0 ; i
--) {
262 if (fd_table
[i
].fd_type
!= FD_UNUSED
) break;
264 if (i
< fd_table_size
- 1) {
265 fd_table_size
= i
+ 1;
266 fd_table
= (fd_table_struct
*)Realloc(fd_table
, fd_table_size
*
267 sizeof(fd_table_struct
));
272 void MainController::set_close_on_exec(int fd
)
274 int flags
= fcntl(fd
, F_GETFD
);
275 if (flags
< 0) fatal_error("MainController::set_close_on_exec: system call "
276 "fcntl(F_GETFD) failed on file descriptor %d.", fd
);
280 if (fcntl(fd
, F_SETFD
, flags
) == -1)
281 fatal_error("MainController::set_close_on_exec: system call "
282 "fcntl(F_SETFD) failed on file descriptor %d.", fd
);
285 unknown_connection
*MainController::unknown_head
, *MainController::unknown_tail
;
287 unknown_connection
*MainController::new_unknown_connection(
290 unknown_connection
*conn
= new unknown_connection
;
291 conn
->unix_socket
= unix_socket
;
292 conn
->prev
= unknown_tail
;
294 if (unknown_tail
!= NULL
) unknown_tail
->next
= conn
;
295 else unknown_head
= conn
;
300 void MainController::delete_unknown_connection(unknown_connection
*conn
)
302 if (conn
->prev
!= NULL
) conn
->prev
->next
= conn
->next
;
303 else unknown_head
= conn
->next
;
304 if (conn
->next
!= NULL
) conn
->next
->prev
= conn
->prev
;
305 else unknown_tail
= conn
->prev
;
309 void MainController::close_unknown_connection(unknown_connection
*conn
)
311 remove_poll_fd(conn
->fd
);
313 remove_fd_from_table(conn
->fd
);
314 delete conn
->text_buf
;
315 delete_unknown_connection(conn
);
319 void MainController::init_string_set(string_set
*set
)
322 set
->elements
= NULL
;
325 void MainController::free_string_set(string_set
*set
)
327 for (int i
= 0; i
< set
->n_elements
; i
++) Free(set
->elements
[i
]);
330 set
->elements
= NULL
;
333 void MainController::add_string_to_set(string_set
*set
, const char *str
)
336 for (i
= 0; i
< set
->n_elements
; i
++) {
337 int result
= strcmp(set
->elements
[i
], str
);
338 if (result
> 0) break;
339 else if (result
== 0) return;
341 set
->elements
= (char**)Realloc(set
->elements
,
342 (set
->n_elements
+ 1) * sizeof(*set
->elements
));
343 memmove(set
->elements
+ i
+ 1, set
->elements
+ i
,
344 (set
->n_elements
- i
) * sizeof(*set
->elements
));
345 set
->elements
[i
] = mcopystr(str
);
349 void MainController::remove_string_from_set(string_set
*set
,
352 for (int i
= 0; i
< set
->n_elements
; i
++) {
353 int result
= strcmp(set
->elements
[i
], str
);
354 if (result
< 0) continue;
355 else if (result
== 0) {
356 Free(set
->elements
[i
]);
358 memmove(set
->elements
+ i
, set
->elements
+ i
+ 1,
359 (set
->n_elements
- i
) * sizeof(*set
->elements
));
360 set
->elements
= (char**)Realloc(set
->elements
,
361 set
->n_elements
* sizeof(*set
->elements
));
367 boolean
MainController::set_has_string(const string_set
*set
,
370 if(str
== NULL
) return FALSE
;
371 for (int i
= 0; i
< set
->n_elements
; i
++) {
372 int result
= strcmp(set
->elements
[i
], str
);
373 if (result
== 0) return TRUE
;
374 else if (result
> 0) break;
379 const char *MainController::get_string_from_set(const string_set
*set
,
382 if (index
>= 0 && index
< set
->n_elements
) return set
->elements
[index
];
386 int MainController::n_host_groups
;
387 host_group_struct
*MainController::host_groups
;
388 string_set
MainController::assigned_components
;
389 boolean
MainController::all_components_assigned
;
391 host_group_struct
*MainController::add_host_group(const char *group_name
)
394 for (i
= 0 ; i
< n_host_groups
; i
++) {
395 host_group_struct
*group
= host_groups
+ i
;
396 int result
= strcmp(group
->group_name
, group_name
);
397 if (result
> 0) break;
398 else if (result
== 0) return group
;
400 host_groups
= (host_group_struct
*)Realloc(host_groups
,
401 (n_host_groups
+ 1) * sizeof(*host_groups
));
402 host_group_struct
*new_group
= host_groups
+ i
;
403 memmove(new_group
+ 1, new_group
,
404 (n_host_groups
- i
) * sizeof(*host_groups
));
405 new_group
->group_name
= mcopystr(group_name
);
406 new_group
->has_all_hosts
= FALSE
;
407 new_group
->has_all_components
= FALSE
;
408 init_string_set(&new_group
->host_members
);
409 init_string_set(&new_group
->assigned_components
);
414 host_group_struct
*MainController::lookup_host_group(const char *group_name
)
416 for (int i
= 0; i
< n_host_groups
; i
++) {
417 host_group_struct
*group
= host_groups
+ i
;
418 int result
= strcmp(group
->group_name
, group_name
);
419 if (result
== 0) return group
;
420 else if (result
> 0) break;
425 boolean
MainController::is_similar_hostname(const char *host1
,
428 for (size_t i
= 0; ; i
++) {
429 unsigned char c1
= host1
[i
], c2
= host2
[i
];
431 // if host2 is the longer one it may contain an additional domain
432 // name with a leading dot (e.g. "foo" is similar to "foo.bar.com")
433 // note: empty string is similar with empty string only
434 if (c2
== '\0' || (i
> 0 && c2
== '.')) return TRUE
;
436 } else if (c2
== '\0') {
438 if (c1
== '\0' || (i
> 0 && c1
== '.')) return TRUE
;
441 // case insensitive comparison of the characters
442 if (tolower(c1
) != tolower(c2
)) return FALSE
;
443 // continue the evaluation if they are matching
448 boolean
MainController::host_has_name(const host_struct
*host
, const char *name
)
450 // name might resemble to host->hostname
451 if (is_similar_hostname(host
->hostname
, name
)) return TRUE
;
452 // to avoid returning true in situations when name is "foo.bar.com", but
453 // host->hostname is "foo.other.com" and host->hostname_local is "foo"
454 // name might resemble to host->hostname_local
455 if (host
->local_hostname_different
&&
456 is_similar_hostname(host
->hostname_local
, name
)) return TRUE
;
457 // name might be an IP address or a DNS alias
458 IPAddress
*ip_addr
= IPAddress::create_addr(nh
.get_family());
459 if (ip_addr
->set_addr(name
)) {
460 // check if IP addresses match
461 if (*ip_addr
== *(host
->ip_addr
)) {
465 // try to handle such strange situations when the local hostname is
466 // mapped to a loopback address by /etc/hosts
467 // (i.e. host->ip_addr contains 127.x.y.z)
468 // but the given name contains the real IP address of the host
469 const char *canonical_name
= ip_addr
->get_host_str();
470 if (is_similar_hostname(host
->hostname
, canonical_name
)) {
474 if (host
->local_hostname_different
&&
475 is_similar_hostname(host
->hostname_local
, canonical_name
)) {
484 boolean
MainController::member_of_group(const host_struct
*host
,
485 const host_group_struct
*group
)
487 if (group
->has_all_hosts
) return TRUE
;
488 for (int i
= 0; ; i
++) {
489 const char *member_name
= get_string_from_set(&group
->host_members
, i
);
490 if (member_name
!= NULL
) {
491 if (host_has_name(host
, member_name
)) return TRUE
;
493 // empty group: the group name is considered as a hostname
494 return host_has_name(host
, group
->group_name
);
503 void MainController::add_allowed_components(host_struct
*host
)
505 init_string_set(&host
->allowed_components
);
506 host
->all_components_allowed
= FALSE
;
507 for (int i
= 0; i
< n_host_groups
; i
++) {
508 host_group_struct
*group
= host_groups
+ i
;
509 if (!member_of_group(host
, group
)) continue;
510 for (int j
= 0; ; j
++) {
511 const char *component_id
=
512 get_string_from_set(&group
->assigned_components
, j
);
513 if (component_id
== NULL
) break;
514 add_string_to_set(&host
->allowed_components
, component_id
);
516 if (group
->has_all_components
) host
->all_components_allowed
= TRUE
;
520 host_struct
*MainController::choose_ptc_location(const char *component_type
,
521 const char *component_name
, const char *component_location
)
523 host_struct
*best_candidate
= NULL
;
524 int load_on_best_candidate
= 0;
525 boolean has_constraint
=
526 set_has_string(&assigned_components
, component_type
) ||
527 set_has_string(&assigned_components
, component_name
);
528 host_group_struct
*group
;
529 if (component_location
!= NULL
)
530 group
= lookup_host_group(component_location
);
532 for (int i
= 0; i
< n_hosts
; i
++) {
533 host_struct
*host
= hosts
[i
];
534 if (host
->hc_state
!= HC_ACTIVE
) continue;
535 if (best_candidate
!= NULL
&&
536 host
->n_active_components
>= load_on_best_candidate
) continue;
537 if (component_location
!= NULL
) {
538 // the explicit location has precedence over the constraints
540 if (!member_of_group(host
, group
)) continue;
542 if (!host_has_name(host
, component_location
)) continue;
544 } else if (has_constraint
) {
545 if (!set_has_string(&host
->allowed_components
, component_type
) &&
546 !set_has_string(&host
->allowed_components
, component_name
))
548 } else if (all_components_assigned
) {
549 if (!host
->all_components_allowed
) continue;
551 best_candidate
= host
;
552 load_on_best_candidate
= host
->n_active_components
;
554 return best_candidate
;
557 int MainController::n_hosts
;
558 host_struct
**MainController::hosts
;
560 host_struct
*MainController::add_new_host(unknown_connection
*conn
)
562 Text_Buf
*text_buf
= conn
->text_buf
;
565 host_struct
*new_host
= new host_struct
;
567 new_host
->ip_addr
= conn
->ip_addr
;
568 new_host
->hostname
= mcopystr(new_host
->ip_addr
->get_host_str());
569 new_host
->hostname_local
= text_buf
->pull_string();
570 new_host
->machine_type
= text_buf
->pull_string();
571 new_host
->system_name
= text_buf
->pull_string();
572 new_host
->system_release
= text_buf
->pull_string();
573 new_host
->system_version
= text_buf
->pull_string();
574 for (int i
= 0; i
< TRANSPORT_NUM
; i
++)
575 new_host
->transport_supported
[i
] = FALSE
;
576 int n_supported_transports
= text_buf
->pull_int().get_val();
577 for (int i
= 0; i
< n_supported_transports
; i
++) {
578 int transport_type
= text_buf
->pull_int().get_val();
579 if (transport_type
>= 0 && transport_type
< TRANSPORT_NUM
) {
580 if (new_host
->transport_supported
[transport_type
]) {
581 send_error(fd
, "Malformed VERSION message was received: "
582 "Transport type %s was specified more than once.",
583 get_transport_name((transport_type_enum
)transport_type
));
584 } else new_host
->transport_supported
[transport_type
] = TRUE
;
586 send_error(fd
, "Malformed VERSION message was received: "
587 "Transport type code %d is invalid.", transport_type
);
590 if (!new_host
->transport_supported
[TRANSPORT_LOCAL
]) {
591 send_error(fd
, "Malformed VERSION message was received: "
592 "Transport type %s must be supported anyway.",
593 get_transport_name(TRANSPORT_LOCAL
));
595 if (!new_host
->transport_supported
[TRANSPORT_INET_STREAM
]) {
596 send_error(fd
, "Malformed VERSION message was received: "
597 "Transport type %s must be supported anyway.",
598 get_transport_name(TRANSPORT_INET_STREAM
));
600 new_host
->log_source
= mprintf("HC@%s", new_host
->hostname_local
);
601 new_host
->hc_state
= HC_IDLE
;
602 new_host
->hc_fd
= fd
;
603 new_host
->text_buf
= text_buf
;
604 new_host
->n_components
= 0;
605 new_host
->components
= NULL
;
606 // in most cases hostname and hostname_local are similar ("foo.bar.com" vs.
607 // "foo") and it is enough to compare only the (fully qualified) hostname
608 // when evaluating PTC location constraints
609 new_host
->local_hostname_different
=
610 !is_similar_hostname(new_host
->hostname
, new_host
->hostname_local
);
611 add_allowed_components(new_host
);
612 new_host
->n_active_components
= 0;
614 text_buf
->cut_message();
616 delete_unknown_connection(conn
);
619 hosts
= (host_struct
**)Realloc(hosts
, n_hosts
* sizeof(*hosts
));
620 hosts
[n_hosts
- 1] = new_host
;
622 fd_table
[fd
].fd_type
= FD_HC
;
623 fd_table
[fd
].host_ptr
= new_host
;
625 notify("New HC connected from %s [%s]. %s: %s %s on %s.",
626 new_host
->hostname
, new_host
->ip_addr
->get_addr_str(),
627 new_host
->hostname_local
, new_host
->system_name
,
628 new_host
->system_release
, new_host
->machine_type
);
633 void MainController::close_hc_connection(host_struct
*hc
)
635 if (hc
->hc_state
!= HC_DOWN
) {
636 remove_poll_fd(hc
->hc_fd
);
638 remove_fd_from_table(hc
->hc_fd
);
642 hc
->hc_state
= HC_DOWN
;
647 boolean
MainController::is_hc_in_state(hc_state_enum checked_state
)
649 for (int i
= 0; i
< n_hosts
; i
++)
650 if (hosts
[i
]->hc_state
== checked_state
) return TRUE
;
654 boolean
MainController::all_hc_in_state(hc_state_enum checked_state
)
656 for (int i
= 0; i
< n_hosts
; i
++)
657 if (hosts
[i
]->hc_state
!= checked_state
) return FALSE
;
661 void MainController::configure_host(host_struct
*host
, boolean should_notify
)
663 if(config_str
== NULL
)
664 fatal_error("MainController::configure_host: no config file");
665 hc_state_enum next_state
= HC_CONFIGURING
;
666 switch(host
->hc_state
) {
668 case HC_CONFIGURING_OVERLOADED
:
670 fatal_error("MainController::configure_host:"
671 " host %s is in wrong state.",
677 next_state
= HC_CONFIGURING_OVERLOADED
;
680 host
->hc_state
= next_state
;
682 notify("Downloading configuration file to HC on host %s.",
685 send_configure(host
, config_str
);
689 void MainController::check_all_hc_configured()
691 if (is_hc_in_state(HC_CONFIGURING
) ||
692 is_hc_in_state(HC_CONFIGURING_OVERLOADED
)) return;
693 if (is_hc_in_state(HC_IDLE
)) {
694 error("There were errors during configuring HCs.");
695 mc_state
= MC_HC_CONNECTED
;
696 } else if (is_hc_in_state(HC_ACTIVE
) || is_hc_in_state(HC_OVERLOADED
)) {
697 notify("Configuration file was processed on all HCs.");
698 mc_state
= MC_ACTIVE
;
700 error("There is no HC connection after processing the configuration "
702 mc_state
= MC_LISTENING
;
706 void MainController::add_component_to_host(host_struct
*host
,
707 component_struct
*comp
)
709 if (comp
->comp_ref
== MTC_COMPREF
)
710 comp
->log_source
= mprintf("MTC@%s", host
->hostname_local
);
711 else if (comp
->comp_name
!= NULL
)
712 comp
->log_source
= mprintf("%s(%d)@%s", comp
->comp_name
,
713 comp
->comp_ref
, host
->hostname_local
);
714 else comp
->log_source
= mprintf("%d@%s", comp
->comp_ref
,
715 host
->hostname_local
);
716 comp
->comp_location
= host
;
718 for (i
= host
->n_components
; i
> 0; i
--) {
719 if (host
->components
[i
- 1] < comp
->comp_ref
) break;
720 else if (host
->components
[i
- 1] == comp
->comp_ref
) return;
722 host
->components
= (component
*)Realloc(host
->components
,
723 (host
->n_components
+ 1) * sizeof(component
));
724 memmove(host
->components
+ i
+ 1, host
->components
+ i
,
725 (host
->n_components
- i
) * sizeof(component
));
726 host
->components
[i
] = comp
->comp_ref
;
727 host
->n_components
++;
730 void MainController::remove_component_from_host(component_struct
*comp
)
732 Free(comp
->log_source
);
733 comp
->log_source
= NULL
;
734 host_struct
*host
= comp
->comp_location
;
736 component comp_ref
= comp
->comp_ref
;
738 for (i
= host
->n_components
- 1; i
>= 0; i
--) {
739 if (host
->components
[i
] == comp_ref
) break;
740 else if (host
->components
[i
] < comp_ref
) return;
743 host
->n_components
--;
744 memmove(host
->components
+ i
, host
->components
+ i
+ 1,
745 (host
->n_components
- i
) * sizeof(component
));
746 host
->components
= (component
*)Realloc(host
->components
,
747 host
->n_components
* sizeof(component
));
751 boolean
MainController::version_known
;
752 int MainController::n_modules
;
753 module_version_info
*MainController::modules
;
755 #ifdef TTCN3_BUILDNUMBER
756 #define TTCN3_BUILDNUMBER_SAFE TTCN3_BUILDNUMBER
758 #define TTCN3_BUILDNUMBER_SAFE 0
762 boolean
MainController::check_version(unknown_connection
*conn
)
764 Text_Buf
& text_buf
= *conn
->text_buf
;
765 int version_major
= text_buf
.pull_int().get_val();
766 int version_minor
= text_buf
.pull_int().get_val();
767 int version_patchlevel
= text_buf
.pull_int().get_val();
768 if (version_major
!= TTCN3_MAJOR
|| version_minor
!= TTCN3_MINOR
||
769 version_patchlevel
!= TTCN3_PATCHLEVEL
) {
770 send_error(conn
->fd
, "Version mismatch: The TTCN-3 Main Controller has "
771 "version " PRODUCT_NUMBER
", but the ETS was built with version "
772 "%d.%d.pl%d.", version_major
, version_minor
, version_patchlevel
);
775 int version_buildnumber
= text_buf
.pull_int().get_val();
776 if (version_buildnumber
!= TTCN3_BUILDNUMBER_SAFE
) {
777 if (version_buildnumber
> 0) send_error(conn
->fd
, "Build number "
778 "mismatch: The TTCN-3 Main Controller has version " PRODUCT_NUMBER
779 ", but the ETS was built with %d.%d.pre%d build %d.",
780 version_major
, version_minor
, version_patchlevel
,
781 version_buildnumber
);
782 else send_error(conn
->fd
, "Build number mismatch: The TTCN-3 Main "
783 "Controller has version " PRODUCT_NUMBER
", but the ETS was built "
784 "with %d.%d.pl%d.", version_major
, version_minor
,
789 int new_n_modules
= text_buf
.pull_int().get_val();
790 if (n_modules
!= new_n_modules
) {
791 send_error(conn
->fd
, "The number of modules in this ETS (%d) "
792 "differs from the number of modules in the firstly connected "
793 "ETS (%d).", new_n_modules
, n_modules
);
796 for (int i
= 0; i
< n_modules
; i
++) {
797 char *module_name
= text_buf
.pull_string();
798 if (strcmp(module_name
, modules
[i
].module_name
)) {
799 send_error(conn
->fd
, "The module number %d in this ETS (%s) "
800 "has different name than in the firstly connected ETS (%s).",
801 i
, module_name
, modules
[i
].module_name
);
802 delete [] module_name
;
805 boolean checksum_differs
= FALSE
;
806 int checksum_length
= text_buf
.pull_int().get_val();
807 unsigned char *module_checksum
;
808 if (checksum_length
!= 0) {
809 module_checksum
= new unsigned char[checksum_length
];
810 text_buf
.pull_raw(checksum_length
, module_checksum
);
811 } else module_checksum
= NULL
;
812 if (checksum_length
!= modules
[i
].checksum_length
||
813 memcmp(module_checksum
, modules
[i
].module_checksum
,
814 checksum_length
)) checksum_differs
= TRUE
;
815 delete [] module_checksum
;
816 if (checksum_differs
) {
817 send_error(conn
->fd
, "The checksum of module %s in this ETS "
818 "is different than that of the firstly connected ETS.",
821 delete [] module_name
;
822 if (checksum_differs
) return TRUE
;
825 n_modules
= text_buf
.pull_int().get_val();
826 modules
= new module_version_info
[n_modules
];
827 for (int i
= 0; i
< n_modules
; i
++) {
828 modules
[i
].module_name
= text_buf
.pull_string();
829 modules
[i
].checksum_length
= text_buf
.pull_int().get_val();
830 if (modules
[i
].checksum_length
> 0) {
831 modules
[i
].module_checksum
=
832 new unsigned char[modules
[i
].checksum_length
];
833 text_buf
.pull_raw(modules
[i
].checksum_length
,
834 modules
[i
].module_checksum
);
835 } else modules
[i
].module_checksum
= NULL
;
837 version_known
= TRUE
;
842 int MainController::n_components
, MainController::n_active_ptcs
,
843 MainController::max_ptcs
;
844 component_struct
**MainController::components
;
845 component_struct
*MainController::mtc
, *MainController::system
;
846 component
MainController::next_comp_ref
, MainController::tc_first_comp_ref
;
848 boolean
MainController::any_component_done_requested
,
849 MainController::any_component_done_sent
,
850 MainController::all_component_done_requested
,
851 MainController::any_component_killed_requested
,
852 MainController::all_component_killed_requested
;
854 void MainController::add_component(component_struct
*comp
)
856 component comp_ref
= comp
->comp_ref
;
857 if (lookup_component(comp_ref
) != NULL
)
858 fatal_error("MainController::add_component: duplicate "
859 "component reference %d.", comp_ref
);
860 if (n_components
<= comp_ref
) {
861 components
= (component_struct
**)Realloc(components
, (comp_ref
+ 1) *
862 sizeof(component_struct
*));
863 for (int i
= n_components
; i
< comp_ref
; i
++) components
[i
] = NULL
;
864 n_components
= comp_ref
+ 1;
866 components
[comp_ref
] = comp
;
869 component_struct
*MainController::lookup_component(component comp_ref
)
871 if (comp_ref
>= 0 && comp_ref
< n_components
) return components
[comp_ref
];
875 void MainController::destroy_all_components()
877 for (component i
= 0; i
< n_components
; i
++) {
878 component_struct
*comp
= components
[i
];
880 close_tc_connection(comp
);
881 remove_component_from_host(comp
);
882 free_qualified_name(&comp
->comp_type
);
883 delete [] comp
->comp_name
;
884 free_qualified_name(&comp
->tc_fn_name
);
885 delete [] comp
->return_type
;
886 Free(comp
->return_value
);
887 if (comp
->verdict_reason
!= NULL
) {
888 delete [] comp
->verdict_reason
;
889 comp
->verdict_reason
= NULL
;
891 switch (comp
->tc_state
) {
893 delete [] comp
->initial
.location_str
;
896 Free(comp
->starting
.arguments_ptr
);
897 free_requestors(&comp
->starting
.cancel_done_sent_to
);
900 case PTC_STOPPING_KILLING
:
902 free_requestors(&comp
->stopping_killing
.stop_requestors
);
903 free_requestors(&comp
->stopping_killing
.kill_requestors
);
907 free_requestors(&comp
->done_requestors
);
908 free_requestors(&comp
->killed_requestors
);
909 free_requestors(&comp
->cancel_done_sent_for
);
910 remove_all_connections(i
);
921 for (int i
= 0; i
< n_hosts
; i
++) hosts
[i
]->n_active_components
= 0;
923 next_comp_ref
= FIRST_PTC_COMPREF
;
925 any_component_done_requested
= FALSE
;
926 any_component_done_sent
= FALSE
;
927 all_component_done_requested
= FALSE
;
928 any_component_killed_requested
= FALSE
;
929 all_component_killed_requested
= FALSE
;
932 void MainController::close_tc_connection(component_struct
*comp
)
934 if (comp
->tc_fd
>= 0) {
935 remove_poll_fd(comp
->tc_fd
);
937 remove_fd_from_table(comp
->tc_fd
);
939 delete comp
->text_buf
;
940 comp
->text_buf
= NULL
;
943 if (comp
->kill_timer
!= NULL
) {
944 cancel_timer(comp
->kill_timer
);
945 comp
->kill_timer
= NULL
;
949 boolean
MainController::stop_after_tc
, MainController::stop_requested
;
951 boolean
MainController::ready_to_finish_testcase()
953 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
954 switch (components
[i
]->tc_state
) {
965 void MainController::finish_testcase()
967 if (stop_requested
) {
968 send_ptc_verdict(FALSE
);
970 mtc
->tc_state
= MTC_CONTROLPART
;
971 mtc
->stop_requested
= TRUE
;
972 start_kill_timer(mtc
);
973 mc_state
= MC_EXECUTING_CONTROL
;
974 } else if (stop_after_tc
) {
975 send_ptc_verdict(FALSE
);
976 mtc
->tc_state
= MTC_PAUSED
;
977 mc_state
= MC_PAUSED
;
978 notify("Execution has been paused.");
980 send_ptc_verdict(TRUE
);
981 mtc
->tc_state
= MTC_CONTROLPART
;
982 mc_state
= MC_EXECUTING_CONTROL
;
985 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
986 components
[i
]->tc_state
= PTC_STALE
;
988 mtc
->local_verdict
= NONE
;
989 free_qualified_name(&mtc
->comp_type
);
990 free_qualified_name(&mtc
->tc_fn_name
);
991 free_qualified_name(&system
->comp_type
);
994 boolean
MainController::message_expected(component_struct
*from
,
995 const char *message_name
)
998 case MC_EXECUTING_TESTCASE
:
999 switch (mtc
->tc_state
) {
1000 case MTC_ALL_COMPONENT_STOP
:
1001 case MTC_ALL_COMPONENT_KILL
:
1007 case MC_TERMINATING_TESTCASE
:
1011 send_error(from
->tc_fd
, "Unexpected message %s was received.",
1017 boolean
MainController::request_allowed(component_struct
*from
,
1018 const char *message_name
)
1020 if (!message_expected(from
, message_name
)) return FALSE
;
1022 switch (from
->tc_state
) {
1024 if (from
== mtc
) return TRUE
;
1027 if (from
!= mtc
) return TRUE
;
1030 case PTC_STOPPING_KILLING
:
1037 send_error(from
->tc_fd
, "The sender of message %s is in "
1038 "unexpected state.", message_name
);
1042 boolean
MainController::valid_endpoint(component component_reference
,
1043 boolean new_connection
, component_struct
*requestor
, const char *operation
)
1045 switch (component_reference
) {
1047 send_error(requestor
->tc_fd
, "The %s operation refers to the null "
1048 "component reference.", operation
);
1050 case SYSTEM_COMPREF
:
1051 send_error(requestor
->tc_fd
, "The %s operation refers to the system "
1052 "component reference.", operation
);
1055 send_error(requestor
->tc_fd
, "The %s operation refers to "
1056 "'any component'.", operation
);
1059 send_error(requestor
->tc_fd
, "The %s operation refers to "
1060 "'all component'.", operation
);
1065 component_struct
*comp
= lookup_component(component_reference
);
1067 send_error(requestor
->tc_fd
, "The %s operation refers to "
1068 "invalid component reference %d.", operation
,
1069 component_reference
);
1072 switch (comp
->tc_state
) {
1089 case PTC_STOPPING_KILLING
:
1090 if (new_connection
) {
1091 send_error(requestor
->tc_fd
, "The %s operation refers to test "
1092 "component with component reference %d, which is currently "
1093 "being terminated.", operation
, component_reference
);
1098 if (new_connection
) {
1099 send_error(requestor
->tc_fd
, "The %s operation refers to test "
1100 "component with component reference %d, which has already "
1101 "terminated.", operation
, component_reference
);
1105 send_error(requestor
->tc_fd
, "The %s operation refers to component "
1106 "reference %d, which belongs to an earlier test case.",
1107 operation
, component_reference
);
1110 send_error(requestor
->tc_fd
, "The %s operation refers to component "
1111 "reference %d, which is in invalid state.",
1112 operation
, component_reference
);
1113 error("Test component with component reference %d is in invalid state "
1114 "when a %s operation was requested on a port of it.",
1115 component_reference
, operation
);
1120 void MainController::destroy_connection(port_connection
*conn
,
1121 component_struct
*tc
)
1123 switch (conn
->conn_state
) {
1124 case CONN_LISTENING
:
1125 case CONN_CONNECTING
:
1126 if (conn
->transport_type
!= TRANSPORT_LOCAL
&&
1127 conn
->head
.comp_ref
!= tc
->comp_ref
) {
1128 // shut down the server side if the client has terminated
1129 send_disconnect_to_server(conn
);
1131 send_error_to_connect_requestors(conn
, "test component %d has "
1132 "terminated during connection setup.", tc
->comp_ref
);
1134 case CONN_CONNECTED
:
1136 case CONN_DISCONNECTING
:
1137 send_disconnect_ack_to_requestors(conn
);
1140 error("The port connection %d:%s - %d:%s is in invalid state when "
1141 "test component %d has terminated.", conn
->head
.comp_ref
,
1142 conn
->head
.port_name
, conn
->tail
.comp_ref
, conn
->tail
.port_name
,
1145 remove_connection(conn
);
1148 void MainController::destroy_mapping(port_connection
*conn
)
1150 component tc_compref
;
1151 const char *tc_port
, *system_port
;
1152 if (conn
->head
.comp_ref
== SYSTEM_COMPREF
) {
1153 tc_compref
= conn
->tail
.comp_ref
;
1154 tc_port
= conn
->tail
.port_name
;
1155 system_port
= conn
->head
.port_name
;
1157 tc_compref
= conn
->head
.comp_ref
;
1158 tc_port
= conn
->head
.port_name
;
1159 system_port
= conn
->tail
.port_name
;
1161 switch (conn
->conn_state
) {
1162 case CONN_UNMAPPING
:
1163 for (int i
= 0; ; i
++) {
1164 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
1165 if (comp
== NULL
) break;
1166 if (comp
->tc_state
== TC_UNMAP
) {
1167 send_unmap_ack(comp
);
1168 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
1169 else comp
->tc_state
= PTC_FUNCTION
;
1174 for (int i
= 0; ; i
++) {
1175 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
1176 if (comp
== NULL
) break;
1177 if (comp
->tc_state
== TC_MAP
) {
1178 send_error(comp
->tc_fd
, "Establishment of port mapping "
1179 "%d:%s - system:%s failed because the test component "
1180 "endpoint has terminated.", tc_compref
, tc_port
,
1182 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
1183 else comp
->tc_state
= PTC_FUNCTION
;
1189 remove_connection(conn
);
1192 boolean
MainController::stop_all_components()
1194 boolean ready_for_ack
= TRUE
;
1195 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1196 component_struct
*tc
= components
[i
];
1197 switch (tc
->tc_state
) {
1199 // we do not have to termiate the PTC (and wait for the control
1200 // connection) if it is alive
1201 if (!tc
->is_alive
) ready_for_ack
= FALSE
;
1204 // do nothing if the component is alive
1205 if (!tc
->is_alive
) {
1207 tc
->tc_state
= PTC_KILLING
;
1208 tc
->stop_requested
= TRUE
;
1209 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1210 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1211 start_kill_timer(tc
);
1212 ready_for_ack
= FALSE
;
1224 // the PTC is executing behaviour
1227 tc
->tc_state
= TC_STOPPING
;
1229 // STOP is never sent to non-alive PTCs
1231 tc
->tc_state
= PTC_STOPPING_KILLING
;
1233 tc
->stop_requested
= TRUE
;
1234 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1235 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1236 start_kill_timer(tc
);
1237 ready_for_ack
= FALSE
;
1240 // do nothing, just put it back to STOPPED state
1241 free_qualified_name(&tc
->tc_fn_name
);
1242 Free(tc
->starting
.arguments_ptr
);
1243 free_requestors(&tc
->starting
.cancel_done_sent_to
);
1244 tc
->tc_state
= PTC_STOPPED
;
1247 case PTC_STOPPING_KILLING
:
1248 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1249 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1250 ready_for_ack
= FALSE
;
1253 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1254 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1255 // we have to wait only if the PTC is non-alive
1256 if (!tc
->is_alive
) ready_for_ack
= FALSE
;
1264 error("Test Component %d is in invalid state when stopping all "
1265 "components.", tc
->comp_ref
);
1267 // only mtc is preserved in done_requestors and killed_requestors
1268 boolean mtc_requested_done
= has_requestor(&tc
->done_requestors
, mtc
);
1269 free_requestors(&tc
->done_requestors
);
1270 if (mtc_requested_done
) add_requestor(&tc
->done_requestors
, mtc
);
1271 boolean mtc_requested_killed
= has_requestor(&tc
->killed_requestors
,
1273 free_requestors(&tc
->killed_requestors
);
1274 if (mtc_requested_killed
) add_requestor(&tc
->killed_requestors
, mtc
);
1275 free_requestors(&tc
->cancel_done_sent_for
);
1277 return ready_for_ack
;
1281 void MainController::check_all_component_stop()
1283 // MTC has requested 'all component.stop'
1284 // we have to send acknowledgement to MTC only
1285 boolean ready_for_ack
= TRUE
;
1286 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1287 component_struct
*comp
= components
[i
];
1288 switch (comp
->tc_state
) {
1291 if (!comp
->is_alive
) ready_for_ack
= FALSE
;
1294 case PTC_STOPPING_KILLING
:
1295 ready_for_ack
= FALSE
;
1303 // only alive components can be in idle state
1304 if (comp
->is_alive
) break;
1306 error("PTC %d is in invalid state when performing "
1307 "'all component.stop' operation.", comp
->comp_ref
);
1309 if (!ready_for_ack
) break;
1311 if (ready_for_ack
) {
1313 mtc
->tc_state
= MTC_TESTCASE
;
1317 void MainController::send_stop_ack_to_requestors(component_struct
*tc
)
1319 for (int i
= 0; ; i
++) {
1320 component_struct
*requestor
=
1321 get_requestor(&tc
->stopping_killing
.stop_requestors
, i
);
1322 if (requestor
== NULL
) break;
1323 if (requestor
->tc_state
== TC_STOP
) {
1324 send_stop_ack(requestor
);
1325 if (requestor
== mtc
) requestor
->tc_state
= MTC_TESTCASE
;
1326 else requestor
->tc_state
= PTC_FUNCTION
;
1329 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1332 boolean
MainController::kill_all_components(boolean testcase_ends
)
1334 boolean ready_for_ack
= TRUE
;
1335 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1336 component_struct
*tc
= components
[i
];
1337 boolean is_inactive
= FALSE
;
1338 switch (tc
->tc_state
) {
1340 // the PTC does not have an identified control connection yet
1341 ready_for_ack
= FALSE
;
1344 free_qualified_name(&tc
->tc_fn_name
);
1345 Free(tc
->starting
.arguments_ptr
);
1346 free_requestors(&tc
->starting
.cancel_done_sent_to
);
1363 // the PTC was inactive
1364 tc
->tc_state
= PTC_KILLING
;
1365 if (!tc
->is_alive
) tc
->stop_requested
= TRUE
;
1367 // the PTC was active
1368 tc
->tc_state
= PTC_STOPPING_KILLING
;
1369 tc
->stop_requested
= TRUE
;
1371 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1372 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1373 start_kill_timer(tc
);
1374 ready_for_ack
= FALSE
;
1378 tc
->tc_state
= PTC_STOPPING_KILLING
;
1379 if (tc
->kill_timer
!= NULL
) cancel_timer(tc
->kill_timer
);
1380 start_kill_timer(tc
);
1383 case PTC_STOPPING_KILLING
:
1384 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1385 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1386 ready_for_ack
= FALSE
;
1389 if (testcase_ends
) ready_for_ack
= FALSE
;
1394 error("Test Component %d is in invalid state when killing all "
1395 "components.", tc
->comp_ref
);
1397 if (testcase_ends
) {
1398 free_requestors(&tc
->done_requestors
);
1399 free_requestors(&tc
->killed_requestors
);
1401 // only mtc is preserved in done_requestors and killed_requestors
1402 boolean mtc_requested_done
= has_requestor(&tc
->done_requestors
,
1404 free_requestors(&tc
->done_requestors
);
1405 if (mtc_requested_done
) add_requestor(&tc
->done_requestors
, mtc
);
1406 boolean mtc_requested_killed
= has_requestor(&tc
->killed_requestors
,
1408 free_requestors(&tc
->killed_requestors
);
1409 if (mtc_requested_killed
)
1410 add_requestor(&tc
->killed_requestors
, mtc
);
1412 free_requestors(&tc
->cancel_done_sent_for
);
1414 return ready_for_ack
;
1417 void MainController::check_all_component_kill()
1419 // MTC has requested 'all component.kill'
1420 // we have to send acknowledgement to MTC only
1421 boolean ready_for_ack
= TRUE
;
1422 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1423 component_struct
*comp
= components
[i
];
1424 switch (comp
->tc_state
) {
1426 case PTC_STOPPING_KILLING
:
1428 ready_for_ack
= FALSE
;
1434 error("PTC %d is in invalid state when performing "
1435 "'all component.kill' operation.", comp
->comp_ref
);
1437 if (!ready_for_ack
) break;
1439 if (ready_for_ack
) {
1441 mtc
->tc_state
= MTC_TESTCASE
;
1445 void MainController::send_kill_ack_to_requestors(component_struct
*tc
)
1447 for (int i
= 0; ; i
++) {
1448 component_struct
*requestor
=
1449 get_requestor(&tc
->stopping_killing
.kill_requestors
, i
);
1450 if (requestor
== NULL
) break;
1451 if (requestor
->tc_state
== TC_KILL
) {
1452 send_kill_ack(requestor
);
1453 if (requestor
== mtc
) requestor
->tc_state
= MTC_TESTCASE
;
1454 else requestor
->tc_state
= PTC_FUNCTION
;
1457 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1460 void MainController::send_component_status_to_requestor(component_struct
*tc
,
1461 component_struct
*requestor
, boolean done_status
, boolean killed_status
)
1463 switch (requestor
->tc_state
) {
1477 send_component_status_ptc(requestor
, tc
->comp_ref
, TRUE
,
1478 killed_status
, tc
->return_type
, tc
->return_value_len
,
1481 send_component_status_ptc(requestor
, tc
->comp_ref
, FALSE
,
1482 killed_status
, NULL
, 0, NULL
);
1485 case PTC_STOPPING_KILLING
:
1489 // the PTC requestor is not interested in the component status anymore
1492 error("PTC %d is in invalid state when sending out COMPONENT_STATUS "
1493 "message about PTC %d.", requestor
->comp_ref
, tc
->comp_ref
);
1497 void MainController::component_stopped(component_struct
*tc
)
1499 // checking and updating the state of tc
1500 tc_state_enum old_state
= tc
->tc_state
;
1501 if (old_state
== PTC_STOPPING_KILLING
) tc
->tc_state
= PTC_KILLING
;
1503 tc
->tc_state
= PTC_STOPPED
;
1504 if (tc
->kill_timer
!= NULL
) {
1505 cancel_timer(tc
->kill_timer
);
1506 tc
->kill_timer
= NULL
;
1510 case MC_EXECUTING_TESTCASE
:
1511 // this is the correct state
1513 case MC_TERMINATING_TESTCASE
:
1514 // do nothing, we are waiting for the end of all PTC connections
1517 error("PTC %d stopped in invalid MC state.", tc
->comp_ref
);
1520 if (!tc
->is_alive
) {
1521 send_error_str(tc
->tc_fd
, "Message STOPPED can only be sent by "
1525 // Note: the COMPONENT_STATUS message must be sent before STOP_ACK because
1526 // the latter may update the component status cache table to an inconsistent
1528 boolean send_status_to_mtc
= FALSE
, send_done_to_mtc
= FALSE
;
1529 // sending out COMPONENT_STATUS messages to PTCs
1530 for (int i
= 0; ; i
++) {
1531 component_struct
*requestor
= get_requestor(&tc
->done_requestors
, i
);
1532 if (requestor
== NULL
) break;
1533 else if (requestor
== mtc
) {
1534 send_status_to_mtc
= TRUE
;
1535 send_done_to_mtc
= TRUE
;
1536 } else send_component_status_to_requestor(tc
, requestor
, TRUE
, FALSE
);
1538 // do not send unsolicited 'any component.done' status
1539 if (any_component_done_requested
) send_status_to_mtc
= TRUE
;
1540 boolean all_done_checked
= FALSE
, all_done_result
= FALSE
;
1541 if (all_component_done_requested
) {
1542 all_done_checked
= TRUE
;
1543 all_done_result
= !is_any_component_running();
1544 if (all_done_result
) send_status_to_mtc
= TRUE
;
1546 if (send_status_to_mtc
) {
1547 if (!all_done_checked
) all_done_result
= !is_any_component_running();
1548 if (send_done_to_mtc
) {
1549 // the return value was requested
1550 send_component_status_mtc(tc
->comp_ref
, TRUE
, FALSE
,
1551 any_component_done_requested
, all_done_result
, FALSE
, FALSE
,
1552 tc
->return_type
, tc
->return_value_len
, tc
->return_value
);
1554 // the return value was not requested
1555 send_component_status_mtc(NULL_COMPREF
, FALSE
, FALSE
,
1556 any_component_done_requested
, all_done_result
, FALSE
, FALSE
,
1559 if (any_component_done_requested
) {
1560 any_component_done_requested
= FALSE
;
1561 any_component_done_sent
= TRUE
;
1563 if (all_done_result
) all_component_done_requested
= FALSE
;
1565 // sending out STOP_ACK messages
1566 if (old_state
!= PTC_FUNCTION
) {
1567 // the PTC was explicitly stopped and/or killed
1568 if (mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
) {
1570 } else if (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
) {
1571 check_all_component_stop();
1573 send_stop_ack_to_requestors(tc
);
1578 void MainController::component_terminated(component_struct
*tc
)
1580 // the state variable of the PTC has to be updated first
1581 // because in case of 'all component.kill' or 'all component.stop'
1582 // we are walking through the states of all PTCs
1583 tc_state_enum old_state
= tc
->tc_state
;
1584 tc
->tc_state
= TC_EXITING
;
1586 tc
->comp_location
->n_active_components
--;
1588 case MC_EXECUTING_TESTCASE
:
1589 // this is the correct state
1591 case MC_TERMINATING_TESTCASE
:
1592 // do nothing, we are waiting for the end of all PTC connections
1595 error("PTC %d terminated in invalid MC state.", tc
->comp_ref
);
1598 // sending out COMPONENT_STATUS messages
1600 // - the COMPONENT_STATUS message must be sent before STOP_ACK and KILL_ACK
1601 // because the latter may update the component status cache table to an
1602 // inconsistent state
1603 // - unsolicited 'done' status and return value is never sent out
1604 // the flags below indicate whether a COMPONENT_STATUS message
1605 // (with or without the return value) has to be sent to the MTC
1606 boolean send_status_to_mtc
= FALSE
, send_done_to_mtc
= TRUE
;
1607 // first send out the COMPONENT_STATUS messages to PTCs
1608 for (int i
= 0; ; i
++) {
1609 component_struct
*requestor
= get_requestor(&tc
->done_requestors
, i
);
1610 if (requestor
== NULL
) break;
1611 else if (requestor
== mtc
) {
1612 send_status_to_mtc
= TRUE
;
1613 send_done_to_mtc
= TRUE
;
1614 } else send_component_status_to_requestor(tc
, requestor
, TRUE
, TRUE
);
1616 for (int i
= 0; ; i
++) {
1617 component_struct
*requestor
= get_requestor(&tc
->killed_requestors
, i
);
1618 if (requestor
== NULL
) break;
1619 else if (requestor
== mtc
) send_status_to_mtc
= TRUE
;
1620 else if (!has_requestor(&tc
->done_requestors
, requestor
)) {
1621 // do not send COMPONENT_STATUS twice to the same PTC
1622 send_component_status_to_requestor(tc
, requestor
, FALSE
, TRUE
);
1625 free_requestors(&tc
->done_requestors
);
1626 free_requestors(&tc
->killed_requestors
);
1627 // deciding whether to send a COMPONENT_STATUS message to MTC
1628 // 'any component.done' status can be safely sent out
1629 // it will not be cancelled later
1630 if (any_component_done_requested
|| any_component_killed_requested
)
1631 send_status_to_mtc
= TRUE
;
1632 boolean all_done_checked
= FALSE
, all_done_result
= FALSE
;
1633 if (all_component_done_requested
) {
1634 all_done_checked
= TRUE
;
1635 all_done_result
= !is_any_component_running();
1636 if (all_done_result
) send_status_to_mtc
= TRUE
;
1638 boolean all_killed_checked
= FALSE
, all_killed_result
= FALSE
;
1639 if (all_component_killed_requested
) {
1640 all_killed_checked
= TRUE
;
1641 all_killed_result
= !is_any_component_alive();
1642 if (all_killed_result
) send_status_to_mtc
= TRUE
;
1644 // sending the COMPONENT_STATUS message to MTC if necessary
1645 if (send_status_to_mtc
) {
1646 if (!all_done_checked
) all_done_result
= !is_any_component_running();
1647 if (!all_killed_checked
) all_killed_result
= !is_any_component_alive();
1648 if (send_done_to_mtc
) {
1649 // the return value was requested
1650 send_component_status_mtc(tc
->comp_ref
, TRUE
, TRUE
, TRUE
,
1651 all_done_result
, TRUE
, all_killed_result
, tc
->return_type
,
1652 tc
->return_value_len
, tc
->return_value
);
1654 // the return value was not requested
1655 send_component_status_mtc(tc
->comp_ref
, FALSE
, TRUE
, TRUE
,
1656 all_done_result
, TRUE
, all_killed_result
, NULL
, 0, NULL
);
1658 any_component_done_requested
= FALSE
;
1659 any_component_done_sent
= TRUE
;
1660 any_component_killed_requested
= FALSE
;
1661 if (all_done_result
) all_component_done_requested
= FALSE
;
1662 if (all_killed_result
) all_component_killed_requested
= FALSE
;
1664 // sending out STOP_ACK and KILL_ACK messages if necessary
1665 switch (old_state
) {
1667 case PTC_STOPPING_KILLING
:
1669 // the component was explicitly stopped and/or killed
1670 if (mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
) {
1671 check_all_component_kill();
1672 } else if (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
) {
1673 check_all_component_stop();
1675 send_stop_ack_to_requestors(tc
);
1676 send_kill_ack_to_requestors(tc
);
1681 // we should behave as we got all pending CANCEL_DONE_ACK messages from tc
1682 for (int i
= 0; ; i
++) {
1683 component_struct
*comp
= get_requestor(&tc
->cancel_done_sent_for
, i
);
1684 if (comp
== NULL
) break;
1685 done_cancelled(tc
, comp
);
1687 free_requestors(&tc
->cancel_done_sent_for
);
1688 // destroy all connections and mappings of the component
1689 // and send out the related messages
1690 while (tc
->conn_head_list
!= NULL
) {
1691 if (tc
->conn_head_list
->tail
.comp_ref
== SYSTEM_COMPREF
)
1692 destroy_mapping(tc
->conn_head_list
);
1693 else destroy_connection(tc
->conn_head_list
, tc
);
1695 while (tc
->conn_tail_list
!= NULL
) {
1696 if (tc
->conn_tail_list
->head
.comp_ref
== SYSTEM_COMPREF
)
1697 destroy_mapping(tc
->conn_tail_list
);
1698 else destroy_connection(tc
->conn_tail_list
, tc
);
1700 // drop the name of the currently executed function
1701 free_qualified_name(&tc
->tc_fn_name
);
1704 void MainController::done_cancelled(component_struct
*from
,
1705 component_struct
*started_tc
)
1707 // do nothing if the PTC to be started is not in starting state anymore
1708 if (started_tc
->tc_state
!= PTC_STARTING
) return;
1709 remove_requestor(&started_tc
->starting
.cancel_done_sent_to
, from
);
1710 // do nothing if we are waiting for more CANCEL_DONE_ACK messages
1711 if (get_requestor(&started_tc
->starting
.cancel_done_sent_to
, 0) != NULL
)
1713 send_start(started_tc
, started_tc
->tc_fn_name
,
1714 started_tc
->starting
.arguments_len
, started_tc
->starting
.arguments_ptr
);
1715 component_struct
*start_requestor
= started_tc
->starting
.start_requestor
;
1716 if (start_requestor
->tc_state
== TC_START
) {
1717 send_start_ack(start_requestor
);
1718 if (start_requestor
== mtc
) start_requestor
->tc_state
= MTC_TESTCASE
;
1719 else start_requestor
->tc_state
= PTC_FUNCTION
;
1721 Free(started_tc
->starting
.arguments_ptr
);
1722 free_requestors(&started_tc
->starting
.cancel_done_sent_to
);
1723 started_tc
->tc_state
= PTC_FUNCTION
;
1727 boolean
MainController::component_is_alive(component_struct
*tc
)
1729 switch (tc
->tc_state
) {
1745 case PTC_STOPPING_KILLING
:
1751 error("PTC %d is in invalid state when checking whether it is alive.",
1757 boolean
MainController::component_is_running(component_struct
*tc
)
1759 switch (tc
->tc_state
) {
1771 case PTC_STOPPING_KILLING
:
1781 error("PTC %d is in invalid state when checking whether it is running.",
1787 boolean
MainController::component_is_done(component_struct
*tc
)
1789 switch (tc
->tc_state
) {
1808 case PTC_STOPPING_KILLING
:
1811 error("PTC %d is in invalid state when checking whether it is done.",
1817 boolean
MainController::is_any_component_alive()
1819 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1820 if (component_is_alive(components
[i
])) return TRUE
;
1824 boolean
MainController::is_all_component_alive()
1826 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1827 if (!component_is_alive(components
[i
])) return FALSE
;
1831 boolean
MainController::is_any_component_running()
1833 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1834 if (component_is_running(components
[i
])) return TRUE
;
1838 boolean
MainController::is_all_component_running()
1840 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1841 component_struct
*tc
= components
[i
];
1842 if (tc
->stop_requested
) continue;
1843 switch (tc
->tc_state
) {
1855 boolean
MainController::is_any_component_done()
1857 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1858 if (component_is_done(components
[i
])) return TRUE
;
1862 void MainController::start_kill_timer(component_struct
*tc
)
1864 if (kill_timer
> 0.0) {
1865 timer_struct
*timer
= new timer_struct
;
1866 timer
->expiration
= time_now() + kill_timer
;
1867 timer
->timer_argument
.component_ptr
= tc
;
1868 tc
->kill_timer
= timer
;
1869 register_timer(timer
);
1870 } else tc
->kill_timer
= NULL
;
1873 void MainController::init_connections(component_struct
*tc
)
1875 tc
->conn_head_list
= NULL
;
1876 tc
->conn_tail_list
= NULL
;
1877 tc
->conn_head_count
= 0;
1878 tc
->conn_tail_count
= 0;
1881 void MainController::add_connection(port_connection
*c
)
1883 // Canonical ordering of endpoints so that head <= tail
1884 if (c
->head
.comp_ref
> c
->tail
.comp_ref
) {
1885 component tmp_comp
= c
->head
.comp_ref
;
1886 c
->head
.comp_ref
= c
->tail
.comp_ref
;
1887 c
->tail
.comp_ref
= tmp_comp
;
1888 char *tmp_port
= c
->head
.port_name
;
1889 c
->head
.port_name
= c
->tail
.port_name
;
1890 c
->tail
.port_name
= tmp_port
;
1891 } else if (c
->head
.comp_ref
== c
->tail
.comp_ref
&&
1892 strcmp(c
->head
.port_name
, c
->tail
.port_name
) > 0) {
1893 char *tmp_port
= c
->head
.port_name
;
1894 c
->head
.port_name
= c
->tail
.port_name
;
1895 c
->tail
.port_name
= tmp_port
;
1897 // Double-chain in according to c->head
1898 component_struct
*head_component
= lookup_component(c
->head
.comp_ref
);
1899 port_connection
*head_connection
= head_component
->conn_head_list
;
1900 if (head_connection
== NULL
) {
1904 c
->head
.prev
= head_connection
->head
.prev
;
1905 head_connection
->head
.prev
= c
;
1906 c
->head
.next
= head_connection
;
1907 c
->head
.prev
->head
.next
= c
;
1909 head_component
->conn_head_list
= c
;
1910 head_component
->conn_head_count
++;
1911 // Double-chain in according to c->tail
1912 component_struct
*tail_component
= lookup_component(c
->tail
.comp_ref
);
1913 port_connection
*tail_connection
= tail_component
->conn_tail_list
;
1914 if (tail_connection
== NULL
) {
1918 c
->tail
.prev
= tail_connection
->tail
.prev
;
1919 tail_connection
->tail
.prev
= c
;
1920 c
->tail
.next
= tail_connection
;
1921 c
->tail
.prev
->tail
.next
= c
;
1923 tail_component
->conn_tail_list
= c
;
1924 tail_component
->conn_tail_count
++;
1927 void MainController::remove_connection(port_connection
*c
)
1929 // Remove from conn_head_list
1930 component_struct
*head_component
= lookup_component(c
->head
.comp_ref
);
1931 if (c
->head
.next
== c
) {
1932 head_component
->conn_head_list
= NULL
;
1933 head_component
->conn_head_count
= 0;
1935 c
->head
.prev
->head
.next
= c
->head
.next
;
1936 c
->head
.next
->head
.prev
= c
->head
.prev
;
1937 head_component
->conn_head_list
= c
->head
.next
;
1938 head_component
->conn_head_count
--;
1940 // Remove from conn_tail_list
1941 component_struct
*tail_component
= lookup_component(c
->tail
.comp_ref
);
1942 if (c
->tail
.next
== c
) {
1943 tail_component
->conn_tail_list
= NULL
;
1944 tail_component
->conn_tail_count
= 0;
1946 c
->tail
.prev
->tail
.next
= c
->tail
.next
;
1947 c
->tail
.next
->tail
.prev
= c
->tail
.prev
;
1948 tail_component
->conn_tail_list
= c
->tail
.next
;
1949 tail_component
->conn_tail_count
--;
1951 // Delete the data members
1952 delete [] c
->head
.port_name
;
1953 delete [] c
->tail
.port_name
;
1954 free_requestors(&c
->requestors
);
1958 port_connection
*MainController::find_connection(component head_comp
,
1959 const char *head_port
, component tail_comp
, const char *tail_port
)
1961 // Canonical ordering of parameters so that head <= tail
1962 if (head_comp
> tail_comp
) {
1963 component tmp_comp
= head_comp
;
1964 head_comp
= tail_comp
;
1965 tail_comp
= tmp_comp
;
1966 const char *tmp_port
= head_port
;
1967 head_port
= tail_port
;
1968 tail_port
= tmp_port
;
1969 } else if (head_comp
== tail_comp
&& strcmp(head_port
, tail_port
) > 0) {
1970 const char *tmp_port
= head_port
;
1971 head_port
= tail_port
;
1972 tail_port
= tmp_port
;
1974 // Check whether one of the endpoints' list is empty
1975 component_struct
*head_component
= lookup_component(head_comp
);
1976 port_connection
*head_connection
= head_component
->conn_head_list
;
1977 if (head_connection
== NULL
) return NULL
;
1978 component_struct
*tail_component
= lookup_component(tail_comp
);
1979 port_connection
*tail_connection
= tail_component
->conn_tail_list
;
1980 if (tail_connection
== NULL
) return NULL
;
1981 // Start searching on the shorter list
1982 if (head_component
->conn_head_count
<= tail_component
->conn_tail_count
) {
1983 port_connection
*iter
= head_connection
;
1985 if (iter
->tail
.comp_ref
== tail_comp
&&
1986 !strcmp(iter
->head
.port_name
, head_port
) &&
1987 !strcmp(iter
->tail
.port_name
, tail_port
)) return iter
;
1988 iter
= iter
->head
.next
;
1989 } while (iter
!= head_connection
);
1992 port_connection
*iter
= tail_connection
;
1994 if (iter
->head
.comp_ref
== head_comp
&&
1995 !strcmp(iter
->head
.port_name
, head_port
) &&
1996 !strcmp(iter
->tail
.port_name
, tail_port
)) return iter
;
1997 iter
= iter
->tail
.next
;
1998 } while (iter
!= tail_connection
);
2003 void MainController::remove_all_connections(component head_or_tail
)
2005 component_struct
*comp
= lookup_component(head_or_tail
);
2006 while (comp
->conn_head_list
!= NULL
)
2007 remove_connection(comp
->conn_head_list
);
2008 while (comp
->conn_tail_list
!= NULL
)
2009 remove_connection(comp
->conn_tail_list
);
2012 transport_type_enum
MainController::choose_port_connection_transport(
2013 component head_comp
, component tail_comp
)
2015 host_struct
*head_location
= components
[head_comp
]->comp_location
;
2016 // use the most efficient software loop if the two endpoints are in the
2017 // same component and the host supports it
2018 if (head_comp
== tail_comp
&&
2019 head_location
->transport_supported
[TRANSPORT_LOCAL
])
2020 return TRANSPORT_LOCAL
;
2021 host_struct
*tail_location
= components
[tail_comp
]->comp_location
;
2022 // use the efficient UNIX domain socket if the two endpoints are on the
2023 // same host and it is supported by the host
2024 if (head_location
== tail_location
&&
2025 head_location
->transport_supported
[TRANSPORT_UNIX_STREAM
])
2026 return TRANSPORT_UNIX_STREAM
;
2027 // use TCP if it is supported by the host of both endpoints
2028 if (head_location
->transport_supported
[TRANSPORT_INET_STREAM
] &&
2029 tail_location
->transport_supported
[TRANSPORT_INET_STREAM
])
2030 return TRANSPORT_INET_STREAM
;
2031 // no suitable transport was found, return an erroneous type
2032 return TRANSPORT_NUM
;
2035 void MainController::send_connect_ack_to_requestors(port_connection
*conn
)
2037 for (int i
= 0; ; i
++) {
2038 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2039 if (comp
== NULL
) break;
2040 else if (comp
->tc_state
== TC_CONNECT
) {
2041 send_connect_ack(comp
);
2042 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2043 else comp
->tc_state
= PTC_FUNCTION
;
2046 free_requestors(&conn
->requestors
);
2049 void MainController::send_error_to_connect_requestors(port_connection
*conn
,
2050 const char *fmt
, ...)
2052 char *reason
= mprintf("Establishment of port connection %d:%s - %d:%s "
2053 "failed because ", conn
->head
.comp_ref
, conn
->head
.port_name
,
2054 conn
->tail
.comp_ref
, conn
->tail
.port_name
);
2057 reason
= mputprintf_va_list(reason
, fmt
, ap
);
2059 for (int i
= 0; ; i
++) {
2060 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2061 if (comp
== NULL
) break;
2062 else if (comp
->tc_state
== TC_CONNECT
) {
2063 send_error_str(comp
->tc_fd
, reason
);
2064 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2065 else comp
->tc_state
= PTC_FUNCTION
;
2069 free_requestors(&conn
->requestors
);
2072 void MainController::send_disconnect_to_server(port_connection
*conn
)
2074 component_struct
*comp
= components
[conn
->head
.comp_ref
];
2075 switch (comp
->tc_state
) {
2090 send_disconnect(comp
, conn
->head
.port_name
, conn
->tail
.comp_ref
,
2091 conn
->tail
.port_name
);
2097 void MainController::send_disconnect_ack_to_requestors(port_connection
*conn
)
2099 for (int i
= 0; ; i
++) {
2100 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2101 if (comp
== NULL
) break;
2102 else if (comp
->tc_state
== TC_DISCONNECT
) {
2103 send_disconnect_ack(comp
);
2104 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2105 else comp
->tc_state
= PTC_FUNCTION
;
2108 free_requestors(&conn
->requestors
);
2111 void MainController::init_requestors(requestor_struct
*reqs
,
2112 component_struct
*tc
)
2115 reqs
->n_components
= 1;
2116 reqs
->the_component
= tc
;
2117 } else reqs
->n_components
= 0;
2120 void MainController::add_requestor(requestor_struct
*reqs
, component_struct
*tc
)
2122 switch (reqs
->n_components
) {
2124 reqs
->n_components
= 1;
2125 reqs
->the_component
= tc
;
2128 if (reqs
->the_component
!= tc
) {
2129 reqs
->n_components
= 2;
2130 component_struct
*tmp
= reqs
->the_component
;
2132 (component_struct
**)Malloc(2 * sizeof(*reqs
->components
));
2133 reqs
->components
[0] = tmp
;
2134 reqs
->components
[1] = tc
;
2138 for (int i
= 0; i
< reqs
->n_components
; i
++)
2139 if (reqs
->components
[i
] == tc
) return;
2140 reqs
->n_components
++;
2141 reqs
->components
= (component_struct
**)Realloc(reqs
->components
,
2142 reqs
->n_components
* sizeof(*reqs
->components
));
2143 reqs
->components
[reqs
->n_components
- 1] = tc
;
2147 void MainController::remove_requestor(requestor_struct
*reqs
,
2148 component_struct
*tc
)
2150 switch (reqs
->n_components
) {
2154 if (reqs
->the_component
== tc
) reqs
->n_components
= 0;
2157 component_struct
*tmp
= NULL
;
2158 if (reqs
->components
[0] == tc
) tmp
= reqs
->components
[1];
2159 else if (reqs
->components
[1] == tc
) tmp
= reqs
->components
[0];
2161 Free(reqs
->components
);
2162 reqs
->n_components
= 1;
2163 reqs
->the_component
= tmp
;
2167 for (int i
= 0; i
< reqs
->n_components
; i
++)
2168 if (reqs
->components
[i
] == tc
) {
2169 reqs
->n_components
--;
2170 memmove(reqs
->components
+ i
, reqs
->components
+ i
+ 1,
2171 (reqs
->n_components
- i
) * sizeof(*reqs
->components
));
2172 reqs
->components
= (component_struct
**)Realloc(reqs
->components
,
2173 reqs
->n_components
* sizeof(*reqs
->components
));
2179 boolean
MainController::has_requestor(const requestor_struct
*reqs
,
2180 component_struct
*tc
)
2182 switch (reqs
->n_components
) {
2186 return reqs
->the_component
== tc
;
2188 for (int i
= 0; i
< reqs
->n_components
; i
++)
2189 if (reqs
->components
[i
] == tc
) return TRUE
;
2194 component_struct
*MainController::get_requestor(const requestor_struct
*reqs
,
2197 if (index
>= 0 && index
< reqs
->n_components
) {
2198 if (reqs
->n_components
== 1) return reqs
->the_component
;
2199 else return reqs
->components
[index
];
2203 void MainController::free_requestors(requestor_struct
*reqs
)
2205 if (reqs
->n_components
> 1) Free(reqs
->components
);
2206 reqs
->n_components
= 0;
2209 void MainController::init_qualified_name(qualified_name
*name
)
2211 name
->module_name
= NULL
;
2212 name
->definition_name
= NULL
;
2215 void MainController::free_qualified_name(qualified_name
*name
)
2217 delete [] name
->module_name
;
2218 name
->module_name
= NULL
;
2219 delete [] name
->definition_name
;
2220 name
->definition_name
= NULL
;
2223 double MainController::kill_timer
;
2225 double MainController::time_now()
2227 static boolean first_call
= TRUE
;
2228 static struct timeval first_time
;
2231 if (gettimeofday(&first_time
, NULL
) < 0)
2232 fatal_error("MainController::time_now: gettimeofday() system call "
2237 if (gettimeofday(&tv
, NULL
) < 0)
2238 fatal_error("MainController::time_now: gettimeofday() system call "
2240 return (tv
.tv_sec
- first_time
.tv_sec
) +
2241 1.0e-6 * (tv
.tv_usec
- first_time
.tv_usec
);
2245 timer_struct
*MainController::timer_head
, *MainController::timer_tail
;
2247 void MainController::register_timer(timer_struct
*timer
)
2250 for (iter
= timer_tail
; iter
!= NULL
; iter
= iter
->prev
)
2251 if (iter
->expiration
<= timer
->expiration
) break;
2253 // inserting after iter
2255 timer
->next
= iter
->next
;
2256 if (iter
->next
!= NULL
) iter
->next
->prev
= timer
;
2257 else timer_tail
= timer
;
2260 // inserting at the beginning of list
2262 timer
->next
= timer_head
;
2263 if (timer_head
!= NULL
) timer_head
->prev
= timer
;
2264 else timer_tail
= timer
;
2269 void MainController::cancel_timer(timer_struct
*timer
)
2271 if (timer
->next
!= NULL
) timer
->next
->prev
= timer
->prev
;
2272 else timer_tail
= timer
->prev
;
2273 if (timer
->prev
!= NULL
) timer
->prev
->next
= timer
->next
;
2274 else timer_head
= timer
->next
;
2278 int MainController::get_poll_timeout()
2280 if (timer_head
!= NULL
) {
2281 double offset
= timer_head
->expiration
- time_now();
2282 if (offset
> 0.0) return (int)(1000.0 * offset
);
2287 void MainController::handle_expired_timers()
2289 if (timer_head
!= NULL
) {
2290 timer_struct
*iter
= timer_head
;
2291 double now
= time_now();
2293 if (iter
->expiration
> now
) break;
2294 timer_struct
*next
= iter
->next
;
2295 handle_kill_timer(iter
);
2297 } while (iter
!= NULL
);
2301 void MainController::handle_kill_timer(timer_struct
*timer
)
2303 component_struct
*tc
= timer
->timer_argument
.component_ptr
;
2304 host_struct
*host
= tc
->comp_location
;
2305 boolean kill_process
= FALSE
;
2306 switch (tc
->tc_state
) {
2312 error("MTC on host %s did not close its control connection in "
2313 "time. Trying to kill it using its HC.", host
->hostname
);
2315 notify("PTC %d on host %s did not close its control connection in "
2316 "time. Trying to kill it using its HC.", tc
->comp_ref
,
2319 kill_process
= TRUE
;
2322 case PTC_STOPPING_KILLING
:
2324 // active PTCs with kill timer can be only in these states
2326 notify("PTC %d on host %s is not responding. Trying to kill it "
2327 "using its HC.", tc
->comp_ref
, host
->hostname
);
2328 kill_process
= TRUE
;
2333 // MTC can be in any state
2335 error("MTC on host %s is not responding. Trying to kill it using "
2336 "its HC. This will abort test execution.", host
->hostname
);
2337 kill_process
= TRUE
;
2339 error("PTC %d is in invalid state when its kill timer expired.",
2344 if (host
->hc_state
== HC_ACTIVE
) {
2345 send_kill_process(host
, tc
->comp_ref
);
2346 tc
->process_killed
= TRUE
;
2348 error("Test Component %d cannot be killed because the HC on host "
2349 "%s is not in active state. Kill the process manually or the "
2350 "test system may get into a deadlock.", tc
->comp_ref
,
2354 cancel_timer(timer
);
2355 tc
->kill_timer
= NULL
;
2358 void MainController::register_termination_handlers()
2360 new_action
.sa_handler
= termination_handler
;
2361 sigemptyset(&new_action
.sa_mask
);
2362 new_action
.sa_flags
= 0;
2364 sigaction(SIGINT
, NULL
, &old_action
);
2365 if (old_action
.sa_handler
!= SIG_IGN
)
2366 sigaction (SIGINT
, &new_action
, NULL
);
2367 sigaction(SIGHUP
, NULL
, &old_action
);
2368 if (old_action
.sa_handler
!= SIG_IGN
)
2369 sigaction (SIGHUP
, &new_action
, NULL
);
2370 sigaction(SIGTERM
, NULL
, &old_action
);
2371 if (old_action
.sa_handler
!= SIG_IGN
)
2372 sigaction(SIGTERM
, &new_action
, NULL
);
2373 sigaction(SIGQUIT
, NULL
, &old_action
);
2374 if (old_action
.sa_handler
!= SIG_IGN
)
2375 sigaction(SIGQUIT
, &new_action
, NULL
);
2376 sigaction(SIGKILL
, NULL
, &old_action
);
2377 if (old_action
.sa_handler
!= SIG_IGN
)
2378 sigaction(SIGKILL
, &new_action
, NULL
);
2381 void MainController::termination_handler(int signum
)
2383 // Call shutdown_server() and reset handlers and re-raise the signal.
2384 // clean_up() or perform_shutdown() is state dependent and cannot be used
2385 // here... Related to HP67376.
2388 new_action
.sa_handler
= SIG_DFL
;
2389 sigemptyset(&new_action
.sa_mask
);
2390 new_action
.sa_flags
= 0;
2392 sigaction(SIGINT
, &new_action
, NULL
);
2393 sigaction(SIGHUP
, &new_action
, NULL
);
2394 sigaction(SIGTERM
, &new_action
, NULL
);
2395 sigaction(SIGQUIT
, &new_action
, NULL
);
2396 sigaction(SIGKILL
, &new_action
, NULL
);
2401 void MainController::error(const char *fmt
, ...)
2405 char *str
= mprintf_va_list(fmt
, ap
);
2408 ui
->error(/*severity*/ 0, str
);
2413 void MainController::notify(const char *fmt
, ...)
2417 char *str
= mprintf_va_list(fmt
, ap
);
2420 if (gettimeofday(&tv
, NULL
) < 0) fatal_error("MainController::notify: "
2421 "gettimeofday() system call failed.");
2422 notify(&tv
, mc_hostname
, TTCN_EXECUTOR
, str
);
2426 void MainController::notify(const struct timeval
*timestamp
,
2427 const char *source
, int severity
, const char *message
)
2430 ui
->notify(timestamp
, source
, severity
, message
);
2434 void MainController::status_change()
2437 ui
->status_change();
2441 void MainController::fatal_error(const char *fmt
, ...)
2445 vfprintf(stderr
, fmt
, ap
);
2447 if (errno
!= 0) fprintf(stderr
, " (%s)", strerror(errno
));
2452 void *MainController::thread_main(void *)
2455 while (mc_state
!= MC_INACTIVE
) {
2460 int timeout
= get_poll_timeout();
2461 if (maxDtInMs
!= 0 && (timeout
< 0 || maxDtInMs
< timeout
))
2462 timeout
= maxDtInMs
;
2464 fds_selected
= epoll_wait(epfd
, epoll_events
, EPOLL_MAX_EVENTS
,
2467 if (fds_selected
>= 0) break;
2468 if (errno
!= EINTR
) fatal_error("epoll_wait() system call failed.");
2469 #else // ! defined USE_EPOLL
2471 int timeout
= get_poll_timeout();
2472 if (maxDtInMs
!= 0 && (timeout
< 0 || maxDtInMs
< timeout
))
2473 timeout
= maxDtInMs
;
2475 fds_selected
= poll(ufds
, nfds
, timeout
);
2477 if (fds_selected
>= 0) break;
2478 if (errno
!= EINTR
) fatal_error("poll() system call failed.");
2482 switch (wakeup_reason
) {
2483 case REASON_NOTHING
:
2484 case REASON_MTC_KILL_TIMER
:
2486 case REASON_SHUTDOWN
:
2487 wakeup_reason
= REASON_NOTHING
;
2491 error("Invalid wakeup reason (%d) was set.", wakeup_reason
);
2492 wakeup_reason
= REASON_NOTHING
;
2494 if (fds_selected
== 0) {
2495 handle_expired_timers();
2499 for (int i
= 0; i
< fds_selected
; i
++) {
2500 int fd
= epoll_events
[i
].data
.fd
;
2501 if (epoll_events
[i
].events
& (EPOLLIN
| EPOLLHUP
| EPOLLERR
)) {
2502 dispatch_socket_event(fd
);
2505 #else // ! defined USE_EPOLL
2506 for (unsigned int i
= 0; i
< nfds
; i
++) {
2507 int fd
= ufds
[i
].fd
;
2508 if (ufds
[i
].revents
& POLLNVAL
) {
2509 fatal_error("Invalid file descriptor (%d) was given for "
2510 "poll() system call.", fd
);
2511 } else if (ufds
[i
].revents
& (POLLIN
| POLLHUP
| POLLERR
)) {
2512 dispatch_socket_event(fd
);
2516 handle_expired_timers();
2519 notify("Shutdown complete.");
2521 // don't try to lock the mutex after ui->status_change() is completed
2522 // the main thread might call in turn terminate(), which destroys the mutex
2523 ui
->status_change();
2527 void MainController::dispatch_socket_event(int fd
)
2529 // a previous event might have closed the socket
2530 if (fd
>= fd_table_size
) return;
2531 switch (fd_table
[fd
].fd_type
) {
2536 handle_incoming_connection(fd
);
2539 handle_unknown_data(fd_table
[fd
].unknown_ptr
);
2542 handle_hc_data(fd_table
[fd
].host_ptr
, TRUE
);
2545 handle_tc_data(fd_table
[fd
].component_ptr
, TRUE
);
2548 fatal_error("Invalid file descriptor type (%d) for "
2549 "file descriptor %d.", fd_table
[fd
].fd_type
, fd
);
2553 int MainController::pipe_fd
[2];
2554 wakeup_reason_t
MainController::wakeup_reason
;
2556 void MainController::wakeup_thread(wakeup_reason_t reason
)
2558 unsigned char msg
= '\0';
2559 if (write(pipe_fd
[1], &msg
, 1) != 1) {
2560 fatal_error("MainController::wakeup_thread: writing to pipe failed.");
2562 wakeup_reason
= reason
;
2565 void MainController::handle_pipe()
2568 if (read(pipe_fd
[0], &buf
, 1) != 1) {
2569 fatal_error("MainController::handle_pipe: reading from pipe failed.");
2573 void MainController::handle_incoming_connection(int p_server_fd
)
2575 IPAddress
*remote_addr
= IPAddress::create_addr(nh
.get_family());
2576 int fd
= remote_addr
->accept(p_server_fd
);
2578 set_close_on_exec(fd
);
2579 unknown_connection
*new_connection
=
2580 new_unknown_connection(p_server_fd
!= MainController::server_fd
);
2581 new_connection
->fd
= fd
;
2582 if (p_server_fd
== MainController::server_fd
)
2583 new_connection
->ip_addr
= remote_addr
;
2584 else { // in case of unix domain socket connection
2586 new_connection
->ip_addr
= IPAddress::create_addr("127.0.0.1");
2588 new_connection
->text_buf
= new Text_Buf
;
2590 add_fd_to_table(fd
);
2591 fd_table
[fd
].fd_type
= FD_UNKNOWN
;
2592 fd_table
[fd
].unknown_ptr
= new_connection
;
2601 error("New incoming connection cannot be accepted "
2602 "because the maximum number of open files has been reached. "
2603 "Try to increase this limit.");
2604 disable_server_fd();
2605 error("No incoming connections will be accepted until at least "
2606 "one component terminates. This may result in deadlock.");
2609 fatal_error("MainController::handle_incoming_connection: "
2610 "system call accept() failed.");
2615 int MainController::recv_to_buffer(int fd
, Text_Buf
& text_buf
,
2616 boolean recv_from_socket
)
2618 // if recv_from_socket is false we are checking the messages that are
2619 // already in text_buf so we are emulating that recv() was successful
2620 if (!recv_from_socket
) return 1;
2624 text_buf
.get_end(buf_ptr
, buf_len
);
2626 int recv_len
= recv(fd
, buf_ptr
, buf_len
, 0);
2628 if (recv_len
> 0) text_buf
.increase_length(recv_len
);
2633 void MainController::handle_unknown_data(unknown_connection
*conn
)
2635 Text_Buf
& text_buf
= *conn
->text_buf
;
2636 int recv_len
= recv_to_buffer(conn
->fd
, text_buf
, TRUE
);
2637 boolean error_flag
= FALSE
;
2641 while (text_buf
.is_message()) {
2642 text_buf
.pull_int(); // message length
2643 int message_type
= text_buf
.pull_int().get_val();
2644 // only the first message is processed in this loop
2645 // except when a generic message is received
2646 boolean process_more_messages
= FALSE
;
2647 switch (message_type
) {
2649 process_error(conn
);
2650 process_more_messages
= TRUE
;
2654 process_more_messages
= TRUE
;
2657 process_version(conn
);
2659 case MSG_MTC_CREATED
:
2660 process_mtc_created(conn
);
2662 case MSG_PTC_CREATED
:
2663 process_ptc_created(conn
);
2666 error("Invalid message type (%d) was received on an "
2667 "unknown connection from %s [%s].", message_type
,
2668 conn
->ip_addr
->get_host_str(),
2669 conn
->ip_addr
->get_addr_str());
2672 if (process_more_messages
) text_buf
.cut_message();
2675 } catch (const TC_Error
& tc_error
) {
2676 error("Maleformed message was received on an unknown connection "
2677 "from %s [%s].", conn
->ip_addr
->get_host_str(),
2678 conn
->ip_addr
->get_addr_str());
2682 send_error_str(conn
->fd
, "The received message was not understood "
2685 } else if (recv_len
== 0) {
2686 error("Unexpected end of an unknown connection from %s [%s].",
2687 conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str());
2690 error("Receiving of data failed on an unknown connection from %s [%s].",
2691 conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str());
2695 close_unknown_connection(conn
);
2699 void MainController::handle_hc_data(host_struct
*hc
, boolean recv_from_socket
)
2701 Text_Buf
& text_buf
= *hc
->text_buf
;
2702 boolean error_flag
= FALSE
;
2703 int recv_len
= recv_to_buffer(hc
->hc_fd
, text_buf
, recv_from_socket
);
2707 while (text_buf
.is_message()) {
2708 text_buf
.pull_int(); // message length
2709 int message_type
= text_buf
.pull_int().get_val();
2710 switch (message_type
) {
2717 case MSG_CONFIGURE_ACK
:
2718 process_configure_ack(hc
);
2720 case MSG_CONFIGURE_NAK
:
2721 process_configure_nak(hc
);
2723 case MSG_CREATE_NAK
:
2724 process_create_nak(hc
);
2727 process_hc_ready(hc
);
2730 error("Invalid message type (%d) was received on HC "
2731 "connection from %s [%s].", message_type
,
2732 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2735 if (error_flag
) break;
2736 text_buf
.cut_message();
2738 } catch (const TC_Error
& tc_error
) {
2739 error("Malformed message was received on HC connection "
2740 "from %s [%s].", hc
->hostname
, hc
->ip_addr
->get_addr_str());
2744 send_error_str(hc
->hc_fd
, "The received message was not understood "
2747 } else if (recv_len
== 0) {
2748 if (hc
->hc_state
== HC_EXITING
) {
2749 close_hc_connection(hc
);
2750 if (mc_state
== MC_SHUTDOWN
&& all_hc_in_state(HC_DOWN
))
2751 mc_state
= MC_INACTIVE
;
2753 error("Unexpected end of HC connection from %s [%s].",
2754 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2758 error("Receiving of data failed on HC connection from %s [%s].",
2759 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2763 close_hc_connection(hc
);
2767 case MC_LISTENING_CONFIGURED
:
2768 fatal_error("MC is in invalid state when a HC connection "
2770 case MC_HC_CONNECTED
:
2771 if (all_hc_in_state(HC_DOWN
)) mc_state
= MC_LISTENING
;
2773 case MC_CONFIGURING
:
2774 check_all_hc_configured();
2777 if (all_hc_in_state(HC_DOWN
)) mc_state
= MC_LISTENING_CONFIGURED
;
2778 else if (!is_hc_in_state(HC_ACTIVE
) &&
2779 !is_hc_in_state(HC_OVERLOADED
)) mc_state
= MC_HC_CONNECTED
;
2782 if (!is_hc_in_state(HC_ACTIVE
)) notify("There is no active HC "
2783 "connection. Further create operations will fail.");
2789 void MainController::handle_tc_data(component_struct
*tc
,
2790 boolean recv_from_socket
)
2792 Text_Buf
& text_buf
= *tc
->text_buf
;
2793 boolean close_connection
= FALSE
;
2794 int recv_len
= recv_to_buffer(tc
->tc_fd
, text_buf
, recv_from_socket
);
2798 while (text_buf
.is_message()) {
2799 int message_len
= text_buf
.pull_int().get_val();
2800 int message_end
= text_buf
.get_pos() + message_len
;
2801 int message_type
= text_buf
.pull_int().get_val();
2802 // these messages can be received both from MTC and PTCs
2803 switch (message_type
) {
2810 case MSG_CREATE_REQ
:
2811 process_create_req(tc
);
2814 process_start_req(tc
, message_end
);
2817 process_stop_req(tc
);
2820 process_kill_req(tc
);
2822 case MSG_IS_RUNNING
:
2823 process_is_running(tc
);
2826 process_is_alive(tc
);
2829 process_done_req(tc
);
2831 case MSG_KILLED_REQ
:
2832 process_killed_req(tc
);
2834 case MSG_CANCEL_DONE_ACK
:
2835 process_cancel_done_ack(tc
);
2837 case MSG_CONNECT_REQ
:
2838 process_connect_req(tc
);
2840 case MSG_CONNECT_LISTEN_ACK
:
2841 process_connect_listen_ack(tc
, message_end
);
2844 process_connected(tc
);
2846 case MSG_CONNECT_ERROR
:
2847 process_connect_error(tc
);
2849 case MSG_DISCONNECT_REQ
:
2850 process_disconnect_req(tc
);
2852 case MSG_DISCONNECTED
:
2853 process_disconnected(tc
);
2856 process_map_req(tc
);
2862 process_unmap_req(tc
);
2865 process_unmapped(tc
);
2869 // these messages can be received only from the MTC
2870 switch (message_type
) {
2871 case MSG_TESTCASE_STARTED
:
2872 process_testcase_started();
2874 case MSG_TESTCASE_FINISHED
:
2875 process_testcase_finished();
2878 process_mtc_ready();
2881 error("Invalid message type (%d) was received "
2882 "from the MTC at %s [%s].", message_type
,
2883 mtc
->comp_location
->hostname
,
2884 mtc
->comp_location
->ip_addr
->get_addr_str());
2885 close_connection
= TRUE
;
2888 // these messages can be received only from PTCs
2889 switch (message_type
) {
2891 process_stopped(tc
, message_end
);
2893 case MSG_STOPPED_KILLED
:
2894 process_stopped_killed(tc
, message_end
);
2900 notify("Invalid message type (%d) was received from "
2901 "PTC %d at %s [%s].", message_type
,
2902 tc
->comp_ref
, tc
->comp_location
->hostname
,
2903 tc
->comp_location
->ip_addr
->get_addr_str());
2904 close_connection
= TRUE
;
2908 if (close_connection
) break;
2909 text_buf
.cut_message();
2911 } catch (const TC_Error
& tc_error
) {
2913 error("Malformed message was received from the MTC at %s "
2914 "[%s].", mtc
->comp_location
->hostname
,
2915 mtc
->comp_location
->ip_addr
->get_addr_str());
2917 notify("Malformed message was received from PTC %d at %s [%s].",
2918 tc
->comp_ref
, tc
->comp_location
->hostname
,
2919 tc
->comp_location
->ip_addr
->get_addr_str());
2921 close_connection
= TRUE
;
2923 if (close_connection
) {
2924 send_error_str(tc
->tc_fd
, "The received message was not understood "
2927 } else if (recv_len
== 0) {
2928 // TCP connection is closed by peer
2929 if (tc
->tc_state
!= TC_EXITING
&& !tc
->process_killed
) {
2931 error("Unexpected end of MTC connection from %s [%s].",
2932 mtc
->comp_location
->hostname
,
2933 mtc
->comp_location
->ip_addr
->get_addr_str());
2935 notify("Unexpected end of PTC connection (%d) from %s [%s].",
2936 tc
->comp_ref
, tc
->comp_location
->hostname
,
2937 tc
->comp_location
->ip_addr
->get_addr_str());
2940 close_connection
= TRUE
;
2942 if (tc
->process_killed
&& errno
== ECONNRESET
) {
2943 // ignore TCP resets if the process was killed
2944 // because the last STOP or KILL message can stuck in TCP buffers
2945 // if the process did not receive any data
2948 error("Receiving of data failed from the MTC at %s [%s]: %s",
2949 mtc
->comp_location
->hostname
,
2950 mtc
->comp_location
->ip_addr
->get_addr_str(), strerror(errno
));
2952 notify("Receiving of data failed from PTC %d at %s [%s]: %s",
2953 tc
->comp_ref
, tc
->comp_location
->hostname
,
2954 tc
->comp_location
->ip_addr
->get_addr_str(), strerror(errno
));
2957 close_connection
= TRUE
;
2959 if (close_connection
) {
2960 close_tc_connection(tc
);
2961 remove_component_from_host(tc
);
2963 if (mc_state
!= MC_TERMINATING_MTC
) {
2964 notify("The control connection to MTC is lost. "
2965 "Destroying all PTC connections.");
2967 destroy_all_components();
2968 notify("MTC terminated.");
2969 if (is_hc_in_state(HC_CONFIGURING
)) mc_state
= MC_CONFIGURING
;
2970 else if (is_hc_in_state(HC_IDLE
)) mc_state
= MC_HC_CONNECTED
;
2971 else if (is_hc_in_state(HC_ACTIVE
) ||
2972 is_hc_in_state(HC_OVERLOADED
)) mc_state
= MC_ACTIVE
;
2973 else mc_state
= MC_LISTENING_CONFIGURED
;
2974 stop_requested
= FALSE
;
2976 if (tc
->tc_state
!= TC_EXITING
) {
2977 // we have no idea about the final verdict of the PTC
2978 tc
->local_verdict
= ERROR
;
2979 component_terminated(tc
);
2981 tc
->tc_state
= TC_EXITED
;
2982 if (mc_state
== MC_TERMINATING_TESTCASE
&&
2983 ready_to_finish_testcase()) finish_testcase();
2989 void MainController::unlink_unix_socket(int socket_fd
) {
2990 struct sockaddr_un local_addr
;
2991 // querying the local pathname used by socket_fd
2992 socklen_type addr_len
= sizeof(local_addr
);
2993 if (getsockname(socket_fd
, (struct sockaddr
*)&local_addr
, &addr_len
)) {
2994 } else if (local_addr
.sun_family
!= AF_UNIX
) {
2995 } else if (unlink(local_addr
.sun_path
)) {
3000 void MainController::shutdown_server()
3002 if (server_fd
>= 0) {
3003 remove_poll_fd(server_fd
);
3004 remove_fd_from_table(server_fd
);
3009 if (server_fd_unix
>= 0) {
3010 unlink_unix_socket(server_fd_unix
);
3011 remove_poll_fd(server_fd_unix
);
3012 remove_fd_from_table(server_fd_unix
);
3013 close(server_fd_unix
);
3014 server_fd_unix
= -1;
3018 void MainController::perform_shutdown()
3020 boolean shutdown_complete
= TRUE
;
3022 case MC_HC_CONNECTED
:
3024 for (int i
= 0; i
< n_hosts
; i
++) {
3025 host_struct
*host
= hosts
[i
];
3026 if (host
->hc_state
!= HC_DOWN
) {
3028 host
->hc_state
= HC_EXITING
;
3029 shutdown_complete
= FALSE
;
3034 case MC_LISTENING_CONFIGURED
:
3036 // don't call status_change() if shutdown is complete
3037 // it will be called from thread_main() later
3038 if (shutdown_complete
) mc_state
= MC_INACTIVE
;
3040 mc_state
= MC_SHUTDOWN
;
3045 fatal_error("MainController::perform_shutdown: called in wrong state.");
3049 void MainController::clean_up()
3053 while (unknown_head
!= NULL
) close_unknown_connection(unknown_head
);
3055 destroy_all_components();
3057 for (int i
= 0; i
< n_hosts
; i
++) {
3058 host_struct
*host
= hosts
[i
];
3059 close_hc_connection(host
);
3060 Free(host
->hostname
);
3061 delete host
->ip_addr
;
3062 delete [] host
->hostname_local
;
3063 delete [] host
->machine_type
;
3064 delete [] host
->system_name
;
3065 delete [] host
->system_release
;
3066 delete [] host
->system_version
;
3067 Free(host
->log_source
);
3068 Free(host
->components
);
3069 free_string_set(&host
->allowed_components
);
3078 while (timer_head
!= NULL
) cancel_timer(timer_head
);
3080 for (int i
= 0; i
< n_modules
; i
++) {
3081 delete [] modules
[i
].module_name
;
3082 delete [] modules
[i
].module_checksum
;
3087 version_known
= FALSE
;
3091 if (close(epfd
) < 0)
3092 error("MainController::clean_up: Error while closing epoll"
3097 epoll_events
= NULL
;
3098 #else // ! defined USE_EPOLL
3105 pollfds_modified
= FALSE
;
3112 mc_state
= MC_INACTIVE
;
3114 if (pipe_fd
[1] >= 0) {
3118 if (pipe_fd
[0] >= 0) {
3124 void MainController::send_configure(host_struct
*hc
, const char *config_file
)
3127 text_buf
.push_int(MSG_CONFIGURE
);
3128 text_buf
.push_string(config_file
);
3129 send_message(hc
->hc_fd
, text_buf
);
3132 void MainController::send_exit_hc(host_struct
*hc
)
3135 text_buf
.push_int(MSG_EXIT_HC
);
3136 send_message(hc
->hc_fd
, text_buf
);
3139 void MainController::send_create_mtc(host_struct
*hc
)
3142 text_buf
.push_int(MSG_CREATE_MTC
);
3143 send_message(hc
->hc_fd
, text_buf
);
3146 void MainController::send_create_ptc(host_struct
*hc
,
3147 component component_reference
, const qualified_name
& component_type
,
3148 const char *component_name
, boolean is_alive
,
3149 const qualified_name
& current_testcase
)
3152 text_buf
.push_int(MSG_CREATE_PTC
);
3153 text_buf
.push_int(component_reference
);
3154 text_buf
.push_qualified_name(component_type
);
3155 text_buf
.push_string(component_name
);
3156 text_buf
.push_int(is_alive
? 1 : 0);
3157 text_buf
.push_qualified_name(current_testcase
);
3158 send_message(hc
->hc_fd
, text_buf
);
3161 void MainController::send_kill_process(host_struct
*hc
,
3162 component component_reference
)
3165 text_buf
.push_int(MSG_KILL_PROCESS
);
3166 text_buf
.push_int(component_reference
);
3167 send_message(hc
->hc_fd
, text_buf
);
3170 void MainController::send_create_ack(component_struct
*tc
,
3171 component component_reference
)
3174 text_buf
.push_int(MSG_CREATE_ACK
);
3175 text_buf
.push_int(component_reference
);
3176 send_message(tc
->tc_fd
, text_buf
);
3179 void MainController::send_start_ack(component_struct
*tc
)
3182 text_buf
.push_int(MSG_START_ACK
);
3183 send_message(tc
->tc_fd
, text_buf
);
3186 void MainController::send_stop(component_struct
*tc
)
3189 text_buf
.push_int(MSG_STOP
);
3190 send_message(tc
->tc_fd
, text_buf
);
3193 void MainController::send_stop_ack(component_struct
*tc
)
3196 text_buf
.push_int(MSG_STOP_ACK
);
3197 send_message(tc
->tc_fd
, text_buf
);
3200 void MainController::send_kill_ack(component_struct
*tc
)
3203 text_buf
.push_int(MSG_KILL_ACK
);
3204 send_message(tc
->tc_fd
, text_buf
);
3207 void MainController::send_running(component_struct
*tc
, boolean answer
)
3210 text_buf
.push_int(MSG_RUNNING
);
3211 text_buf
.push_int(answer
? 1 : 0);
3212 send_message(tc
->tc_fd
, text_buf
);
3215 void MainController::send_alive(component_struct
*tc
, boolean answer
)
3218 text_buf
.push_int(MSG_ALIVE
);
3219 text_buf
.push_int(answer
? 1 : 0);
3220 send_message(tc
->tc_fd
, text_buf
);
3223 void MainController::send_done_ack(component_struct
*tc
, boolean answer
,
3224 const char *return_type
, int return_value_len
, const void *return_value
)
3227 text_buf
.push_int(MSG_DONE_ACK
);
3228 text_buf
.push_int(answer
? 1 : 0);
3229 text_buf
.push_string(return_type
);
3230 text_buf
.push_raw(return_value_len
, return_value
);
3231 send_message(tc
->tc_fd
, text_buf
);
3234 void MainController::send_killed_ack(component_struct
*tc
, boolean answer
)
3237 text_buf
.push_int(MSG_KILLED_ACK
);
3238 text_buf
.push_int(answer
? 1 : 0);
3239 send_message(tc
->tc_fd
, text_buf
);
3242 void MainController::send_connect_listen(component_struct
*tc
,
3243 const char *local_port
, component remote_comp
, const char *remote_comp_name
,
3244 const char *remote_port
, transport_type_enum transport_type
)
3247 text_buf
.push_int(MSG_CONNECT_LISTEN
);
3248 text_buf
.push_string(local_port
);
3249 text_buf
.push_int(remote_comp
);
3250 text_buf
.push_string(remote_comp_name
);
3251 text_buf
.push_string(remote_port
);
3252 text_buf
.push_int(transport_type
);
3253 send_message(tc
->tc_fd
, text_buf
);
3256 void MainController::send_connect(component_struct
*tc
,
3257 const char *local_port
, component remote_comp
, const char *remote_comp_name
,
3258 const char *remote_port
, transport_type_enum transport_type
,
3259 int remote_address_len
, const void *remote_address
)
3262 text_buf
.push_int(MSG_CONNECT
);
3263 text_buf
.push_string(local_port
);
3264 text_buf
.push_int(remote_comp
);
3265 text_buf
.push_string(remote_comp_name
);
3266 text_buf
.push_string(remote_port
);
3267 text_buf
.push_int(transport_type
);
3268 text_buf
.push_raw(remote_address_len
, remote_address
);
3269 send_message(tc
->tc_fd
, text_buf
);
3272 void MainController::send_connect_ack(component_struct
*tc
)
3275 text_buf
.push_int(MSG_CONNECT_ACK
);
3276 send_message(tc
->tc_fd
, text_buf
);
3279 void MainController::send_disconnect(component_struct
*tc
,
3280 const char *local_port
, component remote_comp
, const char *remote_port
)
3283 text_buf
.push_int(MSG_DISCONNECT
);
3284 text_buf
.push_string(local_port
);
3285 text_buf
.push_int(remote_comp
);
3286 text_buf
.push_string(remote_port
);
3287 send_message(tc
->tc_fd
, text_buf
);
3290 void MainController::send_disconnect_ack(component_struct
*tc
)
3293 text_buf
.push_int(MSG_DISCONNECT_ACK
);
3294 send_message(tc
->tc_fd
, text_buf
);
3297 void MainController::send_map(component_struct
*tc
,
3298 const char *local_port
, const char *system_port
)
3301 text_buf
.push_int(MSG_MAP
);
3302 text_buf
.push_string(local_port
);
3303 text_buf
.push_string(system_port
);
3304 send_message(tc
->tc_fd
, text_buf
);
3307 void MainController::send_map_ack(component_struct
*tc
)
3310 text_buf
.push_int(MSG_MAP_ACK
);
3311 send_message(tc
->tc_fd
, text_buf
);
3314 void MainController::send_unmap(component_struct
*tc
,
3315 const char *local_port
, const char *system_port
)
3318 text_buf
.push_int(MSG_UNMAP
);
3319 text_buf
.push_string(local_port
);
3320 text_buf
.push_string(system_port
);
3321 send_message(tc
->tc_fd
, text_buf
);
3324 void MainController::send_unmap_ack(component_struct
*tc
)
3327 text_buf
.push_int(MSG_UNMAP_ACK
);
3328 send_message(tc
->tc_fd
, text_buf
);
3331 void MainController::send_cancel_done_mtc(component component_reference
,
3335 text_buf
.push_int(MSG_CANCEL_DONE
);
3336 text_buf
.push_int(component_reference
);
3337 text_buf
.push_int(cancel_any
? 1 : 0);
3338 send_message(mtc
->tc_fd
, text_buf
);
3341 void MainController::send_component_status_mtc(component component_reference
,
3342 boolean is_done
, boolean is_killed
, boolean is_any_done
,
3343 boolean is_all_done
, boolean is_any_killed
, boolean is_all_killed
,
3344 const char *return_type
, int return_value_len
, const void *return_value
)
3347 text_buf
.push_int(MSG_COMPONENT_STATUS
);
3348 text_buf
.push_int(component_reference
);
3349 text_buf
.push_int(is_done
? 1 : 0);
3350 text_buf
.push_int(is_killed
? 1 : 0);
3351 text_buf
.push_int(is_any_done
? 1 : 0);
3352 text_buf
.push_int(is_all_done
? 1 : 0);
3353 text_buf
.push_int(is_any_killed
? 1 : 0);
3354 text_buf
.push_int(is_all_killed
? 1 : 0);
3355 text_buf
.push_string(return_type
);
3356 text_buf
.push_raw(return_value_len
, return_value
);
3357 send_message(mtc
->tc_fd
, text_buf
);
3360 void MainController::send_execute_control(const char *module_name
)
3363 text_buf
.push_int(MSG_EXECUTE_CONTROL
);
3364 text_buf
.push_string(module_name
);
3365 send_message(mtc
->tc_fd
, text_buf
);
3368 void MainController::send_execute_testcase(const char *module_name
,
3369 const char *testcase_name
)
3372 text_buf
.push_int(MSG_EXECUTE_TESTCASE
);
3373 text_buf
.push_string(module_name
);
3374 text_buf
.push_string(testcase_name
);
3375 send_message(mtc
->tc_fd
, text_buf
);
3378 void MainController::send_ptc_verdict(boolean continue_execution
)
3381 text_buf
.push_int(MSG_PTC_VERDICT
);
3383 for (int i
= tc_first_comp_ref
; i
< n_components
; i
++)
3384 if (components
[i
]->tc_state
!= PTC_STALE
) n_ptcs
++;
3385 text_buf
.push_int(n_ptcs
);
3386 for (int i
= tc_first_comp_ref
; i
< n_components
; i
++) {
3387 if (components
[i
]->tc_state
!= PTC_STALE
) {
3388 text_buf
.push_int(components
[i
]->comp_ref
);
3389 text_buf
.push_string(components
[i
]->comp_name
);
3390 text_buf
.push_int(components
[i
]->local_verdict
);
3391 if (components
[i
]->verdict_reason
!= NULL
)
3392 text_buf
.push_string(components
[i
]->verdict_reason
);
3394 text_buf
.push_string("");
3397 text_buf
.push_int(continue_execution
? 1 : 0);
3398 send_message(mtc
->tc_fd
, text_buf
);
3401 void MainController::send_continue()
3404 text_buf
.push_int(MSG_CONTINUE
);
3405 send_message(mtc
->tc_fd
, text_buf
);
3408 void MainController::send_exit_mtc()
3411 text_buf
.push_int(MSG_EXIT_MTC
);
3412 send_message(mtc
->tc_fd
, text_buf
);
3415 void MainController::send_cancel_done_ptc(component_struct
*tc
,
3416 component component_reference
)
3419 text_buf
.push_int(MSG_CANCEL_DONE
);
3420 text_buf
.push_int(component_reference
);
3421 send_message(tc
->tc_fd
, text_buf
);
3425 void MainController::send_component_status_ptc(component_struct
*tc
,
3426 component component_reference
, boolean is_done
, boolean is_killed
,
3427 const char *return_type
, int return_value_len
, const void *return_value
)
3430 text_buf
.push_int(MSG_COMPONENT_STATUS
);
3431 text_buf
.push_int(component_reference
);
3432 text_buf
.push_int(is_done
? 1 : 0);
3433 text_buf
.push_int(is_killed
? 1 : 0);
3434 text_buf
.push_string(return_type
);
3435 text_buf
.push_raw(return_value_len
, return_value
);
3436 send_message(tc
->tc_fd
, text_buf
);
3439 void MainController::send_start(component_struct
*tc
,
3440 const qualified_name
& function_name
, int arg_len
, const void *arg_ptr
)
3443 text_buf
.push_int(MSG_START
);
3444 text_buf
.push_qualified_name(function_name
);
3445 text_buf
.push_raw(arg_len
, arg_ptr
);
3446 send_message(tc
->tc_fd
, text_buf
);
3449 void MainController::send_kill(component_struct
*tc
)
3452 text_buf
.push_int(MSG_KILL
);
3453 send_message(tc
->tc_fd
, text_buf
);
3456 void MainController::send_error(int fd
, const char *fmt
, ...)
3460 char *reason
= mprintf_va_list(fmt
, ap
);
3462 send_error_str(fd
, reason
);
3466 void MainController::send_error_str(int fd
, const char *reason
)
3469 text_buf
.push_int((RInt
)MSG_ERROR
);
3470 text_buf
.push_string(reason
);
3471 send_message(fd
, text_buf
);
3474 void MainController::send_message(int fd
, Text_Buf
& text_buf
)
3476 text_buf
.calculate_length();
3477 const char *send_ptr
= text_buf
.get_data();
3478 int send_len
= text_buf
.get_len();
3479 int sent_len
= send(fd
, send_ptr
, send_len
, 0);
3480 if (send_len
!= sent_len
) {
3481 error("Sending of message failed: %s", strerror(errno
));
3485 void MainController::process_error(unknown_connection
*conn
)
3487 Text_Buf
& text_buf
= *conn
->text_buf
;
3488 char *reason
= text_buf
.pull_string();
3489 error("Error message was received on an unknown connection from %s [%s]: "
3490 "%s.", conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str(), reason
);
3492 text_buf
.cut_message();
3496 void MainController::process_log(unknown_connection
*conn
)
3498 Text_Buf
& text_buf
= *conn
->text_buf
;
3500 tv
.tv_sec
= text_buf
.pull_int().get_val();
3501 tv
.tv_usec
= text_buf
.pull_int().get_val();
3502 char *source
= mprintf("<unknown>@%s", conn
->ip_addr
->get_host_str());
3503 int severity
= text_buf
.pull_int().get_val();
3504 char *message
= text_buf
.pull_string();
3505 notify(&tv
, source
, severity
, message
);
3510 void MainController::process_version(unknown_connection
*conn
)
3512 if (check_version(conn
)) {
3513 error("HC connection from %s [%s] was refused because of "
3514 "incorrect version.", conn
->ip_addr
->get_host_str(),
3515 conn
->ip_addr
->get_addr_str());
3516 close_unknown_connection(conn
);
3519 host_struct
*hc
= add_new_host(conn
);
3522 mc_state
= MC_HC_CONNECTED
;
3523 case MC_HC_CONNECTED
:
3525 case MC_LISTENING_CONFIGURED
:
3527 configure_host(hc
, TRUE
);
3528 mc_state
= MC_CONFIGURING
;
3532 hc
->hc_state
= HC_EXITING
;
3535 configure_host(hc
, TRUE
);
3537 // handle the remaining messages that are in hc->text_buf
3538 handle_hc_data(hc
, FALSE
);
3542 void MainController::process_mtc_created(unknown_connection
*conn
)
3545 if (mc_state
!= MC_CREATING_MTC
) {
3546 send_error_str(fd
, "Message MTC_CREATED arrived in invalid state.");
3547 close_unknown_connection(conn
);
3550 if (mtc
== NULL
|| mtc
->tc_state
!= TC_INITIAL
)
3551 fatal_error("MainController::process_mtc_created: MTC is in invalid "
3553 if (!conn
->unix_socket
&&
3554 *(mtc
->comp_location
->ip_addr
) != *(conn
->ip_addr
)) {
3555 send_error(fd
, "Message MTC_CREATED arrived from an unexpected "
3556 "IP address. It is accepted only from %s.",
3557 mtc
->comp_location
->ip_addr
->get_addr_str());
3558 close_unknown_connection(conn
);
3562 mc_state
= MC_READY
;
3563 mtc
->tc_state
= TC_IDLE
;
3565 fd_table
[fd
].fd_type
= FD_TC
;
3566 fd_table
[fd
].component_ptr
= mtc
;
3567 Text_Buf
*text_buf
= conn
->text_buf
;
3568 text_buf
->cut_message();
3569 mtc
->text_buf
= text_buf
;
3570 delete [] mtc
->initial
.location_str
;
3572 delete_unknown_connection(conn
);
3574 notify("MTC is created.");
3575 // handle the remaining messages that are in text_buf
3576 handle_tc_data(mtc
, FALSE
);
3580 void MainController::process_ptc_created(unknown_connection
*conn
)
3585 case MC_EXECUTING_TESTCASE
:
3586 case MC_TERMINATING_TESTCASE
:
3589 send_error_str(fd
, "Message PTC_CREATED arrived in invalid state.");
3590 close_unknown_connection(conn
);
3594 Text_Buf
*text_buf
= conn
->text_buf
;
3595 component component_reference
= text_buf
->pull_int().get_val();
3597 switch (component_reference
) {
3599 send_error_str(fd
, "Message PTC_CREATED refers to the null component "
3601 close_unknown_connection(conn
);
3604 send_error_str(fd
, "Message PTC_CREATED refers to the component "
3605 "reference of the MTC.");
3606 close_unknown_connection(conn
);
3608 case SYSTEM_COMPREF
:
3609 send_error_str(fd
, "Message PTC_CREATED refers to the component "
3610 "reference of the system.");
3611 close_unknown_connection(conn
);
3614 send_error_str(fd
, "Message PTC_CREATED refers to 'any component'.");
3615 close_unknown_connection(conn
);
3618 send_error_str(fd
, "Message PTC_CREATED refers to 'all component'.");
3619 close_unknown_connection(conn
);
3623 component_struct
*tc
= lookup_component(component_reference
);
3625 send_error(fd
, "Message PTC_CREATED refers to invalid component "
3626 "reference %d.", component_reference
);
3627 close_unknown_connection(conn
);
3629 } else if (tc
->tc_state
!= TC_INITIAL
) {
3630 send_error(fd
, "Message PTC_CREATED refers to test component "
3631 "%d, which is not being created.", component_reference
);
3632 close_unknown_connection(conn
);
3634 } else if (!conn
->unix_socket
&& *(conn
->ip_addr
) != *(tc
->comp_location
->ip_addr
)) {
3635 char *real_hostname
= mprintf("%s [%s]", conn
->ip_addr
->get_host_str(),
3636 conn
->ip_addr
->get_addr_str());
3637 char *expected_hostname
= mprintf("%s [%s]",
3638 tc
->comp_location
->hostname
, tc
->comp_location
->ip_addr
->get_addr_str());
3639 send_error(fd
, "Invalid source host (%s) for the control "
3640 "connection. Expected: %s.", real_hostname
, expected_hostname
);
3641 error("Connection of PTC %d arrived from an unexpected "
3642 "IP address (%s). Expected: %s.", component_reference
,
3643 real_hostname
, expected_hostname
);
3644 Free(real_hostname
);
3645 Free(expected_hostname
);
3646 close_unknown_connection(conn
);
3650 tc
->tc_state
= TC_IDLE
;
3652 fd_table
[fd
].fd_type
= FD_TC
;
3653 fd_table
[fd
].component_ptr
= tc
;
3654 text_buf
->cut_message();
3655 tc
->text_buf
= text_buf
;
3656 delete [] tc
->initial
.location_str
;
3658 delete_unknown_connection(conn
);
3660 if (mc_state
== MC_TERMINATING_TESTCASE
|| mtc
->stop_requested
||
3661 mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
||
3662 (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
&& !tc
->is_alive
)) {
3664 tc
->tc_state
= PTC_KILLING
;
3665 if (!tc
->is_alive
) tc
->stop_requested
= TRUE
;
3666 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
3667 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
3668 start_kill_timer(tc
);
3670 component_struct
*create_requestor
= tc
->initial
.create_requestor
;
3671 if (create_requestor
->tc_state
== TC_CREATE
) {
3672 send_create_ack(create_requestor
, component_reference
);
3673 if (create_requestor
== mtc
)
3674 create_requestor
->tc_state
= MTC_TESTCASE
;
3675 else create_requestor
->tc_state
= PTC_FUNCTION
;
3678 // handle the remaining messages that are in text_buf
3679 handle_tc_data(tc
, FALSE
);
3683 void MainController::process_error(host_struct
*hc
)
3685 char *reason
= hc
->text_buf
->pull_string();
3686 error("Error message was received from HC at %s [%s]: %s",
3687 hc
->hostname
, hc
->ip_addr
->get_addr_str(), reason
);
3691 void MainController::process_log(host_struct
*hc
)
3693 Text_Buf
& text_buf
= *hc
->text_buf
;
3695 tv
.tv_sec
= text_buf
.pull_int().get_val();
3696 tv
.tv_usec
= text_buf
.pull_int().get_val();
3697 int severity
= text_buf
.pull_int().get_val();
3698 char *message
= text_buf
.pull_string();
3699 notify(&tv
, hc
->log_source
, severity
, message
);
3703 void MainController::process_configure_ack(host_struct
*hc
)
3705 switch (hc
->hc_state
) {
3706 case HC_CONFIGURING
:
3707 hc
->hc_state
= HC_ACTIVE
;
3709 case HC_CONFIGURING_OVERLOADED
:
3710 hc
->hc_state
= HC_OVERLOADED
;
3713 send_error_str(hc
->hc_fd
, "Unexpected message CONFIGURE_ACK was "
3717 if (mc_state
== MC_CONFIGURING
) check_all_hc_configured();
3718 else notify("Host %s was configured successfully.", hc
->hostname
);
3722 void MainController::process_configure_nak(host_struct
*hc
)
3724 switch (hc
->hc_state
) {
3725 case HC_CONFIGURING
:
3726 case HC_CONFIGURING_OVERLOADED
:
3727 hc
->hc_state
= HC_IDLE
;
3730 send_error_str(hc
->hc_fd
, "Unexpected message CONFIGURE_NAK was "
3734 if (mc_state
== MC_CONFIGURING
) check_all_hc_configured();
3735 else notify("Processing of configuration file failed on host %s.",
3740 void MainController::process_create_nak(host_struct
*hc
)
3743 case MC_CREATING_MTC
:
3744 case MC_EXECUTING_TESTCASE
:
3745 case MC_TERMINATING_TESTCASE
:
3748 send_error_str(hc
->hc_fd
, "Message CREATE_NAK arrived in invalid "
3753 switch (hc
->hc_state
) {
3755 notify("Host %s is overloaded. New components will not be created "
3756 "there until further notice.", hc
->hostname
);
3757 hc
->hc_state
= HC_OVERLOADED
;
3762 send_error_str(hc
->hc_fd
, "Unexpected message CREATE_NAK was received: "
3763 "the sender is in invalid state.");
3767 Text_Buf
& text_buf
= *hc
->text_buf
;
3768 component component_reference
= text_buf
.pull_int().get_val();
3770 switch (component_reference
) {
3772 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to the null "
3773 "component reference.");
3775 case SYSTEM_COMPREF
:
3776 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to the component "
3777 "reference of the system.");
3780 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to "
3781 "'any component'.");
3784 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to "
3785 "'all component'.");
3789 component_struct
*tc
= lookup_component(component_reference
);
3791 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to invalid component "
3792 "reference %d.", component_reference
);
3795 if (tc
->tc_state
!= TC_INITIAL
) {
3796 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to test component "
3797 "%d, which is not being created.", component_reference
);
3800 if (tc
->comp_location
!= hc
) {
3801 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to test component "
3802 "%d, which was assigned to a different host (%s).",
3803 component_reference
, tc
->comp_location
->hostname
);
3807 remove_component_from_host(tc
);
3808 hc
->n_active_components
--;
3810 char *reason
= text_buf
.pull_string();
3813 if (mc_state
!= MC_CREATING_MTC
)
3814 fatal_error("MainController::process_create_nak: MC is in "
3815 "unexpected state when CREATE_NAK refers to MTC.");
3816 error("Creation of MTC failed on host %s: %s.", hc
->hostname
, reason
);
3817 destroy_all_components();
3818 mc_state
= MC_ACTIVE
;
3820 host_struct
*new_host
= choose_ptc_location(
3821 tc
->comp_type
.definition_name
, tc
->comp_name
,
3822 tc
->initial
.location_str
);
3823 if (new_host
!= NULL
) {
3824 send_create_ptc(new_host
, component_reference
, tc
->comp_type
,
3825 tc
->comp_name
, tc
->is_alive
, mtc
->tc_fn_name
);
3826 notify("PTC with component reference %d was relocated from host "
3827 "%s to %s because of overload: %s.", component_reference
,
3828 hc
->hostname
, new_host
->hostname
, reason
);
3829 add_component_to_host(new_host
, tc
);
3830 new_host
->n_active_components
++;
3832 char *comp_data
= mprintf("component type: %s.%s",
3833 tc
->comp_type
.module_name
, tc
->comp_type
.definition_name
);
3834 if (tc
->comp_name
!= NULL
)
3835 comp_data
= mputprintf(comp_data
, ", name: %s", tc
->comp_name
);
3836 if (tc
->initial
.location_str
!= NULL
&&
3837 tc
->initial
.location_str
[0] != '\0')
3838 comp_data
= mputprintf(comp_data
, ", location: %s",
3839 tc
->initial
.location_str
);
3840 component_struct
*create_requestor
= tc
->initial
.create_requestor
;
3841 if (create_requestor
->tc_state
== TC_CREATE
) {
3842 send_error(create_requestor
->tc_fd
, "Creation of the new PTC "
3843 "(%s) failed on host %s: %s. Other suitable hosts to "
3844 "relocate the component are not available.", comp_data
,
3845 hc
->hostname
, reason
);
3846 if (create_requestor
== mtc
)
3847 create_requestor
->tc_state
= MTC_TESTCASE
;
3848 else create_requestor
->tc_state
= PTC_FUNCTION
;
3850 delete [] tc
->initial
.location_str
;
3851 tc
->tc_state
= PTC_STALE
;
3853 switch (mtc
->tc_state
) {
3854 case MTC_TERMINATING_TESTCASE
:
3855 if (ready_to_finish_testcase()) finish_testcase();
3857 case MTC_ALL_COMPONENT_KILL
:
3858 check_all_component_kill();
3860 case MTC_ALL_COMPONENT_STOP
:
3861 check_all_component_stop();
3866 notify("Creation of a PTC (%s) failed on host %s: %s. "
3867 "Relocation to other suitable host is not possible.",
3868 comp_data
, hc
->hostname
, reason
);
3878 void MainController::process_hc_ready(host_struct
*hc
)
3880 switch(hc
->hc_state
) {
3882 hc
->hc_state
= HC_ACTIVE
;
3884 case HC_CONFIGURING_OVERLOADED
:
3885 hc
->hc_state
= HC_CONFIGURING
;
3888 send_error_str(hc
->hc_fd
, "Unexpected message HC_READY was received.");
3891 notify("Host %s is no more overloaded.", hc
->hostname
);
3895 void MainController::process_error(component_struct
*tc
)
3897 char *reason
= tc
->text_buf
->pull_string();
3899 error("Error message was received from the MTC at %s [%s]: %s",
3900 mtc
->comp_location
->hostname
,
3901 mtc
->comp_location
->ip_addr
->get_addr_str(), reason
);
3903 notify("Error message was received from PTC %d at %s [%s]: %s",
3904 tc
->comp_ref
, tc
->comp_location
->hostname
,
3905 tc
->comp_location
->ip_addr
->get_addr_str(), reason
);
3910 void MainController::process_log(component_struct
*tc
)
3912 Text_Buf
& text_buf
= *tc
->text_buf
;
3914 tv
.tv_sec
= text_buf
.pull_int().get_val();
3915 tv
.tv_usec
= text_buf
.pull_int().get_val();
3916 int severity
= text_buf
.pull_int().get_val();
3917 char *message
= text_buf
.pull_string();
3918 notify(&tv
, tc
->log_source
, severity
, message
);
3922 void MainController::process_create_req(component_struct
*tc
)
3924 if (!request_allowed(tc
, "CREATE_REQ")) return;
3926 if (max_ptcs
>= 0 && n_active_ptcs
>= max_ptcs
) {
3927 send_error(tc
->tc_fd
, "The license key does not allow more than %d "
3928 "simultaneously active PTCs.", max_ptcs
);
3932 Text_Buf
& text_buf
= *tc
->text_buf
;
3933 qualified_name component_type
;
3934 text_buf
.pull_qualified_name(component_type
);
3935 char *component_name
= text_buf
.pull_string();
3936 if (component_name
[0] == '\0') {
3937 delete [] component_name
;
3938 component_name
= NULL
;
3940 char *component_location
= text_buf
.pull_string();
3941 if (component_location
[0] == '\0') {
3942 delete [] component_location
;
3943 component_location
= NULL
;
3945 boolean is_alive
= text_buf
.pull_int().get_val();
3947 host_struct
*host
= choose_ptc_location(component_type
.definition_name
,
3948 component_name
, component_location
);
3951 if (!is_hc_in_state(HC_ACTIVE
)) {
3952 send_error_str(tc
->tc_fd
, "There is no active HC connection. "
3953 "Create operation cannot be performed.");
3955 char *comp_data
= mprintf("component type: %s.%s",
3956 component_type
.module_name
, component_type
.definition_name
);
3957 if (component_name
!= NULL
)
3958 comp_data
= mputprintf(comp_data
, ", name: %s", component_name
);
3959 if (component_location
!= NULL
)
3960 comp_data
= mputprintf(comp_data
, ", location: %s",
3961 component_location
);
3962 send_error(tc
->tc_fd
, "No suitable host was found to create a "
3963 "new PTC (%s).", comp_data
);
3966 free_qualified_name(&component_type
);
3967 delete [] component_name
;
3968 delete [] component_location
;
3972 component comp_ref
= next_comp_ref
++;
3973 send_create_ptc(host
, comp_ref
, component_type
, component_name
, is_alive
,
3976 tc
->tc_state
= TC_CREATE
;
3978 component_struct
*new_ptc
= new component_struct
;
3979 new_ptc
->comp_ref
= comp_ref
;
3980 new_ptc
->comp_type
= component_type
;
3981 new_ptc
->comp_name
= component_name
;
3982 new_ptc
->tc_state
= TC_INITIAL
;
3983 new_ptc
->local_verdict
= NONE
;
3984 new_ptc
->verdict_reason
= NULL
;
3985 new_ptc
->tc_fd
= -1;
3986 new_ptc
->text_buf
= NULL
;
3987 init_qualified_name(&new_ptc
->tc_fn_name
);
3988 new_ptc
->return_type
= NULL
;
3989 new_ptc
->return_value_len
= 0;
3990 new_ptc
->return_value
= NULL
;
3991 new_ptc
->is_alive
= is_alive
;
3992 new_ptc
->stop_requested
= FALSE
;
3993 new_ptc
->process_killed
= FALSE
;
3994 new_ptc
->initial
.create_requestor
= tc
;
3995 new_ptc
->initial
.location_str
= component_location
;
3996 init_requestors(&new_ptc
->done_requestors
, NULL
);
3997 init_requestors(&new_ptc
->killed_requestors
, NULL
);
3998 init_requestors(&new_ptc
->cancel_done_sent_for
, NULL
);
3999 new_ptc
->kill_timer
= NULL
;
4000 init_connections(new_ptc
);
4002 add_component(new_ptc
);
4003 add_component_to_host(host
, new_ptc
);
4004 host
->n_active_components
++;
4010 void MainController::process_start_req(component_struct
*tc
, int message_end
)
4012 if (!request_allowed(tc
, "START_REQ")) return;
4014 Text_Buf
& text_buf
= *tc
->text_buf
;
4015 component component_reference
= text_buf
.pull_int().get_val();
4016 switch (component_reference
) {
4018 send_error_str(tc
->tc_fd
, "Start operation was requested on the null "
4019 "component reference.");
4022 send_error_str(tc
->tc_fd
, "Start operation was requested on the "
4023 "component reference of the MTC.");
4025 case SYSTEM_COMPREF
:
4026 send_error_str(tc
->tc_fd
, "Start operation was requested on the "
4027 "component reference of the system.");
4030 send_error_str(tc
->tc_fd
, "Start operation was requested on "
4031 "'any component'.");
4034 send_error_str(tc
->tc_fd
, "Start operation was requested on "
4035 "'all component'.");
4038 component_struct
*target
= lookup_component(component_reference
);
4039 if (target
== NULL
) {
4040 send_error(tc
->tc_fd
, "Start operation was requested on invalid "
4041 "component reference: %d.", component_reference
);
4044 switch (target
->tc_state
) {
4047 // these states are correct
4059 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4060 "started because it is already executing function %s.%s.",
4061 component_reference
, target
->tc_fn_name
.module_name
,
4062 target
->tc_fn_name
.definition_name
);
4065 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4066 "started because it function %s.%s is currently being stopped on "
4067 "it.", component_reference
, target
->tc_fn_name
.module_name
,
4068 target
->tc_fn_name
.definition_name
);
4071 case PTC_STOPPING_KILLING
:
4072 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4073 "started because it is currently being killed.",
4074 component_reference
);
4078 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4079 "started because it is not alive anymore.", component_reference
);
4082 send_error(tc
->tc_fd
, "The argument of start operation (%d) is a "
4083 "component reference that belongs to an earlier testcase.",
4084 component_reference
);
4087 send_error(tc
->tc_fd
, "Start operation was requested on component "
4088 "reference %d, which is in invalid state.",
4089 component_reference
);
4092 text_buf
.pull_qualified_name(target
->tc_fn_name
);
4093 target
->stop_requested
= FALSE
;
4094 int arg_begin
= text_buf
.get_pos();
4095 int arg_len
= message_end
- arg_begin
;
4096 const void *arg_ptr
= text_buf
.get_data() + arg_begin
;
4097 boolean send_cancel_done
= FALSE
, cancel_any_component_done
= FALSE
;
4098 if (target
->tc_state
== PTC_STOPPED
) {
4099 // updating the state of target because 'any component.done' cannot
4100 // consider this component anymore
4101 target
->tc_state
= PTC_STARTING
;
4102 // cleaning up the previous return value
4103 delete [] target
->return_type
;
4104 target
->return_type
= NULL
;
4105 target
->return_value_len
= 0;
4106 Free(target
->return_value
);
4107 target
->return_value
= NULL
;
4108 // determining which components we need to send CANCEL_DONE to
4109 init_requestors(&target
->starting
.cancel_done_sent_to
, NULL
);
4110 for (int i
= 0; ; i
++) {
4111 component_struct
*comp
= get_requestor(&target
->done_requestors
, i
);
4112 if (comp
== NULL
) break;
4113 else if (comp
== tc
) {
4114 // the start requestor shall cancel the done status locally
4118 switch (comp
->tc_state
) {
4132 // a CANCEL_DONE message shall be sent to comp
4133 send_cancel_done
= TRUE
;
4134 add_requestor(&target
->starting
.cancel_done_sent_to
, comp
);
4139 case PTC_STOPPING_KILLING
:
4140 // CANCEL_DONE will not be sent to comp
4143 error("Test Component %d is in invalid state when starting "
4144 "PTC %d.", comp
->comp_ref
, component_reference
);
4147 // check whether 'any component.done' needs to be cancelled
4148 if (any_component_done_sent
&& !is_any_component_done()) {
4149 send_cancel_done
= TRUE
;
4150 cancel_any_component_done
= TRUE
;
4151 any_component_done_sent
= FALSE
;
4152 add_requestor(&target
->starting
.cancel_done_sent_to
, mtc
);
4154 free_requestors(&target
->done_requestors
);
4156 if (send_cancel_done
) {
4157 for (int i
= 0; ; i
++) {
4158 component_struct
*comp
=
4159 get_requestor(&target
->starting
.cancel_done_sent_to
, i
);
4160 if (comp
== NULL
) break;
4161 else if (comp
== mtc
) send_cancel_done_mtc(component_reference
,
4162 cancel_any_component_done
);
4163 else send_cancel_done_ptc(comp
, component_reference
);
4164 add_requestor(&comp
->cancel_done_sent_for
, target
);
4166 target
->starting
.start_requestor
= tc
;
4167 target
->starting
.arguments_len
= arg_len
;
4168 target
->starting
.arguments_ptr
= Malloc(arg_len
);
4169 memcpy(target
->starting
.arguments_ptr
, arg_ptr
, arg_len
);
4170 tc
->tc_state
= TC_START
;
4172 send_start(target
, target
->tc_fn_name
, arg_len
, arg_ptr
);
4174 target
->tc_state
= PTC_FUNCTION
;
4179 void MainController::process_stop_req(component_struct
*tc
)
4181 if (!request_allowed(tc
, "STOP_REQ")) return;
4183 component component_reference
= tc
->text_buf
->pull_int().get_val();
4184 switch (component_reference
) {
4186 send_error_str(tc
->tc_fd
, "Stop operation was requested on the null "
4187 "component reference.");
4190 // 'mtc.stop' initiated by a PTC terminates the current testcase
4192 if (!mtc
->stop_requested
) {
4194 kill_all_components(TRUE
);
4195 mtc
->stop_requested
= TRUE
;
4196 start_kill_timer(mtc
);
4197 notify("Test Component %d has requested to stop MTC. "
4198 "Terminating current testcase execution.", tc
->comp_ref
);
4201 } else send_error_str(tc
->tc_fd
, "MTC has requested to stop itself.");
4203 case SYSTEM_COMPREF
:
4204 send_error_str(tc
->tc_fd
, "Stop operation was requested on the "
4205 "component reference of the system.");
4208 send_error_str(tc
->tc_fd
, "Stop operation was requested on "
4209 "'any component'.");
4213 if (stop_all_components()) send_stop_ack(mtc
);
4215 mtc
->tc_state
= MTC_ALL_COMPONENT_STOP
;
4218 } else send_error_str(tc
->tc_fd
, "Operation 'all component.stop' can "
4219 "only be performed on the MTC.");
4224 // the operation refers to a specific PTC
4225 component_struct
*target
= lookup_component(component_reference
);
4226 if (target
== NULL
) {
4227 send_error(tc
->tc_fd
, "The argument of stop operation is an "
4228 "invalid component reference: %d.", component_reference
);
4230 } else if (target
== tc
) {
4231 send_error_str(tc
->tc_fd
, "Stop operation was requested on the "
4232 "requestor component itself.");
4235 boolean target_inactive
= FALSE
;
4236 switch (target
->tc_state
) {
4238 if (!target
->is_alive
) error("PTC %d cannot be in state STOPPED "
4239 "because it is not an alive type PTC.", component_reference
);
4242 target_inactive
= TRUE
;
4253 if (target
->is_alive
) {
4254 if (target_inactive
) {
4255 // do nothing, just send a STOP_ACK to tc
4260 target
->tc_state
= TC_STOPPING
;
4263 // the target is not an alive type PTC: stop operation means kill
4265 if (target_inactive
) target
->tc_state
= PTC_KILLING
;
4266 else target
->tc_state
= PTC_STOPPING_KILLING
;
4268 // a STOP or KILL message was sent out
4269 target
->stop_requested
= TRUE
;
4270 init_requestors(&target
->stopping_killing
.stop_requestors
, tc
);
4271 init_requestors(&target
->stopping_killing
.kill_requestors
, NULL
);
4272 start_kill_timer(target
);
4273 tc
->tc_state
= TC_STOP
;
4277 if (target
->is_alive
) {
4278 // do nothing if the PTC is alive
4284 case PTC_STOPPING_KILLING
:
4285 // the PTC is currently being stopped
4286 add_requestor(&target
->stopping_killing
.stop_requestors
, tc
);
4287 tc
->tc_state
= TC_STOP
;
4292 // the PTC is already terminated, do nothing
4296 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4297 "stopped because it is currently being started.",
4298 component_reference
);
4301 send_error(tc
->tc_fd
, "The argument of stop operation (%d) is a "
4302 "component reference that belongs to an earlier testcase.",
4303 component_reference
);
4306 send_error(tc
->tc_fd
, "The test component that the stop operation "
4307 "refers to (%d) is in invalid state.", component_reference
);
4311 void MainController::process_kill_req(component_struct
*tc
)
4313 if (!request_allowed(tc
, "KILL_REQ")) return;
4315 component component_reference
= tc
->text_buf
->pull_int().get_val();
4316 switch (component_reference
) {
4318 send_error_str(tc
->tc_fd
, "Kill operation was requested on the null "
4319 "component reference.");
4322 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4323 "component reference of the MTC.");
4325 case SYSTEM_COMPREF
:
4326 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4327 "component reference of the system.");
4330 send_error_str(tc
->tc_fd
, "Kill operation was requested on "
4331 "'any component'.");
4335 if (kill_all_components(FALSE
)) send_kill_ack(mtc
);
4337 mtc
->tc_state
= MTC_ALL_COMPONENT_KILL
;
4340 } else send_error_str(tc
->tc_fd
, "Operation 'all component.kill' can "
4341 "only be performed on the MTC.");
4346 // the operation refers to a specific PTC
4347 component_struct
*target
= lookup_component(component_reference
);
4348 if (target
== NULL
) {
4349 send_error(tc
->tc_fd
, "The argument of kill operation is an "
4350 "invalid component reference: %d.", component_reference
);
4352 } else if (target
== tc
) {
4353 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4354 "requestor component itself.");
4357 boolean target_inactive
= FALSE
;
4358 switch (target
->tc_state
) {
4360 // the done status of this PTC is already sent out
4361 // and it will not be cancelled in the future
4362 free_requestors(&target
->done_requestors
);
4365 target_inactive
= TRUE
;
4377 if (target_inactive
) {
4378 // the PTC was inactive
4379 target
->tc_state
= PTC_KILLING
;
4380 if (!target
->is_alive
) target
->stop_requested
= TRUE
;
4382 // the PTC was active
4383 target
->tc_state
= PTC_STOPPING_KILLING
;
4384 target
->stop_requested
= TRUE
;
4386 init_requestors(&target
->stopping_killing
.stop_requestors
, NULL
);
4387 init_requestors(&target
->stopping_killing
.kill_requestors
, tc
);
4388 start_kill_timer(target
);
4389 tc
->tc_state
= TC_KILL
;
4393 // the PTC is currently being stopped
4395 target
->tc_state
= PTC_STOPPING_KILLING
;
4396 if (target
->kill_timer
!= NULL
) cancel_timer(target
->kill_timer
);
4397 start_kill_timer(target
);
4400 case PTC_STOPPING_KILLING
:
4401 // the PTC is currently being terminated
4402 add_requestor(&target
->stopping_killing
.kill_requestors
, tc
);
4403 tc
->tc_state
= TC_KILL
;
4408 // the PTC is already terminated
4412 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4413 "killed because it is currently being started.",
4414 component_reference
);
4417 send_error(tc
->tc_fd
, "The argument of kill operation (%d) is a "
4418 "component reference that belongs to an earlier testcase.",
4419 component_reference
);
4422 send_error(tc
->tc_fd
, "The test component that the kill operation "
4423 "refers to (%d) is in invalid state.", component_reference
);
4427 void MainController::process_is_running(component_struct
*tc
)
4429 if (!request_allowed(tc
, "IS_RUNNING")) return;
4431 component component_reference
= tc
->text_buf
->pull_int().get_val();
4432 switch (component_reference
) {
4434 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4435 "null component reference.");
4438 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4439 "component reference of the MTC.");
4441 case SYSTEM_COMPREF
:
4442 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4443 "component reference of the system.");
4446 if (tc
== mtc
) send_running(mtc
, is_any_component_running());
4447 else send_error_str(tc
->tc_fd
, "Operation 'any component.running' "
4448 "can only be performed on the MTC.");
4451 if (tc
== mtc
) send_running(mtc
, is_all_component_running());
4452 else send_error_str(tc
->tc_fd
, "Operation 'all component.running' "
4453 "can only be performed on the MTC.");
4458 // the operation refers to a specific PTC
4459 component_struct
*comp
= lookup_component(component_reference
);
4461 send_error(tc
->tc_fd
, "The argument of running operation is an "
4462 "invalid component reference: %d.", component_reference
);
4465 switch (comp
->tc_state
) {
4477 case PTC_STOPPING_KILLING
:
4478 send_running(tc
, TRUE
);
4485 send_running(tc
, FALSE
);
4488 send_error(tc
->tc_fd
, "The argument of running operation (%d) is a "
4489 "component reference that belongs to an earlier testcase.",
4490 component_reference
);
4493 send_error(tc
->tc_fd
, "The test component that the running operation "
4494 "refers to (%d) is in invalid state.", component_reference
);
4498 void MainController::process_is_alive(component_struct
*tc
)
4500 if (!request_allowed(tc
, "IS_ALIVE")) return;
4502 component component_reference
= tc
->text_buf
->pull_int().get_val();
4503 switch (component_reference
) {
4505 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4506 "null component reference.");
4509 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4510 "component reference of the MTC.");
4512 case SYSTEM_COMPREF
:
4513 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4514 "component reference of the system.");
4517 if (tc
== mtc
) send_alive(mtc
, is_any_component_alive());
4518 else send_error_str(tc
->tc_fd
, "Operation 'any component.alive' "
4519 "can only be performed on the MTC.");
4522 if (tc
== mtc
) send_alive(mtc
, is_all_component_alive());
4523 else send_error_str(tc
->tc_fd
, "Operation 'all component.alive' "
4524 "can only be performed on the MTC.");
4529 // the operation refers to a specific PTC
4530 component_struct
*comp
= lookup_component(component_reference
);
4532 send_error(tc
->tc_fd
, "The argument of alive operation is an "
4533 "invalid component reference: %d.", component_reference
);
4536 switch (comp
->tc_state
) {
4551 case PTC_STOPPING_KILLING
:
4552 send_alive(tc
, TRUE
);
4556 send_alive(tc
, FALSE
);
4559 send_error(tc
->tc_fd
, "The argument of alive operation (%d) is a "
4560 "component reference that belongs to an earlier testcase.",
4561 component_reference
);
4564 send_error(tc
->tc_fd
, "The test component that the alive operation "
4565 "refers to (%d) is in invalid state.", component_reference
);
4569 void MainController::process_done_req(component_struct
*tc
)
4571 if (!request_allowed(tc
, "DONE_REQ")) return;
4573 component component_reference
= tc
->text_buf
->pull_int().get_val();
4574 switch (component_reference
) {
4576 send_error_str(tc
->tc_fd
, "Done operation was requested on the null "
4577 "component reference.");
4580 send_error_str(tc
->tc_fd
, "Done operation was requested on the "
4581 "component reference of the MTC.");
4583 case SYSTEM_COMPREF
:
4584 send_error_str(tc
->tc_fd
, "Done operation was requested on the "
4585 "component reference of the system.");
4589 boolean answer
= is_any_component_done();
4590 send_done_ack(mtc
, answer
, NULL
, 0, NULL
);
4591 if (answer
) any_component_done_sent
= TRUE
;
4592 else any_component_done_requested
= TRUE
;
4593 } else send_error_str(tc
->tc_fd
, "Operation 'any component.done' can "
4594 "only be performed on the MTC.");
4598 boolean answer
= !is_any_component_running();
4599 send_done_ack(mtc
, answer
, NULL
, 0, NULL
);
4600 if (!answer
) all_component_done_requested
= TRUE
;
4601 } else send_error_str(tc
->tc_fd
, "Operation 'all component.done' can "
4602 "only be performed on the MTC.");
4607 // the operation refers to a specific PTC
4608 component_struct
*comp
= lookup_component(component_reference
);
4610 send_error(tc
->tc_fd
, "The argument of done operation is an "
4611 "invalid component reference: %d.", component_reference
);
4614 switch (comp
->tc_state
) {
4616 // this answer has to be cancelled when the component is re-started
4617 add_requestor(&comp
->done_requestors
, tc
);
4622 send_done_ack(tc
, TRUE
, comp
->return_type
, comp
->return_value_len
,
4623 comp
->return_value
);
4637 case PTC_STOPPING_KILLING
:
4638 send_done_ack(tc
, FALSE
, NULL
, 0, NULL
);
4639 add_requestor(&comp
->done_requestors
, tc
);
4642 send_error(tc
->tc_fd
, "The argument of done operation (%d) is a "
4643 "component reference that belongs to an earlier testcase.",
4644 component_reference
);
4647 send_error(tc
->tc_fd
, "The test component that the done operation "
4648 "refers to (%d) is in invalid state.", component_reference
);
4652 void MainController::process_killed_req(component_struct
*tc
)
4654 if (!request_allowed(tc
, "KILLED_REQ")) return;
4656 component component_reference
= tc
->text_buf
->pull_int().get_val();
4657 switch (component_reference
) {
4659 send_error_str(tc
->tc_fd
, "Killed operation was requested on the null "
4660 "component reference.");
4663 send_error_str(tc
->tc_fd
, "Killed operation was requested on the "
4664 "component reference of the MTC.");
4666 case SYSTEM_COMPREF
:
4667 send_error_str(tc
->tc_fd
, "Killed operation was requested on the "
4668 "component reference of the system.");
4672 boolean answer
= !is_all_component_alive();
4673 send_killed_ack(mtc
, answer
);
4674 if (!answer
) any_component_killed_requested
= TRUE
;
4675 } else send_error_str(tc
->tc_fd
, "Operation 'any component.killed' can "
4676 "only be performed on the MTC.");
4680 boolean answer
= !is_any_component_alive();
4681 send_killed_ack(mtc
, answer
);
4682 if (!answer
) all_component_killed_requested
= TRUE
;
4683 } else send_error_str(tc
->tc_fd
, "Operation 'all component.killed' can "
4684 "only be performed on the MTC.");
4689 // the operation refers to a specific PTC
4690 component_struct
*comp
= lookup_component(component_reference
);
4692 send_error(tc
->tc_fd
, "The argument of killed operation is an "
4693 "invalid component reference: %d.", component_reference
);
4696 switch (comp
->tc_state
) {
4699 send_killed_ack(tc
, TRUE
);
4715 case PTC_STOPPING_KILLING
:
4716 send_killed_ack(tc
, FALSE
);
4717 add_requestor(&comp
->killed_requestors
, tc
);
4720 send_error(tc
->tc_fd
, "The argument of killed operation (%d) is a "
4721 "component reference that belongs to an earlier testcase.",
4722 component_reference
);
4725 send_error(tc
->tc_fd
, "The test component that the killed operation "
4726 "refers to (%d) is in invalid state.", component_reference
);
4730 void MainController::process_cancel_done_ack(component_struct
*tc
)
4732 component component_reference
= tc
->text_buf
->pull_int().get_val();
4733 switch (component_reference
) {
4735 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the null "
4736 "component reference.");
4739 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the "
4740 "component reference of the MTC.");
4742 case SYSTEM_COMPREF
:
4743 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the "
4744 "component reference of the system.");
4747 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to "
4748 "'any component'.");
4751 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to "
4752 "'all component'.");
4757 component_struct
*started_tc
= lookup_component(component_reference
);
4758 if (started_tc
== NULL
) {
4759 send_error(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to an invalid "
4760 "component reference: %d.", component_reference
);
4763 done_cancelled(tc
, started_tc
);
4764 remove_requestor(&tc
->cancel_done_sent_for
, started_tc
);
4767 void MainController::process_connect_req(component_struct
*tc
)
4769 if (!request_allowed(tc
, "CONNECT_REQ")) return;
4771 Text_Buf
& text_buf
= *tc
->text_buf
;
4772 component src_compref
= text_buf
.pull_int().get_val();
4773 char *src_port
= text_buf
.pull_string();
4774 component dst_compref
= text_buf
.pull_int().get_val();
4775 char *dst_port
= text_buf
.pull_string();
4777 if (!valid_endpoint(src_compref
, TRUE
, tc
, "connect") ||
4778 !valid_endpoint(dst_compref
, TRUE
, tc
, "connect")) {
4784 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4787 conn
= new port_connection
;
4788 conn
->transport_type
=
4789 choose_port_connection_transport(src_compref
, dst_compref
);
4790 conn
->head
.comp_ref
= src_compref
;
4791 conn
->head
.port_name
= src_port
;
4792 conn
->tail
.comp_ref
= dst_compref
;
4793 conn
->tail
.port_name
= dst_port
;
4794 init_requestors(&conn
->requestors
, tc
);
4795 add_connection(conn
);
4796 // conn->head and tail is now in canonical order
4797 switch (conn
->transport_type
) {
4798 case TRANSPORT_LOCAL
:
4799 // send an empty string instead of component name
4800 // the component should already know its own name
4801 send_connect(components
[conn
->head
.comp_ref
], conn
->head
.port_name
,
4802 conn
->tail
.comp_ref
, NULL
, conn
->tail
.port_name
,
4803 conn
->transport_type
, 0, NULL
);
4804 conn
->conn_state
= CONN_CONNECTING
;
4806 case TRANSPORT_UNIX_STREAM
:
4807 case TRANSPORT_INET_STREAM
:
4808 // conn->head will be the server side
4809 if (conn
->tail
.comp_ref
!= MTC_COMPREF
&&
4810 conn
->tail
.comp_ref
!= conn
->head
.comp_ref
) {
4811 // send the name of conn->tail
4812 send_connect_listen(components
[conn
->head
.comp_ref
],
4813 conn
->head
.port_name
, conn
->tail
.comp_ref
,
4814 components
[conn
->tail
.comp_ref
]->comp_name
,
4815 conn
->tail
.port_name
, conn
->transport_type
);
4817 // send an empty string instead of the name of conn->tail if
4818 // it is known by conn->head
4819 send_connect_listen(components
[conn
->head
.comp_ref
],
4820 conn
->head
.port_name
, conn
->tail
.comp_ref
, NULL
,
4821 conn
->tail
.port_name
, conn
->transport_type
);
4823 conn
->conn_state
= CONN_LISTENING
;
4826 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4827 "be established because no suitable transport mechanism is "
4828 "available on the corresponding host(s).", src_compref
,
4829 src_port
, dst_compref
, dst_port
);
4830 remove_connection(conn
);
4833 tc
->tc_state
= TC_CONNECT
;
4836 switch (conn
->conn_state
) {
4837 case CONN_LISTENING
:
4838 case CONN_CONNECTING
:
4839 add_requestor(&conn
->requestors
, tc
);
4840 tc
->tc_state
= TC_CONNECT
;
4843 case CONN_CONNECTED
:
4844 send_connect_ack(tc
);
4846 case CONN_DISCONNECTING
:
4847 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4848 "be established because a disconnect operation is in progress "
4849 "on it.", src_compref
, src_port
, dst_compref
, dst_port
);
4852 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4853 "be established due to an internal error in the MC.",
4854 src_compref
, src_port
, dst_compref
, dst_port
);
4855 error("The port connection %d:%s - %d:%s is in invalid state "
4856 "when a connect operation was requested on it.", src_compref
,
4857 src_port
, dst_compref
, dst_port
);
4864 void MainController::process_connect_listen_ack(component_struct
*tc
,
4867 if (!message_expected(tc
, "CONNECT_LISTEN_ACK")) return;
4869 Text_Buf
& text_buf
= *tc
->text_buf
;
4870 component src_compref
= tc
->comp_ref
;
4871 char *src_port
= text_buf
.pull_string();
4872 component dst_compref
= text_buf
.pull_int().get_val();
4873 char *dst_port
= text_buf
.pull_string();
4874 transport_type_enum transport_type
=
4875 (transport_type_enum
)text_buf
.pull_int().get_val();
4876 int local_addr_begin
= text_buf
.get_pos();
4877 int local_addr_len
= message_end
- local_addr_begin
;
4878 const void *local_addr_ptr
= text_buf
.get_data() + local_addr_begin
;
4880 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4883 // this message must arrive in the right state
4884 // and from the server side (head)
4885 if (conn
->conn_state
!= CONN_LISTENING
||
4886 conn
->head
.comp_ref
!= src_compref
||
4887 strcmp(conn
->head
.port_name
, src_port
)) {
4888 send_error(tc
->tc_fd
, "Unexpected message CONNECT_LISTEN_ACK was "
4889 "received for port connection %d:%s - %d:%s.",
4890 src_compref
, src_port
, dst_compref
, dst_port
);
4894 } else if (conn
->transport_type
!= transport_type
) {
4895 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4896 "connection %d:%s - %d:%s contains wrong transport type: %s "
4897 "was expected instead of %s.", src_compref
, src_port
,
4898 dst_compref
, dst_port
, get_transport_name(conn
->transport_type
),
4899 get_transport_name(transport_type
));
4904 component_struct
*dst_comp
= components
[dst_compref
];
4905 switch (dst_comp
->tc_state
) {
4920 if (src_compref
!= MTC_COMPREF
&& src_compref
!= dst_compref
) {
4921 // send the name of tc
4922 send_connect(dst_comp
, dst_port
, src_compref
, tc
->comp_name
,
4923 src_port
, transport_type
, local_addr_len
, local_addr_ptr
);
4925 // send an empty string instead of the name of tc if it is
4926 // known by dst_comp
4927 send_connect(dst_comp
, dst_port
, src_compref
, NULL
, src_port
,
4928 transport_type
, local_addr_len
, local_addr_ptr
);
4930 conn
->conn_state
= CONN_CONNECTING
;
4933 send_disconnect_to_server(conn
);
4934 send_error_to_connect_requestors(conn
, "test component %d has "
4935 "terminated during connection setup.", dst_compref
);
4936 remove_connection(conn
);
4940 // the connection does not exist anymore
4941 // check whether the transport type is valid
4942 switch (transport_type
) {
4943 case TRANSPORT_LOCAL
:
4944 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4945 "connection %d:%s - %d:%s cannot refer to transport type %s.",
4946 src_compref
, src_port
, dst_compref
, dst_port
,
4947 get_transport_name(transport_type
));
4949 case TRANSPORT_INET_STREAM
:
4950 case TRANSPORT_UNIX_STREAM
:
4953 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4954 "connection %d:%s - %d:%s refers to invalid transport type %d.",
4955 src_compref
, src_port
, dst_compref
, dst_port
, transport_type
);
4963 void MainController::process_connected(component_struct
*tc
)
4965 if (!message_expected(tc
, "CONNECTED")) return;
4967 Text_Buf
& text_buf
= *tc
->text_buf
;
4968 component src_compref
= tc
->comp_ref
;
4969 char *src_port
= text_buf
.pull_string();
4970 component dst_compref
= text_buf
.pull_int().get_val();
4971 char *dst_port
= text_buf
.pull_string();
4973 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4976 // this message must arrive in the right state
4977 // and from the server side (head)
4978 if (conn
->conn_state
== CONN_CONNECTING
&&
4979 conn
->head
.comp_ref
== src_compref
&&
4980 !strcmp(conn
->head
.port_name
, src_port
)) {
4981 send_connect_ack_to_requestors(conn
);
4982 conn
->conn_state
= CONN_CONNECTED
;
4985 send_error(tc
->tc_fd
, "Unexpected CONNECTED message was "
4986 "received for port connection %d:%s - %d:%s.",
4987 src_compref
, src_port
, dst_compref
, dst_port
);
4990 // do nothing if the connection does not exist anymore
4996 void MainController::process_connect_error(component_struct
*tc
)
4998 if (!message_expected(tc
, "CONNECT_ERROR")) return;
5000 Text_Buf
& text_buf
= *tc
->text_buf
;
5001 component src_compref
= tc
->comp_ref
;
5002 char *src_port
= text_buf
.pull_string();
5003 component dst_compref
= text_buf
.pull_int().get_val();
5004 char *dst_port
= text_buf
.pull_string();
5005 char *reason
= text_buf
.pull_string();
5007 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
5010 switch (conn
->conn_state
) {
5011 case CONN_CONNECTING
:
5012 // in this state both endpoints can report error
5013 if (conn
->transport_type
!= TRANSPORT_LOCAL
&&
5014 conn
->tail
.comp_ref
== src_compref
&&
5015 !strcmp(conn
->tail
.port_name
, src_port
)) {
5016 // shut down the server side (head) only if the error was reported
5017 // by the client side (tail)
5018 send_disconnect_to_server(conn
);
5021 case CONN_LISTENING
:
5022 // in this state only the server side (head) can report the error
5023 if (conn
->head
.comp_ref
== src_compref
&&
5024 !strcmp(conn
->head
.port_name
, src_port
)) break;
5026 send_error(tc
->tc_fd
, "Unexpected message CONNECT_ERROR was "
5027 "received for port connection %d:%s - %d:%s.",
5028 src_compref
, src_port
, dst_compref
, dst_port
);
5034 send_error_to_connect_requestors(conn
, "test component %d reported "
5035 "error: %s", src_compref
, reason
);
5036 remove_connection(conn
);
5039 // do nothing if the connection does not exist anymore
5046 void MainController::process_disconnect_req(component_struct
*tc
)
5048 if (!request_allowed(tc
, "DISCONNECT_REQ")) return;
5050 Text_Buf
& text_buf
= *tc
->text_buf
;
5051 component src_compref
= text_buf
.pull_int().get_val();
5052 char *src_port
= text_buf
.pull_string();
5053 component dst_compref
= text_buf
.pull_int().get_val();
5054 char *dst_port
= text_buf
.pull_string();
5056 if (!valid_endpoint(src_compref
, FALSE
, tc
, "disconnect") ||
5057 !valid_endpoint(dst_compref
, FALSE
, tc
, "disconnect")) {
5063 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
5066 switch (conn
->conn_state
) {
5067 case CONN_LISTENING
:
5068 case CONN_CONNECTING
:
5069 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
5070 "be destroyed because a connect operation is in progress "
5071 "on it.", src_compref
, src_port
, dst_compref
, dst_port
);
5073 case CONN_CONNECTED
:
5074 send_disconnect(components
[conn
->tail
.comp_ref
],
5075 conn
->tail
.port_name
, conn
->head
.comp_ref
,
5076 conn
->head
.port_name
);
5077 conn
->conn_state
= CONN_DISCONNECTING
;
5079 case CONN_DISCONNECTING
:
5080 add_requestor(&conn
->requestors
, tc
);
5081 tc
->tc_state
= TC_DISCONNECT
;
5085 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
5086 "be destroyed due to an internal error in the MC.",
5087 src_compref
, src_port
, dst_compref
, dst_port
);
5088 error("The port connection %d:%s - %d:%s is in invalid state when "
5089 "a disconnect operation was requested on it.", src_compref
,
5090 src_port
, dst_compref
, dst_port
);
5093 // the connection is already terminated
5094 // send the acknowledgement immediately
5095 send_disconnect_ack(tc
);
5102 void MainController::process_disconnected(component_struct
*tc
)
5104 if (!message_expected(tc
, "DISCONNECTED")) return;
5106 Text_Buf
& text_buf
= *tc
->text_buf
;
5107 component src_compref
= tc
->comp_ref
;
5108 char *src_port
= text_buf
.pull_string();
5109 component dst_compref
= text_buf
.pull_int().get_val();
5110 char *dst_port
= text_buf
.pull_string();
5112 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
5115 switch (conn
->conn_state
) {
5116 case CONN_LISTENING
:
5117 // in this state only the server side (head) can report the end of
5119 if (conn
->head
.comp_ref
!= src_compref
||
5120 strcmp(conn
->head
.port_name
, src_port
)) {
5121 send_error(tc
->tc_fd
, "Unexpected message DISCONNECTED was "
5122 "received for port connection %d:%s - %d:%s.",
5123 src_compref
, src_port
, dst_compref
, dst_port
);
5127 case CONN_CONNECTING
:
5128 // in this state both ends can report the end of the connection
5129 send_error_to_connect_requestors(conn
, "test component %d "
5130 "reported end of the connection during connection setup.",
5132 remove_connection(conn
);
5135 case CONN_CONNECTED
:
5136 remove_connection(conn
);
5139 case CONN_DISCONNECTING
:
5140 send_disconnect_ack_to_requestors(conn
);
5141 remove_connection(conn
);
5145 error("The port connection %d:%s - %d:%s is in invalid state when "
5146 "MC was notified about its termination.", src_compref
, src_port
,
5147 dst_compref
, dst_port
);
5156 void MainController::process_map_req(component_struct
*tc
)
5158 if (!request_allowed(tc
, "MAP_REQ")) return;
5160 Text_Buf
& text_buf
= *tc
->text_buf
;
5161 component src_compref
= text_buf
.pull_int().get_val();
5162 char *src_port
= text_buf
.pull_string();
5163 char *system_port
= text_buf
.pull_string();
5165 if (!valid_endpoint(src_compref
, TRUE
, tc
, "map")) {
5167 delete [] system_port
;
5171 port_connection
*conn
= find_connection(src_compref
, src_port
,
5172 SYSTEM_COMPREF
, system_port
);
5174 send_map(components
[src_compref
], src_port
, system_port
);
5175 conn
= new port_connection
;
5176 conn
->head
.comp_ref
= src_compref
;
5177 conn
->head
.port_name
= src_port
;
5178 conn
->tail
.comp_ref
= SYSTEM_COMPREF
;
5179 conn
->tail
.port_name
= system_port
;
5180 conn
->conn_state
= CONN_MAPPING
;
5181 init_requestors(&conn
->requestors
, tc
);
5182 add_connection(conn
);
5183 tc
->tc_state
= TC_MAP
;
5186 switch (conn
->conn_state
) {
5188 add_requestor(&conn
->requestors
, tc
);
5189 tc
->tc_state
= TC_MAP
;
5195 case CONN_UNMAPPING
:
5196 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s cannot "
5197 "be established because an unmap operation is in progress "
5198 "on it.", src_compref
, src_port
, system_port
);
5201 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s is in "
5202 "invalid state.", src_compref
, src_port
, system_port
);
5205 delete [] system_port
;
5209 void MainController::process_mapped(component_struct
*tc
)
5211 if (!message_expected(tc
, "MAPPED")) return;
5213 Text_Buf
& text_buf
= *tc
->text_buf
;
5214 component src_compref
= tc
->comp_ref
;
5215 char *src_port
= text_buf
.pull_string();
5216 char *system_port
= text_buf
.pull_string();
5218 port_connection
*conn
= find_connection(src_compref
, src_port
,
5219 SYSTEM_COMPREF
, system_port
);
5221 send_error(tc
->tc_fd
, "The MAPPED message refers to a "
5222 "non-existent port mapping %d:%s - system:%s.",
5223 src_compref
, src_port
, system_port
);
5224 } else if (conn
->conn_state
!= CONN_MAPPING
) {
5225 send_error(tc
->tc_fd
, "Unexpected MAPPED message was "
5226 "received for port mapping %d:%s - system:%s.",
5227 src_compref
, src_port
, system_port
);
5229 for (int i
= 0; ; i
++) {
5230 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
5231 if (comp
== NULL
) break;
5232 if (comp
->tc_state
== TC_MAP
) {
5234 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
5235 else comp
->tc_state
= PTC_FUNCTION
;
5238 free_requestors(&conn
->requestors
);
5239 conn
->conn_state
= CONN_MAPPED
;
5244 delete [] system_port
;
5247 void MainController::process_unmap_req(component_struct
*tc
)
5249 if (!request_allowed(tc
, "UNMAP_REQ")) return;
5251 Text_Buf
& text_buf
= *tc
->text_buf
;
5252 component src_compref
= text_buf
.pull_int().get_val();
5253 char *src_port
= text_buf
.pull_string();
5254 char *system_port
= text_buf
.pull_string();
5256 if (!valid_endpoint(src_compref
, FALSE
, tc
, "unmap")) {
5258 delete [] system_port
;
5262 port_connection
*conn
= find_connection(src_compref
, src_port
,
5263 SYSTEM_COMPREF
, system_port
);
5267 switch (conn
->conn_state
) {
5269 send_unmap(components
[src_compref
], src_port
, system_port
);
5270 conn
->conn_state
= CONN_UNMAPPING
;
5271 case CONN_UNMAPPING
:
5272 add_requestor(&conn
->requestors
, tc
);
5273 tc
->tc_state
= TC_UNMAP
;
5277 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s cannot "
5278 "be destroyed because a map operation is in progress "
5279 "on it.", src_compref
, src_port
, system_port
);
5282 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s is in "
5283 "invalid state.", src_compref
, src_port
, system_port
);
5288 delete [] system_port
;
5291 void MainController::process_unmapped(component_struct
*tc
)
5293 if (!message_expected(tc
, "UNMAPPED")) return;
5295 Text_Buf
& text_buf
= *tc
->text_buf
;
5296 component src_compref
= tc
->comp_ref
;
5297 char *src_port
= text_buf
.pull_string();
5298 char *system_port
= text_buf
.pull_string();
5300 port_connection
*conn
= find_connection(src_compref
, src_port
,
5301 SYSTEM_COMPREF
, system_port
);
5303 switch (conn
->conn_state
) {
5306 case CONN_UNMAPPING
:
5307 destroy_mapping(conn
);
5310 send_error(tc
->tc_fd
, "Unexpected UNMAPPED message was "
5311 "received for port mapping %d:%s - system:%s.",
5312 src_compref
, src_port
, system_port
);
5317 delete [] system_port
;
5321 void MainController::process_testcase_started()
5323 if (mc_state
!= MC_EXECUTING_CONTROL
) {
5324 send_error_str(mtc
->tc_fd
, "Unexpected message TESTCASE_STARTED "
5329 Text_Buf
& text_buf
= *mtc
->text_buf
;
5330 text_buf
.pull_qualified_name(mtc
->tc_fn_name
);
5331 text_buf
.pull_qualified_name(mtc
->comp_type
);
5332 text_buf
.pull_qualified_name(system
->comp_type
);
5334 mtc
->tc_state
= MTC_TESTCASE
;
5335 mc_state
= MC_EXECUTING_TESTCASE
;
5336 tc_first_comp_ref
= next_comp_ref
;
5337 any_component_done_requested
= FALSE
;
5338 any_component_done_sent
= FALSE
;
5339 all_component_done_requested
= FALSE
;
5340 any_component_killed_requested
= FALSE
;
5341 all_component_killed_requested
= FALSE
;
5346 void MainController::process_testcase_finished()
5348 if (mc_state
!= MC_EXECUTING_TESTCASE
) {
5349 send_error_str(mtc
->tc_fd
, "Unexpected message TESTCASE_FINISHED "
5354 boolean ready_to_finish
= kill_all_components(TRUE
);
5356 mc_state
= MC_TERMINATING_TESTCASE
;
5357 mtc
->tc_state
= MTC_TERMINATING_TESTCASE
;
5358 mtc
->local_verdict
= (verdicttype
)mtc
->text_buf
->pull_int().get_val();
5359 mtc
->verdict_reason
= mtc
->text_buf
->pull_string();
5360 mtc
->stop_requested
= FALSE
;
5361 if (mtc
->kill_timer
!= NULL
) {
5362 cancel_timer(mtc
->kill_timer
);
5363 mtc
->kill_timer
= NULL
;
5365 any_component_done_requested
= FALSE
;
5366 any_component_done_sent
= FALSE
;
5367 all_component_done_requested
= FALSE
;
5368 any_component_killed_requested
= FALSE
;
5369 all_component_killed_requested
= FALSE
;
5371 if (ready_to_finish
) finish_testcase();
5376 void MainController::process_mtc_ready()
5378 if (mc_state
!= MC_EXECUTING_CONTROL
|| mtc
->tc_state
!= MTC_CONTROLPART
) {
5379 send_error_str(mtc
->tc_fd
, "Unexpected message MTC_READY was "
5383 mc_state
= MC_READY
;
5384 mtc
->tc_state
= TC_IDLE
;
5385 mtc
->stop_requested
= FALSE
;
5386 if (mtc
->kill_timer
!= NULL
) {
5387 cancel_timer(mtc
->kill_timer
);
5388 mtc
->kill_timer
= NULL
;
5390 stop_requested
= FALSE
;
5391 notify("Test execution finished.");
5395 void MainController::process_stopped(component_struct
*tc
, int message_end
)
5397 switch (tc
->tc_state
) {
5400 case PTC_STOPPING_KILLING
:
5401 // only alive PTCs are allowed to send STOPPED
5402 if (tc
->is_alive
) break;
5404 send_error_str(tc
->tc_fd
, "Unexpected message STOPPED was received.");
5407 Text_Buf
& text_buf
= *tc
->text_buf
;
5408 delete [] tc
->return_type
;
5409 tc
->return_type
= text_buf
.pull_string();
5410 tc
->return_value_len
= message_end
- text_buf
.get_pos();
5411 Free(tc
->return_value
);
5412 tc
->return_value
= Malloc(tc
->return_value_len
);
5413 text_buf
.pull_raw(tc
->return_value_len
, tc
->return_value
);
5414 free_qualified_name(&tc
->tc_fn_name
);
5415 component_stopped(tc
);
5419 void MainController::process_stopped_killed(component_struct
*tc
,
5422 switch (tc
->tc_state
) {
5433 case PTC_STOPPING_KILLING
:
5436 send_error_str(tc
->tc_fd
, "Unexpected message STOPPED_KILLED was "
5438 // also notify the user because the above message may get lost
5439 notify("Unexpected message STOPPED_KILLED was received from PTC %d.",
5443 Text_Buf
& text_buf
= *tc
->text_buf
;
5444 tc
->local_verdict
= (verdicttype
)text_buf
.pull_int().get_val();
5445 tc
->verdict_reason
= text_buf
.pull_string();
5446 tc
->return_type
= text_buf
.pull_string();
5447 tc
->return_value_len
= message_end
- text_buf
.get_pos();
5448 tc
->return_value
= Malloc(tc
->return_value_len
);
5449 text_buf
.pull_raw(tc
->return_value_len
, tc
->return_value
);
5450 // start a guard timer to detect whether the control connection is closed
5452 if (tc
->tc_state
!= PTC_STOPPING_KILLING
) start_kill_timer(tc
);
5453 component_terminated(tc
);
5457 void MainController::process_killed(component_struct
*tc
)
5459 switch (tc
->tc_state
) {
5465 send_error_str(tc
->tc_fd
, "Unexpected message KILLED was received.");
5466 // also notify the user because the above message may get lost
5467 notify("Unexpected message KILLED was received from PTC %d.",
5471 tc
->local_verdict
= (verdicttype
)tc
->text_buf
->pull_int().get_val();
5472 tc
->verdict_reason
= tc
->text_buf
->pull_string();
5473 // start a guard timer to detect whether the control connection is closed
5475 if (tc
->tc_state
!= PTC_KILLING
) start_kill_timer(tc
);
5476 component_terminated(tc
);
5480 void MainController::initialize(UserInterface
& par_ui
, int par_max_ptcs
)
5484 max_ptcs
= par_max_ptcs
;
5486 mc_state
= MC_INACTIVE
;
5489 if (uname(&buf
) < 0) fatal_error("MainController::initialize: "
5490 "uname() system call failed.");
5491 mc_hostname
= mprintf("MC@%s", buf
.nodename
);
5495 if (pthread_mutex_init(&mutex
, NULL
))
5496 fatal_error("MainController::initialize: pthread_mutex_init failed.");
5499 epoll_events
= NULL
;
5506 pollfds_modified
= FALSE
;
5512 unknown_head
= NULL
;
5513 unknown_tail
= NULL
;
5517 init_string_set(&assigned_components
);
5518 all_components_assigned
= FALSE
;
5524 version_known
= FALSE
;
5533 next_comp_ref
= FIRST_PTC_COMPREF
;
5535 stop_after_tc
= FALSE
;
5536 stop_requested
= FALSE
;
5545 wakeup_reason
= REASON_NOTHING
;
5547 register_termination_handlers();
5550 void MainController::terminate()
5553 destroy_host_groups();
5555 pthread_mutex_destroy(&mutex
);
5558 void MainController::add_host(const char *group_name
, const char *host_name
)
5561 if (mc_state
!= MC_INACTIVE
) {
5562 error("MainController::add_host: called in wrong state.");
5566 host_group_struct
*group
= add_host_group(group_name
);
5567 if (host_name
!= NULL
) {
5568 if (group
->has_all_hosts
) error("Redundant member `%s' was ignored in "
5569 "host group `%s'. All hosts (`*') are already the members of the "
5570 "group.", host_name
, group_name
);
5572 if (set_has_string(&group
->host_members
, host_name
)) {
5573 error("Duplicate member `%s' was ignored in host group "
5574 "`%s'.", host_name
, group_name
);
5575 } else add_string_to_set(&group
->host_members
, host_name
);
5578 if (group
->has_all_hosts
) error("Duplicate member `*' was ignored in "
5579 "host group `%s'.", group_name
);
5581 for (int i
= 0; ; i
++) {
5582 const char *group_member
=
5583 get_string_from_set(&group
->host_members
, i
);
5584 if (group_member
== NULL
) break;
5585 error("Redundant member `%s' was ignored in host group `%s'. "
5586 "All hosts (`*') are already the members of the group.",
5587 group_member
, group_name
);
5589 free_string_set(&group
->host_members
);
5590 group
->has_all_hosts
= TRUE
;
5596 void MainController::assign_component(const char *host_or_group
,
5597 const char *component_id
)
5600 if (mc_state
!= MC_INACTIVE
) {
5601 error("MainController::assign_component: called in wrong state.");
5605 host_group_struct
*group
= add_host_group(host_or_group
);
5606 if (component_id
== NULL
) {
5607 if (all_components_assigned
) {
5608 for (int i
= 0; i
< n_host_groups
; i
++) {
5609 if (host_groups
[i
].has_all_components
) {
5610 error("Duplicate assignment of all components (*) to host "
5611 "group `%s'. Previous assignment to group `%s' is "
5612 "ignored.", host_or_group
, host_groups
[i
].group_name
);
5613 host_groups
[i
].has_all_components
= FALSE
;
5616 } else all_components_assigned
= TRUE
;
5617 group
->has_all_components
= TRUE
;
5619 if (set_has_string(&assigned_components
, component_id
)) {
5620 for (int i
= 0; i
< n_host_groups
; i
++) {
5621 if (set_has_string(&host_groups
[i
].assigned_components
,
5623 error("Duplicate assignment of component `%s' to host "
5624 "group `%s'. Previous assignment to group `%s' is "
5625 "ignored.", component_id
, host_or_group
,
5626 host_groups
[i
].group_name
);
5627 remove_string_from_set(&host_groups
[i
].assigned_components
,
5631 } else add_string_to_set(&assigned_components
, component_id
);
5632 add_string_to_set(&group
->assigned_components
, component_id
);
5637 void MainController::destroy_host_groups()
5640 if (mc_state
!= MC_INACTIVE
)
5641 error("MainController::destroy_host_groups: called in wrong state.");
5643 for (int i
= 0; i
< n_host_groups
; i
++) {
5644 host_group_struct
*group
= host_groups
+ i
;
5645 Free(group
->group_name
);
5646 free_string_set(&group
->host_members
);
5647 free_string_set(&group
->assigned_components
);
5652 free_string_set(&assigned_components
);
5653 all_components_assigned
= FALSE
;
5658 void MainController::set_kill_timer(double timer_val
)
5661 if (mc_state
!= MC_INACTIVE
)
5662 error("MainController::set_kill_timer: called in wrong state.");
5663 else if (timer_val
< 0.0)
5664 error("MainController::set_kill_timer: setting a negative kill timer "
5666 else kill_timer
= timer_val
;
5670 unsigned short MainController::start_session(const char *local_address
,
5671 unsigned short tcp_port
, bool unix_sockets_enabled
)
5675 if (mc_state
!= MC_INACTIVE
) {
5676 error("MainController::start_session: called in wrong state.");
5682 epoll_events
= (epoll_event
*)Malloc(EPOLL_MAX_EVENTS
* sizeof(*epoll_events
));
5683 epfd
= epoll_create(EPOLL_SIZE_HINT
);
5685 error("System call epoll_create failed: %s", strerror(errno
));
5690 set_close_on_exec(epfd
);
5693 nh
.set_family(local_address
);
5694 server_fd
= nh
.socket();
5695 if (server_fd
< 0) {
5696 error("Server socket creation failed: %s", strerror(errno
));
5703 if (setsockopt(server_fd
, SOL_SOCKET
, SO_REUSEADDR
, (const char*)&on
,
5705 error("System call setsockopt (SO_REUSEADDR) failed on server socket: "
5706 "%s", strerror(errno
));
5712 if (setsockopt(server_fd
, IPPROTO_TCP
, TCP_NODELAY
, (const char*)&on
,
5714 error("System call setsockopt (TCP_NODELAY) failed on server socket: "
5715 "%s", strerror(errno
));
5721 IPAddress
*localaddr
= IPAddress::create_addr(nh
.get_family());
5722 if (localaddr
) localaddr
->set_port(tcp_port
);
5724 if (local_address
!= NULL
) {
5725 if (!localaddr
|| !localaddr
->set_addr(local_address
, tcp_port
)) {
5726 error("Cannot resolve host name `%s' to a local IP address: "
5727 "Host name lookup failure", local_address
);
5735 if (bind(server_fd
, localaddr
->get_addr(), localaddr
->get_addr_len())) {
5736 if (local_address
!= NULL
) {
5737 if (tcp_port
!= 0) error("Binding server socket to IP address "
5738 "%s and TCP port %d failed: %s", localaddr
->get_addr_str(),
5739 tcp_port
, strerror(errno
));
5740 else error("Binding server socket to IP address %s failed: %s",
5741 localaddr
->get_addr_str(), strerror(errno
));
5743 if (tcp_port
!= 0) error("Binding server socket to TCP port %d "
5744 "failed: %s", tcp_port
, strerror(errno
));
5745 else error("Binding server socket to an ephemeral TCP port "
5746 "failed: %s", strerror(errno
));
5754 if (listen(server_fd
, 10)) {
5755 if (local_address
!= NULL
) {
5756 if (tcp_port
!= 0) error("Listening on IP address %s and TCP port "
5757 "%d failed: %s", localaddr
->get_addr_str(), tcp_port
,
5759 else error("Listening on IP address %s failed: %s",
5760 localaddr
->get_addr_str(), strerror(errno
));
5762 if (tcp_port
!= 0) error("Listening on TCP port %d failed: %s",
5763 tcp_port
, strerror(errno
));
5764 else error("Listening on an ephemeral TCP port failed: %s",
5773 if (localaddr
->getsockname(server_fd
)) {
5774 error("System call getsockname() failed on server socket: %s",
5781 tcp_port
= localaddr
->get_port();
5783 set_close_on_exec(server_fd
);
5785 // Trying to open a unix socket for local communication
5786 if (unix_sockets_enabled
) {
5788 server_fd_unix
= socket(PF_UNIX
, SOCK_STREAM
, 0);
5789 if (server_fd_unix
< 0) {
5790 notify("Unix server socket creation failed: %s", strerror(errno
));
5795 struct sockaddr_un localaddr_unix
;
5796 memset(&localaddr_unix
, 0, sizeof(localaddr_unix
));
5797 localaddr_unix
.sun_family
= AF_UNIX
;
5798 snprintf(localaddr_unix
.sun_path
, sizeof(localaddr_unix
.sun_path
),
5799 "/tmp/ttcn3-mctr-%u", tcp_port
);
5800 if (unlink(localaddr_unix
.sun_path
))
5801 errno
= 0; // silently ignore, error handling below
5803 if (bind(server_fd_unix
, (struct sockaddr
*)&localaddr_unix
,
5804 sizeof(localaddr_unix
)) != 0) {
5805 if (errno
== EADDRINUSE
) {
5806 // the temporary file name is already used by someone else
5807 close(server_fd_unix
);
5808 notify("Could not create Unix server socket: '%s' is already existed "
5809 "and cannot be removed.", localaddr_unix
.sun_path
);
5813 close(server_fd_unix
);
5814 notify("Binding of Unix server socket to pathname %s failed. (%s)",
5815 localaddr_unix
.sun_path
, strerror(errno
));
5821 if (listen(server_fd_unix
, 10)) {
5822 notify("Could not listen on the given socket. Unix domain socket "
5823 "communication will not be used.");
5824 close(server_fd_unix
);
5829 set_close_on_exec(server_fd_unix
);
5831 add_fd_to_table(server_fd_unix
);
5832 fd_table
[server_fd_unix
].fd_type
= FD_SERVER
;
5833 add_poll_fd(server_fd_unix
);
5835 notify("Unix server socket created successfully.");
5839 if (pipe(pipe_fd
) < 0) {
5840 error("System call pipe failed: %s", strerror(errno
));
5846 set_close_on_exec(pipe_fd
[0]);
5847 set_close_on_exec(pipe_fd
[1]);
5849 wakeup_reason
= REASON_NOTHING
;
5851 mc_state
= MC_LISTENING
;
5853 add_fd_to_table(server_fd
);
5854 fd_table
[server_fd
].fd_type
= FD_SERVER
;
5855 add_poll_fd(server_fd
);
5856 server_fd_disabled
= FALSE
;
5858 add_fd_to_table(pipe_fd
[0]);
5859 fd_table
[pipe_fd
[0]].fd_type
= FD_PIPE
;
5860 add_poll_fd(pipe_fd
[0]);
5862 pthread_attr_t attr
;
5863 if (pthread_attr_init(&attr
))
5864 fatal_error("MainController::start_session: pthread_attr_init failed.");
5865 if (pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
))
5866 fatal_error("MainController::start_session: "
5867 "pthread_attr_setdetachstate failed.");
5870 if (pthread_create(&thread
, &attr
, thread_main
, NULL
))
5871 fatal_error("MainController::start_session: pthread_create failed.");
5873 if (pthread_attr_destroy(&attr
))
5874 fatal_error("MainController::start_session: pthread_attr_destroy "
5876 if (local_address
!= NULL
)
5877 notify("Listening on IP address %s and TCP port %d.", localaddr
->get_addr_str(), tcp_port
);
5878 else notify("Listening on TCP port %d.", tcp_port
);
5885 void MainController::shutdown_session()
5895 case MC_LISTENING_CONFIGURED
:
5896 case MC_HC_CONNECTED
:
5898 notify("Shutting down session.");
5899 wakeup_thread(REASON_SHUTDOWN
);
5902 error("MainController::shutdown_session: called in wrong state.");
5907 char *MainController::config_str
;
5909 void MainController::configure(const char *config_file
)
5913 case MC_HC_CONNECTED
:
5915 mc_state
= MC_CONFIGURING
;
5918 case MC_LISTENING_CONFIGURED
:
5919 mc_state
= MC_LISTENING_CONFIGURED
;
5922 error("MainController::configure: called in wrong state.");
5927 config_str
= mcopystr(config_file
);
5928 if(mc_state
== MC_CONFIGURING
) {
5929 notify("Downloading configuration file to all HCs.");
5930 for (int i
= 0; i
< n_hosts
; i
++) configure_host(hosts
[i
], FALSE
);
5936 void MainController::create_mtc(int host_index
)
5939 if (mc_state
!= MC_ACTIVE
) {
5940 error("MainController::create_mtc: called in wrong state.");
5944 if (host_index
< 0 || host_index
>= n_hosts
) {
5945 error("MainController::create_mtc: host index (%d) is out of range.",
5950 host_struct
*host
= hosts
[host_index
];
5951 switch (host
->hc_state
) {
5953 notify("HC on host %s reported overload. Trying to create MTC there "
5954 "anyway.", host
->hostname
);
5958 error("MTC cannot be created on %s: HC is not active.", host
->hostname
);
5962 notify("Creating MTC on host %s.", host
->hostname
);
5963 send_create_mtc(host
);
5965 mtc
= new component_struct
;
5966 mtc
->comp_ref
= MTC_COMPREF
;
5967 init_qualified_name(&mtc
->comp_type
);
5968 mtc
->comp_name
= new char[4];
5969 strcpy(mtc
->comp_name
, "MTC");
5970 mtc
->tc_state
= TC_INITIAL
;
5971 mtc
->local_verdict
= NONE
;
5972 mtc
->verdict_reason
= NULL
;
5974 mtc
->text_buf
= NULL
;
5975 init_qualified_name(&mtc
->tc_fn_name
);
5976 mtc
->return_type
= NULL
;
5977 mtc
->return_value_len
= 0;
5978 mtc
->return_value
= NULL
;
5979 mtc
->is_alive
= FALSE
;
5980 mtc
->stop_requested
= FALSE
;
5981 mtc
->process_killed
= FALSE
;
5982 mtc
->initial
.create_requestor
= NULL
;
5983 mtc
->initial
.location_str
= NULL
;
5984 init_requestors(&mtc
->done_requestors
, NULL
);
5985 init_requestors(&mtc
->killed_requestors
, NULL
);
5986 init_requestors(&mtc
->cancel_done_sent_for
, NULL
);
5987 mtc
->kill_timer
= NULL
;
5988 init_connections(mtc
);
5990 add_component_to_host(host
, mtc
);
5991 host
->n_active_components
++;
5993 system
= new component_struct
;
5994 system
->comp_ref
= SYSTEM_COMPREF
;
5995 init_qualified_name(&system
->comp_type
);
5996 system
->comp_name
= new char[7];
5997 strcpy(system
->comp_name
, "SYSTEM");
5998 system
->log_source
= NULL
;
5999 system
->comp_location
= NULL
;
6000 system
->tc_state
= TC_SYSTEM
;
6001 system
->local_verdict
= NONE
;
6002 system
->verdict_reason
= NULL
;
6004 system
->text_buf
= NULL
;
6005 init_qualified_name(&system
->tc_fn_name
);
6006 system
->return_type
= NULL
;
6007 system
->return_value_len
= 0;
6008 system
->return_value
= NULL
;
6009 system
->is_alive
= FALSE
;
6010 system
->stop_requested
= FALSE
;
6011 system
->process_killed
= FALSE
;
6012 init_requestors(&system
->done_requestors
, NULL
);
6013 init_requestors(&system
->killed_requestors
, NULL
);
6014 init_requestors(&system
->cancel_done_sent_for
, NULL
);
6015 system
->kill_timer
= NULL
;
6016 init_connections(system
);
6017 add_component(system
);
6019 mc_state
= MC_CREATING_MTC
;
6024 void MainController::exit_mtc()
6027 if (mc_state
!= MC_READY
) {
6028 error("MainController::exit_mtc: called in wrong state.");
6032 notify("Terminating MTC.");
6034 mtc
->tc_state
= TC_EXITING
;
6035 mtc
->comp_location
->n_active_components
--;
6036 mc_state
= MC_TERMINATING_MTC
;
6037 start_kill_timer(mtc
);
6042 void MainController::execute_control(const char *module_name
)
6045 if (mc_state
!= MC_READY
) {
6046 error("MainController::execute_control: called in wrong state.");
6050 send_execute_control(module_name
);
6051 mtc
->tc_state
= MTC_CONTROLPART
;
6052 mc_state
= MC_EXECUTING_CONTROL
;
6057 void MainController::execute_testcase(const char *module_name
,
6058 const char *testcase_name
)
6061 if (mc_state
!= MC_READY
) {
6062 error("MainController::execute_testcase: called in wrong state.");
6066 send_execute_testcase(module_name
, testcase_name
);
6067 mtc
->tc_state
= MTC_CONTROLPART
;
6068 mc_state
= MC_EXECUTING_CONTROL
;
6073 void MainController::stop_after_testcase(boolean new_state
)
6076 stop_after_tc
= new_state
;
6077 if (mc_state
== MC_PAUSED
&& !stop_after_tc
) {
6079 continue_testcase();
6083 void MainController::continue_testcase()
6086 if (mc_state
== MC_PAUSED
) {
6087 notify("Resuming execution.");
6089 mtc
->tc_state
= MTC_CONTROLPART
;
6090 mc_state
= MC_EXECUTING_CONTROL
;
6092 } else error("MainController::continue_testcase: called in wrong state.");
6096 void MainController::stop_execution()
6099 if (!stop_requested
) {
6100 notify("Stopping execution.");
6103 mc_state
= MC_EXECUTING_CONTROL
;
6104 mtc
->tc_state
= MTC_CONTROLPART
;
6105 case MC_EXECUTING_CONTROL
:
6107 mtc
->stop_requested
= TRUE
;
6108 start_kill_timer(mtc
);
6109 wakeup_thread(REASON_MTC_KILL_TIMER
);
6111 case MC_EXECUTING_TESTCASE
:
6112 if (!mtc
->stop_requested
) {
6114 kill_all_components(TRUE
);
6115 mtc
->stop_requested
= TRUE
;
6116 start_kill_timer(mtc
);
6117 wakeup_thread(REASON_MTC_KILL_TIMER
);
6119 case MC_TERMINATING_TESTCASE
:
6120 // MTC will be stopped later in finish_testcase()
6125 error("MainController::stop_execution: called in wrong state.");
6129 stop_requested
= TRUE
;
6131 } else notify("Stop was already requested. Operation ignored.");
6135 mc_state_enum
MainController::get_state()
6138 mc_state_enum ret_val
= mc_state
;
6143 boolean
MainController::get_stop_after_testcase()
6146 boolean ret_val
= stop_after_tc
;
6151 int MainController::get_nof_hosts()
6154 int ret_val
= n_hosts
;
6159 host_struct
*MainController::get_host_data(int host_index
)
6162 if (host_index
>= 0 && host_index
< n_hosts
) return hosts
[host_index
];
6166 component_struct
*MainController::get_component_data(int component_reference
)
6169 return lookup_component(component_reference
);
6172 void MainController::release_data()
6177 const char *MainController::get_mc_state_name(mc_state_enum state
)
6184 case MC_LISTENING_CONFIGURED
:
6185 return "listening (configured)";
6186 case MC_HC_CONNECTED
:
6187 return "HC connected";
6188 case MC_CONFIGURING
:
6189 return "configuring...";
6192 case MC_CREATING_MTC
:
6193 return "creating MTC...";
6194 case MC_TERMINATING_MTC
:
6195 return "terminating MTC...";
6198 case MC_EXECUTING_CONTROL
:
6199 return "executing control part";
6200 case MC_EXECUTING_TESTCASE
:
6201 return "executing testcase";
6202 case MC_TERMINATING_TESTCASE
:
6203 return "terminating testcase...";
6205 return "paused after testcase";
6207 return "shutting down...";
6209 return "unknown/transient";
6213 const char *MainController::get_hc_state_name(hc_state_enum state
)
6217 return "not configured";
6218 case HC_CONFIGURING
:
6219 case HC_CONFIGURING_OVERLOADED
:
6220 return "being configured";
6224 return "overloaded";
6228 return "unknown/transient";
6232 const char *MainController::get_tc_state_name(tc_state_enum state
)
6236 return "being created";
6238 return "inactive - waiting for start";
6240 return "executing create operation";
6242 return "executing component start operation";
6244 case MTC_ALL_COMPONENT_STOP
:
6245 return "executing component stop operation";
6247 case MTC_ALL_COMPONENT_KILL
:
6248 return "executing kill operation";
6250 return "executing connect operation";
6252 return "executing disconnect operation";
6254 return "executing map operation";
6256 return "executing unmap operation";
6258 return "being stopped";
6260 return "terminated";
6263 case MTC_CONTROLPART
:
6264 return "executing control part";
6266 return "executing testcase";
6267 case MTC_TERMINATING_TESTCASE
:
6268 return "terminating testcase";
6272 return "executing function";
6274 return "being started";
6276 return "stopped - waiting for re-start";
6278 case PTC_STOPPING_KILLING
:
6279 return "being killed";
6281 return "unknown/transient";
6285 const char *MainController::get_transport_name(transport_type_enum transport
)
6287 switch (transport
) {
6288 case TRANSPORT_LOCAL
:
6289 return "LOCAL (software loop)";
6290 case TRANSPORT_INET_STREAM
:
6291 return "INET_STREAM (TCP over IPv4)";
6292 case TRANSPORT_UNIX_STREAM
:
6293 return "UNIX_STREAM (UNIX domain socket)";
6299 //----------------------------------------------------------------------------
6301 } /* namespace mctr */
6303 //----------------------------------------------------------------------------
6307 // indent-tabs-mode: nil
6308 // c-basic-offset: 2