1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
9 // Description: Implementation file for MainController
10 // Author: Janos Zoltan Szabo
11 // mail: tmpjsz@eth.ericsson.se
13 // Copyright Ericsson Telecom AB 2000-2014
15 //----------------------------------------------------------------------------
17 #include "MainController.h"
18 #include "UserInterface.h"
20 #include "../../common/memory.h"
21 #include "../../common/version.h"
22 #include "../../common/version_internal.h"
23 #include "../../core/Message_types.hh"
24 #include "../../core/Error.hh"
25 #include "../../core/Textbuf.hh"
26 #include "../../core/Logger.hh"
36 #include <sys/types.h>
37 #include <sys/socket.h>
40 #include <sys/epoll.h>
44 #include <sys/utsname.h>
45 #include <netinet/in.h>
46 #include <netinet/tcp.h>
47 #include <arpa/inet.h>
52 reffer::reffer(const char*) {}
54 //----------------------------------------------------------------------------
58 //----------------------------------------------------------------------------
60 /* Static variables */
62 UserInterface
*MainController::ui
;
63 NetworkHandler
MainController::nh
;
65 mc_state_enum
MainController::mc_state
;
66 char *MainController::mc_hostname
;
68 struct sigaction
MainController::new_action
, MainController::old_action
;
70 int MainController::server_fd
;
71 int MainController::server_fd_unix
= -1;
72 boolean
MainController::server_fd_disabled
;
74 void MainController::disable_server_fd()
76 if (!server_fd_disabled
) {
77 remove_poll_fd(server_fd
);
78 server_fd_disabled
= TRUE
;
82 void MainController::enable_server_fd()
84 if (server_fd_disabled
) {
85 add_poll_fd(server_fd
);
86 server_fd_disabled
= FALSE
;
90 pthread_mutex_t
MainController::mutex
;
92 void MainController::lock()
94 int result
= pthread_mutex_lock(&mutex
);
96 fatal_error("MainController::lock: "
97 "pthread_mutex_lock failed with code %d.", result
);
101 void MainController::unlock()
103 int result
= pthread_mutex_unlock(&mutex
);
105 fatal_error("MainController::unlock: "
106 "pthread_mutex_unlock failed with code %d.", result
);
111 epoll_event
*MainController::epoll_events
;
112 int MainController::epfd
;
114 unsigned int MainController::nfds
, MainController::new_nfds
;
115 struct pollfd
*MainController::ufds
, *MainController::new_ufds
;
116 boolean
MainController::pollfds_modified
;
120 void MainController::add_poll_fd(int fd
)
124 event
.events
= EPOLLIN
;
126 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, fd
, &event
) < 0)
127 fatal_error("MainController::add_poll_fd: system call epoll_ctl"
128 " failed on file descriptor %d.", fd
);
131 void MainController::remove_poll_fd(int fd
)
135 event
.events
= EPOLLIN
;
137 if (epoll_ctl(epfd
, EPOLL_CTL_DEL
, fd
, &event
) < 0)
138 fatal_error("MainController::remove_poll_fd: system call epoll_ctl"
139 " failed on file descriptor %d.", fd
);
141 #else // ! defined USE_EPOLL
142 void MainController::add_poll_fd(int fd
)
145 if (pollfds_modified
) {
147 for (i
= new_nfds
- 1; i
>= 0; i
--) {
148 if (new_ufds
[i
].fd
< fd
) break;
149 else if (new_ufds
[i
].fd
== fd
) return;
152 new_ufds
= (struct pollfd
*)Realloc(new_ufds
, (new_nfds
+ 1) *
153 sizeof(struct pollfd
));
154 memmove(new_ufds
+ i
+ 1, new_ufds
+ i
, (new_nfds
- i
) *
155 sizeof(struct pollfd
));
157 new_ufds
[i
].events
= POLLIN
;
158 new_ufds
[i
].revents
= 0;
162 for (i
= nfds
- 1; i
>= 0; i
--) {
163 if (ufds
[i
].fd
< fd
) break;
164 else if (ufds
[i
].fd
== fd
) return;
168 new_ufds
= (struct pollfd
*)Malloc(new_nfds
* sizeof(struct pollfd
));
169 memcpy(new_ufds
, ufds
, i
* sizeof(struct pollfd
));
171 new_ufds
[i
].events
= POLLIN
;
172 new_ufds
[i
].revents
= 0;
173 memcpy(new_ufds
+ i
+ 1, ufds
+ i
, (nfds
- i
) * sizeof(struct pollfd
));
174 pollfds_modified
= TRUE
;
178 void MainController::remove_poll_fd(int fd
)
181 if (pollfds_modified
) {
183 for (i
= new_nfds
- 1; i
>= 0; i
--) {
184 if (new_ufds
[i
].fd
== fd
) break;
185 else if (new_ufds
[i
].fd
< fd
) return;
189 memmove(new_ufds
+ i
, new_ufds
+ i
+ 1, (new_nfds
- i
) *
190 sizeof(struct pollfd
));
191 new_ufds
= (struct pollfd
*)Realloc(new_ufds
, new_nfds
*
192 sizeof(struct pollfd
));
195 for (i
= nfds
- 1; i
>= 0; i
--) {
196 if (ufds
[i
].fd
== fd
) break;
197 else if (ufds
[i
].fd
< fd
) return;
201 new_ufds
= (struct pollfd
*)Malloc(new_nfds
* sizeof(struct pollfd
));
202 memcpy(new_ufds
, ufds
, i
* sizeof(struct pollfd
));
203 memcpy(new_ufds
+ i
, ufds
+ i
+ 1, (new_nfds
- i
) *
204 sizeof(struct pollfd
));
205 pollfds_modified
= TRUE
;
209 void MainController::update_pollfds()
211 if (pollfds_modified
) {
217 pollfds_modified
= FALSE
;
222 int MainController::fd_table_size
;
223 fd_table_struct
*MainController::fd_table
;
225 void MainController::add_fd_to_table(int fd
)
227 if (fd
>= fd_table_size
) {
228 fd_table
= (fd_table_struct
*)Realloc(fd_table
, (fd
+ 1) *
229 sizeof(fd_table_struct
));
230 for (int i
= fd_table_size
; i
<= fd
; i
++) {
231 fd_table
[i
].fd_type
= FD_UNUSED
;
232 fd_table
[i
].dummy_ptr
= NULL
;
234 fd_table_size
= fd
+ 1;
238 void MainController::remove_fd_from_table(int fd
)
240 if (fd
< fd_table_size
) {
241 fd_table
[fd
].fd_type
= FD_UNUSED
;
243 for (i
= fd_table_size
- 1; i
>= 0 ; i
--) {
244 if (fd_table
[i
].fd_type
!= FD_UNUSED
) break;
246 if (i
< fd_table_size
- 1) {
247 fd_table_size
= i
+ 1;
248 fd_table
= (fd_table_struct
*)Realloc(fd_table
, fd_table_size
*
249 sizeof(fd_table_struct
));
254 void MainController::set_close_on_exec(int fd
)
256 int flags
= fcntl(fd
, F_GETFD
);
257 if (flags
< 0) fatal_error("MainController::set_close_on_exec: system call "
258 "fcntl(F_GETFD) failed on file descriptor %d.", fd
);
262 if (fcntl(fd
, F_SETFD
, flags
) == -1)
263 fatal_error("MainController::set_close_on_exec: system call "
264 "fcntl(F_SETFD) failed on file descriptor %d.", fd
);
267 unknown_connection
*MainController::unknown_head
, *MainController::unknown_tail
;
269 unknown_connection
*MainController::new_unknown_connection(
272 unknown_connection
*conn
= new unknown_connection
;
273 conn
->unix_socket
= unix_socket
;
274 conn
->prev
= unknown_tail
;
276 if (unknown_tail
!= NULL
) unknown_tail
->next
= conn
;
277 else unknown_head
= conn
;
282 void MainController::delete_unknown_connection(unknown_connection
*conn
)
284 if (conn
->prev
!= NULL
) conn
->prev
->next
= conn
->next
;
285 else unknown_head
= conn
->next
;
286 if (conn
->next
!= NULL
) conn
->next
->prev
= conn
->prev
;
287 else unknown_tail
= conn
->prev
;
291 void MainController::close_unknown_connection(unknown_connection
*conn
)
293 remove_poll_fd(conn
->fd
);
295 remove_fd_from_table(conn
->fd
);
296 delete conn
->text_buf
;
297 delete_unknown_connection(conn
);
301 void MainController::init_string_set(string_set
*set
)
304 set
->elements
= NULL
;
307 void MainController::free_string_set(string_set
*set
)
309 for (int i
= 0; i
< set
->n_elements
; i
++) Free(set
->elements
[i
]);
312 set
->elements
= NULL
;
315 void MainController::add_string_to_set(string_set
*set
, const char *str
)
318 for (i
= 0; i
< set
->n_elements
; i
++) {
319 int result
= strcmp(set
->elements
[i
], str
);
320 if (result
> 0) break;
321 else if (result
== 0) return;
323 set
->elements
= (char**)Realloc(set
->elements
,
324 (set
->n_elements
+ 1) * sizeof(*set
->elements
));
325 memmove(set
->elements
+ i
+ 1, set
->elements
+ i
,
326 (set
->n_elements
- i
) * sizeof(*set
->elements
));
327 set
->elements
[i
] = mcopystr(str
);
331 void MainController::remove_string_from_set(string_set
*set
,
334 for (int i
= 0; i
< set
->n_elements
; i
++) {
335 int result
= strcmp(set
->elements
[i
], str
);
336 if (result
< 0) continue;
337 else if (result
== 0) {
338 Free(set
->elements
[i
]);
340 memmove(set
->elements
+ i
, set
->elements
+ i
+ 1,
341 (set
->n_elements
- i
) * sizeof(*set
->elements
));
342 set
->elements
= (char**)Realloc(set
->elements
,
343 set
->n_elements
* sizeof(*set
->elements
));
349 boolean
MainController::set_has_string(const string_set
*set
,
352 if(str
== NULL
) return FALSE
;
353 for (int i
= 0; i
< set
->n_elements
; i
++) {
354 int result
= strcmp(set
->elements
[i
], str
);
355 if (result
== 0) return TRUE
;
356 else if (result
> 0) break;
361 const char *MainController::get_string_from_set(const string_set
*set
,
364 if (index
>= 0 && index
< set
->n_elements
) return set
->elements
[index
];
368 int MainController::n_host_groups
;
369 host_group_struct
*MainController::host_groups
;
370 string_set
MainController::assigned_components
;
371 boolean
MainController::all_components_assigned
;
373 host_group_struct
*MainController::add_host_group(const char *group_name
)
376 for (i
= 0 ; i
< n_host_groups
; i
++) {
377 host_group_struct
*group
= host_groups
+ i
;
378 int result
= strcmp(group
->group_name
, group_name
);
379 if (result
> 0) break;
380 else if (result
== 0) return group
;
382 host_groups
= (host_group_struct
*)Realloc(host_groups
,
383 (n_host_groups
+ 1) * sizeof(*host_groups
));
384 host_group_struct
*new_group
= host_groups
+ i
;
385 memmove(new_group
+ 1, new_group
,
386 (n_host_groups
- i
) * sizeof(*host_groups
));
387 new_group
->group_name
= mcopystr(group_name
);
388 new_group
->has_all_hosts
= FALSE
;
389 new_group
->has_all_components
= FALSE
;
390 init_string_set(&new_group
->host_members
);
391 init_string_set(&new_group
->assigned_components
);
396 host_group_struct
*MainController::lookup_host_group(const char *group_name
)
398 for (int i
= 0; i
< n_host_groups
; i
++) {
399 host_group_struct
*group
= host_groups
+ i
;
400 int result
= strcmp(group
->group_name
, group_name
);
401 if (result
== 0) return group
;
402 else if (result
> 0) break;
407 boolean
MainController::is_similar_hostname(const char *host1
,
410 for (size_t i
= 0; ; i
++) {
411 unsigned char c1
= host1
[i
], c2
= host2
[i
];
413 // if host2 is the longer one it may contain an additional domain
414 // name with a leading dot (e.g. "foo" is similar to "foo.bar.com")
415 // note: empty string is similar with empty string only
416 if (c2
== '\0' || (i
> 0 && c2
== '.')) return TRUE
;
418 } else if (c2
== '\0') {
420 if (c1
== '\0' || (i
> 0 && c1
== '.')) return TRUE
;
423 // case insensitive comparison of the characters
424 if (tolower(c1
) != tolower(c2
)) return FALSE
;
425 // continue the evaluation if they are matching
430 boolean
MainController::host_has_name(const host_struct
*host
, const char *name
)
432 // name might resemble to host->hostname
433 if (is_similar_hostname(host
->hostname
, name
)) return TRUE
;
434 // to avoid returning true in situations when name is "foo.bar.com", but
435 // host->hostname is "foo.other.com" and host->hostname_local is "foo"
436 // name might resemble to host->hostname_local
437 if (host
->local_hostname_different
&&
438 is_similar_hostname(host
->hostname_local
, name
)) return TRUE
;
439 // name might be an IP address or a DNS alias
440 IPAddress
*ip_addr
= IPAddress::create_addr(nh
.get_family());
441 if (ip_addr
->set_addr(name
)) {
442 // check if IP addresses match
443 if (*ip_addr
== *(host
->ip_addr
)) {
447 // try to handle such strange situations when the local hostname is
448 // mapped to a loopback address by /etc/hosts
449 // (i.e. host->ip_addr contains 127.x.y.z)
450 // but the given name contains the real IP address of the host
451 const char *canonical_name
= ip_addr
->get_host_str();
452 if (is_similar_hostname(host
->hostname
, canonical_name
)) {
456 if (host
->local_hostname_different
&&
457 is_similar_hostname(host
->hostname_local
, canonical_name
)) {
466 boolean
MainController::member_of_group(const host_struct
*host
,
467 const host_group_struct
*group
)
469 if (group
->has_all_hosts
) return TRUE
;
470 for (int i
= 0; ; i
++) {
471 const char *member_name
= get_string_from_set(&group
->host_members
, i
);
472 if (member_name
!= NULL
) {
473 if (host_has_name(host
, member_name
)) return TRUE
;
475 // empty group: the group name is considered as a hostname
476 return host_has_name(host
, group
->group_name
);
485 void MainController::add_allowed_components(host_struct
*host
)
487 init_string_set(&host
->allowed_components
);
488 host
->all_components_allowed
= FALSE
;
489 for (int i
= 0; i
< n_host_groups
; i
++) {
490 host_group_struct
*group
= host_groups
+ i
;
491 if (!member_of_group(host
, group
)) continue;
492 for (int j
= 0; ; j
++) {
493 const char *component_id
=
494 get_string_from_set(&group
->assigned_components
, j
);
495 if (component_id
== NULL
) break;
496 add_string_to_set(&host
->allowed_components
, component_id
);
498 if (group
->has_all_components
) host
->all_components_allowed
= TRUE
;
502 host_struct
*MainController::choose_ptc_location(const char *component_type
,
503 const char *component_name
, const char *component_location
)
505 host_struct
*best_candidate
= NULL
;
506 int load_on_best_candidate
= 0;
507 boolean has_constraint
=
508 set_has_string(&assigned_components
, component_type
) ||
509 set_has_string(&assigned_components
, component_name
);
510 host_group_struct
*group
;
511 if (component_location
!= NULL
)
512 group
= lookup_host_group(component_location
);
514 for (int i
= 0; i
< n_hosts
; i
++) {
515 host_struct
*host
= hosts
[i
];
516 if (host
->hc_state
!= HC_ACTIVE
) continue;
517 if (best_candidate
!= NULL
&&
518 host
->n_active_components
>= load_on_best_candidate
) continue;
519 if (component_location
!= NULL
) {
520 // the explicit location has precedence over the constraints
522 if (!member_of_group(host
, group
)) continue;
524 if (!host_has_name(host
, component_location
)) continue;
526 } else if (has_constraint
) {
527 if (!set_has_string(&host
->allowed_components
, component_type
) &&
528 !set_has_string(&host
->allowed_components
, component_name
))
530 } else if (all_components_assigned
) {
531 if (!host
->all_components_allowed
) continue;
533 best_candidate
= host
;
534 load_on_best_candidate
= host
->n_active_components
;
536 return best_candidate
;
539 int MainController::n_hosts
;
540 host_struct
**MainController::hosts
;
542 host_struct
*MainController::add_new_host(unknown_connection
*conn
)
544 Text_Buf
*text_buf
= conn
->text_buf
;
547 host_struct
*new_host
= new host_struct
;
549 new_host
->ip_addr
= conn
->ip_addr
;
550 new_host
->hostname
= mcopystr(new_host
->ip_addr
->get_host_str());
551 new_host
->hostname_local
= text_buf
->pull_string();
552 new_host
->machine_type
= text_buf
->pull_string();
553 new_host
->system_name
= text_buf
->pull_string();
554 new_host
->system_release
= text_buf
->pull_string();
555 new_host
->system_version
= text_buf
->pull_string();
556 for (int i
= 0; i
< TRANSPORT_NUM
; i
++)
557 new_host
->transport_supported
[i
] = FALSE
;
558 int n_supported_transports
= text_buf
->pull_int().get_val();
559 for (int i
= 0; i
< n_supported_transports
; i
++) {
560 int transport_type
= text_buf
->pull_int().get_val();
561 if (transport_type
>= 0 && transport_type
< TRANSPORT_NUM
) {
562 if (new_host
->transport_supported
[transport_type
]) {
563 send_error(fd
, "Malformed VERSION message was received: "
564 "Transport type %s was specified more than once.",
565 get_transport_name((transport_type_enum
)transport_type
));
566 } else new_host
->transport_supported
[transport_type
] = TRUE
;
568 send_error(fd
, "Malformed VERSION message was received: "
569 "Transport type code %d is invalid.", transport_type
);
572 if (!new_host
->transport_supported
[TRANSPORT_LOCAL
]) {
573 send_error(fd
, "Malformed VERSION message was received: "
574 "Transport type %s must be supported anyway.",
575 get_transport_name(TRANSPORT_LOCAL
));
577 if (!new_host
->transport_supported
[TRANSPORT_INET_STREAM
]) {
578 send_error(fd
, "Malformed VERSION message was received: "
579 "Transport type %s must be supported anyway.",
580 get_transport_name(TRANSPORT_INET_STREAM
));
582 new_host
->log_source
= mprintf("HC@%s", new_host
->hostname_local
);
583 new_host
->hc_state
= HC_IDLE
;
584 new_host
->hc_fd
= fd
;
585 new_host
->text_buf
= text_buf
;
586 new_host
->n_components
= 0;
587 new_host
->components
= NULL
;
588 // in most cases hostname and hostname_local are similar ("foo.bar.com" vs.
589 // "foo") and it is enough to compare only the (fully qualified) hostname
590 // when evaluating PTC location constraints
591 new_host
->local_hostname_different
=
592 !is_similar_hostname(new_host
->hostname
, new_host
->hostname_local
);
593 add_allowed_components(new_host
);
594 new_host
->n_active_components
= 0;
596 text_buf
->cut_message();
598 delete_unknown_connection(conn
);
601 hosts
= (host_struct
**)Realloc(hosts
, n_hosts
* sizeof(*hosts
));
602 hosts
[n_hosts
- 1] = new_host
;
604 fd_table
[fd
].fd_type
= FD_HC
;
605 fd_table
[fd
].host_ptr
= new_host
;
607 notify("New HC connected from %s [%s]. %s: %s %s on %s.",
608 new_host
->hostname
, new_host
->ip_addr
->get_addr_str(),
609 new_host
->hostname_local
, new_host
->system_name
,
610 new_host
->system_release
, new_host
->machine_type
);
615 void MainController::close_hc_connection(host_struct
*hc
)
617 if (hc
->hc_state
!= HC_DOWN
) {
618 remove_poll_fd(hc
->hc_fd
);
620 remove_fd_from_table(hc
->hc_fd
);
624 hc
->hc_state
= HC_DOWN
;
629 boolean
MainController::is_hc_in_state(hc_state_enum checked_state
)
631 for (int i
= 0; i
< n_hosts
; i
++)
632 if (hosts
[i
]->hc_state
== checked_state
) return TRUE
;
636 boolean
MainController::all_hc_in_state(hc_state_enum checked_state
)
638 for (int i
= 0; i
< n_hosts
; i
++)
639 if (hosts
[i
]->hc_state
!= checked_state
) return FALSE
;
643 void MainController::configure_host(host_struct
*host
, boolean should_notify
)
645 if(config_str
== NULL
)
646 fatal_error("MainController::configure_host: no config file");
647 hc_state_enum next_state
= HC_CONFIGURING
;
648 switch(host
->hc_state
) {
650 case HC_CONFIGURING_OVERLOADED
:
652 fatal_error("MainController::configure_host:"
653 " host %s is in wrong state.",
659 next_state
= HC_CONFIGURING_OVERLOADED
;
662 host
->hc_state
= next_state
;
664 notify("Downloading configuration file to HC on host %s.",
667 send_configure(host
, config_str
);
671 void MainController::check_all_hc_configured()
673 if (is_hc_in_state(HC_CONFIGURING
) ||
674 is_hc_in_state(HC_CONFIGURING_OVERLOADED
)) return;
675 if (is_hc_in_state(HC_IDLE
)) {
676 error("There were errors during configuring HCs.");
677 mc_state
= MC_HC_CONNECTED
;
678 } else if (is_hc_in_state(HC_ACTIVE
) || is_hc_in_state(HC_OVERLOADED
)) {
679 notify("Configuration file was processed on all HCs.");
680 mc_state
= MC_ACTIVE
;
682 error("There is no HC connection after processing the configuration "
684 mc_state
= MC_LISTENING
;
688 void MainController::add_component_to_host(host_struct
*host
,
689 component_struct
*comp
)
691 if (comp
->comp_ref
== MTC_COMPREF
)
692 comp
->log_source
= mprintf("MTC@%s", host
->hostname_local
);
693 else if (comp
->comp_name
!= NULL
)
694 comp
->log_source
= mprintf("%s(%d)@%s", comp
->comp_name
,
695 comp
->comp_ref
, host
->hostname_local
);
696 else comp
->log_source
= mprintf("%d@%s", comp
->comp_ref
,
697 host
->hostname_local
);
698 comp
->comp_location
= host
;
700 for (i
= host
->n_components
; i
> 0; i
--) {
701 if (host
->components
[i
- 1] < comp
->comp_ref
) break;
702 else if (host
->components
[i
- 1] == comp
->comp_ref
) return;
704 host
->components
= (component
*)Realloc(host
->components
,
705 (host
->n_components
+ 1) * sizeof(component
));
706 memmove(host
->components
+ i
+ 1, host
->components
+ i
,
707 (host
->n_components
- i
) * sizeof(component
));
708 host
->components
[i
] = comp
->comp_ref
;
709 host
->n_components
++;
712 void MainController::remove_component_from_host(component_struct
*comp
)
714 Free(comp
->log_source
);
715 comp
->log_source
= NULL
;
716 host_struct
*host
= comp
->comp_location
;
718 component comp_ref
= comp
->comp_ref
;
720 for (i
= host
->n_components
- 1; i
>= 0; i
--) {
721 if (host
->components
[i
] == comp_ref
) break;
722 else if (host
->components
[i
] < comp_ref
) return;
725 host
->n_components
--;
726 memmove(host
->components
+ i
, host
->components
+ i
+ 1,
727 (host
->n_components
- i
) * sizeof(component
));
728 host
->components
= (component
*)Realloc(host
->components
,
729 host
->n_components
* sizeof(component
));
733 boolean
MainController::version_known
;
734 int MainController::n_modules
;
735 module_version_info
*MainController::modules
;
737 #ifdef TTCN3_BUILDNUMBER
738 #define TTCN3_BUILDNUMBER_SAFE TTCN3_BUILDNUMBER
740 #define TTCN3_BUILDNUMBER_SAFE 0
744 boolean
MainController::check_version(unknown_connection
*conn
)
746 Text_Buf
& text_buf
= *conn
->text_buf
;
747 int version_major
= text_buf
.pull_int().get_val();
748 int version_minor
= text_buf
.pull_int().get_val();
749 int version_patchlevel
= text_buf
.pull_int().get_val();
750 if (version_major
!= TTCN3_MAJOR
|| version_minor
!= TTCN3_MINOR
||
751 version_patchlevel
!= TTCN3_PATCHLEVEL
) {
752 send_error(conn
->fd
, "Version mismatch: The TTCN-3 Main Controller has "
753 "version " PRODUCT_NUMBER
", but the ETS was built with version "
754 "%d.%d.pl%d.", version_major
, version_minor
, version_patchlevel
);
757 int version_buildnumber
= text_buf
.pull_int().get_val();
758 if (version_buildnumber
!= TTCN3_BUILDNUMBER_SAFE
) {
759 if (version_buildnumber
> 0) send_error(conn
->fd
, "Build number "
760 "mismatch: The TTCN-3 Main Controller has version " PRODUCT_NUMBER
761 ", but the ETS was built with %d.%d.pre%d build %d.",
762 version_major
, version_minor
, version_patchlevel
,
763 version_buildnumber
);
764 else send_error(conn
->fd
, "Build number mismatch: The TTCN-3 Main "
765 "Controller has version " PRODUCT_NUMBER
", but the ETS was built "
766 "with %d.%d.pl%d.", version_major
, version_minor
,
771 int new_n_modules
= text_buf
.pull_int().get_val();
772 if (n_modules
!= new_n_modules
) {
773 send_error(conn
->fd
, "The number of modules in this ETS (%d) "
774 "differs from the number of modules in the firstly connected "
775 "ETS (%d).", new_n_modules
, n_modules
);
778 for (int i
= 0; i
< n_modules
; i
++) {
779 char *module_name
= text_buf
.pull_string();
780 if (strcmp(module_name
, modules
[i
].module_name
)) {
781 send_error(conn
->fd
, "The module number %d in this ETS (%s) "
782 "has different name than in the firstly connected ETS (%s).",
783 i
, module_name
, modules
[i
].module_name
);
784 delete [] module_name
;
787 boolean checksum_differs
= FALSE
;
788 int checksum_length
= text_buf
.pull_int().get_val();
789 unsigned char *module_checksum
;
790 if (checksum_length
!= 0) {
791 module_checksum
= new unsigned char[checksum_length
];
792 text_buf
.pull_raw(checksum_length
, module_checksum
);
793 } else module_checksum
= NULL
;
794 if (checksum_length
!= modules
[i
].checksum_length
||
795 memcmp(module_checksum
, modules
[i
].module_checksum
,
796 checksum_length
)) checksum_differs
= TRUE
;
797 delete [] module_checksum
;
798 if (checksum_differs
) {
799 send_error(conn
->fd
, "The checksum of module %s in this ETS "
800 "is different than that of the firstly connected ETS.",
803 delete [] module_name
;
804 if (checksum_differs
) return TRUE
;
807 n_modules
= text_buf
.pull_int().get_val();
808 modules
= new module_version_info
[n_modules
];
809 for (int i
= 0; i
< n_modules
; i
++) {
810 modules
[i
].module_name
= text_buf
.pull_string();
811 modules
[i
].checksum_length
= text_buf
.pull_int().get_val();
812 if (modules
[i
].checksum_length
> 0) {
813 modules
[i
].module_checksum
=
814 new unsigned char[modules
[i
].checksum_length
];
815 text_buf
.pull_raw(modules
[i
].checksum_length
,
816 modules
[i
].module_checksum
);
817 } else modules
[i
].module_checksum
= NULL
;
819 version_known
= TRUE
;
824 int MainController::n_components
, MainController::n_active_ptcs
,
825 MainController::max_ptcs
;
826 component_struct
**MainController::components
;
827 component_struct
*MainController::mtc
, *MainController::system
;
828 component
MainController::next_comp_ref
, MainController::tc_first_comp_ref
;
830 boolean
MainController::any_component_done_requested
,
831 MainController::any_component_done_sent
,
832 MainController::all_component_done_requested
,
833 MainController::any_component_killed_requested
,
834 MainController::all_component_killed_requested
;
836 void MainController::add_component(component_struct
*comp
)
838 component comp_ref
= comp
->comp_ref
;
839 if (lookup_component(comp_ref
) != NULL
)
840 fatal_error("MainController::add_component: duplicate "
841 "component reference %d.", comp_ref
);
842 if (n_components
<= comp_ref
) {
843 components
= (component_struct
**)Realloc(components
, (comp_ref
+ 1) *
844 sizeof(component_struct
*));
845 for (int i
= n_components
; i
< comp_ref
; i
++) components
[i
] = NULL
;
846 n_components
= comp_ref
+ 1;
848 components
[comp_ref
] = comp
;
851 component_struct
*MainController::lookup_component(component comp_ref
)
853 if (comp_ref
>= 0 && comp_ref
< n_components
) return components
[comp_ref
];
857 void MainController::destroy_all_components()
859 for (component i
= 0; i
< n_components
; i
++) {
860 component_struct
*comp
= components
[i
];
862 close_tc_connection(comp
);
863 remove_component_from_host(comp
);
864 free_qualified_name(&comp
->comp_type
);
865 delete [] comp
->comp_name
;
866 free_qualified_name(&comp
->tc_fn_name
);
867 delete [] comp
->return_type
;
868 Free(comp
->return_value
);
869 if (comp
->verdict_reason
!= NULL
) {
870 delete [] comp
->verdict_reason
;
871 comp
->verdict_reason
= NULL
;
873 switch (comp
->tc_state
) {
875 delete [] comp
->initial
.location_str
;
878 Free(comp
->starting
.arguments_ptr
);
879 free_requestors(&comp
->starting
.cancel_done_sent_to
);
882 case PTC_STOPPING_KILLING
:
884 free_requestors(&comp
->stopping_killing
.stop_requestors
);
885 free_requestors(&comp
->stopping_killing
.kill_requestors
);
889 free_requestors(&comp
->done_requestors
);
890 free_requestors(&comp
->killed_requestors
);
891 free_requestors(&comp
->cancel_done_sent_for
);
892 remove_all_connections(i
);
903 for (int i
= 0; i
< n_hosts
; i
++) hosts
[i
]->n_active_components
= 0;
905 next_comp_ref
= FIRST_PTC_COMPREF
;
907 any_component_done_requested
= FALSE
;
908 any_component_done_sent
= FALSE
;
909 all_component_done_requested
= FALSE
;
910 any_component_killed_requested
= FALSE
;
911 all_component_killed_requested
= FALSE
;
914 void MainController::close_tc_connection(component_struct
*comp
)
916 if (comp
->tc_fd
>= 0) {
917 remove_poll_fd(comp
->tc_fd
);
919 remove_fd_from_table(comp
->tc_fd
);
921 delete comp
->text_buf
;
922 comp
->text_buf
= NULL
;
925 if (comp
->kill_timer
!= NULL
) {
926 cancel_timer(comp
->kill_timer
);
927 comp
->kill_timer
= NULL
;
931 boolean
MainController::stop_after_tc
, MainController::stop_requested
;
933 boolean
MainController::ready_to_finish_testcase()
935 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
936 switch (components
[i
]->tc_state
) {
947 void MainController::finish_testcase()
949 if (stop_requested
) {
950 send_ptc_verdict(FALSE
);
952 mtc
->tc_state
= MTC_CONTROLPART
;
953 mtc
->stop_requested
= TRUE
;
954 start_kill_timer(mtc
);
955 mc_state
= MC_EXECUTING_CONTROL
;
956 } else if (stop_after_tc
) {
957 send_ptc_verdict(FALSE
);
958 mtc
->tc_state
= MTC_PAUSED
;
959 mc_state
= MC_PAUSED
;
960 notify("Execution has been paused.");
962 send_ptc_verdict(TRUE
);
963 mtc
->tc_state
= MTC_CONTROLPART
;
964 mc_state
= MC_EXECUTING_CONTROL
;
967 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
968 components
[i
]->tc_state
= PTC_STALE
;
970 mtc
->local_verdict
= NONE
;
971 free_qualified_name(&mtc
->comp_type
);
972 free_qualified_name(&mtc
->tc_fn_name
);
973 free_qualified_name(&system
->comp_type
);
976 boolean
MainController::message_expected(component_struct
*from
,
977 const char *message_name
)
980 case MC_EXECUTING_TESTCASE
:
981 switch (mtc
->tc_state
) {
982 case MTC_ALL_COMPONENT_STOP
:
983 case MTC_ALL_COMPONENT_KILL
:
989 case MC_TERMINATING_TESTCASE
:
993 send_error(from
->tc_fd
, "Unexpected message %s was received.",
999 boolean
MainController::request_allowed(component_struct
*from
,
1000 const char *message_name
)
1002 if (!message_expected(from
, message_name
)) return FALSE
;
1004 switch (from
->tc_state
) {
1006 if (from
== mtc
) return TRUE
;
1009 if (from
!= mtc
) return TRUE
;
1012 case PTC_STOPPING_KILLING
:
1019 send_error(from
->tc_fd
, "The sender of message %s is in "
1020 "unexpected state.", message_name
);
1024 boolean
MainController::valid_endpoint(component component_reference
,
1025 boolean new_connection
, component_struct
*requestor
, const char *operation
)
1027 switch (component_reference
) {
1029 send_error(requestor
->tc_fd
, "The %s operation refers to the null "
1030 "component reference.", operation
);
1032 case SYSTEM_COMPREF
:
1033 send_error(requestor
->tc_fd
, "The %s operation refers to the system "
1034 "component reference.", operation
);
1037 send_error(requestor
->tc_fd
, "The %s operation refers to "
1038 "'any component'.", operation
);
1041 send_error(requestor
->tc_fd
, "The %s operation refers to "
1042 "'all component'.", operation
);
1047 component_struct
*comp
= lookup_component(component_reference
);
1049 send_error(requestor
->tc_fd
, "The %s operation refers to "
1050 "invalid component reference %d.", operation
,
1051 component_reference
);
1054 switch (comp
->tc_state
) {
1071 case PTC_STOPPING_KILLING
:
1072 if (new_connection
) {
1073 send_error(requestor
->tc_fd
, "The %s operation refers to test "
1074 "component with component reference %d, which is currently "
1075 "being terminated.", operation
, component_reference
);
1080 if (new_connection
) {
1081 send_error(requestor
->tc_fd
, "The %s operation refers to test "
1082 "component with component reference %d, which has already "
1083 "terminated.", operation
, component_reference
);
1087 send_error(requestor
->tc_fd
, "The %s operation refers to component "
1088 "reference %d, which belongs to an earlier test case.",
1089 operation
, component_reference
);
1092 send_error(requestor
->tc_fd
, "The %s operation refers to component "
1093 "reference %d, which is in invalid state.",
1094 operation
, component_reference
);
1095 error("Test component with component reference %d is in invalid state "
1096 "when a %s operation was requested on a port of it.",
1097 component_reference
, operation
);
1102 void MainController::destroy_connection(port_connection
*conn
,
1103 component_struct
*tc
)
1105 switch (conn
->conn_state
) {
1106 case CONN_LISTENING
:
1107 case CONN_CONNECTING
:
1108 if (conn
->transport_type
!= TRANSPORT_LOCAL
&&
1109 conn
->head
.comp_ref
!= tc
->comp_ref
) {
1110 // shut down the server side if the client has terminated
1111 send_disconnect_to_server(conn
);
1113 send_error_to_connect_requestors(conn
, "test component %d has "
1114 "terminated during connection setup.", tc
->comp_ref
);
1116 case CONN_CONNECTED
:
1118 case CONN_DISCONNECTING
:
1119 send_disconnect_ack_to_requestors(conn
);
1122 error("The port connection %d:%s - %d:%s is in invalid state when "
1123 "test component %d has terminated.", conn
->head
.comp_ref
,
1124 conn
->head
.port_name
, conn
->tail
.comp_ref
, conn
->tail
.port_name
,
1127 remove_connection(conn
);
1130 void MainController::destroy_mapping(port_connection
*conn
)
1132 component tc_compref
;
1133 const char *tc_port
, *system_port
;
1134 if (conn
->head
.comp_ref
== SYSTEM_COMPREF
) {
1135 tc_compref
= conn
->tail
.comp_ref
;
1136 tc_port
= conn
->tail
.port_name
;
1137 system_port
= conn
->head
.port_name
;
1139 tc_compref
= conn
->head
.comp_ref
;
1140 tc_port
= conn
->head
.port_name
;
1141 system_port
= conn
->tail
.port_name
;
1143 switch (conn
->conn_state
) {
1144 case CONN_UNMAPPING
:
1145 for (int i
= 0; ; i
++) {
1146 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
1147 if (comp
== NULL
) break;
1148 if (comp
->tc_state
== TC_UNMAP
) {
1149 send_unmap_ack(comp
);
1150 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
1151 else comp
->tc_state
= PTC_FUNCTION
;
1156 for (int i
= 0; ; i
++) {
1157 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
1158 if (comp
== NULL
) break;
1159 if (comp
->tc_state
== TC_MAP
) {
1160 send_error(comp
->tc_fd
, "Establishment of port mapping "
1161 "%d:%s - system:%s failed because the test component "
1162 "endpoint has terminated.", tc_compref
, tc_port
,
1164 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
1165 else comp
->tc_state
= PTC_FUNCTION
;
1171 remove_connection(conn
);
1174 boolean
MainController::stop_all_components()
1176 boolean ready_for_ack
= TRUE
;
1177 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1178 component_struct
*tc
= components
[i
];
1179 switch (tc
->tc_state
) {
1181 // we do not have to termiate the PTC (and wait for the control
1182 // connection) if it is alive
1183 if (!tc
->is_alive
) ready_for_ack
= FALSE
;
1186 // do nothing if the component is alive
1187 if (!tc
->is_alive
) {
1189 tc
->tc_state
= PTC_KILLING
;
1190 tc
->stop_requested
= TRUE
;
1191 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1192 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1193 start_kill_timer(tc
);
1194 ready_for_ack
= FALSE
;
1206 // the PTC is executing behaviour
1209 tc
->tc_state
= TC_STOPPING
;
1211 // STOP is never sent to non-alive PTCs
1213 tc
->tc_state
= PTC_STOPPING_KILLING
;
1215 tc
->stop_requested
= TRUE
;
1216 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1217 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1218 start_kill_timer(tc
);
1219 ready_for_ack
= FALSE
;
1222 // do nothing, just put it back to STOPPED state
1223 free_qualified_name(&tc
->tc_fn_name
);
1224 Free(tc
->starting
.arguments_ptr
);
1225 free_requestors(&tc
->starting
.cancel_done_sent_to
);
1226 tc
->tc_state
= PTC_STOPPED
;
1229 case PTC_STOPPING_KILLING
:
1230 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1231 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1232 ready_for_ack
= FALSE
;
1235 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1236 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1237 // we have to wait only if the PTC is non-alive
1238 if (!tc
->is_alive
) ready_for_ack
= FALSE
;
1246 error("Test Component %d is in invalid state when stopping all "
1247 "components.", tc
->comp_ref
);
1249 // only mtc is preserved in done_requestors and killed_requestors
1250 boolean mtc_requested_done
= has_requestor(&tc
->done_requestors
, mtc
);
1251 free_requestors(&tc
->done_requestors
);
1252 if (mtc_requested_done
) add_requestor(&tc
->done_requestors
, mtc
);
1253 boolean mtc_requested_killed
= has_requestor(&tc
->killed_requestors
,
1255 free_requestors(&tc
->killed_requestors
);
1256 if (mtc_requested_killed
) add_requestor(&tc
->killed_requestors
, mtc
);
1257 free_requestors(&tc
->cancel_done_sent_for
);
1259 return ready_for_ack
;
1263 void MainController::check_all_component_stop()
1265 // MTC has requested 'all component.stop'
1266 // we have to send acknowledgement to MTC only
1267 boolean ready_for_ack
= TRUE
;
1268 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1269 component_struct
*comp
= components
[i
];
1270 switch (comp
->tc_state
) {
1273 if (!comp
->is_alive
) ready_for_ack
= FALSE
;
1276 case PTC_STOPPING_KILLING
:
1277 ready_for_ack
= FALSE
;
1285 // only alive components can be in idle state
1286 if (comp
->is_alive
) break;
1288 error("PTC %d is in invalid state when performing "
1289 "'all component.stop' operation.", comp
->comp_ref
);
1291 if (!ready_for_ack
) break;
1293 if (ready_for_ack
) {
1295 mtc
->tc_state
= MTC_TESTCASE
;
1299 void MainController::send_stop_ack_to_requestors(component_struct
*tc
)
1301 for (int i
= 0; ; i
++) {
1302 component_struct
*requestor
=
1303 get_requestor(&tc
->stopping_killing
.stop_requestors
, i
);
1304 if (requestor
== NULL
) break;
1305 if (requestor
->tc_state
== TC_STOP
) {
1306 send_stop_ack(requestor
);
1307 if (requestor
== mtc
) requestor
->tc_state
= MTC_TESTCASE
;
1308 else requestor
->tc_state
= PTC_FUNCTION
;
1311 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1314 boolean
MainController::kill_all_components(boolean testcase_ends
)
1316 boolean ready_for_ack
= TRUE
;
1317 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1318 component_struct
*tc
= components
[i
];
1319 boolean is_inactive
= FALSE
;
1320 switch (tc
->tc_state
) {
1322 // the PTC does not have an identified control connection yet
1323 ready_for_ack
= FALSE
;
1326 free_qualified_name(&tc
->tc_fn_name
);
1327 Free(tc
->starting
.arguments_ptr
);
1328 free_requestors(&tc
->starting
.cancel_done_sent_to
);
1345 // the PTC was inactive
1346 tc
->tc_state
= PTC_KILLING
;
1347 if (!tc
->is_alive
) tc
->stop_requested
= TRUE
;
1349 // the PTC was active
1350 tc
->tc_state
= PTC_STOPPING_KILLING
;
1351 tc
->stop_requested
= TRUE
;
1353 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1354 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1355 start_kill_timer(tc
);
1356 ready_for_ack
= FALSE
;
1360 tc
->tc_state
= PTC_STOPPING_KILLING
;
1361 if (tc
->kill_timer
!= NULL
) cancel_timer(tc
->kill_timer
);
1362 start_kill_timer(tc
);
1365 case PTC_STOPPING_KILLING
:
1366 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1367 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1368 ready_for_ack
= FALSE
;
1371 if (testcase_ends
) ready_for_ack
= FALSE
;
1376 error("Test Component %d is in invalid state when killing all "
1377 "components.", tc
->comp_ref
);
1379 if (testcase_ends
) {
1380 free_requestors(&tc
->done_requestors
);
1381 free_requestors(&tc
->killed_requestors
);
1383 // only mtc is preserved in done_requestors and killed_requestors
1384 boolean mtc_requested_done
= has_requestor(&tc
->done_requestors
,
1386 free_requestors(&tc
->done_requestors
);
1387 if (mtc_requested_done
) add_requestor(&tc
->done_requestors
, mtc
);
1388 boolean mtc_requested_killed
= has_requestor(&tc
->killed_requestors
,
1390 free_requestors(&tc
->killed_requestors
);
1391 if (mtc_requested_killed
)
1392 add_requestor(&tc
->killed_requestors
, mtc
);
1394 free_requestors(&tc
->cancel_done_sent_for
);
1396 return ready_for_ack
;
1399 void MainController::check_all_component_kill()
1401 // MTC has requested 'all component.kill'
1402 // we have to send acknowledgement to MTC only
1403 boolean ready_for_ack
= TRUE
;
1404 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1405 component_struct
*comp
= components
[i
];
1406 switch (comp
->tc_state
) {
1408 case PTC_STOPPING_KILLING
:
1410 ready_for_ack
= FALSE
;
1416 error("PTC %d is in invalid state when performing "
1417 "'all component.kill' operation.", comp
->comp_ref
);
1419 if (!ready_for_ack
) break;
1421 if (ready_for_ack
) {
1423 mtc
->tc_state
= MTC_TESTCASE
;
1427 void MainController::send_kill_ack_to_requestors(component_struct
*tc
)
1429 for (int i
= 0; ; i
++) {
1430 component_struct
*requestor
=
1431 get_requestor(&tc
->stopping_killing
.kill_requestors
, i
);
1432 if (requestor
== NULL
) break;
1433 if (requestor
->tc_state
== TC_KILL
) {
1434 send_kill_ack(requestor
);
1435 if (requestor
== mtc
) requestor
->tc_state
= MTC_TESTCASE
;
1436 else requestor
->tc_state
= PTC_FUNCTION
;
1439 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1442 void MainController::send_component_status_to_requestor(component_struct
*tc
,
1443 component_struct
*requestor
, boolean done_status
, boolean killed_status
)
1445 switch (requestor
->tc_state
) {
1459 send_component_status_ptc(requestor
, tc
->comp_ref
, TRUE
,
1460 killed_status
, tc
->return_type
, tc
->return_value_len
,
1463 send_component_status_ptc(requestor
, tc
->comp_ref
, FALSE
,
1464 killed_status
, NULL
, 0, NULL
);
1467 case PTC_STOPPING_KILLING
:
1471 // the PTC requestor is not interested in the component status anymore
1474 error("PTC %d is in invalid state when sending out COMPONENT_STATUS "
1475 "message about PTC %d.", requestor
->comp_ref
, tc
->comp_ref
);
1479 void MainController::component_stopped(component_struct
*tc
)
1481 // checking and updating the state of tc
1482 tc_state_enum old_state
= tc
->tc_state
;
1483 if (old_state
== PTC_STOPPING_KILLING
) tc
->tc_state
= PTC_KILLING
;
1485 tc
->tc_state
= PTC_STOPPED
;
1486 if (tc
->kill_timer
!= NULL
) {
1487 cancel_timer(tc
->kill_timer
);
1488 tc
->kill_timer
= NULL
;
1492 case MC_EXECUTING_TESTCASE
:
1493 // this is the correct state
1495 case MC_TERMINATING_TESTCASE
:
1496 // do nothing, we are waiting for the end of all PTC connections
1499 error("PTC %d stopped in invalid MC state.", tc
->comp_ref
);
1502 if (!tc
->is_alive
) {
1503 send_error_str(tc
->tc_fd
, "Message STOPPED can only be sent by "
1507 // Note: the COMPONENT_STATUS message must be sent before STOP_ACK because
1508 // the latter may update the component status cache table to an inconsistent
1510 boolean send_status_to_mtc
= FALSE
, send_done_to_mtc
= FALSE
;
1511 // sending out COMPONENT_STATUS messages to PTCs
1512 for (int i
= 0; ; i
++) {
1513 component_struct
*requestor
= get_requestor(&tc
->done_requestors
, i
);
1514 if (requestor
== NULL
) break;
1515 else if (requestor
== mtc
) {
1516 send_status_to_mtc
= TRUE
;
1517 send_done_to_mtc
= TRUE
;
1518 } else send_component_status_to_requestor(tc
, requestor
, TRUE
, FALSE
);
1520 // do not send unsolicited 'any component.done' status
1521 if (any_component_done_requested
) send_status_to_mtc
= TRUE
;
1522 boolean all_done_checked
= FALSE
, all_done_result
= FALSE
;
1523 if (all_component_done_requested
) {
1524 all_done_checked
= TRUE
;
1525 all_done_result
= !is_any_component_running();
1526 if (all_done_result
) send_status_to_mtc
= TRUE
;
1528 if (send_status_to_mtc
) {
1529 if (!all_done_checked
) all_done_result
= !is_any_component_running();
1530 if (send_done_to_mtc
) {
1531 // the return value was requested
1532 send_component_status_mtc(tc
->comp_ref
, TRUE
, FALSE
,
1533 any_component_done_requested
, all_done_result
, FALSE
, FALSE
,
1534 tc
->return_type
, tc
->return_value_len
, tc
->return_value
);
1536 // the return value was not requested
1537 send_component_status_mtc(NULL_COMPREF
, FALSE
, FALSE
,
1538 any_component_done_requested
, all_done_result
, FALSE
, FALSE
,
1541 if (any_component_done_requested
) {
1542 any_component_done_requested
= FALSE
;
1543 any_component_done_sent
= TRUE
;
1545 if (all_done_result
) all_component_done_requested
= FALSE
;
1547 // sending out STOP_ACK messages
1548 if (old_state
!= PTC_FUNCTION
) {
1549 // the PTC was explicitly stopped and/or killed
1550 if (mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
) {
1552 } else if (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
) {
1553 check_all_component_stop();
1555 send_stop_ack_to_requestors(tc
);
1560 void MainController::component_terminated(component_struct
*tc
)
1562 // the state variable of the PTC has to be updated first
1563 // because in case of 'all component.kill' or 'all component.stop'
1564 // we are walking through the states of all PTCs
1565 tc_state_enum old_state
= tc
->tc_state
;
1566 tc
->tc_state
= TC_EXITING
;
1568 tc
->comp_location
->n_active_components
--;
1570 case MC_EXECUTING_TESTCASE
:
1571 // this is the correct state
1573 case MC_TERMINATING_TESTCASE
:
1574 // do nothing, we are waiting for the end of all PTC connections
1577 error("PTC %d terminated in invalid MC state.", tc
->comp_ref
);
1580 // sending out COMPONENT_STATUS messages
1582 // - the COMPONENT_STATUS message must be sent before STOP_ACK and KILL_ACK
1583 // because the latter may update the component status cache table to an
1584 // inconsistent state
1585 // - unsolicited 'done' status and return value is never sent out
1586 // the flags below indicate whether a COMPONENT_STATUS message
1587 // (with or without the return value) has to be sent to the MTC
1588 boolean send_status_to_mtc
= FALSE
, send_done_to_mtc
= TRUE
;
1589 // first send out the COMPONENT_STATUS messages to PTCs
1590 for (int i
= 0; ; i
++) {
1591 component_struct
*requestor
= get_requestor(&tc
->done_requestors
, i
);
1592 if (requestor
== NULL
) break;
1593 else if (requestor
== mtc
) {
1594 send_status_to_mtc
= TRUE
;
1595 send_done_to_mtc
= TRUE
;
1596 } else send_component_status_to_requestor(tc
, requestor
, TRUE
, TRUE
);
1598 for (int i
= 0; ; i
++) {
1599 component_struct
*requestor
= get_requestor(&tc
->killed_requestors
, i
);
1600 if (requestor
== NULL
) break;
1601 else if (requestor
== mtc
) send_status_to_mtc
= TRUE
;
1602 else if (!has_requestor(&tc
->done_requestors
, requestor
)) {
1603 // do not send COMPONENT_STATUS twice to the same PTC
1604 send_component_status_to_requestor(tc
, requestor
, FALSE
, TRUE
);
1607 free_requestors(&tc
->done_requestors
);
1608 free_requestors(&tc
->killed_requestors
);
1609 // deciding whether to send a COMPONENT_STATUS message to MTC
1610 // 'any component.done' status can be safely sent out
1611 // it will not be cancelled later
1612 if (any_component_done_requested
|| any_component_killed_requested
)
1613 send_status_to_mtc
= TRUE
;
1614 boolean all_done_checked
= FALSE
, all_done_result
= FALSE
;
1615 if (all_component_done_requested
) {
1616 all_done_checked
= TRUE
;
1617 all_done_result
= !is_any_component_running();
1618 if (all_done_result
) send_status_to_mtc
= TRUE
;
1620 boolean all_killed_checked
= FALSE
, all_killed_result
= FALSE
;
1621 if (all_component_killed_requested
) {
1622 all_killed_checked
= TRUE
;
1623 all_killed_result
= !is_any_component_alive();
1624 if (all_killed_result
) send_status_to_mtc
= TRUE
;
1626 // sending the COMPONENT_STATUS message to MTC if necessary
1627 if (send_status_to_mtc
) {
1628 if (!all_done_checked
) all_done_result
= !is_any_component_running();
1629 if (!all_killed_checked
) all_killed_result
= !is_any_component_alive();
1630 if (send_done_to_mtc
) {
1631 // the return value was requested
1632 send_component_status_mtc(tc
->comp_ref
, TRUE
, TRUE
, TRUE
,
1633 all_done_result
, TRUE
, all_killed_result
, tc
->return_type
,
1634 tc
->return_value_len
, tc
->return_value
);
1636 // the return value was not requested
1637 send_component_status_mtc(tc
->comp_ref
, FALSE
, TRUE
, TRUE
,
1638 all_done_result
, TRUE
, all_killed_result
, NULL
, 0, NULL
);
1640 any_component_done_requested
= FALSE
;
1641 any_component_done_sent
= TRUE
;
1642 any_component_killed_requested
= FALSE
;
1643 if (all_done_result
) all_component_done_requested
= FALSE
;
1644 if (all_killed_result
) all_component_killed_requested
= FALSE
;
1646 // sending out STOP_ACK and KILL_ACK messages if necessary
1647 switch (old_state
) {
1649 case PTC_STOPPING_KILLING
:
1651 // the component was explicitly stopped and/or killed
1652 if (mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
) {
1653 check_all_component_kill();
1654 } else if (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
) {
1655 check_all_component_stop();
1657 send_stop_ack_to_requestors(tc
);
1658 send_kill_ack_to_requestors(tc
);
1663 // we should behave as we got all pending CANCEL_DONE_ACK messages from tc
1664 for (int i
= 0; ; i
++) {
1665 component_struct
*comp
= get_requestor(&tc
->cancel_done_sent_for
, i
);
1666 if (comp
== NULL
) break;
1667 done_cancelled(tc
, comp
);
1669 free_requestors(&tc
->cancel_done_sent_for
);
1670 // destroy all connections and mappings of the component
1671 // and send out the related messages
1672 while (tc
->conn_head_list
!= NULL
) {
1673 if (tc
->conn_head_list
->tail
.comp_ref
== SYSTEM_COMPREF
)
1674 destroy_mapping(tc
->conn_head_list
);
1675 else destroy_connection(tc
->conn_head_list
, tc
);
1677 while (tc
->conn_tail_list
!= NULL
) {
1678 if (tc
->conn_tail_list
->head
.comp_ref
== SYSTEM_COMPREF
)
1679 destroy_mapping(tc
->conn_tail_list
);
1680 else destroy_connection(tc
->conn_tail_list
, tc
);
1682 // drop the name of the currently executed function
1683 free_qualified_name(&tc
->tc_fn_name
);
1686 void MainController::done_cancelled(component_struct
*from
,
1687 component_struct
*started_tc
)
1689 // do nothing if the PTC to be started is not in starting state anymore
1690 if (started_tc
->tc_state
!= PTC_STARTING
) return;
1691 remove_requestor(&started_tc
->starting
.cancel_done_sent_to
, from
);
1692 // do nothing if we are waiting for more CANCEL_DONE_ACK messages
1693 if (get_requestor(&started_tc
->starting
.cancel_done_sent_to
, 0) != NULL
)
1695 send_start(started_tc
, started_tc
->tc_fn_name
,
1696 started_tc
->starting
.arguments_len
, started_tc
->starting
.arguments_ptr
);
1697 component_struct
*start_requestor
= started_tc
->starting
.start_requestor
;
1698 if (start_requestor
->tc_state
== TC_START
) {
1699 send_start_ack(start_requestor
);
1700 if (start_requestor
== mtc
) start_requestor
->tc_state
= MTC_TESTCASE
;
1701 else start_requestor
->tc_state
= PTC_FUNCTION
;
1703 Free(started_tc
->starting
.arguments_ptr
);
1704 free_requestors(&started_tc
->starting
.cancel_done_sent_to
);
1705 started_tc
->tc_state
= PTC_FUNCTION
;
1709 boolean
MainController::component_is_alive(component_struct
*tc
)
1711 switch (tc
->tc_state
) {
1727 case PTC_STOPPING_KILLING
:
1733 error("PTC %d is in invalid state when checking whether it is alive.",
1739 boolean
MainController::component_is_running(component_struct
*tc
)
1741 switch (tc
->tc_state
) {
1753 case PTC_STOPPING_KILLING
:
1763 error("PTC %d is in invalid state when checking whether it is running.",
1769 boolean
MainController::component_is_done(component_struct
*tc
)
1771 switch (tc
->tc_state
) {
1790 case PTC_STOPPING_KILLING
:
1793 error("PTC %d is in invalid state when checking whether it is done.",
1799 boolean
MainController::is_any_component_alive()
1801 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1802 if (component_is_alive(components
[i
])) return TRUE
;
1806 boolean
MainController::is_all_component_alive()
1808 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1809 if (!component_is_alive(components
[i
])) return FALSE
;
1813 boolean
MainController::is_any_component_running()
1815 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1816 if (component_is_running(components
[i
])) return TRUE
;
1820 boolean
MainController::is_all_component_running()
1822 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1823 component_struct
*tc
= components
[i
];
1824 if (tc
->stop_requested
) continue;
1825 switch (tc
->tc_state
) {
1837 boolean
MainController::is_any_component_done()
1839 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1840 if (component_is_done(components
[i
])) return TRUE
;
1844 void MainController::start_kill_timer(component_struct
*tc
)
1846 if (kill_timer
> 0.0) {
1847 timer_struct
*timer
= new timer_struct
;
1848 timer
->expiration
= time_now() + kill_timer
;
1849 timer
->timer_argument
.component_ptr
= tc
;
1850 tc
->kill_timer
= timer
;
1851 register_timer(timer
);
1852 } else tc
->kill_timer
= NULL
;
1855 void MainController::init_connections(component_struct
*tc
)
1857 tc
->conn_head_list
= NULL
;
1858 tc
->conn_tail_list
= NULL
;
1859 tc
->conn_head_count
= 0;
1860 tc
->conn_tail_count
= 0;
1863 void MainController::add_connection(port_connection
*c
)
1865 // Canonical ordering of endpoints so that head <= tail
1866 if (c
->head
.comp_ref
> c
->tail
.comp_ref
) {
1867 component tmp_comp
= c
->head
.comp_ref
;
1868 c
->head
.comp_ref
= c
->tail
.comp_ref
;
1869 c
->tail
.comp_ref
= tmp_comp
;
1870 char *tmp_port
= c
->head
.port_name
;
1871 c
->head
.port_name
= c
->tail
.port_name
;
1872 c
->tail
.port_name
= tmp_port
;
1873 } else if (c
->head
.comp_ref
== c
->tail
.comp_ref
&&
1874 strcmp(c
->head
.port_name
, c
->tail
.port_name
) > 0) {
1875 char *tmp_port
= c
->head
.port_name
;
1876 c
->head
.port_name
= c
->tail
.port_name
;
1877 c
->tail
.port_name
= tmp_port
;
1879 // Double-chain in according to c->head
1880 component_struct
*head_component
= lookup_component(c
->head
.comp_ref
);
1881 port_connection
*head_connection
= head_component
->conn_head_list
;
1882 if (head_connection
== NULL
) {
1886 c
->head
.prev
= head_connection
->head
.prev
;
1887 head_connection
->head
.prev
= c
;
1888 c
->head
.next
= head_connection
;
1889 c
->head
.prev
->head
.next
= c
;
1891 head_component
->conn_head_list
= c
;
1892 head_component
->conn_head_count
++;
1893 // Double-chain in according to c->tail
1894 component_struct
*tail_component
= lookup_component(c
->tail
.comp_ref
);
1895 port_connection
*tail_connection
= tail_component
->conn_tail_list
;
1896 if (tail_connection
== NULL
) {
1900 c
->tail
.prev
= tail_connection
->tail
.prev
;
1901 tail_connection
->tail
.prev
= c
;
1902 c
->tail
.next
= tail_connection
;
1903 c
->tail
.prev
->tail
.next
= c
;
1905 tail_component
->conn_tail_list
= c
;
1906 tail_component
->conn_tail_count
++;
1909 void MainController::remove_connection(port_connection
*c
)
1911 // Remove from conn_head_list
1912 component_struct
*head_component
= lookup_component(c
->head
.comp_ref
);
1913 if (c
->head
.next
== c
) {
1914 head_component
->conn_head_list
= NULL
;
1915 head_component
->conn_head_count
= 0;
1917 c
->head
.prev
->head
.next
= c
->head
.next
;
1918 c
->head
.next
->head
.prev
= c
->head
.prev
;
1919 head_component
->conn_head_list
= c
->head
.next
;
1920 head_component
->conn_head_count
--;
1922 // Remove from conn_tail_list
1923 component_struct
*tail_component
= lookup_component(c
->tail
.comp_ref
);
1924 if (c
->tail
.next
== c
) {
1925 tail_component
->conn_tail_list
= NULL
;
1926 tail_component
->conn_tail_count
= 0;
1928 c
->tail
.prev
->tail
.next
= c
->tail
.next
;
1929 c
->tail
.next
->tail
.prev
= c
->tail
.prev
;
1930 tail_component
->conn_tail_list
= c
->tail
.next
;
1931 tail_component
->conn_tail_count
--;
1933 // Delete the data members
1934 delete [] c
->head
.port_name
;
1935 delete [] c
->tail
.port_name
;
1936 free_requestors(&c
->requestors
);
1940 port_connection
*MainController::find_connection(component head_comp
,
1941 const char *head_port
, component tail_comp
, const char *tail_port
)
1943 // Canonical ordering of parameters so that head <= tail
1944 if (head_comp
> tail_comp
) {
1945 component tmp_comp
= head_comp
;
1946 head_comp
= tail_comp
;
1947 tail_comp
= tmp_comp
;
1948 const char *tmp_port
= head_port
;
1949 head_port
= tail_port
;
1950 tail_port
= tmp_port
;
1951 } else if (head_comp
== tail_comp
&& strcmp(head_port
, tail_port
) > 0) {
1952 const char *tmp_port
= head_port
;
1953 head_port
= tail_port
;
1954 tail_port
= tmp_port
;
1956 // Check whether one of the endpoints' list is empty
1957 component_struct
*head_component
= lookup_component(head_comp
);
1958 port_connection
*head_connection
= head_component
->conn_head_list
;
1959 if (head_connection
== NULL
) return NULL
;
1960 component_struct
*tail_component
= lookup_component(tail_comp
);
1961 port_connection
*tail_connection
= tail_component
->conn_tail_list
;
1962 if (tail_connection
== NULL
) return NULL
;
1963 // Start searching on the shorter list
1964 if (head_component
->conn_head_count
<= tail_component
->conn_tail_count
) {
1965 port_connection
*iter
= head_connection
;
1967 if (iter
->tail
.comp_ref
== tail_comp
&&
1968 !strcmp(iter
->head
.port_name
, head_port
) &&
1969 !strcmp(iter
->tail
.port_name
, tail_port
)) return iter
;
1970 iter
= iter
->head
.next
;
1971 } while (iter
!= head_connection
);
1974 port_connection
*iter
= tail_connection
;
1976 if (iter
->head
.comp_ref
== head_comp
&&
1977 !strcmp(iter
->head
.port_name
, head_port
) &&
1978 !strcmp(iter
->tail
.port_name
, tail_port
)) return iter
;
1979 iter
= iter
->tail
.next
;
1980 } while (iter
!= tail_connection
);
1985 void MainController::remove_all_connections(component head_or_tail
)
1987 component_struct
*comp
= lookup_component(head_or_tail
);
1988 while (comp
->conn_head_list
!= NULL
)
1989 remove_connection(comp
->conn_head_list
);
1990 while (comp
->conn_tail_list
!= NULL
)
1991 remove_connection(comp
->conn_tail_list
);
1994 transport_type_enum
MainController::choose_port_connection_transport(
1995 component head_comp
, component tail_comp
)
1997 host_struct
*head_location
= components
[head_comp
]->comp_location
;
1998 // use the most efficient software loop if the two endpoints are in the
1999 // same component and the host supports it
2000 if (head_comp
== tail_comp
&&
2001 head_location
->transport_supported
[TRANSPORT_LOCAL
])
2002 return TRANSPORT_LOCAL
;
2003 host_struct
*tail_location
= components
[tail_comp
]->comp_location
;
2004 // use the efficient UNIX domain socket if the two endpoints are on the
2005 // same host and it is supported by the host
2006 if (head_location
== tail_location
&&
2007 head_location
->transport_supported
[TRANSPORT_UNIX_STREAM
])
2008 return TRANSPORT_UNIX_STREAM
;
2009 // use TCP if it is supported by the host of both endpoints
2010 if (head_location
->transport_supported
[TRANSPORT_INET_STREAM
] &&
2011 tail_location
->transport_supported
[TRANSPORT_INET_STREAM
])
2012 return TRANSPORT_INET_STREAM
;
2013 // no suitable transport was found, return an erroneous type
2014 return TRANSPORT_NUM
;
2017 void MainController::send_connect_ack_to_requestors(port_connection
*conn
)
2019 for (int i
= 0; ; i
++) {
2020 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2021 if (comp
== NULL
) break;
2022 else if (comp
->tc_state
== TC_CONNECT
) {
2023 send_connect_ack(comp
);
2024 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2025 else comp
->tc_state
= PTC_FUNCTION
;
2028 free_requestors(&conn
->requestors
);
2031 void MainController::send_error_to_connect_requestors(port_connection
*conn
,
2032 const char *fmt
, ...)
2034 char *reason
= mprintf("Establishment of port connection %d:%s - %d:%s "
2035 "failed because ", conn
->head
.comp_ref
, conn
->head
.port_name
,
2036 conn
->tail
.comp_ref
, conn
->tail
.port_name
);
2039 reason
= mputprintf_va_list(reason
, fmt
, ap
);
2041 for (int i
= 0; ; i
++) {
2042 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2043 if (comp
== NULL
) break;
2044 else if (comp
->tc_state
== TC_CONNECT
) {
2045 send_error_str(comp
->tc_fd
, reason
);
2046 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2047 else comp
->tc_state
= PTC_FUNCTION
;
2051 free_requestors(&conn
->requestors
);
2054 void MainController::send_disconnect_to_server(port_connection
*conn
)
2056 component_struct
*comp
= components
[conn
->head
.comp_ref
];
2057 switch (comp
->tc_state
) {
2072 send_disconnect(comp
, conn
->head
.port_name
, conn
->tail
.comp_ref
,
2073 conn
->tail
.port_name
);
2079 void MainController::send_disconnect_ack_to_requestors(port_connection
*conn
)
2081 for (int i
= 0; ; i
++) {
2082 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2083 if (comp
== NULL
) break;
2084 else if (comp
->tc_state
== TC_DISCONNECT
) {
2085 send_disconnect_ack(comp
);
2086 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2087 else comp
->tc_state
= PTC_FUNCTION
;
2090 free_requestors(&conn
->requestors
);
2093 void MainController::init_requestors(requestor_struct
*reqs
,
2094 component_struct
*tc
)
2097 reqs
->n_components
= 1;
2098 reqs
->the_component
= tc
;
2099 } else reqs
->n_components
= 0;
2102 void MainController::add_requestor(requestor_struct
*reqs
, component_struct
*tc
)
2104 switch (reqs
->n_components
) {
2106 reqs
->n_components
= 1;
2107 reqs
->the_component
= tc
;
2110 if (reqs
->the_component
!= tc
) {
2111 reqs
->n_components
= 2;
2112 component_struct
*tmp
= reqs
->the_component
;
2114 (component_struct
**)Malloc(2 * sizeof(*reqs
->components
));
2115 reqs
->components
[0] = tmp
;
2116 reqs
->components
[1] = tc
;
2120 for (int i
= 0; i
< reqs
->n_components
; i
++)
2121 if (reqs
->components
[i
] == tc
) return;
2122 reqs
->n_components
++;
2123 reqs
->components
= (component_struct
**)Realloc(reqs
->components
,
2124 reqs
->n_components
* sizeof(*reqs
->components
));
2125 reqs
->components
[reqs
->n_components
- 1] = tc
;
2129 void MainController::remove_requestor(requestor_struct
*reqs
,
2130 component_struct
*tc
)
2132 switch (reqs
->n_components
) {
2136 if (reqs
->the_component
== tc
) reqs
->n_components
= 0;
2139 component_struct
*tmp
= NULL
;
2140 if (reqs
->components
[0] == tc
) tmp
= reqs
->components
[1];
2141 else if (reqs
->components
[1] == tc
) tmp
= reqs
->components
[0];
2143 Free(reqs
->components
);
2144 reqs
->n_components
= 1;
2145 reqs
->the_component
= tmp
;
2149 for (int i
= 0; i
< reqs
->n_components
; i
++)
2150 if (reqs
->components
[i
] == tc
) {
2151 reqs
->n_components
--;
2152 memmove(reqs
->components
+ i
, reqs
->components
+ i
+ 1,
2153 (reqs
->n_components
- i
) * sizeof(*reqs
->components
));
2154 reqs
->components
= (component_struct
**)Realloc(reqs
->components
,
2155 reqs
->n_components
* sizeof(*reqs
->components
));
2161 boolean
MainController::has_requestor(const requestor_struct
*reqs
,
2162 component_struct
*tc
)
2164 switch (reqs
->n_components
) {
2168 return reqs
->the_component
== tc
;
2170 for (int i
= 0; i
< reqs
->n_components
; i
++)
2171 if (reqs
->components
[i
] == tc
) return TRUE
;
2176 component_struct
*MainController::get_requestor(const requestor_struct
*reqs
,
2179 if (index
>= 0 && index
< reqs
->n_components
) {
2180 if (reqs
->n_components
== 1) return reqs
->the_component
;
2181 else return reqs
->components
[index
];
2185 void MainController::free_requestors(requestor_struct
*reqs
)
2187 if (reqs
->n_components
> 1) Free(reqs
->components
);
2188 reqs
->n_components
= 0;
2191 void MainController::init_qualified_name(qualified_name
*name
)
2193 name
->module_name
= NULL
;
2194 name
->definition_name
= NULL
;
2197 void MainController::free_qualified_name(qualified_name
*name
)
2199 delete [] name
->module_name
;
2200 name
->module_name
= NULL
;
2201 delete [] name
->definition_name
;
2202 name
->definition_name
= NULL
;
2205 double MainController::kill_timer
;
2207 double MainController::time_now()
2209 static boolean first_call
= TRUE
;
2210 static struct timeval first_time
;
2213 if (gettimeofday(&first_time
, NULL
) < 0)
2214 fatal_error("MainController::time_now: gettimeofday() system call "
2219 if (gettimeofday(&tv
, NULL
) < 0)
2220 fatal_error("MainController::time_now: gettimeofday() system call "
2222 return (tv
.tv_sec
- first_time
.tv_sec
) +
2223 1.0e-6 * (tv
.tv_usec
- first_time
.tv_usec
);
2227 timer_struct
*MainController::timer_head
, *MainController::timer_tail
;
2229 void MainController::register_timer(timer_struct
*timer
)
2232 for (iter
= timer_tail
; iter
!= NULL
; iter
= iter
->prev
)
2233 if (iter
->expiration
<= timer
->expiration
) break;
2235 // inserting after iter
2237 timer
->next
= iter
->next
;
2238 if (iter
->next
!= NULL
) iter
->next
->prev
= timer
;
2239 else timer_tail
= timer
;
2242 // inserting at the beginning of list
2244 timer
->next
= timer_head
;
2245 if (timer_head
!= NULL
) timer_head
->prev
= timer
;
2246 else timer_tail
= timer
;
2251 void MainController::cancel_timer(timer_struct
*timer
)
2253 if (timer
->next
!= NULL
) timer
->next
->prev
= timer
->prev
;
2254 else timer_tail
= timer
->prev
;
2255 if (timer
->prev
!= NULL
) timer
->prev
->next
= timer
->next
;
2256 else timer_head
= timer
->next
;
2260 int MainController::get_poll_timeout()
2262 if (timer_head
!= NULL
) {
2263 double offset
= timer_head
->expiration
- time_now();
2264 if (offset
> 0.0) return (int)(1000.0 * offset
);
2269 void MainController::handle_expired_timers()
2271 if (timer_head
!= NULL
) {
2272 timer_struct
*iter
= timer_head
;
2273 double now
= time_now();
2275 if (iter
->expiration
> now
) break;
2276 timer_struct
*next
= iter
->next
;
2277 handle_kill_timer(iter
);
2279 } while (iter
!= NULL
);
2283 void MainController::handle_kill_timer(timer_struct
*timer
)
2285 component_struct
*tc
= timer
->timer_argument
.component_ptr
;
2286 host_struct
*host
= tc
->comp_location
;
2287 boolean kill_process
= FALSE
;
2288 switch (tc
->tc_state
) {
2294 error("MTC on host %s did not close its control connection in "
2295 "time. Trying to kill it using its HC.", host
->hostname
);
2297 notify("PTC %d on host %s did not close its control connection in "
2298 "time. Trying to kill it using its HC.", tc
->comp_ref
,
2301 kill_process
= TRUE
;
2304 case PTC_STOPPING_KILLING
:
2306 // active PTCs with kill timer can be only in these states
2308 notify("PTC %d on host %s is not responding. Trying to kill it "
2309 "using its HC.", tc
->comp_ref
, host
->hostname
);
2310 kill_process
= TRUE
;
2315 // MTC can be in any state
2317 error("MTC on host %s is not responding. Trying to kill it using "
2318 "its HC. This will abort test execution.", host
->hostname
);
2319 kill_process
= TRUE
;
2321 error("PTC %d is in invalid state when its kill timer expired.",
2326 if (host
->hc_state
== HC_ACTIVE
) {
2327 send_kill_process(host
, tc
->comp_ref
);
2328 tc
->process_killed
= TRUE
;
2330 error("Test Component %d cannot be killed because the HC on host "
2331 "%s is not in active state. Kill the process manually or the "
2332 "test system may get into a deadlock.", tc
->comp_ref
,
2336 cancel_timer(timer
);
2337 tc
->kill_timer
= NULL
;
2340 void MainController::register_termination_handlers()
2342 new_action
.sa_handler
= termination_handler
;
2343 sigemptyset(&new_action
.sa_mask
);
2344 new_action
.sa_flags
= 0;
2346 sigaction(SIGINT
, NULL
, &old_action
);
2347 if (old_action
.sa_handler
!= SIG_IGN
)
2348 sigaction (SIGINT
, &new_action
, NULL
);
2349 sigaction(SIGHUP
, NULL
, &old_action
);
2350 if (old_action
.sa_handler
!= SIG_IGN
)
2351 sigaction (SIGHUP
, &new_action
, NULL
);
2352 sigaction(SIGTERM
, NULL
, &old_action
);
2353 if (old_action
.sa_handler
!= SIG_IGN
)
2354 sigaction(SIGTERM
, &new_action
, NULL
);
2355 sigaction(SIGQUIT
, NULL
, &old_action
);
2356 if (old_action
.sa_handler
!= SIG_IGN
)
2357 sigaction(SIGQUIT
, &new_action
, NULL
);
2358 sigaction(SIGKILL
, NULL
, &old_action
);
2359 if (old_action
.sa_handler
!= SIG_IGN
)
2360 sigaction(SIGKILL
, &new_action
, NULL
);
2363 void MainController::termination_handler(int signum
)
2365 // Call shutdown_server() and reset handlers and re-raise the signal.
2366 // clean_up() or perform_shutdown() is state dependent and cannot be used
2367 // here... Related to HP67376.
2370 new_action
.sa_handler
= SIG_DFL
;
2371 sigemptyset(&new_action
.sa_mask
);
2372 new_action
.sa_flags
= 0;
2374 sigaction(SIGINT
, &new_action
, NULL
);
2375 sigaction(SIGHUP
, &new_action
, NULL
);
2376 sigaction(SIGTERM
, &new_action
, NULL
);
2377 sigaction(SIGQUIT
, &new_action
, NULL
);
2378 sigaction(SIGKILL
, &new_action
, NULL
);
2383 void MainController::error(const char *fmt
, ...)
2387 char *str
= mprintf_va_list(fmt
, ap
);
2390 ui
->error(/*severity*/ 0, str
);
2395 void MainController::notify(const char *fmt
, ...)
2399 char *str
= mprintf_va_list(fmt
, ap
);
2402 if (gettimeofday(&tv
, NULL
) < 0) fatal_error("MainController::notify: "
2403 "gettimeofday() system call failed.");
2404 notify(&tv
, mc_hostname
, TTCN_EXECUTOR
, str
);
2408 void MainController::notify(const struct timeval
*timestamp
,
2409 const char *source
, int severity
, const char *message
)
2412 ui
->notify(timestamp
, source
, severity
, message
);
2416 void MainController::status_change()
2419 ui
->status_change();
2423 void MainController::fatal_error(const char *fmt
, ...)
2427 vfprintf(stderr
, fmt
, ap
);
2429 if (errno
!= 0) fprintf(stderr
, " (%s)", strerror(errno
));
2434 void *MainController::thread_main(void *)
2437 while (mc_state
!= MC_INACTIVE
) {
2442 int timeout
= get_poll_timeout();
2443 if (maxDtInMs
!= 0 && (timeout
< 0 || maxDtInMs
< timeout
))
2444 timeout
= maxDtInMs
;
2446 fds_selected
= epoll_wait(epfd
, epoll_events
, EPOLL_MAX_EVENTS
,
2449 if (fds_selected
>= 0) break;
2450 if (errno
!= EINTR
) fatal_error("epoll_wait() system call failed.");
2451 #else // ! defined USE_EPOLL
2453 int timeout
= get_poll_timeout();
2454 if (maxDtInMs
!= 0 && (timeout
< 0 || maxDtInMs
< timeout
))
2455 timeout
= maxDtInMs
;
2457 fds_selected
= poll(ufds
, nfds
, timeout
);
2459 if (fds_selected
>= 0) break;
2460 if (errno
!= EINTR
) fatal_error("poll() system call failed.");
2464 switch (wakeup_reason
) {
2465 case REASON_NOTHING
:
2466 case REASON_MTC_KILL_TIMER
:
2468 case REASON_SHUTDOWN
:
2469 wakeup_reason
= REASON_NOTHING
;
2473 error("Invalid wakeup reason (%d) was set.", wakeup_reason
);
2474 wakeup_reason
= REASON_NOTHING
;
2476 if (fds_selected
== 0) {
2477 handle_expired_timers();
2481 for (int i
= 0; i
< fds_selected
; i
++) {
2482 int fd
= epoll_events
[i
].data
.fd
;
2483 if (epoll_events
[i
].events
& (EPOLLIN
| EPOLLHUP
| EPOLLERR
)) {
2484 dispatch_socket_event(fd
);
2487 #else // ! defined USE_EPOLL
2488 for (unsigned int i
= 0; i
< nfds
; i
++) {
2489 int fd
= ufds
[i
].fd
;
2490 if (ufds
[i
].revents
& POLLNVAL
) {
2491 fatal_error("Invalid file descriptor (%d) was given for "
2492 "poll() system call.", fd
);
2493 } else if (ufds
[i
].revents
& (POLLIN
| POLLHUP
| POLLERR
)) {
2494 dispatch_socket_event(fd
);
2498 handle_expired_timers();
2501 notify("Shutdown complete.");
2503 // don't try to lock the mutex after ui->status_change() is completed
2504 // the main thread might call in turn terminate(), which destroys the mutex
2505 ui
->status_change();
2509 void MainController::dispatch_socket_event(int fd
)
2511 // a previous event might have closed the socket
2512 if (fd
>= fd_table_size
) return;
2513 switch (fd_table
[fd
].fd_type
) {
2518 handle_incoming_connection(fd
);
2521 handle_unknown_data(fd_table
[fd
].unknown_ptr
);
2524 handle_hc_data(fd_table
[fd
].host_ptr
, TRUE
);
2527 handle_tc_data(fd_table
[fd
].component_ptr
, TRUE
);
2530 fatal_error("Invalid file descriptor type (%d) for "
2531 "file descriptor %d.", fd_table
[fd
].fd_type
, fd
);
2535 int MainController::pipe_fd
[2];
2536 wakeup_reason_t
MainController::wakeup_reason
;
2538 void MainController::wakeup_thread(wakeup_reason_t reason
)
2540 unsigned char msg
= '\0';
2541 if (write(pipe_fd
[1], &msg
, 1) != 1) {
2542 fatal_error("MainController::wakeup_thread: writing to pipe failed.");
2544 wakeup_reason
= reason
;
2547 void MainController::handle_pipe()
2550 if (read(pipe_fd
[0], &buf
, 1) != 1) {
2551 fatal_error("MainController::handle_pipe: reading from pipe failed.");
2555 void MainController::handle_incoming_connection(int p_server_fd
)
2557 IPAddress
*remote_addr
= IPAddress::create_addr(nh
.get_family());
2558 int fd
= remote_addr
->accept(p_server_fd
);
2560 set_close_on_exec(fd
);
2561 unknown_connection
*new_connection
=
2562 new_unknown_connection(p_server_fd
!= MainController::server_fd
);
2563 new_connection
->fd
= fd
;
2564 if (p_server_fd
== MainController::server_fd
)
2565 new_connection
->ip_addr
= remote_addr
;
2566 else { // in case of unix domain socket connection
2568 new_connection
->ip_addr
= IPAddress::create_addr("127.0.0.1");
2570 new_connection
->text_buf
= new Text_Buf
;
2572 add_fd_to_table(fd
);
2573 fd_table
[fd
].fd_type
= FD_UNKNOWN
;
2574 fd_table
[fd
].unknown_ptr
= new_connection
;
2583 error("New incoming connection cannot be accepted "
2584 "because the maximum number of open files has been reached. "
2585 "Try to increase this limit.");
2586 disable_server_fd();
2587 error("No incoming connections will be accepted until at least "
2588 "one component terminates. This may result in deadlock.");
2591 fatal_error("MainController::handle_incoming_connection: "
2592 "system call accept() failed.");
2597 int MainController::recv_to_buffer(int fd
, Text_Buf
& text_buf
,
2598 boolean recv_from_socket
)
2600 // if recv_from_socket is false we are checking the messages that are
2601 // already in text_buf so we are emulating that recv() was successful
2602 if (!recv_from_socket
) return 1;
2606 text_buf
.get_end(buf_ptr
, buf_len
);
2608 int recv_len
= recv(fd
, buf_ptr
, buf_len
, 0);
2610 if (recv_len
> 0) text_buf
.increase_length(recv_len
);
2615 void MainController::handle_unknown_data(unknown_connection
*conn
)
2617 Text_Buf
& text_buf
= *conn
->text_buf
;
2618 int recv_len
= recv_to_buffer(conn
->fd
, text_buf
, TRUE
);
2619 boolean error_flag
= FALSE
;
2623 while (text_buf
.is_message()) {
2624 text_buf
.pull_int(); // message length
2625 int message_type
= text_buf
.pull_int().get_val();
2626 // only the first message is processed in this loop
2627 // except when a generic message is received
2628 boolean process_more_messages
= FALSE
;
2629 switch (message_type
) {
2631 process_error(conn
);
2632 process_more_messages
= TRUE
;
2636 process_more_messages
= TRUE
;
2639 process_version(conn
);
2641 case MSG_MTC_CREATED
:
2642 process_mtc_created(conn
);
2644 case MSG_PTC_CREATED
:
2645 process_ptc_created(conn
);
2648 error("Invalid message type (%d) was received on an "
2649 "unknown connection from %s [%s].", message_type
,
2650 conn
->ip_addr
->get_host_str(),
2651 conn
->ip_addr
->get_addr_str());
2654 if (process_more_messages
) text_buf
.cut_message();
2657 } catch (const TC_Error
& tc_error
) {
2658 error("Maleformed message was received on an unknown connection "
2659 "from %s [%s].", conn
->ip_addr
->get_host_str(),
2660 conn
->ip_addr
->get_addr_str());
2664 send_error_str(conn
->fd
, "The received message was not understood "
2667 } else if (recv_len
== 0) {
2668 error("Unexpected end of an unknown connection from %s [%s].",
2669 conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str());
2672 error("Receiving of data failed on an unknown connection from %s [%s].",
2673 conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str());
2677 close_unknown_connection(conn
);
2681 void MainController::handle_hc_data(host_struct
*hc
, boolean recv_from_socket
)
2683 Text_Buf
& text_buf
= *hc
->text_buf
;
2684 boolean error_flag
= FALSE
;
2685 int recv_len
= recv_to_buffer(hc
->hc_fd
, text_buf
, recv_from_socket
);
2689 while (text_buf
.is_message()) {
2690 text_buf
.pull_int(); // message length
2691 int message_type
= text_buf
.pull_int().get_val();
2692 switch (message_type
) {
2699 case MSG_CONFIGURE_ACK
:
2700 process_configure_ack(hc
);
2702 case MSG_CONFIGURE_NAK
:
2703 process_configure_nak(hc
);
2705 case MSG_CREATE_NAK
:
2706 process_create_nak(hc
);
2709 process_hc_ready(hc
);
2712 error("Invalid message type (%d) was received on HC "
2713 "connection from %s [%s].", message_type
,
2714 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2717 if (error_flag
) break;
2718 text_buf
.cut_message();
2720 } catch (const TC_Error
& tc_error
) {
2721 error("Malformed message was received on HC connection "
2722 "from %s [%s].", hc
->hostname
, hc
->ip_addr
->get_addr_str());
2726 send_error_str(hc
->hc_fd
, "The received message was not understood "
2729 } else if (recv_len
== 0) {
2730 if (hc
->hc_state
== HC_EXITING
) {
2731 close_hc_connection(hc
);
2732 if (mc_state
== MC_SHUTDOWN
&& all_hc_in_state(HC_DOWN
))
2733 mc_state
= MC_INACTIVE
;
2735 error("Unexpected end of HC connection from %s [%s].",
2736 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2740 error("Receiving of data failed on HC connection from %s [%s].",
2741 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2745 close_hc_connection(hc
);
2749 case MC_LISTENING_CONFIGURED
:
2750 fatal_error("MC is in invalid state when a HC connection "
2752 case MC_HC_CONNECTED
:
2753 if (all_hc_in_state(HC_DOWN
)) mc_state
= MC_LISTENING
;
2755 case MC_CONFIGURING
:
2756 check_all_hc_configured();
2759 if (all_hc_in_state(HC_DOWN
)) mc_state
= MC_LISTENING_CONFIGURED
;
2760 else if (!is_hc_in_state(HC_ACTIVE
) &&
2761 !is_hc_in_state(HC_OVERLOADED
)) mc_state
= MC_HC_CONNECTED
;
2764 if (!is_hc_in_state(HC_ACTIVE
)) notify("There is no active HC "
2765 "connection. Further create operations will fail.");
2771 void MainController::handle_tc_data(component_struct
*tc
,
2772 boolean recv_from_socket
)
2774 Text_Buf
& text_buf
= *tc
->text_buf
;
2775 boolean close_connection
= FALSE
;
2776 int recv_len
= recv_to_buffer(tc
->tc_fd
, text_buf
, recv_from_socket
);
2780 while (text_buf
.is_message()) {
2781 int message_len
= text_buf
.pull_int().get_val();
2782 int message_end
= text_buf
.get_pos() + message_len
;
2783 int message_type
= text_buf
.pull_int().get_val();
2784 // these messages can be received both from MTC and PTCs
2785 switch (message_type
) {
2792 case MSG_CREATE_REQ
:
2793 process_create_req(tc
);
2796 process_start_req(tc
, message_end
);
2799 process_stop_req(tc
);
2802 process_kill_req(tc
);
2804 case MSG_IS_RUNNING
:
2805 process_is_running(tc
);
2808 process_is_alive(tc
);
2811 process_done_req(tc
);
2813 case MSG_KILLED_REQ
:
2814 process_killed_req(tc
);
2816 case MSG_CANCEL_DONE_ACK
:
2817 process_cancel_done_ack(tc
);
2819 case MSG_CONNECT_REQ
:
2820 process_connect_req(tc
);
2822 case MSG_CONNECT_LISTEN_ACK
:
2823 process_connect_listen_ack(tc
, message_end
);
2826 process_connected(tc
);
2828 case MSG_CONNECT_ERROR
:
2829 process_connect_error(tc
);
2831 case MSG_DISCONNECT_REQ
:
2832 process_disconnect_req(tc
);
2834 case MSG_DISCONNECTED
:
2835 process_disconnected(tc
);
2838 process_map_req(tc
);
2844 process_unmap_req(tc
);
2847 process_unmapped(tc
);
2851 // these messages can be received only from the MTC
2852 switch (message_type
) {
2853 case MSG_TESTCASE_STARTED
:
2854 process_testcase_started();
2856 case MSG_TESTCASE_FINISHED
:
2857 process_testcase_finished();
2860 process_mtc_ready();
2863 error("Invalid message type (%d) was received "
2864 "from the MTC at %s [%s].", message_type
,
2865 mtc
->comp_location
->hostname
,
2866 mtc
->comp_location
->ip_addr
->get_addr_str());
2867 close_connection
= TRUE
;
2870 // these messages can be received only from PTCs
2871 switch (message_type
) {
2873 process_stopped(tc
, message_end
);
2875 case MSG_STOPPED_KILLED
:
2876 process_stopped_killed(tc
, message_end
);
2882 notify("Invalid message type (%d) was received from "
2883 "PTC %d at %s [%s].", message_type
,
2884 tc
->comp_ref
, tc
->comp_location
->hostname
,
2885 tc
->comp_location
->ip_addr
->get_addr_str());
2886 close_connection
= TRUE
;
2890 if (close_connection
) break;
2891 text_buf
.cut_message();
2893 } catch (const TC_Error
& tc_error
) {
2895 error("Malformed message was received from the MTC at %s "
2896 "[%s].", mtc
->comp_location
->hostname
,
2897 mtc
->comp_location
->ip_addr
->get_addr_str());
2899 notify("Malformed message was received from PTC %d at %s [%s].",
2900 tc
->comp_ref
, tc
->comp_location
->hostname
,
2901 tc
->comp_location
->ip_addr
->get_addr_str());
2903 close_connection
= TRUE
;
2905 if (close_connection
) {
2906 send_error_str(tc
->tc_fd
, "The received message was not understood "
2909 } else if (recv_len
== 0) {
2910 // TCP connection is closed by peer
2911 if (tc
->tc_state
!= TC_EXITING
&& !tc
->process_killed
) {
2913 error("Unexpected end of MTC connection from %s [%s].",
2914 mtc
->comp_location
->hostname
,
2915 mtc
->comp_location
->ip_addr
->get_addr_str());
2917 notify("Unexpected end of PTC connection (%d) from %s [%s].",
2918 tc
->comp_ref
, tc
->comp_location
->hostname
,
2919 tc
->comp_location
->ip_addr
->get_addr_str());
2922 close_connection
= TRUE
;
2924 if (tc
->process_killed
&& errno
== ECONNRESET
) {
2925 // ignore TCP resets if the process was killed
2926 // because the last STOP or KILL message can stuck in TCP buffers
2927 // if the process did not receive any data
2930 error("Receiving of data failed from the MTC at %s [%s]: %s",
2931 mtc
->comp_location
->hostname
,
2932 mtc
->comp_location
->ip_addr
->get_addr_str(), strerror(errno
));
2934 notify("Receiving of data failed from PTC %d at %s [%s]: %s",
2935 tc
->comp_ref
, tc
->comp_location
->hostname
,
2936 tc
->comp_location
->ip_addr
->get_addr_str(), strerror(errno
));
2939 close_connection
= TRUE
;
2941 if (close_connection
) {
2942 close_tc_connection(tc
);
2943 remove_component_from_host(tc
);
2945 if (mc_state
!= MC_TERMINATING_MTC
) {
2946 notify("The control connection to MTC is lost. "
2947 "Destroying all PTC connections.");
2949 destroy_all_components();
2950 notify("MTC terminated.");
2951 if (is_hc_in_state(HC_CONFIGURING
)) mc_state
= MC_CONFIGURING
;
2952 else if (is_hc_in_state(HC_IDLE
)) mc_state
= MC_HC_CONNECTED
;
2953 else if (is_hc_in_state(HC_ACTIVE
) ||
2954 is_hc_in_state(HC_OVERLOADED
)) mc_state
= MC_ACTIVE
;
2955 else mc_state
= MC_LISTENING_CONFIGURED
;
2956 stop_requested
= FALSE
;
2958 if (tc
->tc_state
!= TC_EXITING
) {
2959 // we have no idea about the final verdict of the PTC
2960 tc
->local_verdict
= ERROR
;
2961 component_terminated(tc
);
2963 tc
->tc_state
= TC_EXITED
;
2964 if (mc_state
== MC_TERMINATING_TESTCASE
&&
2965 ready_to_finish_testcase()) finish_testcase();
2971 void MainController::unlink_unix_socket(int socket_fd
) {
2972 struct sockaddr_un local_addr
;
2973 // querying the local pathname used by socket_fd
2974 socklen_type addr_len
= sizeof(local_addr
);
2975 if (getsockname(socket_fd
, (struct sockaddr
*)&local_addr
, &addr_len
)) {
2976 } else if (local_addr
.sun_family
!= AF_UNIX
) {
2977 } else if (unlink(local_addr
.sun_path
)) {
2982 void MainController::shutdown_server()
2984 if (server_fd
>= 0) {
2985 remove_poll_fd(server_fd
);
2986 remove_fd_from_table(server_fd
);
2991 if (server_fd_unix
>= 0) {
2992 unlink_unix_socket(server_fd_unix
);
2993 remove_poll_fd(server_fd_unix
);
2994 remove_fd_from_table(server_fd_unix
);
2995 close(server_fd_unix
);
2996 server_fd_unix
= -1;
3000 void MainController::perform_shutdown()
3002 boolean shutdown_complete
= TRUE
;
3004 case MC_HC_CONNECTED
:
3006 for (int i
= 0; i
< n_hosts
; i
++) {
3007 host_struct
*host
= hosts
[i
];
3008 if (host
->hc_state
!= HC_DOWN
) {
3010 host
->hc_state
= HC_EXITING
;
3011 shutdown_complete
= FALSE
;
3016 case MC_LISTENING_CONFIGURED
:
3018 // don't call status_change() if shutdown is complete
3019 // it will be called from thread_main() later
3020 if (shutdown_complete
) mc_state
= MC_INACTIVE
;
3022 mc_state
= MC_SHUTDOWN
;
3027 fatal_error("MainController::perform_shutdown: called in wrong state.");
3031 void MainController::clean_up()
3035 while (unknown_head
!= NULL
) close_unknown_connection(unknown_head
);
3037 destroy_all_components();
3039 for (int i
= 0; i
< n_hosts
; i
++) {
3040 host_struct
*host
= hosts
[i
];
3041 close_hc_connection(host
);
3042 Free(host
->hostname
);
3043 delete host
->ip_addr
;
3044 delete [] host
->hostname_local
;
3045 delete [] host
->machine_type
;
3046 delete [] host
->system_name
;
3047 delete [] host
->system_release
;
3048 delete [] host
->system_version
;
3049 Free(host
->log_source
);
3050 Free(host
->components
);
3051 free_string_set(&host
->allowed_components
);
3060 while (timer_head
!= NULL
) cancel_timer(timer_head
);
3062 for (int i
= 0; i
< n_modules
; i
++) {
3063 delete [] modules
[i
].module_name
;
3064 delete [] modules
[i
].module_checksum
;
3069 version_known
= FALSE
;
3073 if (close(epfd
) < 0)
3074 error("MainController::clean_up: Error while closing epoll"
3079 epoll_events
= NULL
;
3080 #else // ! defined USE_EPOLL
3087 pollfds_modified
= FALSE
;
3094 mc_state
= MC_INACTIVE
;
3096 if (pipe_fd
[1] >= 0) {
3100 if (pipe_fd
[0] >= 0) {
3106 void MainController::send_configure(host_struct
*hc
, const char *config_file
)
3109 text_buf
.push_int(MSG_CONFIGURE
);
3110 text_buf
.push_string(config_file
);
3111 send_message(hc
->hc_fd
, text_buf
);
3114 void MainController::send_exit_hc(host_struct
*hc
)
3117 text_buf
.push_int(MSG_EXIT_HC
);
3118 send_message(hc
->hc_fd
, text_buf
);
3121 void MainController::send_create_mtc(host_struct
*hc
)
3124 text_buf
.push_int(MSG_CREATE_MTC
);
3125 send_message(hc
->hc_fd
, text_buf
);
3128 void MainController::send_create_ptc(host_struct
*hc
,
3129 component component_reference
, const qualified_name
& component_type
,
3130 const char *component_name
, boolean is_alive
,
3131 const qualified_name
& current_testcase
)
3134 text_buf
.push_int(MSG_CREATE_PTC
);
3135 text_buf
.push_int(component_reference
);
3136 text_buf
.push_qualified_name(component_type
);
3137 text_buf
.push_string(component_name
);
3138 text_buf
.push_int(is_alive
? 1 : 0);
3139 text_buf
.push_qualified_name(current_testcase
);
3140 send_message(hc
->hc_fd
, text_buf
);
3143 void MainController::send_kill_process(host_struct
*hc
,
3144 component component_reference
)
3147 text_buf
.push_int(MSG_KILL_PROCESS
);
3148 text_buf
.push_int(component_reference
);
3149 send_message(hc
->hc_fd
, text_buf
);
3152 void MainController::send_create_ack(component_struct
*tc
,
3153 component component_reference
)
3156 text_buf
.push_int(MSG_CREATE_ACK
);
3157 text_buf
.push_int(component_reference
);
3158 send_message(tc
->tc_fd
, text_buf
);
3161 void MainController::send_start_ack(component_struct
*tc
)
3164 text_buf
.push_int(MSG_START_ACK
);
3165 send_message(tc
->tc_fd
, text_buf
);
3168 void MainController::send_stop(component_struct
*tc
)
3171 text_buf
.push_int(MSG_STOP
);
3172 send_message(tc
->tc_fd
, text_buf
);
3175 void MainController::send_stop_ack(component_struct
*tc
)
3178 text_buf
.push_int(MSG_STOP_ACK
);
3179 send_message(tc
->tc_fd
, text_buf
);
3182 void MainController::send_kill_ack(component_struct
*tc
)
3185 text_buf
.push_int(MSG_KILL_ACK
);
3186 send_message(tc
->tc_fd
, text_buf
);
3189 void MainController::send_running(component_struct
*tc
, boolean answer
)
3192 text_buf
.push_int(MSG_RUNNING
);
3193 text_buf
.push_int(answer
? 1 : 0);
3194 send_message(tc
->tc_fd
, text_buf
);
3197 void MainController::send_alive(component_struct
*tc
, boolean answer
)
3200 text_buf
.push_int(MSG_ALIVE
);
3201 text_buf
.push_int(answer
? 1 : 0);
3202 send_message(tc
->tc_fd
, text_buf
);
3205 void MainController::send_done_ack(component_struct
*tc
, boolean answer
,
3206 const char *return_type
, int return_value_len
, const void *return_value
)
3209 text_buf
.push_int(MSG_DONE_ACK
);
3210 text_buf
.push_int(answer
? 1 : 0);
3211 text_buf
.push_string(return_type
);
3212 text_buf
.push_raw(return_value_len
, return_value
);
3213 send_message(tc
->tc_fd
, text_buf
);
3216 void MainController::send_killed_ack(component_struct
*tc
, boolean answer
)
3219 text_buf
.push_int(MSG_KILLED_ACK
);
3220 text_buf
.push_int(answer
? 1 : 0);
3221 send_message(tc
->tc_fd
, text_buf
);
3224 void MainController::send_connect_listen(component_struct
*tc
,
3225 const char *local_port
, component remote_comp
, const char *remote_comp_name
,
3226 const char *remote_port
, transport_type_enum transport_type
)
3229 text_buf
.push_int(MSG_CONNECT_LISTEN
);
3230 text_buf
.push_string(local_port
);
3231 text_buf
.push_int(remote_comp
);
3232 text_buf
.push_string(remote_comp_name
);
3233 text_buf
.push_string(remote_port
);
3234 text_buf
.push_int(transport_type
);
3235 send_message(tc
->tc_fd
, text_buf
);
3238 void MainController::send_connect(component_struct
*tc
,
3239 const char *local_port
, component remote_comp
, const char *remote_comp_name
,
3240 const char *remote_port
, transport_type_enum transport_type
,
3241 int remote_address_len
, const void *remote_address
)
3244 text_buf
.push_int(MSG_CONNECT
);
3245 text_buf
.push_string(local_port
);
3246 text_buf
.push_int(remote_comp
);
3247 text_buf
.push_string(remote_comp_name
);
3248 text_buf
.push_string(remote_port
);
3249 text_buf
.push_int(transport_type
);
3250 text_buf
.push_raw(remote_address_len
, remote_address
);
3251 send_message(tc
->tc_fd
, text_buf
);
3254 void MainController::send_connect_ack(component_struct
*tc
)
3257 text_buf
.push_int(MSG_CONNECT_ACK
);
3258 send_message(tc
->tc_fd
, text_buf
);
3261 void MainController::send_disconnect(component_struct
*tc
,
3262 const char *local_port
, component remote_comp
, const char *remote_port
)
3265 text_buf
.push_int(MSG_DISCONNECT
);
3266 text_buf
.push_string(local_port
);
3267 text_buf
.push_int(remote_comp
);
3268 text_buf
.push_string(remote_port
);
3269 send_message(tc
->tc_fd
, text_buf
);
3272 void MainController::send_disconnect_ack(component_struct
*tc
)
3275 text_buf
.push_int(MSG_DISCONNECT_ACK
);
3276 send_message(tc
->tc_fd
, text_buf
);
3279 void MainController::send_map(component_struct
*tc
,
3280 const char *local_port
, const char *system_port
)
3283 text_buf
.push_int(MSG_MAP
);
3284 text_buf
.push_string(local_port
);
3285 text_buf
.push_string(system_port
);
3286 send_message(tc
->tc_fd
, text_buf
);
3289 void MainController::send_map_ack(component_struct
*tc
)
3292 text_buf
.push_int(MSG_MAP_ACK
);
3293 send_message(tc
->tc_fd
, text_buf
);
3296 void MainController::send_unmap(component_struct
*tc
,
3297 const char *local_port
, const char *system_port
)
3300 text_buf
.push_int(MSG_UNMAP
);
3301 text_buf
.push_string(local_port
);
3302 text_buf
.push_string(system_port
);
3303 send_message(tc
->tc_fd
, text_buf
);
3306 void MainController::send_unmap_ack(component_struct
*tc
)
3309 text_buf
.push_int(MSG_UNMAP_ACK
);
3310 send_message(tc
->tc_fd
, text_buf
);
3313 void MainController::send_cancel_done_mtc(component component_reference
,
3317 text_buf
.push_int(MSG_CANCEL_DONE
);
3318 text_buf
.push_int(component_reference
);
3319 text_buf
.push_int(cancel_any
? 1 : 0);
3320 send_message(mtc
->tc_fd
, text_buf
);
3323 void MainController::send_component_status_mtc(component component_reference
,
3324 boolean is_done
, boolean is_killed
, boolean is_any_done
,
3325 boolean is_all_done
, boolean is_any_killed
, boolean is_all_killed
,
3326 const char *return_type
, int return_value_len
, const void *return_value
)
3329 text_buf
.push_int(MSG_COMPONENT_STATUS
);
3330 text_buf
.push_int(component_reference
);
3331 text_buf
.push_int(is_done
? 1 : 0);
3332 text_buf
.push_int(is_killed
? 1 : 0);
3333 text_buf
.push_int(is_any_done
? 1 : 0);
3334 text_buf
.push_int(is_all_done
? 1 : 0);
3335 text_buf
.push_int(is_any_killed
? 1 : 0);
3336 text_buf
.push_int(is_all_killed
? 1 : 0);
3337 text_buf
.push_string(return_type
);
3338 text_buf
.push_raw(return_value_len
, return_value
);
3339 send_message(mtc
->tc_fd
, text_buf
);
3342 void MainController::send_execute_control(const char *module_name
)
3345 text_buf
.push_int(MSG_EXECUTE_CONTROL
);
3346 text_buf
.push_string(module_name
);
3347 send_message(mtc
->tc_fd
, text_buf
);
3350 void MainController::send_execute_testcase(const char *module_name
,
3351 const char *testcase_name
)
3354 text_buf
.push_int(MSG_EXECUTE_TESTCASE
);
3355 text_buf
.push_string(module_name
);
3356 text_buf
.push_string(testcase_name
);
3357 send_message(mtc
->tc_fd
, text_buf
);
3360 void MainController::send_ptc_verdict(boolean continue_execution
)
3363 text_buf
.push_int(MSG_PTC_VERDICT
);
3365 for (int i
= tc_first_comp_ref
; i
< n_components
; i
++)
3366 if (components
[i
]->tc_state
!= PTC_STALE
) n_ptcs
++;
3367 text_buf
.push_int(n_ptcs
);
3368 for (int i
= tc_first_comp_ref
; i
< n_components
; i
++) {
3369 if (components
[i
]->tc_state
!= PTC_STALE
) {
3370 text_buf
.push_int(components
[i
]->comp_ref
);
3371 text_buf
.push_string(components
[i
]->comp_name
);
3372 text_buf
.push_int(components
[i
]->local_verdict
);
3373 if (components
[i
]->verdict_reason
!= NULL
)
3374 text_buf
.push_string(components
[i
]->verdict_reason
);
3376 text_buf
.push_string("");
3379 text_buf
.push_int(continue_execution
? 1 : 0);
3380 send_message(mtc
->tc_fd
, text_buf
);
3383 void MainController::send_continue()
3386 text_buf
.push_int(MSG_CONTINUE
);
3387 send_message(mtc
->tc_fd
, text_buf
);
3390 void MainController::send_exit_mtc()
3393 text_buf
.push_int(MSG_EXIT_MTC
);
3394 send_message(mtc
->tc_fd
, text_buf
);
3397 void MainController::send_cancel_done_ptc(component_struct
*tc
,
3398 component component_reference
)
3401 text_buf
.push_int(MSG_CANCEL_DONE
);
3402 text_buf
.push_int(component_reference
);
3403 send_message(tc
->tc_fd
, text_buf
);
3407 void MainController::send_component_status_ptc(component_struct
*tc
,
3408 component component_reference
, boolean is_done
, boolean is_killed
,
3409 const char *return_type
, int return_value_len
, const void *return_value
)
3412 text_buf
.push_int(MSG_COMPONENT_STATUS
);
3413 text_buf
.push_int(component_reference
);
3414 text_buf
.push_int(is_done
? 1 : 0);
3415 text_buf
.push_int(is_killed
? 1 : 0);
3416 text_buf
.push_string(return_type
);
3417 text_buf
.push_raw(return_value_len
, return_value
);
3418 send_message(tc
->tc_fd
, text_buf
);
3421 void MainController::send_start(component_struct
*tc
,
3422 const qualified_name
& function_name
, int arg_len
, const void *arg_ptr
)
3425 text_buf
.push_int(MSG_START
);
3426 text_buf
.push_qualified_name(function_name
);
3427 text_buf
.push_raw(arg_len
, arg_ptr
);
3428 send_message(tc
->tc_fd
, text_buf
);
3431 void MainController::send_kill(component_struct
*tc
)
3434 text_buf
.push_int(MSG_KILL
);
3435 send_message(tc
->tc_fd
, text_buf
);
3438 void MainController::send_error(int fd
, const char *fmt
, ...)
3442 char *reason
= mprintf_va_list(fmt
, ap
);
3444 send_error_str(fd
, reason
);
3448 void MainController::send_error_str(int fd
, const char *reason
)
3451 text_buf
.push_int((RInt
)MSG_ERROR
);
3452 text_buf
.push_string(reason
);
3453 send_message(fd
, text_buf
);
3456 void MainController::send_message(int fd
, Text_Buf
& text_buf
)
3458 text_buf
.calculate_length();
3459 const char *send_ptr
= text_buf
.get_data();
3460 int send_len
= text_buf
.get_len();
3461 int sent_len
= send(fd
, send_ptr
, send_len
, 0);
3462 if (send_len
!= sent_len
) {
3463 error("Sending of message failed: %s", strerror(errno
));
3467 void MainController::process_error(unknown_connection
*conn
)
3469 Text_Buf
& text_buf
= *conn
->text_buf
;
3470 char *reason
= text_buf
.pull_string();
3471 error("Error message was received on an unknown connection from %s [%s]: "
3472 "%s.", conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str(), reason
);
3474 text_buf
.cut_message();
3478 void MainController::process_log(unknown_connection
*conn
)
3480 Text_Buf
& text_buf
= *conn
->text_buf
;
3482 tv
.tv_sec
= text_buf
.pull_int().get_val();
3483 tv
.tv_usec
= text_buf
.pull_int().get_val();
3484 char *source
= mprintf("<unknown>@%s", conn
->ip_addr
->get_host_str());
3485 int severity
= text_buf
.pull_int().get_val();
3486 char *message
= text_buf
.pull_string();
3487 notify(&tv
, source
, severity
, message
);
3492 void MainController::process_version(unknown_connection
*conn
)
3494 if (check_version(conn
)) {
3495 error("HC connection from %s [%s] was refused because of "
3496 "incorrect version.", conn
->ip_addr
->get_host_str(),
3497 conn
->ip_addr
->get_addr_str());
3498 close_unknown_connection(conn
);
3501 host_struct
*hc
= add_new_host(conn
);
3504 mc_state
= MC_HC_CONNECTED
;
3505 case MC_HC_CONNECTED
:
3507 case MC_LISTENING_CONFIGURED
:
3509 configure_host(hc
, TRUE
);
3510 mc_state
= MC_CONFIGURING
;
3514 hc
->hc_state
= HC_EXITING
;
3517 configure_host(hc
, TRUE
);
3519 // handle the remaining messages that are in hc->text_buf
3520 handle_hc_data(hc
, FALSE
);
3524 void MainController::process_mtc_created(unknown_connection
*conn
)
3527 if (mc_state
!= MC_CREATING_MTC
) {
3528 send_error_str(fd
, "Message MTC_CREATED arrived in invalid state.");
3529 close_unknown_connection(conn
);
3532 if (mtc
== NULL
|| mtc
->tc_state
!= TC_INITIAL
)
3533 fatal_error("MainController::process_mtc_created: MTC is in invalid "
3535 if (!conn
->unix_socket
&&
3536 *(mtc
->comp_location
->ip_addr
) != *(conn
->ip_addr
)) {
3537 send_error(fd
, "Message MTC_CREATED arrived from an unexpected "
3538 "IP address. It is accepted only from %s.",
3539 mtc
->comp_location
->ip_addr
->get_addr_str());
3540 close_unknown_connection(conn
);
3544 mc_state
= MC_READY
;
3545 mtc
->tc_state
= TC_IDLE
;
3547 fd_table
[fd
].fd_type
= FD_TC
;
3548 fd_table
[fd
].component_ptr
= mtc
;
3549 Text_Buf
*text_buf
= conn
->text_buf
;
3550 text_buf
->cut_message();
3551 mtc
->text_buf
= text_buf
;
3552 delete [] mtc
->initial
.location_str
;
3554 delete_unknown_connection(conn
);
3556 notify("MTC is created.");
3557 // handle the remaining messages that are in text_buf
3558 handle_tc_data(mtc
, FALSE
);
3562 void MainController::process_ptc_created(unknown_connection
*conn
)
3567 case MC_EXECUTING_TESTCASE
:
3568 case MC_TERMINATING_TESTCASE
:
3571 send_error_str(fd
, "Message PTC_CREATED arrived in invalid state.");
3572 close_unknown_connection(conn
);
3576 Text_Buf
*text_buf
= conn
->text_buf
;
3577 component component_reference
= text_buf
->pull_int().get_val();
3579 switch (component_reference
) {
3581 send_error_str(fd
, "Message PTC_CREATED refers to the null component "
3583 close_unknown_connection(conn
);
3586 send_error_str(fd
, "Message PTC_CREATED refers to the component "
3587 "reference of the MTC.");
3588 close_unknown_connection(conn
);
3590 case SYSTEM_COMPREF
:
3591 send_error_str(fd
, "Message PTC_CREATED refers to the component "
3592 "reference of the system.");
3593 close_unknown_connection(conn
);
3596 send_error_str(fd
, "Message PTC_CREATED refers to 'any component'.");
3597 close_unknown_connection(conn
);
3600 send_error_str(fd
, "Message PTC_CREATED refers to 'all component'.");
3601 close_unknown_connection(conn
);
3605 component_struct
*tc
= lookup_component(component_reference
);
3607 send_error(fd
, "Message PTC_CREATED refers to invalid component "
3608 "reference %d.", component_reference
);
3609 close_unknown_connection(conn
);
3611 } else if (tc
->tc_state
!= TC_INITIAL
) {
3612 send_error(fd
, "Message PTC_CREATED refers to test component "
3613 "%d, which is not being created.", component_reference
);
3614 close_unknown_connection(conn
);
3616 } else if (!conn
->unix_socket
&& *(conn
->ip_addr
) != *(tc
->comp_location
->ip_addr
)) {
3617 char *real_hostname
= mprintf("%s [%s]", conn
->ip_addr
->get_host_str(),
3618 conn
->ip_addr
->get_addr_str());
3619 char *expected_hostname
= mprintf("%s [%s]",
3620 tc
->comp_location
->hostname
, tc
->comp_location
->ip_addr
->get_addr_str());
3621 send_error(fd
, "Invalid source host (%s) for the control "
3622 "connection. Expected: %s.", real_hostname
, expected_hostname
);
3623 error("Connection of PTC %d arrived from an unexpected "
3624 "IP address (%s). Expected: %s.", component_reference
,
3625 real_hostname
, expected_hostname
);
3626 Free(real_hostname
);
3627 Free(expected_hostname
);
3628 close_unknown_connection(conn
);
3632 tc
->tc_state
= TC_IDLE
;
3634 fd_table
[fd
].fd_type
= FD_TC
;
3635 fd_table
[fd
].component_ptr
= tc
;
3636 text_buf
->cut_message();
3637 tc
->text_buf
= text_buf
;
3638 delete [] tc
->initial
.location_str
;
3640 delete_unknown_connection(conn
);
3642 if (mc_state
== MC_TERMINATING_TESTCASE
|| mtc
->stop_requested
||
3643 mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
||
3644 (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
&& !tc
->is_alive
)) {
3646 tc
->tc_state
= PTC_KILLING
;
3647 if (!tc
->is_alive
) tc
->stop_requested
= TRUE
;
3648 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
3649 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
3650 start_kill_timer(tc
);
3652 component_struct
*create_requestor
= tc
->initial
.create_requestor
;
3653 if (create_requestor
->tc_state
== TC_CREATE
) {
3654 send_create_ack(create_requestor
, component_reference
);
3655 if (create_requestor
== mtc
)
3656 create_requestor
->tc_state
= MTC_TESTCASE
;
3657 else create_requestor
->tc_state
= PTC_FUNCTION
;
3660 // handle the remaining messages that are in text_buf
3661 handle_tc_data(tc
, FALSE
);
3665 void MainController::process_error(host_struct
*hc
)
3667 char *reason
= hc
->text_buf
->pull_string();
3668 error("Error message was received from HC at %s [%s]: %s",
3669 hc
->hostname
, hc
->ip_addr
->get_addr_str(), reason
);
3673 void MainController::process_log(host_struct
*hc
)
3675 Text_Buf
& text_buf
= *hc
->text_buf
;
3677 tv
.tv_sec
= text_buf
.pull_int().get_val();
3678 tv
.tv_usec
= text_buf
.pull_int().get_val();
3679 int severity
= text_buf
.pull_int().get_val();
3680 char *message
= text_buf
.pull_string();
3681 notify(&tv
, hc
->log_source
, severity
, message
);
3685 void MainController::process_configure_ack(host_struct
*hc
)
3687 switch (hc
->hc_state
) {
3688 case HC_CONFIGURING
:
3689 hc
->hc_state
= HC_ACTIVE
;
3691 case HC_CONFIGURING_OVERLOADED
:
3692 hc
->hc_state
= HC_OVERLOADED
;
3695 send_error_str(hc
->hc_fd
, "Unexpected message CONFIGURE_ACK was "
3699 if (mc_state
== MC_CONFIGURING
) check_all_hc_configured();
3700 else notify("Host %s was configured successfully.", hc
->hostname
);
3704 void MainController::process_configure_nak(host_struct
*hc
)
3706 switch (hc
->hc_state
) {
3707 case HC_CONFIGURING
:
3708 case HC_CONFIGURING_OVERLOADED
:
3709 hc
->hc_state
= HC_IDLE
;
3712 send_error_str(hc
->hc_fd
, "Unexpected message CONFIGURE_NAK was "
3716 if (mc_state
== MC_CONFIGURING
) check_all_hc_configured();
3717 else notify("Processing of configuration file failed on host %s.",
3722 void MainController::process_create_nak(host_struct
*hc
)
3725 case MC_CREATING_MTC
:
3726 case MC_EXECUTING_TESTCASE
:
3727 case MC_TERMINATING_TESTCASE
:
3730 send_error_str(hc
->hc_fd
, "Message CREATE_NAK arrived in invalid "
3735 switch (hc
->hc_state
) {
3737 notify("Host %s is overloaded. New components will not be created "
3738 "there until further notice.", hc
->hostname
);
3739 hc
->hc_state
= HC_OVERLOADED
;
3744 send_error_str(hc
->hc_fd
, "Unexpected message CREATE_NAK was received: "
3745 "the sender is in invalid state.");
3749 Text_Buf
& text_buf
= *hc
->text_buf
;
3750 component component_reference
= text_buf
.pull_int().get_val();
3752 switch (component_reference
) {
3754 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to the null "
3755 "component reference.");
3757 case SYSTEM_COMPREF
:
3758 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to the component "
3759 "reference of the system.");
3762 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to "
3763 "'any component'.");
3766 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to "
3767 "'all component'.");
3771 component_struct
*tc
= lookup_component(component_reference
);
3773 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to invalid component "
3774 "reference %d.", component_reference
);
3777 if (tc
->tc_state
!= TC_INITIAL
) {
3778 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to test component "
3779 "%d, which is not being created.", component_reference
);
3782 if (tc
->comp_location
!= hc
) {
3783 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to test component "
3784 "%d, which was assigned to a different host (%s).",
3785 component_reference
, tc
->comp_location
->hostname
);
3789 remove_component_from_host(tc
);
3790 hc
->n_active_components
--;
3792 char *reason
= text_buf
.pull_string();
3795 if (mc_state
!= MC_CREATING_MTC
)
3796 fatal_error("MainController::process_create_nak: MC is in "
3797 "unexpected state when CREATE_NAK refers to MTC.");
3798 error("Creation of MTC failed on host %s: %s.", hc
->hostname
, reason
);
3799 destroy_all_components();
3800 mc_state
= MC_ACTIVE
;
3802 host_struct
*new_host
= choose_ptc_location(
3803 tc
->comp_type
.definition_name
, tc
->comp_name
,
3804 tc
->initial
.location_str
);
3805 if (new_host
!= NULL
) {
3806 send_create_ptc(new_host
, component_reference
, tc
->comp_type
,
3807 tc
->comp_name
, tc
->is_alive
, mtc
->tc_fn_name
);
3808 notify("PTC with component reference %d was relocated from host "
3809 "%s to %s because of overload: %s.", component_reference
,
3810 hc
->hostname
, new_host
->hostname
, reason
);
3811 add_component_to_host(new_host
, tc
);
3812 new_host
->n_active_components
++;
3814 char *comp_data
= mprintf("component type: %s.%s",
3815 tc
->comp_type
.module_name
, tc
->comp_type
.definition_name
);
3816 if (tc
->comp_name
!= NULL
)
3817 comp_data
= mputprintf(comp_data
, ", name: %s", tc
->comp_name
);
3818 if (tc
->initial
.location_str
!= NULL
&&
3819 tc
->initial
.location_str
[0] != '\0')
3820 comp_data
= mputprintf(comp_data
, ", location: %s",
3821 tc
->initial
.location_str
);
3822 component_struct
*create_requestor
= tc
->initial
.create_requestor
;
3823 if (create_requestor
->tc_state
== TC_CREATE
) {
3824 send_error(create_requestor
->tc_fd
, "Creation of the new PTC "
3825 "(%s) failed on host %s: %s. Other suitable hosts to "
3826 "relocate the component are not available.", comp_data
,
3827 hc
->hostname
, reason
);
3828 if (create_requestor
== mtc
)
3829 create_requestor
->tc_state
= MTC_TESTCASE
;
3830 else create_requestor
->tc_state
= PTC_FUNCTION
;
3832 delete [] tc
->initial
.location_str
;
3833 tc
->tc_state
= PTC_STALE
;
3835 switch (mtc
->tc_state
) {
3836 case MTC_TERMINATING_TESTCASE
:
3837 if (ready_to_finish_testcase()) finish_testcase();
3839 case MTC_ALL_COMPONENT_KILL
:
3840 check_all_component_kill();
3842 case MTC_ALL_COMPONENT_STOP
:
3843 check_all_component_stop();
3848 notify("Creation of a PTC (%s) failed on host %s: %s. "
3849 "Relocation to other suitable host is not possible.",
3850 comp_data
, hc
->hostname
, reason
);
3860 void MainController::process_hc_ready(host_struct
*hc
)
3862 switch(hc
->hc_state
) {
3864 hc
->hc_state
= HC_ACTIVE
;
3866 case HC_CONFIGURING_OVERLOADED
:
3867 hc
->hc_state
= HC_CONFIGURING
;
3870 send_error_str(hc
->hc_fd
, "Unexpected message HC_READY was received.");
3873 notify("Host %s is no more overloaded.", hc
->hostname
);
3877 void MainController::process_error(component_struct
*tc
)
3879 char *reason
= tc
->text_buf
->pull_string();
3881 error("Error message was received from the MTC at %s [%s]: %s",
3882 mtc
->comp_location
->hostname
,
3883 mtc
->comp_location
->ip_addr
->get_addr_str(), reason
);
3885 notify("Error message was received from PTC %d at %s [%s]: %s",
3886 tc
->comp_ref
, tc
->comp_location
->hostname
,
3887 tc
->comp_location
->ip_addr
->get_addr_str(), reason
);
3892 void MainController::process_log(component_struct
*tc
)
3894 Text_Buf
& text_buf
= *tc
->text_buf
;
3896 tv
.tv_sec
= text_buf
.pull_int().get_val();
3897 tv
.tv_usec
= text_buf
.pull_int().get_val();
3898 int severity
= text_buf
.pull_int().get_val();
3899 char *message
= text_buf
.pull_string();
3900 notify(&tv
, tc
->log_source
, severity
, message
);
3904 void MainController::process_create_req(component_struct
*tc
)
3906 if (!request_allowed(tc
, "CREATE_REQ")) return;
3908 if (max_ptcs
>= 0 && n_active_ptcs
>= max_ptcs
) {
3909 send_error(tc
->tc_fd
, "The license key does not allow more than %d "
3910 "simultaneously active PTCs.", max_ptcs
);
3914 Text_Buf
& text_buf
= *tc
->text_buf
;
3915 qualified_name component_type
;
3916 text_buf
.pull_qualified_name(component_type
);
3917 char *component_name
= text_buf
.pull_string();
3918 if (component_name
[0] == '\0') {
3919 delete [] component_name
;
3920 component_name
= NULL
;
3922 char *component_location
= text_buf
.pull_string();
3923 if (component_location
[0] == '\0') {
3924 delete [] component_location
;
3925 component_location
= NULL
;
3927 boolean is_alive
= text_buf
.pull_int().get_val();
3929 host_struct
*host
= choose_ptc_location(component_type
.definition_name
,
3930 component_name
, component_location
);
3933 if (!is_hc_in_state(HC_ACTIVE
)) {
3934 send_error_str(tc
->tc_fd
, "There is no active HC connection. "
3935 "Create operation cannot be performed.");
3937 char *comp_data
= mprintf("component type: %s.%s",
3938 component_type
.module_name
, component_type
.definition_name
);
3939 if (component_name
!= NULL
)
3940 comp_data
= mputprintf(comp_data
, ", name: %s", component_name
);
3941 if (component_location
!= NULL
)
3942 comp_data
= mputprintf(comp_data
, ", location: %s",
3943 component_location
);
3944 send_error(tc
->tc_fd
, "No suitable host was found to create a "
3945 "new PTC (%s).", comp_data
);
3948 free_qualified_name(&component_type
);
3949 delete [] component_name
;
3950 delete [] component_location
;
3954 component comp_ref
= next_comp_ref
++;
3955 send_create_ptc(host
, comp_ref
, component_type
, component_name
, is_alive
,
3958 tc
->tc_state
= TC_CREATE
;
3960 component_struct
*new_ptc
= new component_struct
;
3961 new_ptc
->comp_ref
= comp_ref
;
3962 new_ptc
->comp_type
= component_type
;
3963 new_ptc
->comp_name
= component_name
;
3964 new_ptc
->tc_state
= TC_INITIAL
;
3965 new_ptc
->local_verdict
= NONE
;
3966 new_ptc
->verdict_reason
= NULL
;
3967 new_ptc
->tc_fd
= -1;
3968 new_ptc
->text_buf
= NULL
;
3969 init_qualified_name(&new_ptc
->tc_fn_name
);
3970 new_ptc
->return_type
= NULL
;
3971 new_ptc
->return_value_len
= 0;
3972 new_ptc
->return_value
= NULL
;
3973 new_ptc
->is_alive
= is_alive
;
3974 new_ptc
->stop_requested
= FALSE
;
3975 new_ptc
->process_killed
= FALSE
;
3976 new_ptc
->initial
.create_requestor
= tc
;
3977 new_ptc
->initial
.location_str
= component_location
;
3978 init_requestors(&new_ptc
->done_requestors
, NULL
);
3979 init_requestors(&new_ptc
->killed_requestors
, NULL
);
3980 init_requestors(&new_ptc
->cancel_done_sent_for
, NULL
);
3981 new_ptc
->kill_timer
= NULL
;
3982 init_connections(new_ptc
);
3984 add_component(new_ptc
);
3985 add_component_to_host(host
, new_ptc
);
3986 host
->n_active_components
++;
3992 void MainController::process_start_req(component_struct
*tc
, int message_end
)
3994 if (!request_allowed(tc
, "START_REQ")) return;
3996 Text_Buf
& text_buf
= *tc
->text_buf
;
3997 component component_reference
= text_buf
.pull_int().get_val();
3998 switch (component_reference
) {
4000 send_error_str(tc
->tc_fd
, "Start operation was requested on the null "
4001 "component reference.");
4004 send_error_str(tc
->tc_fd
, "Start operation was requested on the "
4005 "component reference of the MTC.");
4007 case SYSTEM_COMPREF
:
4008 send_error_str(tc
->tc_fd
, "Start operation was requested on the "
4009 "component reference of the system.");
4012 send_error_str(tc
->tc_fd
, "Start operation was requested on "
4013 "'any component'.");
4016 send_error_str(tc
->tc_fd
, "Start operation was requested on "
4017 "'all component'.");
4020 component_struct
*target
= lookup_component(component_reference
);
4021 if (target
== NULL
) {
4022 send_error(tc
->tc_fd
, "Start operation was requested on invalid "
4023 "component reference: %d.", component_reference
);
4026 switch (target
->tc_state
) {
4029 // these states are correct
4041 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4042 "started because it is already executing function %s.%s.",
4043 component_reference
, target
->tc_fn_name
.module_name
,
4044 target
->tc_fn_name
.definition_name
);
4047 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4048 "started because it function %s.%s is currently being stopped on "
4049 "it.", component_reference
, target
->tc_fn_name
.module_name
,
4050 target
->tc_fn_name
.definition_name
);
4053 case PTC_STOPPING_KILLING
:
4054 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4055 "started because it is currently being killed.",
4056 component_reference
);
4060 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4061 "started because it is not alive anymore.", component_reference
);
4064 send_error(tc
->tc_fd
, "The argument of start operation (%d) is a "
4065 "component reference that belongs to an earlier testcase.",
4066 component_reference
);
4069 send_error(tc
->tc_fd
, "Start operation was requested on component "
4070 "reference %d, which is in invalid state.",
4071 component_reference
);
4074 text_buf
.pull_qualified_name(target
->tc_fn_name
);
4075 target
->stop_requested
= FALSE
;
4076 int arg_begin
= text_buf
.get_pos();
4077 int arg_len
= message_end
- arg_begin
;
4078 const void *arg_ptr
= text_buf
.get_data() + arg_begin
;
4079 boolean send_cancel_done
= FALSE
, cancel_any_component_done
= FALSE
;
4080 if (target
->tc_state
== PTC_STOPPED
) {
4081 // updating the state of target because 'any component.done' cannot
4082 // consider this component anymore
4083 target
->tc_state
= PTC_STARTING
;
4084 // cleaning up the previous return value
4085 delete [] target
->return_type
;
4086 target
->return_type
= NULL
;
4087 target
->return_value_len
= 0;
4088 Free(target
->return_value
);
4089 target
->return_value
= NULL
;
4090 // determining which components we need to send CANCEL_DONE to
4091 init_requestors(&target
->starting
.cancel_done_sent_to
, NULL
);
4092 for (int i
= 0; ; i
++) {
4093 component_struct
*comp
= get_requestor(&target
->done_requestors
, i
);
4094 if (comp
== NULL
) break;
4095 else if (comp
== tc
) {
4096 // the start requestor shall cancel the done status locally
4100 switch (comp
->tc_state
) {
4114 // a CANCEL_DONE message shall be sent to comp
4115 send_cancel_done
= TRUE
;
4116 add_requestor(&target
->starting
.cancel_done_sent_to
, comp
);
4121 case PTC_STOPPING_KILLING
:
4122 // CANCEL_DONE will not be sent to comp
4125 error("Test Component %d is in invalid state when starting "
4126 "PTC %d.", comp
->comp_ref
, component_reference
);
4129 // check whether 'any component.done' needs to be cancelled
4130 if (any_component_done_sent
&& !is_any_component_done()) {
4131 send_cancel_done
= TRUE
;
4132 cancel_any_component_done
= TRUE
;
4133 any_component_done_sent
= FALSE
;
4134 add_requestor(&target
->starting
.cancel_done_sent_to
, mtc
);
4136 free_requestors(&target
->done_requestors
);
4138 if (send_cancel_done
) {
4139 for (int i
= 0; ; i
++) {
4140 component_struct
*comp
=
4141 get_requestor(&target
->starting
.cancel_done_sent_to
, i
);
4142 if (comp
== NULL
) break;
4143 else if (comp
== mtc
) send_cancel_done_mtc(component_reference
,
4144 cancel_any_component_done
);
4145 else send_cancel_done_ptc(comp
, component_reference
);
4146 add_requestor(&comp
->cancel_done_sent_for
, target
);
4148 target
->starting
.start_requestor
= tc
;
4149 target
->starting
.arguments_len
= arg_len
;
4150 target
->starting
.arguments_ptr
= Malloc(arg_len
);
4151 memcpy(target
->starting
.arguments_ptr
, arg_ptr
, arg_len
);
4152 tc
->tc_state
= TC_START
;
4154 send_start(target
, target
->tc_fn_name
, arg_len
, arg_ptr
);
4156 target
->tc_state
= PTC_FUNCTION
;
4161 void MainController::process_stop_req(component_struct
*tc
)
4163 if (!request_allowed(tc
, "STOP_REQ")) return;
4165 component component_reference
= tc
->text_buf
->pull_int().get_val();
4166 switch (component_reference
) {
4168 send_error_str(tc
->tc_fd
, "Stop operation was requested on the null "
4169 "component reference.");
4172 // 'mtc.stop' initiated by a PTC terminates the current testcase
4174 if (!mtc
->stop_requested
) {
4176 kill_all_components(TRUE
);
4177 mtc
->stop_requested
= TRUE
;
4178 start_kill_timer(mtc
);
4179 notify("Test Component %d has requested to stop MTC. "
4180 "Terminating current testcase execution.", tc
->comp_ref
);
4183 } else send_error_str(tc
->tc_fd
, "MTC has requested to stop itself.");
4185 case SYSTEM_COMPREF
:
4186 send_error_str(tc
->tc_fd
, "Stop operation was requested on the "
4187 "component reference of the system.");
4190 send_error_str(tc
->tc_fd
, "Stop operation was requested on "
4191 "'any component'.");
4195 if (stop_all_components()) send_stop_ack(mtc
);
4197 mtc
->tc_state
= MTC_ALL_COMPONENT_STOP
;
4200 } else send_error_str(tc
->tc_fd
, "Operation 'all component.stop' can "
4201 "only be performed on the MTC.");
4206 // the operation refers to a specific PTC
4207 component_struct
*target
= lookup_component(component_reference
);
4208 if (target
== NULL
) {
4209 send_error(tc
->tc_fd
, "The argument of stop operation is an "
4210 "invalid component reference: %d.", component_reference
);
4212 } else if (target
== tc
) {
4213 send_error_str(tc
->tc_fd
, "Stop operation was requested on the "
4214 "requestor component itself.");
4217 boolean target_inactive
= FALSE
;
4218 switch (target
->tc_state
) {
4220 if (!target
->is_alive
) error("PTC %d cannot be in state STOPPED "
4221 "because it is not an alive type PTC.", component_reference
);
4224 target_inactive
= TRUE
;
4235 if (target
->is_alive
) {
4236 if (target_inactive
) {
4237 // do nothing, just send a STOP_ACK to tc
4242 target
->tc_state
= TC_STOPPING
;
4245 // the target is not an alive type PTC: stop operation means kill
4247 if (target_inactive
) target
->tc_state
= PTC_KILLING
;
4248 else target
->tc_state
= PTC_STOPPING_KILLING
;
4250 // a STOP or KILL message was sent out
4251 target
->stop_requested
= TRUE
;
4252 init_requestors(&target
->stopping_killing
.stop_requestors
, tc
);
4253 init_requestors(&target
->stopping_killing
.kill_requestors
, NULL
);
4254 start_kill_timer(target
);
4255 tc
->tc_state
= TC_STOP
;
4259 if (target
->is_alive
) {
4260 // do nothing if the PTC is alive
4266 case PTC_STOPPING_KILLING
:
4267 // the PTC is currently being stopped
4268 add_requestor(&target
->stopping_killing
.stop_requestors
, tc
);
4269 tc
->tc_state
= TC_STOP
;
4274 // the PTC is already terminated, do nothing
4278 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4279 "stopped because it is currently being started.",
4280 component_reference
);
4283 send_error(tc
->tc_fd
, "The argument of stop operation (%d) is a "
4284 "component reference that belongs to an earlier testcase.",
4285 component_reference
);
4288 send_error(tc
->tc_fd
, "The test component that the stop operation "
4289 "refers to (%d) is in invalid state.", component_reference
);
4293 void MainController::process_kill_req(component_struct
*tc
)
4295 if (!request_allowed(tc
, "KILL_REQ")) return;
4297 component component_reference
= tc
->text_buf
->pull_int().get_val();
4298 switch (component_reference
) {
4300 send_error_str(tc
->tc_fd
, "Kill operation was requested on the null "
4301 "component reference.");
4304 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4305 "component reference of the MTC.");
4307 case SYSTEM_COMPREF
:
4308 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4309 "component reference of the system.");
4312 send_error_str(tc
->tc_fd
, "Kill operation was requested on "
4313 "'any component'.");
4317 if (kill_all_components(FALSE
)) send_kill_ack(mtc
);
4319 mtc
->tc_state
= MTC_ALL_COMPONENT_KILL
;
4322 } else send_error_str(tc
->tc_fd
, "Operation 'all component.kill' can "
4323 "only be performed on the MTC.");
4328 // the operation refers to a specific PTC
4329 component_struct
*target
= lookup_component(component_reference
);
4330 if (target
== NULL
) {
4331 send_error(tc
->tc_fd
, "The argument of kill operation is an "
4332 "invalid component reference: %d.", component_reference
);
4334 } else if (target
== tc
) {
4335 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4336 "requestor component itself.");
4339 boolean target_inactive
= FALSE
;
4340 switch (target
->tc_state
) {
4342 // the done status of this PTC is already sent out
4343 // and it will not be cancelled in the future
4344 free_requestors(&target
->done_requestors
);
4347 target_inactive
= TRUE
;
4359 if (target_inactive
) {
4360 // the PTC was inactive
4361 target
->tc_state
= PTC_KILLING
;
4362 if (!target
->is_alive
) target
->stop_requested
= TRUE
;
4364 // the PTC was active
4365 target
->tc_state
= PTC_STOPPING_KILLING
;
4366 target
->stop_requested
= TRUE
;
4368 init_requestors(&target
->stopping_killing
.stop_requestors
, NULL
);
4369 init_requestors(&target
->stopping_killing
.kill_requestors
, tc
);
4370 start_kill_timer(target
);
4371 tc
->tc_state
= TC_KILL
;
4375 // the PTC is currently being stopped
4377 target
->tc_state
= PTC_STOPPING_KILLING
;
4378 if (target
->kill_timer
!= NULL
) cancel_timer(target
->kill_timer
);
4379 start_kill_timer(target
);
4382 case PTC_STOPPING_KILLING
:
4383 // the PTC is currently being terminated
4384 add_requestor(&target
->stopping_killing
.kill_requestors
, tc
);
4385 tc
->tc_state
= TC_KILL
;
4390 // the PTC is already terminated
4394 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4395 "killed because it is currently being started.",
4396 component_reference
);
4399 send_error(tc
->tc_fd
, "The argument of kill operation (%d) is a "
4400 "component reference that belongs to an earlier testcase.",
4401 component_reference
);
4404 send_error(tc
->tc_fd
, "The test component that the kill operation "
4405 "refers to (%d) is in invalid state.", component_reference
);
4409 void MainController::process_is_running(component_struct
*tc
)
4411 if (!request_allowed(tc
, "IS_RUNNING")) return;
4413 component component_reference
= tc
->text_buf
->pull_int().get_val();
4414 switch (component_reference
) {
4416 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4417 "null component reference.");
4420 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4421 "component reference of the MTC.");
4423 case SYSTEM_COMPREF
:
4424 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4425 "component reference of the system.");
4428 if (tc
== mtc
) send_running(mtc
, is_any_component_running());
4429 else send_error_str(tc
->tc_fd
, "Operation 'any component.running' "
4430 "can only be performed on the MTC.");
4433 if (tc
== mtc
) send_running(mtc
, is_all_component_running());
4434 else send_error_str(tc
->tc_fd
, "Operation 'all component.running' "
4435 "can only be performed on the MTC.");
4440 // the operation refers to a specific PTC
4441 component_struct
*comp
= lookup_component(component_reference
);
4443 send_error(tc
->tc_fd
, "The argument of running operation is an "
4444 "invalid component reference: %d.", component_reference
);
4447 switch (comp
->tc_state
) {
4459 case PTC_STOPPING_KILLING
:
4460 send_running(tc
, TRUE
);
4467 send_running(tc
, FALSE
);
4470 send_error(tc
->tc_fd
, "The argument of running operation (%d) is a "
4471 "component reference that belongs to an earlier testcase.",
4472 component_reference
);
4475 send_error(tc
->tc_fd
, "The test component that the running operation "
4476 "refers to (%d) is in invalid state.", component_reference
);
4480 void MainController::process_is_alive(component_struct
*tc
)
4482 if (!request_allowed(tc
, "IS_ALIVE")) return;
4484 component component_reference
= tc
->text_buf
->pull_int().get_val();
4485 switch (component_reference
) {
4487 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4488 "null component reference.");
4491 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4492 "component reference of the MTC.");
4494 case SYSTEM_COMPREF
:
4495 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4496 "component reference of the system.");
4499 if (tc
== mtc
) send_alive(mtc
, is_any_component_alive());
4500 else send_error_str(tc
->tc_fd
, "Operation 'any component.alive' "
4501 "can only be performed on the MTC.");
4504 if (tc
== mtc
) send_alive(mtc
, is_all_component_alive());
4505 else send_error_str(tc
->tc_fd
, "Operation 'all component.alive' "
4506 "can only be performed on the MTC.");
4511 // the operation refers to a specific PTC
4512 component_struct
*comp
= lookup_component(component_reference
);
4514 send_error(tc
->tc_fd
, "The argument of alive operation is an "
4515 "invalid component reference: %d.", component_reference
);
4518 switch (comp
->tc_state
) {
4533 case PTC_STOPPING_KILLING
:
4534 send_alive(tc
, TRUE
);
4538 send_alive(tc
, FALSE
);
4541 send_error(tc
->tc_fd
, "The argument of alive operation (%d) is a "
4542 "component reference that belongs to an earlier testcase.",
4543 component_reference
);
4546 send_error(tc
->tc_fd
, "The test component that the alive operation "
4547 "refers to (%d) is in invalid state.", component_reference
);
4551 void MainController::process_done_req(component_struct
*tc
)
4553 if (!request_allowed(tc
, "DONE_REQ")) return;
4555 component component_reference
= tc
->text_buf
->pull_int().get_val();
4556 switch (component_reference
) {
4558 send_error_str(tc
->tc_fd
, "Done operation was requested on the null "
4559 "component reference.");
4562 send_error_str(tc
->tc_fd
, "Done operation was requested on the "
4563 "component reference of the MTC.");
4565 case SYSTEM_COMPREF
:
4566 send_error_str(tc
->tc_fd
, "Done operation was requested on the "
4567 "component reference of the system.");
4571 boolean answer
= is_any_component_done();
4572 send_done_ack(mtc
, answer
, NULL
, 0, NULL
);
4573 if (answer
) any_component_done_sent
= TRUE
;
4574 else any_component_done_requested
= TRUE
;
4575 } else send_error_str(tc
->tc_fd
, "Operation 'any component.done' can "
4576 "only be performed on the MTC.");
4580 boolean answer
= !is_any_component_running();
4581 send_done_ack(mtc
, answer
, NULL
, 0, NULL
);
4582 if (!answer
) all_component_done_requested
= TRUE
;
4583 } else send_error_str(tc
->tc_fd
, "Operation 'all component.done' can "
4584 "only be performed on the MTC.");
4589 // the operation refers to a specific PTC
4590 component_struct
*comp
= lookup_component(component_reference
);
4592 send_error(tc
->tc_fd
, "The argument of done operation is an "
4593 "invalid component reference: %d.", component_reference
);
4596 switch (comp
->tc_state
) {
4598 // this answer has to be cancelled when the component is re-started
4599 add_requestor(&comp
->done_requestors
, tc
);
4604 send_done_ack(tc
, TRUE
, comp
->return_type
, comp
->return_value_len
,
4605 comp
->return_value
);
4619 case PTC_STOPPING_KILLING
:
4620 send_done_ack(tc
, FALSE
, NULL
, 0, NULL
);
4621 add_requestor(&comp
->done_requestors
, tc
);
4624 send_error(tc
->tc_fd
, "The argument of done operation (%d) is a "
4625 "component reference that belongs to an earlier testcase.",
4626 component_reference
);
4629 send_error(tc
->tc_fd
, "The test component that the done operation "
4630 "refers to (%d) is in invalid state.", component_reference
);
4634 void MainController::process_killed_req(component_struct
*tc
)
4636 if (!request_allowed(tc
, "KILLED_REQ")) return;
4638 component component_reference
= tc
->text_buf
->pull_int().get_val();
4639 switch (component_reference
) {
4641 send_error_str(tc
->tc_fd
, "Killed operation was requested on the null "
4642 "component reference.");
4645 send_error_str(tc
->tc_fd
, "Killed operation was requested on the "
4646 "component reference of the MTC.");
4648 case SYSTEM_COMPREF
:
4649 send_error_str(tc
->tc_fd
, "Killed operation was requested on the "
4650 "component reference of the system.");
4654 boolean answer
= !is_all_component_alive();
4655 send_killed_ack(mtc
, answer
);
4656 if (!answer
) any_component_killed_requested
= TRUE
;
4657 } else send_error_str(tc
->tc_fd
, "Operation 'any component.killed' can "
4658 "only be performed on the MTC.");
4662 boolean answer
= !is_any_component_alive();
4663 send_killed_ack(mtc
, answer
);
4664 if (!answer
) all_component_killed_requested
= TRUE
;
4665 } else send_error_str(tc
->tc_fd
, "Operation 'all component.killed' can "
4666 "only be performed on the MTC.");
4671 // the operation refers to a specific PTC
4672 component_struct
*comp
= lookup_component(component_reference
);
4674 send_error(tc
->tc_fd
, "The argument of killed operation is an "
4675 "invalid component reference: %d.", component_reference
);
4678 switch (comp
->tc_state
) {
4681 send_killed_ack(tc
, TRUE
);
4697 case PTC_STOPPING_KILLING
:
4698 send_killed_ack(tc
, FALSE
);
4699 add_requestor(&comp
->killed_requestors
, tc
);
4702 send_error(tc
->tc_fd
, "The argument of killed operation (%d) is a "
4703 "component reference that belongs to an earlier testcase.",
4704 component_reference
);
4707 send_error(tc
->tc_fd
, "The test component that the killed operation "
4708 "refers to (%d) is in invalid state.", component_reference
);
4712 void MainController::process_cancel_done_ack(component_struct
*tc
)
4714 component component_reference
= tc
->text_buf
->pull_int().get_val();
4715 switch (component_reference
) {
4717 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the null "
4718 "component reference.");
4721 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the "
4722 "component reference of the MTC.");
4724 case SYSTEM_COMPREF
:
4725 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the "
4726 "component reference of the system.");
4729 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to "
4730 "'any component'.");
4733 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to "
4734 "'all component'.");
4739 component_struct
*started_tc
= lookup_component(component_reference
);
4740 if (started_tc
== NULL
) {
4741 send_error(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to an invalid "
4742 "component reference: %d.", component_reference
);
4745 done_cancelled(tc
, started_tc
);
4746 remove_requestor(&tc
->cancel_done_sent_for
, started_tc
);
4749 void MainController::process_connect_req(component_struct
*tc
)
4751 if (!request_allowed(tc
, "CONNECT_REQ")) return;
4753 Text_Buf
& text_buf
= *tc
->text_buf
;
4754 component src_compref
= text_buf
.pull_int().get_val();
4755 char *src_port
= text_buf
.pull_string();
4756 component dst_compref
= text_buf
.pull_int().get_val();
4757 char *dst_port
= text_buf
.pull_string();
4759 if (!valid_endpoint(src_compref
, TRUE
, tc
, "connect") ||
4760 !valid_endpoint(dst_compref
, TRUE
, tc
, "connect")) {
4766 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4769 conn
= new port_connection
;
4770 conn
->transport_type
=
4771 choose_port_connection_transport(src_compref
, dst_compref
);
4772 conn
->head
.comp_ref
= src_compref
;
4773 conn
->head
.port_name
= src_port
;
4774 conn
->tail
.comp_ref
= dst_compref
;
4775 conn
->tail
.port_name
= dst_port
;
4776 init_requestors(&conn
->requestors
, tc
);
4777 add_connection(conn
);
4778 // conn->head and tail is now in canonical order
4779 switch (conn
->transport_type
) {
4780 case TRANSPORT_LOCAL
:
4781 // send an empty string instead of component name
4782 // the component should already know its own name
4783 send_connect(components
[conn
->head
.comp_ref
], conn
->head
.port_name
,
4784 conn
->tail
.comp_ref
, NULL
, conn
->tail
.port_name
,
4785 conn
->transport_type
, 0, NULL
);
4786 conn
->conn_state
= CONN_CONNECTING
;
4788 case TRANSPORT_UNIX_STREAM
:
4789 case TRANSPORT_INET_STREAM
:
4790 // conn->head will be the server side
4791 if (conn
->tail
.comp_ref
!= MTC_COMPREF
&&
4792 conn
->tail
.comp_ref
!= conn
->head
.comp_ref
) {
4793 // send the name of conn->tail
4794 send_connect_listen(components
[conn
->head
.comp_ref
],
4795 conn
->head
.port_name
, conn
->tail
.comp_ref
,
4796 components
[conn
->tail
.comp_ref
]->comp_name
,
4797 conn
->tail
.port_name
, conn
->transport_type
);
4799 // send an empty string instead of the name of conn->tail if
4800 // it is known by conn->head
4801 send_connect_listen(components
[conn
->head
.comp_ref
],
4802 conn
->head
.port_name
, conn
->tail
.comp_ref
, NULL
,
4803 conn
->tail
.port_name
, conn
->transport_type
);
4805 conn
->conn_state
= CONN_LISTENING
;
4808 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4809 "be established because no suitable transport mechanism is "
4810 "available on the corresponding host(s).", src_compref
,
4811 src_port
, dst_compref
, dst_port
);
4812 remove_connection(conn
);
4815 tc
->tc_state
= TC_CONNECT
;
4818 switch (conn
->conn_state
) {
4819 case CONN_LISTENING
:
4820 case CONN_CONNECTING
:
4821 add_requestor(&conn
->requestors
, tc
);
4822 tc
->tc_state
= TC_CONNECT
;
4825 case CONN_CONNECTED
:
4826 send_connect_ack(tc
);
4828 case CONN_DISCONNECTING
:
4829 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4830 "be established because a disconnect operation is in progress "
4831 "on it.", src_compref
, src_port
, dst_compref
, dst_port
);
4834 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4835 "be established due to an internal error in the MC.",
4836 src_compref
, src_port
, dst_compref
, dst_port
);
4837 error("The port connection %d:%s - %d:%s is in invalid state "
4838 "when a connect operation was requested on it.", src_compref
,
4839 src_port
, dst_compref
, dst_port
);
4846 void MainController::process_connect_listen_ack(component_struct
*tc
,
4849 if (!message_expected(tc
, "CONNECT_LISTEN_ACK")) return;
4851 Text_Buf
& text_buf
= *tc
->text_buf
;
4852 component src_compref
= tc
->comp_ref
;
4853 char *src_port
= text_buf
.pull_string();
4854 component dst_compref
= text_buf
.pull_int().get_val();
4855 char *dst_port
= text_buf
.pull_string();
4856 transport_type_enum transport_type
=
4857 (transport_type_enum
)text_buf
.pull_int().get_val();
4858 int local_addr_begin
= text_buf
.get_pos();
4859 int local_addr_len
= message_end
- local_addr_begin
;
4860 const void *local_addr_ptr
= text_buf
.get_data() + local_addr_begin
;
4862 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4865 // this message must arrive in the right state
4866 // and from the server side (head)
4867 if (conn
->conn_state
!= CONN_LISTENING
||
4868 conn
->head
.comp_ref
!= src_compref
||
4869 strcmp(conn
->head
.port_name
, src_port
)) {
4870 send_error(tc
->tc_fd
, "Unexpected message CONNECT_LISTEN_ACK was "
4871 "received for port connection %d:%s - %d:%s.",
4872 src_compref
, src_port
, dst_compref
, dst_port
);
4876 } else if (conn
->transport_type
!= transport_type
) {
4877 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4878 "connection %d:%s - %d:%s contains wrong transport type: %s "
4879 "was expected instead of %s.", src_compref
, src_port
,
4880 dst_compref
, dst_port
, get_transport_name(conn
->transport_type
),
4881 get_transport_name(transport_type
));
4886 component_struct
*dst_comp
= components
[dst_compref
];
4887 switch (dst_comp
->tc_state
) {
4902 if (src_compref
!= MTC_COMPREF
&& src_compref
!= dst_compref
) {
4903 // send the name of tc
4904 send_connect(dst_comp
, dst_port
, src_compref
, tc
->comp_name
,
4905 src_port
, transport_type
, local_addr_len
, local_addr_ptr
);
4907 // send an empty string instead of the name of tc if it is
4908 // known by dst_comp
4909 send_connect(dst_comp
, dst_port
, src_compref
, NULL
, src_port
,
4910 transport_type
, local_addr_len
, local_addr_ptr
);
4912 conn
->conn_state
= CONN_CONNECTING
;
4915 send_disconnect_to_server(conn
);
4916 send_error_to_connect_requestors(conn
, "test component %d has "
4917 "terminated during connection setup.", dst_compref
);
4918 remove_connection(conn
);
4922 // the connection does not exist anymore
4923 // check whether the transport type is valid
4924 switch (transport_type
) {
4925 case TRANSPORT_LOCAL
:
4926 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4927 "connection %d:%s - %d:%s cannot refer to transport type %s.",
4928 src_compref
, src_port
, dst_compref
, dst_port
,
4929 get_transport_name(transport_type
));
4931 case TRANSPORT_INET_STREAM
:
4932 case TRANSPORT_UNIX_STREAM
:
4935 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4936 "connection %d:%s - %d:%s refers to invalid transport type %d.",
4937 src_compref
, src_port
, dst_compref
, dst_port
, transport_type
);
4945 void MainController::process_connected(component_struct
*tc
)
4947 if (!message_expected(tc
, "CONNECTED")) return;
4949 Text_Buf
& text_buf
= *tc
->text_buf
;
4950 component src_compref
= tc
->comp_ref
;
4951 char *src_port
= text_buf
.pull_string();
4952 component dst_compref
= text_buf
.pull_int().get_val();
4953 char *dst_port
= text_buf
.pull_string();
4955 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4958 // this message must arrive in the right state
4959 // and from the server side (head)
4960 if (conn
->conn_state
== CONN_CONNECTING
&&
4961 conn
->head
.comp_ref
== src_compref
&&
4962 !strcmp(conn
->head
.port_name
, src_port
)) {
4963 send_connect_ack_to_requestors(conn
);
4964 conn
->conn_state
= CONN_CONNECTED
;
4967 send_error(tc
->tc_fd
, "Unexpected CONNECTED message was "
4968 "received for port connection %d:%s - %d:%s.",
4969 src_compref
, src_port
, dst_compref
, dst_port
);
4972 // do nothing if the connection does not exist anymore
4978 void MainController::process_connect_error(component_struct
*tc
)
4980 if (!message_expected(tc
, "CONNECT_ERROR")) return;
4982 Text_Buf
& text_buf
= *tc
->text_buf
;
4983 component src_compref
= tc
->comp_ref
;
4984 char *src_port
= text_buf
.pull_string();
4985 component dst_compref
= text_buf
.pull_int().get_val();
4986 char *dst_port
= text_buf
.pull_string();
4987 char *reason
= text_buf
.pull_string();
4989 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4992 switch (conn
->conn_state
) {
4993 case CONN_CONNECTING
:
4994 // in this state both endpoints can report error
4995 if (conn
->transport_type
!= TRANSPORT_LOCAL
&&
4996 conn
->tail
.comp_ref
== src_compref
&&
4997 !strcmp(conn
->tail
.port_name
, src_port
)) {
4998 // shut down the server side (head) only if the error was reported
4999 // by the client side (tail)
5000 send_disconnect_to_server(conn
);
5003 case CONN_LISTENING
:
5004 // in this state only the server side (head) can report the error
5005 if (conn
->head
.comp_ref
== src_compref
&&
5006 !strcmp(conn
->head
.port_name
, src_port
)) break;
5008 send_error(tc
->tc_fd
, "Unexpected message CONNECT_ERROR was "
5009 "received for port connection %d:%s - %d:%s.",
5010 src_compref
, src_port
, dst_compref
, dst_port
);
5016 send_error_to_connect_requestors(conn
, "test component %d reported "
5017 "error: %s", src_compref
, reason
);
5018 remove_connection(conn
);
5021 // do nothing if the connection does not exist anymore
5028 void MainController::process_disconnect_req(component_struct
*tc
)
5030 if (!request_allowed(tc
, "DISCONNECT_REQ")) return;
5032 Text_Buf
& text_buf
= *tc
->text_buf
;
5033 component src_compref
= text_buf
.pull_int().get_val();
5034 char *src_port
= text_buf
.pull_string();
5035 component dst_compref
= text_buf
.pull_int().get_val();
5036 char *dst_port
= text_buf
.pull_string();
5038 if (!valid_endpoint(src_compref
, FALSE
, tc
, "disconnect") ||
5039 !valid_endpoint(dst_compref
, FALSE
, tc
, "disconnect")) {
5045 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
5048 switch (conn
->conn_state
) {
5049 case CONN_LISTENING
:
5050 case CONN_CONNECTING
:
5051 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
5052 "be destroyed because a connect operation is in progress "
5053 "on it.", src_compref
, src_port
, dst_compref
, dst_port
);
5055 case CONN_CONNECTED
:
5056 send_disconnect(components
[conn
->tail
.comp_ref
],
5057 conn
->tail
.port_name
, conn
->head
.comp_ref
,
5058 conn
->head
.port_name
);
5059 conn
->conn_state
= CONN_DISCONNECTING
;
5061 case CONN_DISCONNECTING
:
5062 add_requestor(&conn
->requestors
, tc
);
5063 tc
->tc_state
= TC_DISCONNECT
;
5067 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
5068 "be destroyed due to an internal error in the MC.",
5069 src_compref
, src_port
, dst_compref
, dst_port
);
5070 error("The port connection %d:%s - %d:%s is in invalid state when "
5071 "a disconnect operation was requested on it.", src_compref
,
5072 src_port
, dst_compref
, dst_port
);
5075 // the connection is already terminated
5076 // send the acknowledgement immediately
5077 send_disconnect_ack(tc
);
5084 void MainController::process_disconnected(component_struct
*tc
)
5086 if (!message_expected(tc
, "DISCONNECTED")) return;
5088 Text_Buf
& text_buf
= *tc
->text_buf
;
5089 component src_compref
= tc
->comp_ref
;
5090 char *src_port
= text_buf
.pull_string();
5091 component dst_compref
= text_buf
.pull_int().get_val();
5092 char *dst_port
= text_buf
.pull_string();
5094 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
5097 switch (conn
->conn_state
) {
5098 case CONN_LISTENING
:
5099 // in this state only the server side (head) can report the end of
5101 if (conn
->head
.comp_ref
!= src_compref
||
5102 strcmp(conn
->head
.port_name
, src_port
)) {
5103 send_error(tc
->tc_fd
, "Unexpected message DISCONNECTED was "
5104 "received for port connection %d:%s - %d:%s.",
5105 src_compref
, src_port
, dst_compref
, dst_port
);
5109 case CONN_CONNECTING
:
5110 // in this state both ends can report the end of the connection
5111 send_error_to_connect_requestors(conn
, "test component %d "
5112 "reported end of the connection during connection setup.",
5114 remove_connection(conn
);
5117 case CONN_CONNECTED
:
5118 remove_connection(conn
);
5121 case CONN_DISCONNECTING
:
5122 send_disconnect_ack_to_requestors(conn
);
5123 remove_connection(conn
);
5127 error("The port connection %d:%s - %d:%s is in invalid state when "
5128 "MC was notified about its termination.", src_compref
, src_port
,
5129 dst_compref
, dst_port
);
5138 void MainController::process_map_req(component_struct
*tc
)
5140 if (!request_allowed(tc
, "MAP_REQ")) return;
5142 Text_Buf
& text_buf
= *tc
->text_buf
;
5143 component src_compref
= text_buf
.pull_int().get_val();
5144 char *src_port
= text_buf
.pull_string();
5145 char *system_port
= text_buf
.pull_string();
5147 if (!valid_endpoint(src_compref
, TRUE
, tc
, "map")) {
5149 delete [] system_port
;
5153 port_connection
*conn
= find_connection(src_compref
, src_port
,
5154 SYSTEM_COMPREF
, system_port
);
5156 send_map(components
[src_compref
], src_port
, system_port
);
5157 conn
= new port_connection
;
5158 conn
->head
.comp_ref
= src_compref
;
5159 conn
->head
.port_name
= src_port
;
5160 conn
->tail
.comp_ref
= SYSTEM_COMPREF
;
5161 conn
->tail
.port_name
= system_port
;
5162 conn
->conn_state
= CONN_MAPPING
;
5163 init_requestors(&conn
->requestors
, tc
);
5164 add_connection(conn
);
5165 tc
->tc_state
= TC_MAP
;
5168 switch (conn
->conn_state
) {
5170 add_requestor(&conn
->requestors
, tc
);
5171 tc
->tc_state
= TC_MAP
;
5177 case CONN_UNMAPPING
:
5178 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s cannot "
5179 "be established because an unmap operation is in progress "
5180 "on it.", src_compref
, src_port
, system_port
);
5183 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s is in "
5184 "invalid state.", src_compref
, src_port
, system_port
);
5187 delete [] system_port
;
5191 void MainController::process_mapped(component_struct
*tc
)
5193 if (!message_expected(tc
, "MAPPED")) return;
5195 Text_Buf
& text_buf
= *tc
->text_buf
;
5196 component src_compref
= tc
->comp_ref
;
5197 char *src_port
= text_buf
.pull_string();
5198 char *system_port
= text_buf
.pull_string();
5200 port_connection
*conn
= find_connection(src_compref
, src_port
,
5201 SYSTEM_COMPREF
, system_port
);
5203 send_error(tc
->tc_fd
, "The MAPPED message refers to a "
5204 "non-existent port mapping %d:%s - system:%s.",
5205 src_compref
, src_port
, system_port
);
5206 } else if (conn
->conn_state
!= CONN_MAPPING
) {
5207 send_error(tc
->tc_fd
, "Unexpected MAPPED message was "
5208 "received for port mapping %d:%s - system:%s.",
5209 src_compref
, src_port
, system_port
);
5211 for (int i
= 0; ; i
++) {
5212 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
5213 if (comp
== NULL
) break;
5214 if (comp
->tc_state
== TC_MAP
) {
5216 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
5217 else comp
->tc_state
= PTC_FUNCTION
;
5220 free_requestors(&conn
->requestors
);
5221 conn
->conn_state
= CONN_MAPPED
;
5226 delete [] system_port
;
5229 void MainController::process_unmap_req(component_struct
*tc
)
5231 if (!request_allowed(tc
, "UNMAP_REQ")) return;
5233 Text_Buf
& text_buf
= *tc
->text_buf
;
5234 component src_compref
= text_buf
.pull_int().get_val();
5235 char *src_port
= text_buf
.pull_string();
5236 char *system_port
= text_buf
.pull_string();
5238 if (!valid_endpoint(src_compref
, FALSE
, tc
, "unmap")) {
5240 delete [] system_port
;
5244 port_connection
*conn
= find_connection(src_compref
, src_port
,
5245 SYSTEM_COMPREF
, system_port
);
5249 switch (conn
->conn_state
) {
5251 send_unmap(components
[src_compref
], src_port
, system_port
);
5252 conn
->conn_state
= CONN_UNMAPPING
;
5253 case CONN_UNMAPPING
:
5254 add_requestor(&conn
->requestors
, tc
);
5255 tc
->tc_state
= TC_UNMAP
;
5259 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s cannot "
5260 "be destroyed because a map operation is in progress "
5261 "on it.", src_compref
, src_port
, system_port
);
5264 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s is in "
5265 "invalid state.", src_compref
, src_port
, system_port
);
5270 delete [] system_port
;
5273 void MainController::process_unmapped(component_struct
*tc
)
5275 if (!message_expected(tc
, "UNMAPPED")) return;
5277 Text_Buf
& text_buf
= *tc
->text_buf
;
5278 component src_compref
= tc
->comp_ref
;
5279 char *src_port
= text_buf
.pull_string();
5280 char *system_port
= text_buf
.pull_string();
5282 port_connection
*conn
= find_connection(src_compref
, src_port
,
5283 SYSTEM_COMPREF
, system_port
);
5285 switch (conn
->conn_state
) {
5288 case CONN_UNMAPPING
:
5289 destroy_mapping(conn
);
5292 send_error(tc
->tc_fd
, "Unexpected UNMAPPED message was "
5293 "received for port mapping %d:%s - system:%s.",
5294 src_compref
, src_port
, system_port
);
5299 delete [] system_port
;
5303 void MainController::process_testcase_started()
5305 if (mc_state
!= MC_EXECUTING_CONTROL
) {
5306 send_error_str(mtc
->tc_fd
, "Unexpected message TESTCASE_STARTED "
5311 Text_Buf
& text_buf
= *mtc
->text_buf
;
5312 text_buf
.pull_qualified_name(mtc
->tc_fn_name
);
5313 text_buf
.pull_qualified_name(mtc
->comp_type
);
5314 text_buf
.pull_qualified_name(system
->comp_type
);
5316 mtc
->tc_state
= MTC_TESTCASE
;
5317 mc_state
= MC_EXECUTING_TESTCASE
;
5318 tc_first_comp_ref
= next_comp_ref
;
5319 any_component_done_requested
= FALSE
;
5320 any_component_done_sent
= FALSE
;
5321 all_component_done_requested
= FALSE
;
5322 any_component_killed_requested
= FALSE
;
5323 all_component_killed_requested
= FALSE
;
5328 void MainController::process_testcase_finished()
5330 if (mc_state
!= MC_EXECUTING_TESTCASE
) {
5331 send_error_str(mtc
->tc_fd
, "Unexpected message TESTCASE_FINISHED "
5336 boolean ready_to_finish
= kill_all_components(TRUE
);
5338 mc_state
= MC_TERMINATING_TESTCASE
;
5339 mtc
->tc_state
= MTC_TERMINATING_TESTCASE
;
5340 mtc
->local_verdict
= (verdicttype
)mtc
->text_buf
->pull_int().get_val();
5341 mtc
->verdict_reason
= mtc
->text_buf
->pull_string();
5342 mtc
->stop_requested
= FALSE
;
5343 if (mtc
->kill_timer
!= NULL
) {
5344 cancel_timer(mtc
->kill_timer
);
5345 mtc
->kill_timer
= NULL
;
5347 any_component_done_requested
= FALSE
;
5348 any_component_done_sent
= FALSE
;
5349 all_component_done_requested
= FALSE
;
5350 any_component_killed_requested
= FALSE
;
5351 all_component_killed_requested
= FALSE
;
5353 if (ready_to_finish
) finish_testcase();
5358 void MainController::process_mtc_ready()
5360 if (mc_state
!= MC_EXECUTING_CONTROL
|| mtc
->tc_state
!= MTC_CONTROLPART
) {
5361 send_error_str(mtc
->tc_fd
, "Unexpected message MTC_READY was "
5365 mc_state
= MC_READY
;
5366 mtc
->tc_state
= TC_IDLE
;
5367 mtc
->stop_requested
= FALSE
;
5368 if (mtc
->kill_timer
!= NULL
) {
5369 cancel_timer(mtc
->kill_timer
);
5370 mtc
->kill_timer
= NULL
;
5372 stop_requested
= FALSE
;
5373 notify("Test execution finished.");
5377 void MainController::process_stopped(component_struct
*tc
, int message_end
)
5379 switch (tc
->tc_state
) {
5382 case PTC_STOPPING_KILLING
:
5383 // only alive PTCs are allowed to send STOPPED
5384 if (tc
->is_alive
) break;
5386 send_error_str(tc
->tc_fd
, "Unexpected message STOPPED was received.");
5389 Text_Buf
& text_buf
= *tc
->text_buf
;
5390 delete [] tc
->return_type
;
5391 tc
->return_type
= text_buf
.pull_string();
5392 tc
->return_value_len
= message_end
- text_buf
.get_pos();
5393 Free(tc
->return_value
);
5394 tc
->return_value
= Malloc(tc
->return_value_len
);
5395 text_buf
.pull_raw(tc
->return_value_len
, tc
->return_value
);
5396 free_qualified_name(&tc
->tc_fn_name
);
5397 component_stopped(tc
);
5401 void MainController::process_stopped_killed(component_struct
*tc
,
5404 switch (tc
->tc_state
) {
5415 case PTC_STOPPING_KILLING
:
5418 send_error_str(tc
->tc_fd
, "Unexpected message STOPPED_KILLED was "
5420 // also notify the user because the above message may get lost
5421 notify("Unexpected message STOPPED_KILLED was received from PTC %d.",
5425 Text_Buf
& text_buf
= *tc
->text_buf
;
5426 tc
->local_verdict
= (verdicttype
)text_buf
.pull_int().get_val();
5427 tc
->verdict_reason
= text_buf
.pull_string();
5428 tc
->return_type
= text_buf
.pull_string();
5429 tc
->return_value_len
= message_end
- text_buf
.get_pos();
5430 tc
->return_value
= Malloc(tc
->return_value_len
);
5431 text_buf
.pull_raw(tc
->return_value_len
, tc
->return_value
);
5432 // start a guard timer to detect whether the control connection is closed
5434 if (tc
->tc_state
!= PTC_STOPPING_KILLING
) start_kill_timer(tc
);
5435 component_terminated(tc
);
5439 void MainController::process_killed(component_struct
*tc
)
5441 switch (tc
->tc_state
) {
5447 send_error_str(tc
->tc_fd
, "Unexpected message KILLED was received.");
5448 // also notify the user because the above message may get lost
5449 notify("Unexpected message KILLED was received from PTC %d.",
5453 tc
->local_verdict
= (verdicttype
)tc
->text_buf
->pull_int().get_val();
5454 tc
->verdict_reason
= tc
->text_buf
->pull_string();
5455 // start a guard timer to detect whether the control connection is closed
5457 if (tc
->tc_state
!= PTC_KILLING
) start_kill_timer(tc
);
5458 component_terminated(tc
);
5462 void MainController::initialize(UserInterface
& par_ui
, int par_max_ptcs
)
5466 max_ptcs
= par_max_ptcs
;
5468 mc_state
= MC_INACTIVE
;
5471 if (uname(&buf
) < 0) fatal_error("MainController::initialize: "
5472 "uname() system call failed.");
5473 mc_hostname
= mprintf("MC@%s", buf
.nodename
);
5477 if (pthread_mutex_init(&mutex
, NULL
))
5478 fatal_error("MainController::initialize: pthread_mutex_init failed.");
5481 epoll_events
= NULL
;
5488 pollfds_modified
= FALSE
;
5494 unknown_head
= NULL
;
5495 unknown_tail
= NULL
;
5499 init_string_set(&assigned_components
);
5500 all_components_assigned
= FALSE
;
5506 version_known
= FALSE
;
5515 next_comp_ref
= FIRST_PTC_COMPREF
;
5517 stop_after_tc
= FALSE
;
5518 stop_requested
= FALSE
;
5527 wakeup_reason
= REASON_NOTHING
;
5529 register_termination_handlers();
5532 void MainController::terminate()
5535 destroy_host_groups();
5537 pthread_mutex_destroy(&mutex
);
5540 void MainController::add_host(const char *group_name
, const char *host_name
)
5543 if (mc_state
!= MC_INACTIVE
) {
5544 error("MainController::add_host: called in wrong state.");
5548 host_group_struct
*group
= add_host_group(group_name
);
5549 if (host_name
!= NULL
) {
5550 if (group
->has_all_hosts
) error("Redundant member `%s' was ignored in "
5551 "host group `%s'. All hosts (`*') are already the members of the "
5552 "group.", host_name
, group_name
);
5554 if (set_has_string(&group
->host_members
, host_name
)) {
5555 error("Duplicate member `%s' was ignored in host group "
5556 "`%s'.", host_name
, group_name
);
5557 } else add_string_to_set(&group
->host_members
, host_name
);
5560 if (group
->has_all_hosts
) error("Duplicate member `*' was ignored in "
5561 "host group `%s'.", group_name
);
5563 for (int i
= 0; ; i
++) {
5564 const char *group_member
=
5565 get_string_from_set(&group
->host_members
, i
);
5566 if (group_member
== NULL
) break;
5567 error("Redundant member `%s' was ignored in host group `%s'. "
5568 "All hosts (`*') are already the members of the group.",
5569 group_member
, group_name
);
5571 free_string_set(&group
->host_members
);
5572 group
->has_all_hosts
= TRUE
;
5578 void MainController::assign_component(const char *host_or_group
,
5579 const char *component_id
)
5582 if (mc_state
!= MC_INACTIVE
) {
5583 error("MainController::assign_component: called in wrong state.");
5587 host_group_struct
*group
= add_host_group(host_or_group
);
5588 if (component_id
== NULL
) {
5589 if (all_components_assigned
) {
5590 for (int i
= 0; i
< n_host_groups
; i
++) {
5591 if (host_groups
[i
].has_all_components
) {
5592 error("Duplicate assignment of all components (*) to host "
5593 "group `%s'. Previous assignment to group `%s' is "
5594 "ignored.", host_or_group
, host_groups
[i
].group_name
);
5595 host_groups
[i
].has_all_components
= FALSE
;
5598 } else all_components_assigned
= TRUE
;
5599 group
->has_all_components
= TRUE
;
5601 if (set_has_string(&assigned_components
, component_id
)) {
5602 for (int i
= 0; i
< n_host_groups
; i
++) {
5603 if (set_has_string(&host_groups
[i
].assigned_components
,
5605 error("Duplicate assignment of component `%s' to host "
5606 "group `%s'. Previous assignment to group `%s' is "
5607 "ignored.", component_id
, host_or_group
,
5608 host_groups
[i
].group_name
);
5609 remove_string_from_set(&host_groups
[i
].assigned_components
,
5613 } else add_string_to_set(&assigned_components
, component_id
);
5614 add_string_to_set(&group
->assigned_components
, component_id
);
5619 void MainController::destroy_host_groups()
5622 if (mc_state
!= MC_INACTIVE
)
5623 error("MainController::destroy_host_groups: called in wrong state.");
5625 for (int i
= 0; i
< n_host_groups
; i
++) {
5626 host_group_struct
*group
= host_groups
+ i
;
5627 Free(group
->group_name
);
5628 free_string_set(&group
->host_members
);
5629 free_string_set(&group
->assigned_components
);
5634 free_string_set(&assigned_components
);
5635 all_components_assigned
= FALSE
;
5640 void MainController::set_kill_timer(double timer_val
)
5643 if (mc_state
!= MC_INACTIVE
)
5644 error("MainController::set_kill_timer: called in wrong state.");
5645 else if (timer_val
< 0.0)
5646 error("MainController::set_kill_timer: setting a negative kill timer "
5648 else kill_timer
= timer_val
;
5652 unsigned short MainController::start_session(const char *local_address
,
5653 unsigned short tcp_port
, bool unix_sockets_enabled
)
5657 if (mc_state
!= MC_INACTIVE
) {
5658 error("MainController::start_session: called in wrong state.");
5664 epoll_events
= (epoll_event
*)Malloc(EPOLL_MAX_EVENTS
* sizeof(*epoll_events
));
5665 epfd
= epoll_create(EPOLL_SIZE_HINT
);
5667 error("System call epoll_create failed: %s", strerror(errno
));
5672 set_close_on_exec(epfd
);
5675 nh
.set_family(local_address
);
5676 server_fd
= nh
.socket();
5677 if (server_fd
< 0) {
5678 error("Server socket creation failed: %s", strerror(errno
));
5685 if (setsockopt(server_fd
, SOL_SOCKET
, SO_REUSEADDR
, (const char*)&on
,
5687 error("System call setsockopt (SO_REUSEADDR) failed on server socket: "
5688 "%s", strerror(errno
));
5694 if (setsockopt(server_fd
, IPPROTO_TCP
, TCP_NODELAY
, (const char*)&on
,
5696 error("System call setsockopt (TCP_NODELAY) failed on server socket: "
5697 "%s", strerror(errno
));
5703 IPAddress
*localaddr
= IPAddress::create_addr(nh
.get_family());
5704 if (localaddr
) localaddr
->set_port(tcp_port
);
5706 if (local_address
!= NULL
) {
5707 if (!localaddr
|| !localaddr
->set_addr(local_address
, tcp_port
)) {
5708 error("Cannot resolve host name `%s' to a local IP address: "
5709 "Host name lookup failure", local_address
);
5717 if (bind(server_fd
, localaddr
->get_addr(), localaddr
->get_addr_len())) {
5718 if (local_address
!= NULL
) {
5719 if (tcp_port
!= 0) error("Binding server socket to IP address "
5720 "%s and TCP port %d failed: %s", localaddr
->get_addr_str(),
5721 tcp_port
, strerror(errno
));
5722 else error("Binding server socket to IP address %s failed: %s",
5723 localaddr
->get_addr_str(), strerror(errno
));
5725 if (tcp_port
!= 0) error("Binding server socket to TCP port %d "
5726 "failed: %s", tcp_port
, strerror(errno
));
5727 else error("Binding server socket to an ephemeral TCP port "
5728 "failed: %s", strerror(errno
));
5736 if (listen(server_fd
, 10)) {
5737 if (local_address
!= NULL
) {
5738 if (tcp_port
!= 0) error("Listening on IP address %s and TCP port "
5739 "%d failed: %s", localaddr
->get_addr_str(), tcp_port
,
5741 else error("Listening on IP address %s failed: %s",
5742 localaddr
->get_addr_str(), strerror(errno
));
5744 if (tcp_port
!= 0) error("Listening on TCP port %d failed: %s",
5745 tcp_port
, strerror(errno
));
5746 else error("Listening on an ephemeral TCP port failed: %s",
5755 if (localaddr
->getsockname(server_fd
)) {
5756 error("System call getsockname() failed on server socket: %s",
5763 tcp_port
= localaddr
->get_port();
5765 set_close_on_exec(server_fd
);
5767 // Trying to open a unix socket for local communication
5768 if (unix_sockets_enabled
) {
5770 server_fd_unix
= socket(PF_UNIX
, SOCK_STREAM
, 0);
5771 if (server_fd_unix
< 0) {
5772 notify("Unix server socket creation failed: %s", strerror(errno
));
5777 struct sockaddr_un localaddr_unix
;
5778 memset(&localaddr_unix
, 0, sizeof(localaddr_unix
));
5779 localaddr_unix
.sun_family
= AF_UNIX
;
5780 snprintf(localaddr_unix
.sun_path
, sizeof(localaddr_unix
.sun_path
),
5781 "/tmp/ttcn3-mctr-%u", tcp_port
);
5782 if (unlink(localaddr_unix
.sun_path
))
5783 errno
= 0; // silently ignore, error handling below
5785 if (bind(server_fd_unix
, (struct sockaddr
*)&localaddr_unix
,
5786 sizeof(localaddr_unix
)) != 0) {
5787 if (errno
== EADDRINUSE
) {
5788 // the temporary file name is already used by someone else
5789 close(server_fd_unix
);
5790 notify("Could not create Unix server socket: '%s' is already existed "
5791 "and cannot be removed.", localaddr_unix
.sun_path
);
5795 close(server_fd_unix
);
5796 notify("Binding of Unix server socket to pathname %s failed. (%s)",
5797 localaddr_unix
.sun_path
, strerror(errno
));
5803 if (listen(server_fd_unix
, 10)) {
5804 notify("Could not listen on the given socket. Unix domain socket "
5805 "communication will not be used.");
5806 close(server_fd_unix
);
5811 set_close_on_exec(server_fd_unix
);
5813 add_fd_to_table(server_fd_unix
);
5814 fd_table
[server_fd_unix
].fd_type
= FD_SERVER
;
5815 add_poll_fd(server_fd_unix
);
5817 notify("Unix server socket created successfully.");
5821 if (pipe(pipe_fd
) < 0) {
5822 error("System call pipe failed: %s", strerror(errno
));
5828 set_close_on_exec(pipe_fd
[0]);
5829 set_close_on_exec(pipe_fd
[1]);
5831 wakeup_reason
= REASON_NOTHING
;
5833 mc_state
= MC_LISTENING
;
5835 add_fd_to_table(server_fd
);
5836 fd_table
[server_fd
].fd_type
= FD_SERVER
;
5837 add_poll_fd(server_fd
);
5838 server_fd_disabled
= FALSE
;
5840 add_fd_to_table(pipe_fd
[0]);
5841 fd_table
[pipe_fd
[0]].fd_type
= FD_PIPE
;
5842 add_poll_fd(pipe_fd
[0]);
5844 pthread_attr_t attr
;
5845 if (pthread_attr_init(&attr
))
5846 fatal_error("MainController::start_session: pthread_attr_init failed.");
5847 if (pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
))
5848 fatal_error("MainController::start_session: "
5849 "pthread_attr_setdetachstate failed.");
5852 if (pthread_create(&thread
, &attr
, thread_main
, NULL
))
5853 fatal_error("MainController::start_session: pthread_create failed.");
5855 if (pthread_attr_destroy(&attr
))
5856 fatal_error("MainController::start_session: pthread_attr_destroy "
5858 if (local_address
!= NULL
)
5859 notify("Listening on IP address %s and TCP port %d.", localaddr
->get_addr_str(), tcp_port
);
5860 else notify("Listening on TCP port %d.", tcp_port
);
5867 void MainController::shutdown_session()
5877 case MC_LISTENING_CONFIGURED
:
5878 case MC_HC_CONNECTED
:
5880 notify("Shutting down session.");
5881 wakeup_thread(REASON_SHUTDOWN
);
5884 error("MainController::shutdown_session: called in wrong state.");
5889 char *MainController::config_str
;
5891 void MainController::configure(const char *config_file
)
5895 case MC_HC_CONNECTED
:
5897 mc_state
= MC_CONFIGURING
;
5900 case MC_LISTENING_CONFIGURED
:
5901 mc_state
= MC_LISTENING_CONFIGURED
;
5904 error("MainController::configure: called in wrong state.");
5909 config_str
= mcopystr(config_file
);
5910 if(mc_state
== MC_CONFIGURING
) {
5911 notify("Downloading configuration file to all HCs.");
5912 for (int i
= 0; i
< n_hosts
; i
++) configure_host(hosts
[i
], FALSE
);
5918 void MainController::create_mtc(int host_index
)
5921 if (mc_state
!= MC_ACTIVE
) {
5922 error("MainController::create_mtc: called in wrong state.");
5926 if (host_index
< 0 || host_index
>= n_hosts
) {
5927 error("MainController::create_mtc: host index (%d) is out of range.",
5932 host_struct
*host
= hosts
[host_index
];
5933 switch (host
->hc_state
) {
5935 notify("HC on host %s reported overload. Trying to create MTC there "
5936 "anyway.", host
->hostname
);
5940 error("MTC cannot be created on %s: HC is not active.", host
->hostname
);
5944 notify("Creating MTC on host %s.", host
->hostname
);
5945 send_create_mtc(host
);
5947 mtc
= new component_struct
;
5948 mtc
->comp_ref
= MTC_COMPREF
;
5949 init_qualified_name(&mtc
->comp_type
);
5950 mtc
->comp_name
= new char[4];
5951 strcpy(mtc
->comp_name
, "MTC");
5952 mtc
->tc_state
= TC_INITIAL
;
5953 mtc
->local_verdict
= NONE
;
5954 mtc
->verdict_reason
= NULL
;
5956 mtc
->text_buf
= NULL
;
5957 init_qualified_name(&mtc
->tc_fn_name
);
5958 mtc
->return_type
= NULL
;
5959 mtc
->return_value_len
= 0;
5960 mtc
->return_value
= NULL
;
5961 mtc
->is_alive
= FALSE
;
5962 mtc
->stop_requested
= FALSE
;
5963 mtc
->process_killed
= FALSE
;
5964 mtc
->initial
.create_requestor
= NULL
;
5965 mtc
->initial
.location_str
= NULL
;
5966 init_requestors(&mtc
->done_requestors
, NULL
);
5967 init_requestors(&mtc
->killed_requestors
, NULL
);
5968 init_requestors(&mtc
->cancel_done_sent_for
, NULL
);
5969 mtc
->kill_timer
= NULL
;
5970 init_connections(mtc
);
5972 add_component_to_host(host
, mtc
);
5973 host
->n_active_components
++;
5975 system
= new component_struct
;
5976 system
->comp_ref
= SYSTEM_COMPREF
;
5977 init_qualified_name(&system
->comp_type
);
5978 system
->comp_name
= new char[7];
5979 strcpy(system
->comp_name
, "SYSTEM");
5980 system
->log_source
= NULL
;
5981 system
->comp_location
= NULL
;
5982 system
->tc_state
= TC_SYSTEM
;
5983 system
->local_verdict
= NONE
;
5984 system
->verdict_reason
= NULL
;
5986 system
->text_buf
= NULL
;
5987 init_qualified_name(&system
->tc_fn_name
);
5988 system
->return_type
= NULL
;
5989 system
->return_value_len
= 0;
5990 system
->return_value
= NULL
;
5991 system
->is_alive
= FALSE
;
5992 system
->stop_requested
= FALSE
;
5993 system
->process_killed
= FALSE
;
5994 init_requestors(&system
->done_requestors
, NULL
);
5995 init_requestors(&system
->killed_requestors
, NULL
);
5996 init_requestors(&system
->cancel_done_sent_for
, NULL
);
5997 system
->kill_timer
= NULL
;
5998 init_connections(system
);
5999 add_component(system
);
6001 mc_state
= MC_CREATING_MTC
;
6006 void MainController::exit_mtc()
6009 if (mc_state
!= MC_READY
) {
6010 error("MainController::exit_mtc: called in wrong state.");
6014 notify("Terminating MTC.");
6016 mtc
->tc_state
= TC_EXITING
;
6017 mtc
->comp_location
->n_active_components
--;
6018 mc_state
= MC_TERMINATING_MTC
;
6019 start_kill_timer(mtc
);
6024 void MainController::execute_control(const char *module_name
)
6027 if (mc_state
!= MC_READY
) {
6028 error("MainController::execute_control: called in wrong state.");
6032 send_execute_control(module_name
);
6033 mtc
->tc_state
= MTC_CONTROLPART
;
6034 mc_state
= MC_EXECUTING_CONTROL
;
6039 void MainController::execute_testcase(const char *module_name
,
6040 const char *testcase_name
)
6043 if (mc_state
!= MC_READY
) {
6044 error("MainController::execute_testcase: called in wrong state.");
6048 send_execute_testcase(module_name
, testcase_name
);
6049 mtc
->tc_state
= MTC_CONTROLPART
;
6050 mc_state
= MC_EXECUTING_CONTROL
;
6055 void MainController::stop_after_testcase(boolean new_state
)
6058 stop_after_tc
= new_state
;
6059 if (mc_state
== MC_PAUSED
&& !stop_after_tc
) {
6061 continue_testcase();
6065 void MainController::continue_testcase()
6068 if (mc_state
== MC_PAUSED
) {
6069 notify("Resuming execution.");
6071 mtc
->tc_state
= MTC_CONTROLPART
;
6072 mc_state
= MC_EXECUTING_CONTROL
;
6074 } else error("MainController::continue_testcase: called in wrong state.");
6078 void MainController::stop_execution()
6081 if (!stop_requested
) {
6082 notify("Stopping execution.");
6085 mc_state
= MC_EXECUTING_CONTROL
;
6086 mtc
->tc_state
= MTC_CONTROLPART
;
6087 case MC_EXECUTING_CONTROL
:
6089 mtc
->stop_requested
= TRUE
;
6090 start_kill_timer(mtc
);
6091 wakeup_thread(REASON_MTC_KILL_TIMER
);
6093 case MC_EXECUTING_TESTCASE
:
6094 if (!mtc
->stop_requested
) {
6096 kill_all_components(TRUE
);
6097 mtc
->stop_requested
= TRUE
;
6098 start_kill_timer(mtc
);
6099 wakeup_thread(REASON_MTC_KILL_TIMER
);
6101 case MC_TERMINATING_TESTCASE
:
6102 // MTC will be stopped later in finish_testcase()
6107 error("MainController::stop_execution: called in wrong state.");
6111 stop_requested
= TRUE
;
6113 } else notify("Stop was already requested. Operation ignored.");
6117 mc_state_enum
MainController::get_state()
6120 mc_state_enum ret_val
= mc_state
;
6125 boolean
MainController::get_stop_after_testcase()
6128 boolean ret_val
= stop_after_tc
;
6133 int MainController::get_nof_hosts()
6136 int ret_val
= n_hosts
;
6141 host_struct
*MainController::get_host_data(int host_index
)
6144 if (host_index
>= 0 && host_index
< n_hosts
) return hosts
[host_index
];
6148 component_struct
*MainController::get_component_data(int component_reference
)
6151 return lookup_component(component_reference
);
6154 void MainController::release_data()
6159 const char *MainController::get_mc_state_name(mc_state_enum state
)
6166 case MC_LISTENING_CONFIGURED
:
6167 return "listening (configured)";
6168 case MC_HC_CONNECTED
:
6169 return "HC connected";
6170 case MC_CONFIGURING
:
6171 return "configuring...";
6174 case MC_CREATING_MTC
:
6175 return "creating MTC...";
6176 case MC_TERMINATING_MTC
:
6177 return "terminating MTC...";
6180 case MC_EXECUTING_CONTROL
:
6181 return "executing control part";
6182 case MC_EXECUTING_TESTCASE
:
6183 return "executing testcase";
6184 case MC_TERMINATING_TESTCASE
:
6185 return "terminating testcase...";
6187 return "paused after testcase";
6189 return "shutting down...";
6191 return "unknown/transient";
6195 const char *MainController::get_hc_state_name(hc_state_enum state
)
6199 return "not configured";
6200 case HC_CONFIGURING
:
6201 case HC_CONFIGURING_OVERLOADED
:
6202 return "being configured";
6206 return "overloaded";
6210 return "unknown/transient";
6214 const char *MainController::get_tc_state_name(tc_state_enum state
)
6218 return "being created";
6220 return "inactive - waiting for start";
6222 return "executing create operation";
6224 return "executing component start operation";
6226 case MTC_ALL_COMPONENT_STOP
:
6227 return "executing component stop operation";
6229 case MTC_ALL_COMPONENT_KILL
:
6230 return "executing kill operation";
6232 return "executing connect operation";
6234 return "executing disconnect operation";
6236 return "executing map operation";
6238 return "executing unmap operation";
6240 return "being stopped";
6242 return "terminated";
6245 case MTC_CONTROLPART
:
6246 return "executing control part";
6248 return "executing testcase";
6249 case MTC_TERMINATING_TESTCASE
:
6250 return "terminating testcase";
6254 return "executing function";
6256 return "being started";
6258 return "stopped - waiting for re-start";
6260 case PTC_STOPPING_KILLING
:
6261 return "being killed";
6263 return "unknown/transient";
6267 const char *MainController::get_transport_name(transport_type_enum transport
)
6269 switch (transport
) {
6270 case TRANSPORT_LOCAL
:
6271 return "LOCAL (software loop)";
6272 case TRANSPORT_INET_STREAM
:
6273 return "INET_STREAM (TCP over IPv4)";
6274 case TRANSPORT_UNIX_STREAM
:
6275 return "UNIX_STREAM (UNIX domain socket)";
6281 //----------------------------------------------------------------------------
6283 } /* namespace mctr */
6285 //----------------------------------------------------------------------------
6289 // indent-tabs-mode: nil
6290 // c-basic-offset: 2