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 memset(&event
,0,sizeof(event
));
125 event
.events
= EPOLLIN
;
127 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, fd
, &event
) < 0)
128 fatal_error("MainController::add_poll_fd: system call epoll_ctl"
129 " failed on file descriptor %d.", fd
);
132 void MainController::remove_poll_fd(int fd
)
136 memset(&event
,0,sizeof(event
));
137 event
.events
= EPOLLIN
;
139 if (epoll_ctl(epfd
, EPOLL_CTL_DEL
, fd
, &event
) < 0)
140 fatal_error("MainController::remove_poll_fd: system call epoll_ctl"
141 " failed on file descriptor %d.", fd
);
143 #else // ! defined USE_EPOLL
144 void MainController::add_poll_fd(int fd
)
147 if (pollfds_modified
) {
149 for (i
= new_nfds
- 1; i
>= 0; i
--) {
150 if (new_ufds
[i
].fd
< fd
) break;
151 else if (new_ufds
[i
].fd
== fd
) return;
154 new_ufds
= (struct pollfd
*)Realloc(new_ufds
, (new_nfds
+ 1) *
155 sizeof(struct pollfd
));
156 memmove(new_ufds
+ i
+ 1, new_ufds
+ i
, (new_nfds
- i
) *
157 sizeof(struct pollfd
));
159 new_ufds
[i
].events
= POLLIN
;
160 new_ufds
[i
].revents
= 0;
164 for (i
= nfds
- 1; i
>= 0; i
--) {
165 if (ufds
[i
].fd
< fd
) break;
166 else if (ufds
[i
].fd
== fd
) return;
170 new_ufds
= (struct pollfd
*)Malloc(new_nfds
* sizeof(struct pollfd
));
171 memcpy(new_ufds
, ufds
, i
* sizeof(struct pollfd
));
173 new_ufds
[i
].events
= POLLIN
;
174 new_ufds
[i
].revents
= 0;
175 memcpy(new_ufds
+ i
+ 1, ufds
+ i
, (nfds
- i
) * sizeof(struct pollfd
));
176 pollfds_modified
= TRUE
;
180 void MainController::remove_poll_fd(int fd
)
183 if (pollfds_modified
) {
185 for (i
= new_nfds
- 1; i
>= 0; i
--) {
186 if (new_ufds
[i
].fd
== fd
) break;
187 else if (new_ufds
[i
].fd
< fd
) return;
191 memmove(new_ufds
+ i
, new_ufds
+ i
+ 1, (new_nfds
- i
) *
192 sizeof(struct pollfd
));
193 new_ufds
= (struct pollfd
*)Realloc(new_ufds
, new_nfds
*
194 sizeof(struct pollfd
));
197 for (i
= nfds
- 1; i
>= 0; i
--) {
198 if (ufds
[i
].fd
== fd
) break;
199 else if (ufds
[i
].fd
< fd
) return;
203 new_ufds
= (struct pollfd
*)Malloc(new_nfds
* sizeof(struct pollfd
));
204 memcpy(new_ufds
, ufds
, i
* sizeof(struct pollfd
));
205 memcpy(new_ufds
+ i
, ufds
+ i
+ 1, (new_nfds
- i
) *
206 sizeof(struct pollfd
));
207 pollfds_modified
= TRUE
;
211 void MainController::update_pollfds()
213 if (pollfds_modified
) {
219 pollfds_modified
= FALSE
;
224 int MainController::fd_table_size
;
225 fd_table_struct
*MainController::fd_table
;
227 void MainController::add_fd_to_table(int fd
)
229 if (fd
>= fd_table_size
) {
230 fd_table
= (fd_table_struct
*)Realloc(fd_table
, (fd
+ 1) *
231 sizeof(fd_table_struct
));
232 for (int i
= fd_table_size
; i
<= fd
; i
++) {
233 fd_table
[i
].fd_type
= FD_UNUSED
;
234 fd_table
[i
].dummy_ptr
= NULL
;
236 fd_table_size
= fd
+ 1;
240 void MainController::remove_fd_from_table(int fd
)
242 if (fd
< fd_table_size
) {
243 fd_table
[fd
].fd_type
= FD_UNUSED
;
245 for (i
= fd_table_size
- 1; i
>= 0 ; i
--) {
246 if (fd_table
[i
].fd_type
!= FD_UNUSED
) break;
248 if (i
< fd_table_size
- 1) {
249 fd_table_size
= i
+ 1;
250 fd_table
= (fd_table_struct
*)Realloc(fd_table
, fd_table_size
*
251 sizeof(fd_table_struct
));
256 void MainController::set_close_on_exec(int fd
)
258 int flags
= fcntl(fd
, F_GETFD
);
259 if (flags
< 0) fatal_error("MainController::set_close_on_exec: system call "
260 "fcntl(F_GETFD) failed on file descriptor %d.", fd
);
264 if (fcntl(fd
, F_SETFD
, flags
) == -1)
265 fatal_error("MainController::set_close_on_exec: system call "
266 "fcntl(F_SETFD) failed on file descriptor %d.", fd
);
269 unknown_connection
*MainController::unknown_head
, *MainController::unknown_tail
;
271 unknown_connection
*MainController::new_unknown_connection(
274 unknown_connection
*conn
= new unknown_connection
;
275 conn
->unix_socket
= unix_socket
;
276 conn
->prev
= unknown_tail
;
278 if (unknown_tail
!= NULL
) unknown_tail
->next
= conn
;
279 else unknown_head
= conn
;
284 void MainController::delete_unknown_connection(unknown_connection
*conn
)
286 if (conn
->prev
!= NULL
) conn
->prev
->next
= conn
->next
;
287 else unknown_head
= conn
->next
;
288 if (conn
->next
!= NULL
) conn
->next
->prev
= conn
->prev
;
289 else unknown_tail
= conn
->prev
;
293 void MainController::close_unknown_connection(unknown_connection
*conn
)
295 remove_poll_fd(conn
->fd
);
297 remove_fd_from_table(conn
->fd
);
298 delete conn
->text_buf
;
299 delete_unknown_connection(conn
);
303 void MainController::init_string_set(string_set
*set
)
306 set
->elements
= NULL
;
309 void MainController::free_string_set(string_set
*set
)
311 for (int i
= 0; i
< set
->n_elements
; i
++) Free(set
->elements
[i
]);
314 set
->elements
= NULL
;
317 void MainController::add_string_to_set(string_set
*set
, const char *str
)
320 for (i
= 0; i
< set
->n_elements
; i
++) {
321 int result
= strcmp(set
->elements
[i
], str
);
322 if (result
> 0) break;
323 else if (result
== 0) return;
325 set
->elements
= (char**)Realloc(set
->elements
,
326 (set
->n_elements
+ 1) * sizeof(*set
->elements
));
327 memmove(set
->elements
+ i
+ 1, set
->elements
+ i
,
328 (set
->n_elements
- i
) * sizeof(*set
->elements
));
329 set
->elements
[i
] = mcopystr(str
);
333 void MainController::remove_string_from_set(string_set
*set
,
336 for (int i
= 0; i
< set
->n_elements
; i
++) {
337 int result
= strcmp(set
->elements
[i
], str
);
338 if (result
< 0) continue;
339 else if (result
== 0) {
340 Free(set
->elements
[i
]);
342 memmove(set
->elements
+ i
, set
->elements
+ i
+ 1,
343 (set
->n_elements
- i
) * sizeof(*set
->elements
));
344 set
->elements
= (char**)Realloc(set
->elements
,
345 set
->n_elements
* sizeof(*set
->elements
));
351 boolean
MainController::set_has_string(const string_set
*set
,
354 if(str
== NULL
) return FALSE
;
355 for (int i
= 0; i
< set
->n_elements
; i
++) {
356 int result
= strcmp(set
->elements
[i
], str
);
357 if (result
== 0) return TRUE
;
358 else if (result
> 0) break;
363 const char *MainController::get_string_from_set(const string_set
*set
,
366 if (index
>= 0 && index
< set
->n_elements
) return set
->elements
[index
];
370 int MainController::n_host_groups
;
371 host_group_struct
*MainController::host_groups
;
372 string_set
MainController::assigned_components
;
373 boolean
MainController::all_components_assigned
;
375 host_group_struct
*MainController::add_host_group(const char *group_name
)
378 for (i
= 0 ; i
< n_host_groups
; i
++) {
379 host_group_struct
*group
= host_groups
+ i
;
380 int result
= strcmp(group
->group_name
, group_name
);
381 if (result
> 0) break;
382 else if (result
== 0) return group
;
384 host_groups
= (host_group_struct
*)Realloc(host_groups
,
385 (n_host_groups
+ 1) * sizeof(*host_groups
));
386 host_group_struct
*new_group
= host_groups
+ i
;
387 memmove(new_group
+ 1, new_group
,
388 (n_host_groups
- i
) * sizeof(*host_groups
));
389 new_group
->group_name
= mcopystr(group_name
);
390 new_group
->has_all_hosts
= FALSE
;
391 new_group
->has_all_components
= FALSE
;
392 init_string_set(&new_group
->host_members
);
393 init_string_set(&new_group
->assigned_components
);
398 host_group_struct
*MainController::lookup_host_group(const char *group_name
)
400 for (int i
= 0; i
< n_host_groups
; i
++) {
401 host_group_struct
*group
= host_groups
+ i
;
402 int result
= strcmp(group
->group_name
, group_name
);
403 if (result
== 0) return group
;
404 else if (result
> 0) break;
409 boolean
MainController::is_similar_hostname(const char *host1
,
412 for (size_t i
= 0; ; i
++) {
413 unsigned char c1
= host1
[i
], c2
= host2
[i
];
415 // if host2 is the longer one it may contain an additional domain
416 // name with a leading dot (e.g. "foo" is similar to "foo.bar.com")
417 // note: empty string is similar with empty string only
418 if (c2
== '\0' || (i
> 0 && c2
== '.')) return TRUE
;
420 } else if (c2
== '\0') {
422 if (c1
== '\0' || (i
> 0 && c1
== '.')) return TRUE
;
425 // case insensitive comparison of the characters
426 if (tolower(c1
) != tolower(c2
)) return FALSE
;
427 // continue the evaluation if they are matching
432 boolean
MainController::host_has_name(const host_struct
*host
, const char *name
)
434 // name might resemble to host->hostname
435 if (is_similar_hostname(host
->hostname
, name
)) return TRUE
;
436 // to avoid returning true in situations when name is "foo.bar.com", but
437 // host->hostname is "foo.other.com" and host->hostname_local is "foo"
438 // name might resemble to host->hostname_local
439 if (host
->local_hostname_different
&&
440 is_similar_hostname(host
->hostname_local
, name
)) return TRUE
;
441 // name might be an IP address or a DNS alias
442 IPAddress
*ip_addr
= IPAddress::create_addr(nh
.get_family());
443 if (ip_addr
->set_addr(name
)) {
444 // check if IP addresses match
445 if (*ip_addr
== *(host
->ip_addr
)) {
449 // try to handle such strange situations when the local hostname is
450 // mapped to a loopback address by /etc/hosts
451 // (i.e. host->ip_addr contains 127.x.y.z)
452 // but the given name contains the real IP address of the host
453 const char *canonical_name
= ip_addr
->get_host_str();
454 if (is_similar_hostname(host
->hostname
, canonical_name
)) {
458 if (host
->local_hostname_different
&&
459 is_similar_hostname(host
->hostname_local
, canonical_name
)) {
468 boolean
MainController::member_of_group(const host_struct
*host
,
469 const host_group_struct
*group
)
471 if (group
->has_all_hosts
) return TRUE
;
472 for (int i
= 0; ; i
++) {
473 const char *member_name
= get_string_from_set(&group
->host_members
, i
);
474 if (member_name
!= NULL
) {
475 if (host_has_name(host
, member_name
)) return TRUE
;
477 // empty group: the group name is considered as a hostname
478 return host_has_name(host
, group
->group_name
);
487 void MainController::add_allowed_components(host_struct
*host
)
489 init_string_set(&host
->allowed_components
);
490 host
->all_components_allowed
= FALSE
;
491 for (int i
= 0; i
< n_host_groups
; i
++) {
492 host_group_struct
*group
= host_groups
+ i
;
493 if (!member_of_group(host
, group
)) continue;
494 for (int j
= 0; ; j
++) {
495 const char *component_id
=
496 get_string_from_set(&group
->assigned_components
, j
);
497 if (component_id
== NULL
) break;
498 add_string_to_set(&host
->allowed_components
, component_id
);
500 if (group
->has_all_components
) host
->all_components_allowed
= TRUE
;
504 host_struct
*MainController::choose_ptc_location(const char *component_type
,
505 const char *component_name
, const char *component_location
)
507 host_struct
*best_candidate
= NULL
;
508 int load_on_best_candidate
= 0;
509 boolean has_constraint
=
510 set_has_string(&assigned_components
, component_type
) ||
511 set_has_string(&assigned_components
, component_name
);
512 host_group_struct
*group
;
513 if (component_location
!= NULL
)
514 group
= lookup_host_group(component_location
);
516 for (int i
= 0; i
< n_hosts
; i
++) {
517 host_struct
*host
= hosts
[i
];
518 if (host
->hc_state
!= HC_ACTIVE
) continue;
519 if (best_candidate
!= NULL
&&
520 host
->n_active_components
>= load_on_best_candidate
) continue;
521 if (component_location
!= NULL
) {
522 // the explicit location has precedence over the constraints
524 if (!member_of_group(host
, group
)) continue;
526 if (!host_has_name(host
, component_location
)) continue;
528 } else if (has_constraint
) {
529 if (!set_has_string(&host
->allowed_components
, component_type
) &&
530 !set_has_string(&host
->allowed_components
, component_name
))
532 } else if (all_components_assigned
) {
533 if (!host
->all_components_allowed
) continue;
535 best_candidate
= host
;
536 load_on_best_candidate
= host
->n_active_components
;
538 return best_candidate
;
541 int MainController::n_hosts
;
542 host_struct
**MainController::hosts
;
544 host_struct
*MainController::add_new_host(unknown_connection
*conn
)
546 Text_Buf
*text_buf
= conn
->text_buf
;
549 host_struct
*new_host
= new host_struct
;
551 new_host
->ip_addr
= conn
->ip_addr
;
552 new_host
->hostname
= mcopystr(new_host
->ip_addr
->get_host_str());
553 new_host
->hostname_local
= text_buf
->pull_string();
554 new_host
->machine_type
= text_buf
->pull_string();
555 new_host
->system_name
= text_buf
->pull_string();
556 new_host
->system_release
= text_buf
->pull_string();
557 new_host
->system_version
= text_buf
->pull_string();
558 for (int i
= 0; i
< TRANSPORT_NUM
; i
++)
559 new_host
->transport_supported
[i
] = FALSE
;
560 int n_supported_transports
= text_buf
->pull_int().get_val();
561 for (int i
= 0; i
< n_supported_transports
; i
++) {
562 int transport_type
= text_buf
->pull_int().get_val();
563 if (transport_type
>= 0 && transport_type
< TRANSPORT_NUM
) {
564 if (new_host
->transport_supported
[transport_type
]) {
565 send_error(fd
, "Malformed VERSION message was received: "
566 "Transport type %s was specified more than once.",
567 get_transport_name((transport_type_enum
)transport_type
));
568 } else new_host
->transport_supported
[transport_type
] = TRUE
;
570 send_error(fd
, "Malformed VERSION message was received: "
571 "Transport type code %d is invalid.", transport_type
);
574 if (!new_host
->transport_supported
[TRANSPORT_LOCAL
]) {
575 send_error(fd
, "Malformed VERSION message was received: "
576 "Transport type %s must be supported anyway.",
577 get_transport_name(TRANSPORT_LOCAL
));
579 if (!new_host
->transport_supported
[TRANSPORT_INET_STREAM
]) {
580 send_error(fd
, "Malformed VERSION message was received: "
581 "Transport type %s must be supported anyway.",
582 get_transport_name(TRANSPORT_INET_STREAM
));
584 new_host
->log_source
= mprintf("HC@%s", new_host
->hostname_local
);
585 new_host
->hc_state
= HC_IDLE
;
586 new_host
->hc_fd
= fd
;
587 new_host
->text_buf
= text_buf
;
588 new_host
->n_components
= 0;
589 new_host
->components
= NULL
;
590 // in most cases hostname and hostname_local are similar ("foo.bar.com" vs.
591 // "foo") and it is enough to compare only the (fully qualified) hostname
592 // when evaluating PTC location constraints
593 new_host
->local_hostname_different
=
594 !is_similar_hostname(new_host
->hostname
, new_host
->hostname_local
);
595 add_allowed_components(new_host
);
596 new_host
->n_active_components
= 0;
598 text_buf
->cut_message();
600 delete_unknown_connection(conn
);
603 hosts
= (host_struct
**)Realloc(hosts
, n_hosts
* sizeof(*hosts
));
604 hosts
[n_hosts
- 1] = new_host
;
606 fd_table
[fd
].fd_type
= FD_HC
;
607 fd_table
[fd
].host_ptr
= new_host
;
609 notify("New HC connected from %s [%s]. %s: %s %s on %s.",
610 new_host
->hostname
, new_host
->ip_addr
->get_addr_str(),
611 new_host
->hostname_local
, new_host
->system_name
,
612 new_host
->system_release
, new_host
->machine_type
);
617 void MainController::close_hc_connection(host_struct
*hc
)
619 if (hc
->hc_state
!= HC_DOWN
) {
620 remove_poll_fd(hc
->hc_fd
);
622 remove_fd_from_table(hc
->hc_fd
);
626 hc
->hc_state
= HC_DOWN
;
631 boolean
MainController::is_hc_in_state(hc_state_enum checked_state
)
633 for (int i
= 0; i
< n_hosts
; i
++)
634 if (hosts
[i
]->hc_state
== checked_state
) return TRUE
;
638 boolean
MainController::all_hc_in_state(hc_state_enum checked_state
)
640 for (int i
= 0; i
< n_hosts
; i
++)
641 if (hosts
[i
]->hc_state
!= checked_state
) return FALSE
;
645 void MainController::configure_host(host_struct
*host
, boolean should_notify
)
647 if(config_str
== NULL
)
648 fatal_error("MainController::configure_host: no config file");
649 hc_state_enum next_state
= HC_CONFIGURING
;
650 switch(host
->hc_state
) {
652 case HC_CONFIGURING_OVERLOADED
:
654 fatal_error("MainController::configure_host:"
655 " host %s is in wrong state.",
661 next_state
= HC_CONFIGURING_OVERLOADED
;
664 host
->hc_state
= next_state
;
666 notify("Downloading configuration file to HC on host %s.",
669 send_configure(host
, config_str
);
673 void MainController::check_all_hc_configured()
675 if (is_hc_in_state(HC_CONFIGURING
) ||
676 is_hc_in_state(HC_CONFIGURING_OVERLOADED
)) return;
677 if (is_hc_in_state(HC_IDLE
)) {
678 error("There were errors during configuring HCs.");
679 mc_state
= MC_HC_CONNECTED
;
680 } else if (is_hc_in_state(HC_ACTIVE
) || is_hc_in_state(HC_OVERLOADED
)) {
681 notify("Configuration file was processed on all HCs.");
682 mc_state
= MC_ACTIVE
;
684 error("There is no HC connection after processing the configuration "
686 mc_state
= MC_LISTENING
;
690 void MainController::add_component_to_host(host_struct
*host
,
691 component_struct
*comp
)
693 if (comp
->comp_ref
== MTC_COMPREF
)
694 comp
->log_source
= mprintf("MTC@%s", host
->hostname_local
);
695 else if (comp
->comp_name
!= NULL
)
696 comp
->log_source
= mprintf("%s(%d)@%s", comp
->comp_name
,
697 comp
->comp_ref
, host
->hostname_local
);
698 else comp
->log_source
= mprintf("%d@%s", comp
->comp_ref
,
699 host
->hostname_local
);
700 comp
->comp_location
= host
;
702 for (i
= host
->n_components
; i
> 0; i
--) {
703 if (host
->components
[i
- 1] < comp
->comp_ref
) break;
704 else if (host
->components
[i
- 1] == comp
->comp_ref
) return;
706 host
->components
= (component
*)Realloc(host
->components
,
707 (host
->n_components
+ 1) * sizeof(component
));
708 memmove(host
->components
+ i
+ 1, host
->components
+ i
,
709 (host
->n_components
- i
) * sizeof(component
));
710 host
->components
[i
] = comp
->comp_ref
;
711 host
->n_components
++;
714 void MainController::remove_component_from_host(component_struct
*comp
)
716 Free(comp
->log_source
);
717 comp
->log_source
= NULL
;
718 host_struct
*host
= comp
->comp_location
;
720 component comp_ref
= comp
->comp_ref
;
722 for (i
= host
->n_components
- 1; i
>= 0; i
--) {
723 if (host
->components
[i
] == comp_ref
) break;
724 else if (host
->components
[i
] < comp_ref
) return;
727 host
->n_components
--;
728 memmove(host
->components
+ i
, host
->components
+ i
+ 1,
729 (host
->n_components
- i
) * sizeof(component
));
730 host
->components
= (component
*)Realloc(host
->components
,
731 host
->n_components
* sizeof(component
));
735 boolean
MainController::version_known
;
736 int MainController::n_modules
;
737 module_version_info
*MainController::modules
;
739 #ifdef TTCN3_BUILDNUMBER
740 #define TTCN3_BUILDNUMBER_SAFE TTCN3_BUILDNUMBER
742 #define TTCN3_BUILDNUMBER_SAFE 0
746 boolean
MainController::check_version(unknown_connection
*conn
)
748 Text_Buf
& text_buf
= *conn
->text_buf
;
749 int version_major
= text_buf
.pull_int().get_val();
750 int version_minor
= text_buf
.pull_int().get_val();
751 int version_patchlevel
= text_buf
.pull_int().get_val();
752 if (version_major
!= TTCN3_MAJOR
|| version_minor
!= TTCN3_MINOR
||
753 version_patchlevel
!= TTCN3_PATCHLEVEL
) {
754 send_error(conn
->fd
, "Version mismatch: The TTCN-3 Main Controller has "
755 "version " PRODUCT_NUMBER
", but the ETS was built with version "
756 "%d.%d.pl%d.", version_major
, version_minor
, version_patchlevel
);
759 int version_buildnumber
= text_buf
.pull_int().get_val();
760 if (version_buildnumber
!= TTCN3_BUILDNUMBER_SAFE
) {
761 if (version_buildnumber
> 0) send_error(conn
->fd
, "Build number "
762 "mismatch: The TTCN-3 Main Controller has version " PRODUCT_NUMBER
763 ", but the ETS was built with %d.%d.pre%d build %d.",
764 version_major
, version_minor
, version_patchlevel
,
765 version_buildnumber
);
766 else send_error(conn
->fd
, "Build number mismatch: The TTCN-3 Main "
767 "Controller has version " PRODUCT_NUMBER
", but the ETS was built "
768 "with %d.%d.pl%d.", version_major
, version_minor
,
773 int new_n_modules
= text_buf
.pull_int().get_val();
774 if (n_modules
!= new_n_modules
) {
775 send_error(conn
->fd
, "The number of modules in this ETS (%d) "
776 "differs from the number of modules in the firstly connected "
777 "ETS (%d).", new_n_modules
, n_modules
);
780 for (int i
= 0; i
< n_modules
; i
++) {
781 char *module_name
= text_buf
.pull_string();
782 if (strcmp(module_name
, modules
[i
].module_name
)) {
783 send_error(conn
->fd
, "The module number %d in this ETS (%s) "
784 "has different name than in the firstly connected ETS (%s).",
785 i
, module_name
, modules
[i
].module_name
);
786 delete [] module_name
;
789 boolean checksum_differs
= FALSE
;
790 int checksum_length
= text_buf
.pull_int().get_val();
791 unsigned char *module_checksum
;
792 if (checksum_length
!= 0) {
793 module_checksum
= new unsigned char[checksum_length
];
794 text_buf
.pull_raw(checksum_length
, module_checksum
);
795 } else module_checksum
= NULL
;
796 if (checksum_length
!= modules
[i
].checksum_length
||
797 memcmp(module_checksum
, modules
[i
].module_checksum
,
798 checksum_length
)) checksum_differs
= TRUE
;
799 delete [] module_checksum
;
800 if (checksum_differs
) {
801 send_error(conn
->fd
, "The checksum of module %s in this ETS "
802 "is different than that of the firstly connected ETS.",
805 delete [] module_name
;
806 if (checksum_differs
) return TRUE
;
809 n_modules
= text_buf
.pull_int().get_val();
810 modules
= new module_version_info
[n_modules
];
811 for (int i
= 0; i
< n_modules
; i
++) {
812 modules
[i
].module_name
= text_buf
.pull_string();
813 modules
[i
].checksum_length
= text_buf
.pull_int().get_val();
814 if (modules
[i
].checksum_length
> 0) {
815 modules
[i
].module_checksum
=
816 new unsigned char[modules
[i
].checksum_length
];
817 text_buf
.pull_raw(modules
[i
].checksum_length
,
818 modules
[i
].module_checksum
);
819 } else modules
[i
].module_checksum
= NULL
;
821 version_known
= TRUE
;
826 int MainController::n_components
, MainController::n_active_ptcs
,
827 MainController::max_ptcs
;
828 component_struct
**MainController::components
;
829 component_struct
*MainController::mtc
, *MainController::system
;
830 component
MainController::next_comp_ref
, MainController::tc_first_comp_ref
;
832 boolean
MainController::any_component_done_requested
,
833 MainController::any_component_done_sent
,
834 MainController::all_component_done_requested
,
835 MainController::any_component_killed_requested
,
836 MainController::all_component_killed_requested
;
838 void MainController::add_component(component_struct
*comp
)
840 component comp_ref
= comp
->comp_ref
;
841 if (lookup_component(comp_ref
) != NULL
)
842 fatal_error("MainController::add_component: duplicate "
843 "component reference %d.", comp_ref
);
844 if (n_components
<= comp_ref
) {
845 components
= (component_struct
**)Realloc(components
, (comp_ref
+ 1) *
846 sizeof(component_struct
*));
847 for (int i
= n_components
; i
< comp_ref
; i
++) components
[i
] = NULL
;
848 n_components
= comp_ref
+ 1;
850 components
[comp_ref
] = comp
;
853 component_struct
*MainController::lookup_component(component comp_ref
)
855 if (comp_ref
>= 0 && comp_ref
< n_components
) return components
[comp_ref
];
859 void MainController::destroy_all_components()
861 for (component i
= 0; i
< n_components
; i
++) {
862 component_struct
*comp
= components
[i
];
864 close_tc_connection(comp
);
865 remove_component_from_host(comp
);
866 free_qualified_name(&comp
->comp_type
);
867 delete [] comp
->comp_name
;
868 free_qualified_name(&comp
->tc_fn_name
);
869 delete [] comp
->return_type
;
870 Free(comp
->return_value
);
871 if (comp
->verdict_reason
!= NULL
) {
872 delete [] comp
->verdict_reason
;
873 comp
->verdict_reason
= NULL
;
875 switch (comp
->tc_state
) {
877 delete [] comp
->initial
.location_str
;
880 Free(comp
->starting
.arguments_ptr
);
881 free_requestors(&comp
->starting
.cancel_done_sent_to
);
884 case PTC_STOPPING_KILLING
:
886 free_requestors(&comp
->stopping_killing
.stop_requestors
);
887 free_requestors(&comp
->stopping_killing
.kill_requestors
);
891 free_requestors(&comp
->done_requestors
);
892 free_requestors(&comp
->killed_requestors
);
893 free_requestors(&comp
->cancel_done_sent_for
);
894 remove_all_connections(i
);
905 for (int i
= 0; i
< n_hosts
; i
++) hosts
[i
]->n_active_components
= 0;
907 next_comp_ref
= FIRST_PTC_COMPREF
;
909 any_component_done_requested
= FALSE
;
910 any_component_done_sent
= FALSE
;
911 all_component_done_requested
= FALSE
;
912 any_component_killed_requested
= FALSE
;
913 all_component_killed_requested
= FALSE
;
916 void MainController::close_tc_connection(component_struct
*comp
)
918 if (comp
->tc_fd
>= 0) {
919 remove_poll_fd(comp
->tc_fd
);
921 remove_fd_from_table(comp
->tc_fd
);
923 delete comp
->text_buf
;
924 comp
->text_buf
= NULL
;
927 if (comp
->kill_timer
!= NULL
) {
928 cancel_timer(comp
->kill_timer
);
929 comp
->kill_timer
= NULL
;
933 boolean
MainController::stop_after_tc
, MainController::stop_requested
;
935 boolean
MainController::ready_to_finish_testcase()
937 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
938 switch (components
[i
]->tc_state
) {
949 void MainController::finish_testcase()
951 if (stop_requested
) {
952 send_ptc_verdict(FALSE
);
954 mtc
->tc_state
= MTC_CONTROLPART
;
955 mtc
->stop_requested
= TRUE
;
956 start_kill_timer(mtc
);
957 mc_state
= MC_EXECUTING_CONTROL
;
958 } else if (stop_after_tc
) {
959 send_ptc_verdict(FALSE
);
960 mtc
->tc_state
= MTC_PAUSED
;
961 mc_state
= MC_PAUSED
;
962 notify("Execution has been paused.");
964 send_ptc_verdict(TRUE
);
965 mtc
->tc_state
= MTC_CONTROLPART
;
966 mc_state
= MC_EXECUTING_CONTROL
;
969 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
970 components
[i
]->tc_state
= PTC_STALE
;
972 mtc
->local_verdict
= NONE
;
973 free_qualified_name(&mtc
->comp_type
);
974 free_qualified_name(&mtc
->tc_fn_name
);
975 free_qualified_name(&system
->comp_type
);
978 boolean
MainController::message_expected(component_struct
*from
,
979 const char *message_name
)
982 case MC_EXECUTING_TESTCASE
:
983 switch (mtc
->tc_state
) {
984 case MTC_ALL_COMPONENT_STOP
:
985 case MTC_ALL_COMPONENT_KILL
:
991 case MC_TERMINATING_TESTCASE
:
995 send_error(from
->tc_fd
, "Unexpected message %s was received.",
1001 boolean
MainController::request_allowed(component_struct
*from
,
1002 const char *message_name
)
1004 if (!message_expected(from
, message_name
)) return FALSE
;
1006 switch (from
->tc_state
) {
1008 if (from
== mtc
) return TRUE
;
1011 if (from
!= mtc
) return TRUE
;
1014 case PTC_STOPPING_KILLING
:
1021 send_error(from
->tc_fd
, "The sender of message %s is in "
1022 "unexpected state.", message_name
);
1026 boolean
MainController::valid_endpoint(component component_reference
,
1027 boolean new_connection
, component_struct
*requestor
, const char *operation
)
1029 switch (component_reference
) {
1031 send_error(requestor
->tc_fd
, "The %s operation refers to the null "
1032 "component reference.", operation
);
1034 case SYSTEM_COMPREF
:
1035 send_error(requestor
->tc_fd
, "The %s operation refers to the system "
1036 "component reference.", operation
);
1039 send_error(requestor
->tc_fd
, "The %s operation refers to "
1040 "'any component'.", operation
);
1043 send_error(requestor
->tc_fd
, "The %s operation refers to "
1044 "'all component'.", operation
);
1049 component_struct
*comp
= lookup_component(component_reference
);
1051 send_error(requestor
->tc_fd
, "The %s operation refers to "
1052 "invalid component reference %d.", operation
,
1053 component_reference
);
1056 switch (comp
->tc_state
) {
1073 case PTC_STOPPING_KILLING
:
1074 if (new_connection
) {
1075 send_error(requestor
->tc_fd
, "The %s operation refers to test "
1076 "component with component reference %d, which is currently "
1077 "being terminated.", operation
, component_reference
);
1082 if (new_connection
) {
1083 send_error(requestor
->tc_fd
, "The %s operation refers to test "
1084 "component with component reference %d, which has already "
1085 "terminated.", operation
, component_reference
);
1089 send_error(requestor
->tc_fd
, "The %s operation refers to component "
1090 "reference %d, which belongs to an earlier test case.",
1091 operation
, component_reference
);
1094 send_error(requestor
->tc_fd
, "The %s operation refers to component "
1095 "reference %d, which is in invalid state.",
1096 operation
, component_reference
);
1097 error("Test component with component reference %d is in invalid state "
1098 "when a %s operation was requested on a port of it.",
1099 component_reference
, operation
);
1104 void MainController::destroy_connection(port_connection
*conn
,
1105 component_struct
*tc
)
1107 switch (conn
->conn_state
) {
1108 case CONN_LISTENING
:
1109 case CONN_CONNECTING
:
1110 if (conn
->transport_type
!= TRANSPORT_LOCAL
&&
1111 conn
->head
.comp_ref
!= tc
->comp_ref
) {
1112 // shut down the server side if the client has terminated
1113 send_disconnect_to_server(conn
);
1115 send_error_to_connect_requestors(conn
, "test component %d has "
1116 "terminated during connection setup.", tc
->comp_ref
);
1118 case CONN_CONNECTED
:
1120 case CONN_DISCONNECTING
:
1121 send_disconnect_ack_to_requestors(conn
);
1124 error("The port connection %d:%s - %d:%s is in invalid state when "
1125 "test component %d has terminated.", conn
->head
.comp_ref
,
1126 conn
->head
.port_name
, conn
->tail
.comp_ref
, conn
->tail
.port_name
,
1129 remove_connection(conn
);
1132 void MainController::destroy_mapping(port_connection
*conn
)
1134 component tc_compref
;
1135 const char *tc_port
, *system_port
;
1136 if (conn
->head
.comp_ref
== SYSTEM_COMPREF
) {
1137 tc_compref
= conn
->tail
.comp_ref
;
1138 tc_port
= conn
->tail
.port_name
;
1139 system_port
= conn
->head
.port_name
;
1141 tc_compref
= conn
->head
.comp_ref
;
1142 tc_port
= conn
->head
.port_name
;
1143 system_port
= conn
->tail
.port_name
;
1145 switch (conn
->conn_state
) {
1146 case CONN_UNMAPPING
:
1147 for (int i
= 0; ; i
++) {
1148 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
1149 if (comp
== NULL
) break;
1150 if (comp
->tc_state
== TC_UNMAP
) {
1151 send_unmap_ack(comp
);
1152 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
1153 else comp
->tc_state
= PTC_FUNCTION
;
1158 for (int i
= 0; ; i
++) {
1159 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
1160 if (comp
== NULL
) break;
1161 if (comp
->tc_state
== TC_MAP
) {
1162 send_error(comp
->tc_fd
, "Establishment of port mapping "
1163 "%d:%s - system:%s failed because the test component "
1164 "endpoint has terminated.", tc_compref
, tc_port
,
1166 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
1167 else comp
->tc_state
= PTC_FUNCTION
;
1173 remove_connection(conn
);
1176 boolean
MainController::stop_all_components()
1178 boolean ready_for_ack
= TRUE
;
1179 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1180 component_struct
*tc
= components
[i
];
1181 switch (tc
->tc_state
) {
1183 // we do not have to termiate the PTC (and wait for the control
1184 // connection) if it is alive
1185 if (!tc
->is_alive
) ready_for_ack
= FALSE
;
1188 // do nothing if the component is alive
1189 if (!tc
->is_alive
) {
1191 tc
->tc_state
= PTC_KILLING
;
1192 tc
->stop_requested
= TRUE
;
1193 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1194 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1195 start_kill_timer(tc
);
1196 ready_for_ack
= FALSE
;
1208 // the PTC is executing behaviour
1211 tc
->tc_state
= TC_STOPPING
;
1213 // STOP is never sent to non-alive PTCs
1215 tc
->tc_state
= PTC_STOPPING_KILLING
;
1217 tc
->stop_requested
= TRUE
;
1218 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1219 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1220 start_kill_timer(tc
);
1221 ready_for_ack
= FALSE
;
1224 // do nothing, just put it back to STOPPED state
1225 free_qualified_name(&tc
->tc_fn_name
);
1226 Free(tc
->starting
.arguments_ptr
);
1227 free_requestors(&tc
->starting
.cancel_done_sent_to
);
1228 tc
->tc_state
= PTC_STOPPED
;
1231 case PTC_STOPPING_KILLING
:
1232 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1233 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1234 ready_for_ack
= FALSE
;
1237 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1238 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1239 // we have to wait only if the PTC is non-alive
1240 if (!tc
->is_alive
) ready_for_ack
= FALSE
;
1248 error("Test Component %d is in invalid state when stopping all "
1249 "components.", tc
->comp_ref
);
1251 // only mtc is preserved in done_requestors and killed_requestors
1252 boolean mtc_requested_done
= has_requestor(&tc
->done_requestors
, mtc
);
1253 free_requestors(&tc
->done_requestors
);
1254 if (mtc_requested_done
) add_requestor(&tc
->done_requestors
, mtc
);
1255 boolean mtc_requested_killed
= has_requestor(&tc
->killed_requestors
,
1257 free_requestors(&tc
->killed_requestors
);
1258 if (mtc_requested_killed
) add_requestor(&tc
->killed_requestors
, mtc
);
1259 free_requestors(&tc
->cancel_done_sent_for
);
1261 return ready_for_ack
;
1265 void MainController::check_all_component_stop()
1267 // MTC has requested 'all component.stop'
1268 // we have to send acknowledgement to MTC only
1269 boolean ready_for_ack
= TRUE
;
1270 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1271 component_struct
*comp
= components
[i
];
1272 switch (comp
->tc_state
) {
1275 if (!comp
->is_alive
) ready_for_ack
= FALSE
;
1278 case PTC_STOPPING_KILLING
:
1279 ready_for_ack
= FALSE
;
1287 // only alive components can be in idle state
1288 if (comp
->is_alive
) break;
1290 error("PTC %d is in invalid state when performing "
1291 "'all component.stop' operation.", comp
->comp_ref
);
1293 if (!ready_for_ack
) break;
1295 if (ready_for_ack
) {
1297 mtc
->tc_state
= MTC_TESTCASE
;
1301 void MainController::send_stop_ack_to_requestors(component_struct
*tc
)
1303 for (int i
= 0; ; i
++) {
1304 component_struct
*requestor
=
1305 get_requestor(&tc
->stopping_killing
.stop_requestors
, i
);
1306 if (requestor
== NULL
) break;
1307 if (requestor
->tc_state
== TC_STOP
) {
1308 send_stop_ack(requestor
);
1309 if (requestor
== mtc
) requestor
->tc_state
= MTC_TESTCASE
;
1310 else requestor
->tc_state
= PTC_FUNCTION
;
1313 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1316 boolean
MainController::kill_all_components(boolean testcase_ends
)
1318 boolean ready_for_ack
= TRUE
;
1319 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1320 component_struct
*tc
= components
[i
];
1321 boolean is_inactive
= FALSE
;
1322 switch (tc
->tc_state
) {
1324 // the PTC does not have an identified control connection yet
1325 ready_for_ack
= FALSE
;
1328 free_qualified_name(&tc
->tc_fn_name
);
1329 Free(tc
->starting
.arguments_ptr
);
1330 free_requestors(&tc
->starting
.cancel_done_sent_to
);
1347 // the PTC was inactive
1348 tc
->tc_state
= PTC_KILLING
;
1349 if (!tc
->is_alive
) tc
->stop_requested
= TRUE
;
1351 // the PTC was active
1352 tc
->tc_state
= PTC_STOPPING_KILLING
;
1353 tc
->stop_requested
= TRUE
;
1355 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
1356 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
1357 start_kill_timer(tc
);
1358 ready_for_ack
= FALSE
;
1362 tc
->tc_state
= PTC_STOPPING_KILLING
;
1363 if (tc
->kill_timer
!= NULL
) cancel_timer(tc
->kill_timer
);
1364 start_kill_timer(tc
);
1367 case PTC_STOPPING_KILLING
:
1368 free_requestors(&tc
->stopping_killing
.stop_requestors
);
1369 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1370 ready_for_ack
= FALSE
;
1373 if (testcase_ends
) ready_for_ack
= FALSE
;
1378 error("Test Component %d is in invalid state when killing all "
1379 "components.", tc
->comp_ref
);
1381 if (testcase_ends
) {
1382 free_requestors(&tc
->done_requestors
);
1383 free_requestors(&tc
->killed_requestors
);
1385 // only mtc is preserved in done_requestors and killed_requestors
1386 boolean mtc_requested_done
= has_requestor(&tc
->done_requestors
,
1388 free_requestors(&tc
->done_requestors
);
1389 if (mtc_requested_done
) add_requestor(&tc
->done_requestors
, mtc
);
1390 boolean mtc_requested_killed
= has_requestor(&tc
->killed_requestors
,
1392 free_requestors(&tc
->killed_requestors
);
1393 if (mtc_requested_killed
)
1394 add_requestor(&tc
->killed_requestors
, mtc
);
1396 free_requestors(&tc
->cancel_done_sent_for
);
1398 return ready_for_ack
;
1401 void MainController::check_all_component_kill()
1403 // MTC has requested 'all component.kill'
1404 // we have to send acknowledgement to MTC only
1405 boolean ready_for_ack
= TRUE
;
1406 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1407 component_struct
*comp
= components
[i
];
1408 switch (comp
->tc_state
) {
1410 case PTC_STOPPING_KILLING
:
1412 ready_for_ack
= FALSE
;
1418 error("PTC %d is in invalid state when performing "
1419 "'all component.kill' operation.", comp
->comp_ref
);
1421 if (!ready_for_ack
) break;
1423 if (ready_for_ack
) {
1425 mtc
->tc_state
= MTC_TESTCASE
;
1429 void MainController::send_kill_ack_to_requestors(component_struct
*tc
)
1431 for (int i
= 0; ; i
++) {
1432 component_struct
*requestor
=
1433 get_requestor(&tc
->stopping_killing
.kill_requestors
, i
);
1434 if (requestor
== NULL
) break;
1435 if (requestor
->tc_state
== TC_KILL
) {
1436 send_kill_ack(requestor
);
1437 if (requestor
== mtc
) requestor
->tc_state
= MTC_TESTCASE
;
1438 else requestor
->tc_state
= PTC_FUNCTION
;
1441 free_requestors(&tc
->stopping_killing
.kill_requestors
);
1444 void MainController::send_component_status_to_requestor(component_struct
*tc
,
1445 component_struct
*requestor
, boolean done_status
, boolean killed_status
)
1447 switch (requestor
->tc_state
) {
1461 send_component_status_ptc(requestor
, tc
->comp_ref
, TRUE
,
1462 killed_status
, tc
->return_type
, tc
->return_value_len
,
1465 send_component_status_ptc(requestor
, tc
->comp_ref
, FALSE
,
1466 killed_status
, NULL
, 0, NULL
);
1469 case PTC_STOPPING_KILLING
:
1473 // the PTC requestor is not interested in the component status anymore
1476 error("PTC %d is in invalid state when sending out COMPONENT_STATUS "
1477 "message about PTC %d.", requestor
->comp_ref
, tc
->comp_ref
);
1481 void MainController::component_stopped(component_struct
*tc
)
1483 // checking and updating the state of tc
1484 tc_state_enum old_state
= tc
->tc_state
;
1485 if (old_state
== PTC_STOPPING_KILLING
) tc
->tc_state
= PTC_KILLING
;
1487 tc
->tc_state
= PTC_STOPPED
;
1488 if (tc
->kill_timer
!= NULL
) {
1489 cancel_timer(tc
->kill_timer
);
1490 tc
->kill_timer
= NULL
;
1494 case MC_EXECUTING_TESTCASE
:
1495 // this is the correct state
1497 case MC_TERMINATING_TESTCASE
:
1498 // do nothing, we are waiting for the end of all PTC connections
1501 error("PTC %d stopped in invalid MC state.", tc
->comp_ref
);
1504 if (!tc
->is_alive
) {
1505 send_error_str(tc
->tc_fd
, "Message STOPPED can only be sent by "
1509 // Note: the COMPONENT_STATUS message must be sent before STOP_ACK because
1510 // the latter may update the component status cache table to an inconsistent
1512 boolean send_status_to_mtc
= FALSE
, send_done_to_mtc
= FALSE
;
1513 // sending out COMPONENT_STATUS messages to PTCs
1514 for (int i
= 0; ; i
++) {
1515 component_struct
*requestor
= get_requestor(&tc
->done_requestors
, i
);
1516 if (requestor
== NULL
) break;
1517 else if (requestor
== mtc
) {
1518 send_status_to_mtc
= TRUE
;
1519 send_done_to_mtc
= TRUE
;
1520 } else send_component_status_to_requestor(tc
, requestor
, TRUE
, FALSE
);
1522 // do not send unsolicited 'any component.done' status
1523 if (any_component_done_requested
) send_status_to_mtc
= TRUE
;
1524 boolean all_done_checked
= FALSE
, all_done_result
= FALSE
;
1525 if (all_component_done_requested
) {
1526 all_done_checked
= TRUE
;
1527 all_done_result
= !is_any_component_running();
1528 if (all_done_result
) send_status_to_mtc
= TRUE
;
1530 if (send_status_to_mtc
) {
1531 if (!all_done_checked
) all_done_result
= !is_any_component_running();
1532 if (send_done_to_mtc
) {
1533 // the return value was requested
1534 send_component_status_mtc(tc
->comp_ref
, TRUE
, FALSE
,
1535 any_component_done_requested
, all_done_result
, FALSE
, FALSE
,
1536 tc
->return_type
, tc
->return_value_len
, tc
->return_value
);
1538 // the return value was not requested
1539 send_component_status_mtc(NULL_COMPREF
, FALSE
, FALSE
,
1540 any_component_done_requested
, all_done_result
, FALSE
, FALSE
,
1543 if (any_component_done_requested
) {
1544 any_component_done_requested
= FALSE
;
1545 any_component_done_sent
= TRUE
;
1547 if (all_done_result
) all_component_done_requested
= FALSE
;
1549 // sending out STOP_ACK messages
1550 if (old_state
!= PTC_FUNCTION
) {
1551 // the PTC was explicitly stopped and/or killed
1552 if (mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
) {
1554 } else if (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
) {
1555 check_all_component_stop();
1557 send_stop_ack_to_requestors(tc
);
1562 void MainController::component_terminated(component_struct
*tc
)
1564 // the state variable of the PTC has to be updated first
1565 // because in case of 'all component.kill' or 'all component.stop'
1566 // we are walking through the states of all PTCs
1567 tc_state_enum old_state
= tc
->tc_state
;
1568 tc
->tc_state
= TC_EXITING
;
1570 tc
->comp_location
->n_active_components
--;
1572 case MC_EXECUTING_TESTCASE
:
1573 // this is the correct state
1575 case MC_TERMINATING_TESTCASE
:
1576 // do nothing, we are waiting for the end of all PTC connections
1579 error("PTC %d terminated in invalid MC state.", tc
->comp_ref
);
1582 // sending out COMPONENT_STATUS messages
1584 // - the COMPONENT_STATUS message must be sent before STOP_ACK and KILL_ACK
1585 // because the latter may update the component status cache table to an
1586 // inconsistent state
1587 // - unsolicited 'done' status and return value is never sent out
1588 // the flags below indicate whether a COMPONENT_STATUS message
1589 // (with or without the return value) has to be sent to the MTC
1590 boolean send_status_to_mtc
= FALSE
, send_done_to_mtc
= TRUE
;
1591 // first send out the COMPONENT_STATUS messages to PTCs
1592 for (int i
= 0; ; i
++) {
1593 component_struct
*requestor
= get_requestor(&tc
->done_requestors
, i
);
1594 if (requestor
== NULL
) break;
1595 else if (requestor
== mtc
) {
1596 send_status_to_mtc
= TRUE
;
1597 send_done_to_mtc
= TRUE
;
1598 } else send_component_status_to_requestor(tc
, requestor
, TRUE
, TRUE
);
1600 for (int i
= 0; ; i
++) {
1601 component_struct
*requestor
= get_requestor(&tc
->killed_requestors
, i
);
1602 if (requestor
== NULL
) break;
1603 else if (requestor
== mtc
) send_status_to_mtc
= TRUE
;
1604 else if (!has_requestor(&tc
->done_requestors
, requestor
)) {
1605 // do not send COMPONENT_STATUS twice to the same PTC
1606 send_component_status_to_requestor(tc
, requestor
, FALSE
, TRUE
);
1609 free_requestors(&tc
->done_requestors
);
1610 free_requestors(&tc
->killed_requestors
);
1611 // deciding whether to send a COMPONENT_STATUS message to MTC
1612 // 'any component.done' status can be safely sent out
1613 // it will not be cancelled later
1614 if (any_component_done_requested
|| any_component_killed_requested
)
1615 send_status_to_mtc
= TRUE
;
1616 boolean all_done_checked
= FALSE
, all_done_result
= FALSE
;
1617 if (all_component_done_requested
) {
1618 all_done_checked
= TRUE
;
1619 all_done_result
= !is_any_component_running();
1620 if (all_done_result
) send_status_to_mtc
= TRUE
;
1622 boolean all_killed_checked
= FALSE
, all_killed_result
= FALSE
;
1623 if (all_component_killed_requested
) {
1624 all_killed_checked
= TRUE
;
1625 all_killed_result
= !is_any_component_alive();
1626 if (all_killed_result
) send_status_to_mtc
= TRUE
;
1628 // sending the COMPONENT_STATUS message to MTC if necessary
1629 if (send_status_to_mtc
) {
1630 if (!all_done_checked
) all_done_result
= !is_any_component_running();
1631 if (!all_killed_checked
) all_killed_result
= !is_any_component_alive();
1632 if (send_done_to_mtc
) {
1633 // the return value was requested
1634 send_component_status_mtc(tc
->comp_ref
, TRUE
, TRUE
, TRUE
,
1635 all_done_result
, TRUE
, all_killed_result
, tc
->return_type
,
1636 tc
->return_value_len
, tc
->return_value
);
1638 // the return value was not requested
1639 send_component_status_mtc(tc
->comp_ref
, FALSE
, TRUE
, TRUE
,
1640 all_done_result
, TRUE
, all_killed_result
, NULL
, 0, NULL
);
1642 any_component_done_requested
= FALSE
;
1643 any_component_done_sent
= TRUE
;
1644 any_component_killed_requested
= FALSE
;
1645 if (all_done_result
) all_component_done_requested
= FALSE
;
1646 if (all_killed_result
) all_component_killed_requested
= FALSE
;
1648 // sending out STOP_ACK and KILL_ACK messages if necessary
1649 switch (old_state
) {
1651 case PTC_STOPPING_KILLING
:
1653 // the component was explicitly stopped and/or killed
1654 if (mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
) {
1655 check_all_component_kill();
1656 } else if (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
) {
1657 check_all_component_stop();
1659 send_stop_ack_to_requestors(tc
);
1660 send_kill_ack_to_requestors(tc
);
1665 // we should behave as we got all pending CANCEL_DONE_ACK messages from tc
1666 for (int i
= 0; ; i
++) {
1667 component_struct
*comp
= get_requestor(&tc
->cancel_done_sent_for
, i
);
1668 if (comp
== NULL
) break;
1669 done_cancelled(tc
, comp
);
1671 free_requestors(&tc
->cancel_done_sent_for
);
1672 // destroy all connections and mappings of the component
1673 // and send out the related messages
1674 while (tc
->conn_head_list
!= NULL
) {
1675 if (tc
->conn_head_list
->tail
.comp_ref
== SYSTEM_COMPREF
)
1676 destroy_mapping(tc
->conn_head_list
);
1677 else destroy_connection(tc
->conn_head_list
, tc
);
1679 while (tc
->conn_tail_list
!= NULL
) {
1680 if (tc
->conn_tail_list
->head
.comp_ref
== SYSTEM_COMPREF
)
1681 destroy_mapping(tc
->conn_tail_list
);
1682 else destroy_connection(tc
->conn_tail_list
, tc
);
1684 // drop the name of the currently executed function
1685 free_qualified_name(&tc
->tc_fn_name
);
1688 void MainController::done_cancelled(component_struct
*from
,
1689 component_struct
*started_tc
)
1691 // do nothing if the PTC to be started is not in starting state anymore
1692 if (started_tc
->tc_state
!= PTC_STARTING
) return;
1693 remove_requestor(&started_tc
->starting
.cancel_done_sent_to
, from
);
1694 // do nothing if we are waiting for more CANCEL_DONE_ACK messages
1695 if (get_requestor(&started_tc
->starting
.cancel_done_sent_to
, 0) != NULL
)
1697 send_start(started_tc
, started_tc
->tc_fn_name
,
1698 started_tc
->starting
.arguments_len
, started_tc
->starting
.arguments_ptr
);
1699 component_struct
*start_requestor
= started_tc
->starting
.start_requestor
;
1700 if (start_requestor
->tc_state
== TC_START
) {
1701 send_start_ack(start_requestor
);
1702 if (start_requestor
== mtc
) start_requestor
->tc_state
= MTC_TESTCASE
;
1703 else start_requestor
->tc_state
= PTC_FUNCTION
;
1705 Free(started_tc
->starting
.arguments_ptr
);
1706 free_requestors(&started_tc
->starting
.cancel_done_sent_to
);
1707 started_tc
->tc_state
= PTC_FUNCTION
;
1711 boolean
MainController::component_is_alive(component_struct
*tc
)
1713 switch (tc
->tc_state
) {
1729 case PTC_STOPPING_KILLING
:
1735 error("PTC %d is in invalid state when checking whether it is alive.",
1741 boolean
MainController::component_is_running(component_struct
*tc
)
1743 switch (tc
->tc_state
) {
1755 case PTC_STOPPING_KILLING
:
1765 error("PTC %d is in invalid state when checking whether it is running.",
1771 boolean
MainController::component_is_done(component_struct
*tc
)
1773 switch (tc
->tc_state
) {
1792 case PTC_STOPPING_KILLING
:
1795 error("PTC %d is in invalid state when checking whether it is done.",
1801 boolean
MainController::is_any_component_alive()
1803 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1804 if (component_is_alive(components
[i
])) return TRUE
;
1808 boolean
MainController::is_all_component_alive()
1810 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1811 if (!component_is_alive(components
[i
])) return FALSE
;
1815 boolean
MainController::is_any_component_running()
1817 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1818 if (component_is_running(components
[i
])) return TRUE
;
1822 boolean
MainController::is_all_component_running()
1824 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++) {
1825 component_struct
*tc
= components
[i
];
1826 if (tc
->stop_requested
) continue;
1827 switch (tc
->tc_state
) {
1839 boolean
MainController::is_any_component_done()
1841 for (component i
= tc_first_comp_ref
; i
< n_components
; i
++)
1842 if (component_is_done(components
[i
])) return TRUE
;
1846 void MainController::start_kill_timer(component_struct
*tc
)
1848 if (kill_timer
> 0.0) {
1849 timer_struct
*timer
= new timer_struct
;
1850 timer
->expiration
= time_now() + kill_timer
;
1851 timer
->timer_argument
.component_ptr
= tc
;
1852 tc
->kill_timer
= timer
;
1853 register_timer(timer
);
1854 } else tc
->kill_timer
= NULL
;
1857 void MainController::init_connections(component_struct
*tc
)
1859 tc
->conn_head_list
= NULL
;
1860 tc
->conn_tail_list
= NULL
;
1861 tc
->conn_head_count
= 0;
1862 tc
->conn_tail_count
= 0;
1865 void MainController::add_connection(port_connection
*c
)
1867 // Canonical ordering of endpoints so that head <= tail
1868 if (c
->head
.comp_ref
> c
->tail
.comp_ref
) {
1869 component tmp_comp
= c
->head
.comp_ref
;
1870 c
->head
.comp_ref
= c
->tail
.comp_ref
;
1871 c
->tail
.comp_ref
= tmp_comp
;
1872 char *tmp_port
= c
->head
.port_name
;
1873 c
->head
.port_name
= c
->tail
.port_name
;
1874 c
->tail
.port_name
= tmp_port
;
1875 } else if (c
->head
.comp_ref
== c
->tail
.comp_ref
&&
1876 strcmp(c
->head
.port_name
, c
->tail
.port_name
) > 0) {
1877 char *tmp_port
= c
->head
.port_name
;
1878 c
->head
.port_name
= c
->tail
.port_name
;
1879 c
->tail
.port_name
= tmp_port
;
1881 // Double-chain in according to c->head
1882 component_struct
*head_component
= lookup_component(c
->head
.comp_ref
);
1883 port_connection
*head_connection
= head_component
->conn_head_list
;
1884 if (head_connection
== NULL
) {
1888 c
->head
.prev
= head_connection
->head
.prev
;
1889 head_connection
->head
.prev
= c
;
1890 c
->head
.next
= head_connection
;
1891 c
->head
.prev
->head
.next
= c
;
1893 head_component
->conn_head_list
= c
;
1894 head_component
->conn_head_count
++;
1895 // Double-chain in according to c->tail
1896 component_struct
*tail_component
= lookup_component(c
->tail
.comp_ref
);
1897 port_connection
*tail_connection
= tail_component
->conn_tail_list
;
1898 if (tail_connection
== NULL
) {
1902 c
->tail
.prev
= tail_connection
->tail
.prev
;
1903 tail_connection
->tail
.prev
= c
;
1904 c
->tail
.next
= tail_connection
;
1905 c
->tail
.prev
->tail
.next
= c
;
1907 tail_component
->conn_tail_list
= c
;
1908 tail_component
->conn_tail_count
++;
1911 void MainController::remove_connection(port_connection
*c
)
1913 // Remove from conn_head_list
1914 component_struct
*head_component
= lookup_component(c
->head
.comp_ref
);
1915 if (c
->head
.next
== c
) {
1916 head_component
->conn_head_list
= NULL
;
1917 head_component
->conn_head_count
= 0;
1919 c
->head
.prev
->head
.next
= c
->head
.next
;
1920 c
->head
.next
->head
.prev
= c
->head
.prev
;
1921 head_component
->conn_head_list
= c
->head
.next
;
1922 head_component
->conn_head_count
--;
1924 // Remove from conn_tail_list
1925 component_struct
*tail_component
= lookup_component(c
->tail
.comp_ref
);
1926 if (c
->tail
.next
== c
) {
1927 tail_component
->conn_tail_list
= NULL
;
1928 tail_component
->conn_tail_count
= 0;
1930 c
->tail
.prev
->tail
.next
= c
->tail
.next
;
1931 c
->tail
.next
->tail
.prev
= c
->tail
.prev
;
1932 tail_component
->conn_tail_list
= c
->tail
.next
;
1933 tail_component
->conn_tail_count
--;
1935 // Delete the data members
1936 delete [] c
->head
.port_name
;
1937 delete [] c
->tail
.port_name
;
1938 free_requestors(&c
->requestors
);
1942 port_connection
*MainController::find_connection(component head_comp
,
1943 const char *head_port
, component tail_comp
, const char *tail_port
)
1945 // Canonical ordering of parameters so that head <= tail
1946 if (head_comp
> tail_comp
) {
1947 component tmp_comp
= head_comp
;
1948 head_comp
= tail_comp
;
1949 tail_comp
= tmp_comp
;
1950 const char *tmp_port
= head_port
;
1951 head_port
= tail_port
;
1952 tail_port
= tmp_port
;
1953 } else if (head_comp
== tail_comp
&& strcmp(head_port
, tail_port
) > 0) {
1954 const char *tmp_port
= head_port
;
1955 head_port
= tail_port
;
1956 tail_port
= tmp_port
;
1958 // Check whether one of the endpoints' list is empty
1959 component_struct
*head_component
= lookup_component(head_comp
);
1960 port_connection
*head_connection
= head_component
->conn_head_list
;
1961 if (head_connection
== NULL
) return NULL
;
1962 component_struct
*tail_component
= lookup_component(tail_comp
);
1963 port_connection
*tail_connection
= tail_component
->conn_tail_list
;
1964 if (tail_connection
== NULL
) return NULL
;
1965 // Start searching on the shorter list
1966 if (head_component
->conn_head_count
<= tail_component
->conn_tail_count
) {
1967 port_connection
*iter
= head_connection
;
1969 if (iter
->tail
.comp_ref
== tail_comp
&&
1970 !strcmp(iter
->head
.port_name
, head_port
) &&
1971 !strcmp(iter
->tail
.port_name
, tail_port
)) return iter
;
1972 iter
= iter
->head
.next
;
1973 } while (iter
!= head_connection
);
1976 port_connection
*iter
= tail_connection
;
1978 if (iter
->head
.comp_ref
== head_comp
&&
1979 !strcmp(iter
->head
.port_name
, head_port
) &&
1980 !strcmp(iter
->tail
.port_name
, tail_port
)) return iter
;
1981 iter
= iter
->tail
.next
;
1982 } while (iter
!= tail_connection
);
1987 void MainController::remove_all_connections(component head_or_tail
)
1989 component_struct
*comp
= lookup_component(head_or_tail
);
1990 while (comp
->conn_head_list
!= NULL
)
1991 remove_connection(comp
->conn_head_list
);
1992 while (comp
->conn_tail_list
!= NULL
)
1993 remove_connection(comp
->conn_tail_list
);
1996 transport_type_enum
MainController::choose_port_connection_transport(
1997 component head_comp
, component tail_comp
)
1999 host_struct
*head_location
= components
[head_comp
]->comp_location
;
2000 // use the most efficient software loop if the two endpoints are in the
2001 // same component and the host supports it
2002 if (head_comp
== tail_comp
&&
2003 head_location
->transport_supported
[TRANSPORT_LOCAL
])
2004 return TRANSPORT_LOCAL
;
2005 host_struct
*tail_location
= components
[tail_comp
]->comp_location
;
2006 // use the efficient UNIX domain socket if the two endpoints are on the
2007 // same host and it is supported by the host
2008 if (head_location
== tail_location
&&
2009 head_location
->transport_supported
[TRANSPORT_UNIX_STREAM
])
2010 return TRANSPORT_UNIX_STREAM
;
2011 // use TCP if it is supported by the host of both endpoints
2012 if (head_location
->transport_supported
[TRANSPORT_INET_STREAM
] &&
2013 tail_location
->transport_supported
[TRANSPORT_INET_STREAM
])
2014 return TRANSPORT_INET_STREAM
;
2015 // no suitable transport was found, return an erroneous type
2016 return TRANSPORT_NUM
;
2019 void MainController::send_connect_ack_to_requestors(port_connection
*conn
)
2021 for (int i
= 0; ; i
++) {
2022 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2023 if (comp
== NULL
) break;
2024 else if (comp
->tc_state
== TC_CONNECT
) {
2025 send_connect_ack(comp
);
2026 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2027 else comp
->tc_state
= PTC_FUNCTION
;
2030 free_requestors(&conn
->requestors
);
2033 void MainController::send_error_to_connect_requestors(port_connection
*conn
,
2034 const char *fmt
, ...)
2036 char *reason
= mprintf("Establishment of port connection %d:%s - %d:%s "
2037 "failed because ", conn
->head
.comp_ref
, conn
->head
.port_name
,
2038 conn
->tail
.comp_ref
, conn
->tail
.port_name
);
2041 reason
= mputprintf_va_list(reason
, fmt
, ap
);
2043 for (int i
= 0; ; i
++) {
2044 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2045 if (comp
== NULL
) break;
2046 else if (comp
->tc_state
== TC_CONNECT
) {
2047 send_error_str(comp
->tc_fd
, reason
);
2048 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2049 else comp
->tc_state
= PTC_FUNCTION
;
2053 free_requestors(&conn
->requestors
);
2056 void MainController::send_disconnect_to_server(port_connection
*conn
)
2058 component_struct
*comp
= components
[conn
->head
.comp_ref
];
2059 switch (comp
->tc_state
) {
2074 send_disconnect(comp
, conn
->head
.port_name
, conn
->tail
.comp_ref
,
2075 conn
->tail
.port_name
);
2081 void MainController::send_disconnect_ack_to_requestors(port_connection
*conn
)
2083 for (int i
= 0; ; i
++) {
2084 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
2085 if (comp
== NULL
) break;
2086 else if (comp
->tc_state
== TC_DISCONNECT
) {
2087 send_disconnect_ack(comp
);
2088 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
2089 else comp
->tc_state
= PTC_FUNCTION
;
2092 free_requestors(&conn
->requestors
);
2095 void MainController::init_requestors(requestor_struct
*reqs
,
2096 component_struct
*tc
)
2099 reqs
->n_components
= 1;
2100 reqs
->the_component
= tc
;
2101 } else reqs
->n_components
= 0;
2104 void MainController::add_requestor(requestor_struct
*reqs
, component_struct
*tc
)
2106 switch (reqs
->n_components
) {
2108 reqs
->n_components
= 1;
2109 reqs
->the_component
= tc
;
2112 if (reqs
->the_component
!= tc
) {
2113 reqs
->n_components
= 2;
2114 component_struct
*tmp
= reqs
->the_component
;
2116 (component_struct
**)Malloc(2 * sizeof(*reqs
->components
));
2117 reqs
->components
[0] = tmp
;
2118 reqs
->components
[1] = tc
;
2122 for (int i
= 0; i
< reqs
->n_components
; i
++)
2123 if (reqs
->components
[i
] == tc
) return;
2124 reqs
->n_components
++;
2125 reqs
->components
= (component_struct
**)Realloc(reqs
->components
,
2126 reqs
->n_components
* sizeof(*reqs
->components
));
2127 reqs
->components
[reqs
->n_components
- 1] = tc
;
2131 void MainController::remove_requestor(requestor_struct
*reqs
,
2132 component_struct
*tc
)
2134 switch (reqs
->n_components
) {
2138 if (reqs
->the_component
== tc
) reqs
->n_components
= 0;
2141 component_struct
*tmp
= NULL
;
2142 if (reqs
->components
[0] == tc
) tmp
= reqs
->components
[1];
2143 else if (reqs
->components
[1] == tc
) tmp
= reqs
->components
[0];
2145 Free(reqs
->components
);
2146 reqs
->n_components
= 1;
2147 reqs
->the_component
= tmp
;
2151 for (int i
= 0; i
< reqs
->n_components
; i
++)
2152 if (reqs
->components
[i
] == tc
) {
2153 reqs
->n_components
--;
2154 memmove(reqs
->components
+ i
, reqs
->components
+ i
+ 1,
2155 (reqs
->n_components
- i
) * sizeof(*reqs
->components
));
2156 reqs
->components
= (component_struct
**)Realloc(reqs
->components
,
2157 reqs
->n_components
* sizeof(*reqs
->components
));
2163 boolean
MainController::has_requestor(const requestor_struct
*reqs
,
2164 component_struct
*tc
)
2166 switch (reqs
->n_components
) {
2170 return reqs
->the_component
== tc
;
2172 for (int i
= 0; i
< reqs
->n_components
; i
++)
2173 if (reqs
->components
[i
] == tc
) return TRUE
;
2178 component_struct
*MainController::get_requestor(const requestor_struct
*reqs
,
2181 if (index
>= 0 && index
< reqs
->n_components
) {
2182 if (reqs
->n_components
== 1) return reqs
->the_component
;
2183 else return reqs
->components
[index
];
2187 void MainController::free_requestors(requestor_struct
*reqs
)
2189 if (reqs
->n_components
> 1) Free(reqs
->components
);
2190 reqs
->n_components
= 0;
2193 void MainController::init_qualified_name(qualified_name
*name
)
2195 name
->module_name
= NULL
;
2196 name
->definition_name
= NULL
;
2199 void MainController::free_qualified_name(qualified_name
*name
)
2201 delete [] name
->module_name
;
2202 name
->module_name
= NULL
;
2203 delete [] name
->definition_name
;
2204 name
->definition_name
= NULL
;
2207 double MainController::kill_timer
;
2209 double MainController::time_now()
2211 static boolean first_call
= TRUE
;
2212 static struct timeval first_time
;
2215 if (gettimeofday(&first_time
, NULL
) < 0)
2216 fatal_error("MainController::time_now: gettimeofday() system call "
2221 if (gettimeofday(&tv
, NULL
) < 0)
2222 fatal_error("MainController::time_now: gettimeofday() system call "
2224 return (tv
.tv_sec
- first_time
.tv_sec
) +
2225 1.0e-6 * (tv
.tv_usec
- first_time
.tv_usec
);
2229 timer_struct
*MainController::timer_head
, *MainController::timer_tail
;
2231 void MainController::register_timer(timer_struct
*timer
)
2234 for (iter
= timer_tail
; iter
!= NULL
; iter
= iter
->prev
)
2235 if (iter
->expiration
<= timer
->expiration
) break;
2237 // inserting after iter
2239 timer
->next
= iter
->next
;
2240 if (iter
->next
!= NULL
) iter
->next
->prev
= timer
;
2241 else timer_tail
= timer
;
2244 // inserting at the beginning of list
2246 timer
->next
= timer_head
;
2247 if (timer_head
!= NULL
) timer_head
->prev
= timer
;
2248 else timer_tail
= timer
;
2253 void MainController::cancel_timer(timer_struct
*timer
)
2255 if (timer
->next
!= NULL
) timer
->next
->prev
= timer
->prev
;
2256 else timer_tail
= timer
->prev
;
2257 if (timer
->prev
!= NULL
) timer
->prev
->next
= timer
->next
;
2258 else timer_head
= timer
->next
;
2262 int MainController::get_poll_timeout()
2264 if (timer_head
!= NULL
) {
2265 double offset
= timer_head
->expiration
- time_now();
2266 if (offset
> 0.0) return (int)(1000.0 * offset
);
2271 void MainController::handle_expired_timers()
2273 if (timer_head
!= NULL
) {
2274 timer_struct
*iter
= timer_head
;
2275 double now
= time_now();
2277 if (iter
->expiration
> now
) break;
2278 timer_struct
*next
= iter
->next
;
2279 handle_kill_timer(iter
);
2281 } while (iter
!= NULL
);
2285 void MainController::handle_kill_timer(timer_struct
*timer
)
2287 component_struct
*tc
= timer
->timer_argument
.component_ptr
;
2288 host_struct
*host
= tc
->comp_location
;
2289 boolean kill_process
= FALSE
;
2290 switch (tc
->tc_state
) {
2296 error("MTC on host %s did not close its control connection in "
2297 "time. Trying to kill it using its HC.", host
->hostname
);
2299 notify("PTC %d on host %s did not close its control connection in "
2300 "time. Trying to kill it using its HC.", tc
->comp_ref
,
2303 kill_process
= TRUE
;
2306 case PTC_STOPPING_KILLING
:
2308 // active PTCs with kill timer can be only in these states
2310 notify("PTC %d on host %s is not responding. Trying to kill it "
2311 "using its HC.", tc
->comp_ref
, host
->hostname
);
2312 kill_process
= TRUE
;
2317 // MTC can be in any state
2319 error("MTC on host %s is not responding. Trying to kill it using "
2320 "its HC. This will abort test execution.", host
->hostname
);
2321 kill_process
= TRUE
;
2323 error("PTC %d is in invalid state when its kill timer expired.",
2328 if (host
->hc_state
== HC_ACTIVE
) {
2329 send_kill_process(host
, tc
->comp_ref
);
2330 tc
->process_killed
= TRUE
;
2332 error("Test Component %d cannot be killed because the HC on host "
2333 "%s is not in active state. Kill the process manually or the "
2334 "test system may get into a deadlock.", tc
->comp_ref
,
2338 cancel_timer(timer
);
2339 tc
->kill_timer
= NULL
;
2342 void MainController::register_termination_handlers()
2344 new_action
.sa_handler
= termination_handler
;
2345 sigemptyset(&new_action
.sa_mask
);
2346 new_action
.sa_flags
= 0;
2348 sigaction(SIGINT
, NULL
, &old_action
);
2349 if (old_action
.sa_handler
!= SIG_IGN
)
2350 sigaction (SIGINT
, &new_action
, NULL
);
2351 sigaction(SIGHUP
, NULL
, &old_action
);
2352 if (old_action
.sa_handler
!= SIG_IGN
)
2353 sigaction (SIGHUP
, &new_action
, NULL
);
2354 sigaction(SIGTERM
, NULL
, &old_action
);
2355 if (old_action
.sa_handler
!= SIG_IGN
)
2356 sigaction(SIGTERM
, &new_action
, NULL
);
2357 sigaction(SIGQUIT
, NULL
, &old_action
);
2358 if (old_action
.sa_handler
!= SIG_IGN
)
2359 sigaction(SIGQUIT
, &new_action
, NULL
);
2360 sigaction(SIGKILL
, NULL
, &old_action
);
2361 if (old_action
.sa_handler
!= SIG_IGN
)
2362 sigaction(SIGKILL
, &new_action
, NULL
);
2365 void MainController::termination_handler(int signum
)
2367 // Call shutdown_server() and reset handlers and re-raise the signal.
2368 // clean_up() or perform_shutdown() is state dependent and cannot be used
2369 // here... Related to HP67376.
2372 new_action
.sa_handler
= SIG_DFL
;
2373 sigemptyset(&new_action
.sa_mask
);
2374 new_action
.sa_flags
= 0;
2376 sigaction(SIGINT
, &new_action
, NULL
);
2377 sigaction(SIGHUP
, &new_action
, NULL
);
2378 sigaction(SIGTERM
, &new_action
, NULL
);
2379 sigaction(SIGQUIT
, &new_action
, NULL
);
2380 sigaction(SIGKILL
, &new_action
, NULL
);
2385 void MainController::error(const char *fmt
, ...)
2389 char *str
= mprintf_va_list(fmt
, ap
);
2392 ui
->error(/*severity*/ 0, str
);
2397 void MainController::notify(const char *fmt
, ...)
2401 char *str
= mprintf_va_list(fmt
, ap
);
2404 if (gettimeofday(&tv
, NULL
) < 0) fatal_error("MainController::notify: "
2405 "gettimeofday() system call failed.");
2406 notify(&tv
, mc_hostname
, TTCN_EXECUTOR
, str
);
2410 void MainController::notify(const struct timeval
*timestamp
,
2411 const char *source
, int severity
, const char *message
)
2414 ui
->notify(timestamp
, source
, severity
, message
);
2418 void MainController::status_change()
2421 ui
->status_change();
2425 void MainController::fatal_error(const char *fmt
, ...)
2429 vfprintf(stderr
, fmt
, ap
);
2431 if (errno
!= 0) fprintf(stderr
, " (%s)", strerror(errno
));
2436 void *MainController::thread_main(void *)
2439 while (mc_state
!= MC_INACTIVE
) {
2444 int timeout
= get_poll_timeout();
2445 if (maxDtInMs
!= 0 && (timeout
< 0 || maxDtInMs
< timeout
))
2446 timeout
= maxDtInMs
;
2448 fds_selected
= epoll_wait(epfd
, epoll_events
, EPOLL_MAX_EVENTS
,
2451 if (fds_selected
>= 0) break;
2452 if (errno
!= EINTR
) fatal_error("epoll_wait() system call failed.");
2453 #else // ! defined USE_EPOLL
2455 int timeout
= get_poll_timeout();
2456 if (maxDtInMs
!= 0 && (timeout
< 0 || maxDtInMs
< timeout
))
2457 timeout
= maxDtInMs
;
2459 fds_selected
= poll(ufds
, nfds
, timeout
);
2461 if (fds_selected
>= 0) break;
2462 if (errno
!= EINTR
) fatal_error("poll() system call failed.");
2466 switch (wakeup_reason
) {
2467 case REASON_NOTHING
:
2468 case REASON_MTC_KILL_TIMER
:
2470 case REASON_SHUTDOWN
:
2471 wakeup_reason
= REASON_NOTHING
;
2475 error("Invalid wakeup reason (%d) was set.", wakeup_reason
);
2476 wakeup_reason
= REASON_NOTHING
;
2478 if (fds_selected
== 0) {
2479 handle_expired_timers();
2483 for (int i
= 0; i
< fds_selected
; i
++) {
2484 int fd
= epoll_events
[i
].data
.fd
;
2485 if (epoll_events
[i
].events
& (EPOLLIN
| EPOLLHUP
| EPOLLERR
)) {
2486 dispatch_socket_event(fd
);
2489 #else // ! defined USE_EPOLL
2490 for (unsigned int i
= 0; i
< nfds
; i
++) {
2491 int fd
= ufds
[i
].fd
;
2492 if (ufds
[i
].revents
& POLLNVAL
) {
2493 fatal_error("Invalid file descriptor (%d) was given for "
2494 "poll() system call.", fd
);
2495 } else if (ufds
[i
].revents
& (POLLIN
| POLLHUP
| POLLERR
)) {
2496 dispatch_socket_event(fd
);
2500 handle_expired_timers();
2503 notify("Shutdown complete.");
2505 // don't try to lock the mutex after ui->status_change() is completed
2506 // the main thread might call in turn terminate(), which destroys the mutex
2507 ui
->status_change();
2511 void MainController::dispatch_socket_event(int fd
)
2513 // a previous event might have closed the socket
2514 if (fd
>= fd_table_size
) return;
2515 switch (fd_table
[fd
].fd_type
) {
2520 handle_incoming_connection(fd
);
2523 handle_unknown_data(fd_table
[fd
].unknown_ptr
);
2526 handle_hc_data(fd_table
[fd
].host_ptr
, TRUE
);
2529 handle_tc_data(fd_table
[fd
].component_ptr
, TRUE
);
2532 fatal_error("Invalid file descriptor type (%d) for "
2533 "file descriptor %d.", fd_table
[fd
].fd_type
, fd
);
2537 int MainController::pipe_fd
[2];
2538 wakeup_reason_t
MainController::wakeup_reason
;
2540 void MainController::wakeup_thread(wakeup_reason_t reason
)
2542 unsigned char msg
= '\0';
2543 if (write(pipe_fd
[1], &msg
, 1) != 1) {
2544 fatal_error("MainController::wakeup_thread: writing to pipe failed.");
2546 wakeup_reason
= reason
;
2549 void MainController::handle_pipe()
2552 if (read(pipe_fd
[0], &buf
, 1) != 1) {
2553 fatal_error("MainController::handle_pipe: reading from pipe failed.");
2557 void MainController::handle_incoming_connection(int p_server_fd
)
2559 IPAddress
*remote_addr
= IPAddress::create_addr(nh
.get_family());
2560 int fd
= remote_addr
->accept(p_server_fd
);
2562 set_close_on_exec(fd
);
2563 unknown_connection
*new_connection
=
2564 new_unknown_connection(p_server_fd
!= MainController::server_fd
);
2565 new_connection
->fd
= fd
;
2566 if (p_server_fd
== MainController::server_fd
)
2567 new_connection
->ip_addr
= remote_addr
;
2568 else { // in case of unix domain socket connection
2570 new_connection
->ip_addr
= IPAddress::create_addr("127.0.0.1");
2572 new_connection
->text_buf
= new Text_Buf
;
2574 add_fd_to_table(fd
);
2575 fd_table
[fd
].fd_type
= FD_UNKNOWN
;
2576 fd_table
[fd
].unknown_ptr
= new_connection
;
2585 error("New incoming connection cannot be accepted "
2586 "because the maximum number of open files has been reached. "
2587 "Try to increase this limit.");
2588 disable_server_fd();
2589 error("No incoming connections will be accepted until at least "
2590 "one component terminates. This may result in deadlock.");
2593 fatal_error("MainController::handle_incoming_connection: "
2594 "system call accept() failed.");
2599 int MainController::recv_to_buffer(int fd
, Text_Buf
& text_buf
,
2600 boolean recv_from_socket
)
2602 // if recv_from_socket is false we are checking the messages that are
2603 // already in text_buf so we are emulating that recv() was successful
2604 if (!recv_from_socket
) return 1;
2608 text_buf
.get_end(buf_ptr
, buf_len
);
2610 int recv_len
= recv(fd
, buf_ptr
, buf_len
, 0);
2612 if (recv_len
> 0) text_buf
.increase_length(recv_len
);
2617 void MainController::handle_unknown_data(unknown_connection
*conn
)
2619 Text_Buf
& text_buf
= *conn
->text_buf
;
2620 int recv_len
= recv_to_buffer(conn
->fd
, text_buf
, TRUE
);
2621 boolean error_flag
= FALSE
;
2625 while (text_buf
.is_message()) {
2626 text_buf
.pull_int(); // message length
2627 int message_type
= text_buf
.pull_int().get_val();
2628 // only the first message is processed in this loop
2629 // except when a generic message is received
2630 boolean process_more_messages
= FALSE
;
2631 switch (message_type
) {
2633 process_error(conn
);
2634 process_more_messages
= TRUE
;
2638 process_more_messages
= TRUE
;
2641 process_version(conn
);
2643 case MSG_MTC_CREATED
:
2644 process_mtc_created(conn
);
2646 case MSG_PTC_CREATED
:
2647 process_ptc_created(conn
);
2650 error("Invalid message type (%d) was received on an "
2651 "unknown connection from %s [%s].", message_type
,
2652 conn
->ip_addr
->get_host_str(),
2653 conn
->ip_addr
->get_addr_str());
2656 if (process_more_messages
) text_buf
.cut_message();
2659 } catch (const TC_Error
& tc_error
) {
2660 error("Maleformed message was received on an unknown connection "
2661 "from %s [%s].", conn
->ip_addr
->get_host_str(),
2662 conn
->ip_addr
->get_addr_str());
2666 send_error_str(conn
->fd
, "The received message was not understood "
2669 } else if (recv_len
== 0) {
2670 error("Unexpected end of an unknown connection from %s [%s].",
2671 conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str());
2674 error("Receiving of data failed on an unknown connection from %s [%s].",
2675 conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str());
2679 close_unknown_connection(conn
);
2683 void MainController::handle_hc_data(host_struct
*hc
, boolean recv_from_socket
)
2685 Text_Buf
& text_buf
= *hc
->text_buf
;
2686 boolean error_flag
= FALSE
;
2687 int recv_len
= recv_to_buffer(hc
->hc_fd
, text_buf
, recv_from_socket
);
2691 while (text_buf
.is_message()) {
2692 text_buf
.pull_int(); // message length
2693 int message_type
= text_buf
.pull_int().get_val();
2694 switch (message_type
) {
2701 case MSG_CONFIGURE_ACK
:
2702 process_configure_ack(hc
);
2704 case MSG_CONFIGURE_NAK
:
2705 process_configure_nak(hc
);
2707 case MSG_CREATE_NAK
:
2708 process_create_nak(hc
);
2711 process_hc_ready(hc
);
2714 error("Invalid message type (%d) was received on HC "
2715 "connection from %s [%s].", message_type
,
2716 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2719 if (error_flag
) break;
2720 text_buf
.cut_message();
2722 } catch (const TC_Error
& tc_error
) {
2723 error("Malformed message was received on HC connection "
2724 "from %s [%s].", hc
->hostname
, hc
->ip_addr
->get_addr_str());
2728 send_error_str(hc
->hc_fd
, "The received message was not understood "
2731 } else if (recv_len
== 0) {
2732 if (hc
->hc_state
== HC_EXITING
) {
2733 close_hc_connection(hc
);
2734 if (mc_state
== MC_SHUTDOWN
&& all_hc_in_state(HC_DOWN
))
2735 mc_state
= MC_INACTIVE
;
2737 error("Unexpected end of HC connection from %s [%s].",
2738 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2742 error("Receiving of data failed on HC connection from %s [%s].",
2743 hc
->hostname
, hc
->ip_addr
->get_addr_str());
2747 close_hc_connection(hc
);
2751 case MC_LISTENING_CONFIGURED
:
2752 fatal_error("MC is in invalid state when a HC connection "
2754 case MC_HC_CONNECTED
:
2755 if (all_hc_in_state(HC_DOWN
)) mc_state
= MC_LISTENING
;
2757 case MC_CONFIGURING
:
2758 check_all_hc_configured();
2761 if (all_hc_in_state(HC_DOWN
)) mc_state
= MC_LISTENING_CONFIGURED
;
2762 else if (!is_hc_in_state(HC_ACTIVE
) &&
2763 !is_hc_in_state(HC_OVERLOADED
)) mc_state
= MC_HC_CONNECTED
;
2766 if (!is_hc_in_state(HC_ACTIVE
)) notify("There is no active HC "
2767 "connection. Further create operations will fail.");
2773 void MainController::handle_tc_data(component_struct
*tc
,
2774 boolean recv_from_socket
)
2776 Text_Buf
& text_buf
= *tc
->text_buf
;
2777 boolean close_connection
= FALSE
;
2778 int recv_len
= recv_to_buffer(tc
->tc_fd
, text_buf
, recv_from_socket
);
2782 while (text_buf
.is_message()) {
2783 int message_len
= text_buf
.pull_int().get_val();
2784 int message_end
= text_buf
.get_pos() + message_len
;
2785 int message_type
= text_buf
.pull_int().get_val();
2786 // these messages can be received both from MTC and PTCs
2787 switch (message_type
) {
2794 case MSG_CREATE_REQ
:
2795 process_create_req(tc
);
2798 process_start_req(tc
, message_end
);
2801 process_stop_req(tc
);
2804 process_kill_req(tc
);
2806 case MSG_IS_RUNNING
:
2807 process_is_running(tc
);
2810 process_is_alive(tc
);
2813 process_done_req(tc
);
2815 case MSG_KILLED_REQ
:
2816 process_killed_req(tc
);
2818 case MSG_CANCEL_DONE_ACK
:
2819 process_cancel_done_ack(tc
);
2821 case MSG_CONNECT_REQ
:
2822 process_connect_req(tc
);
2824 case MSG_CONNECT_LISTEN_ACK
:
2825 process_connect_listen_ack(tc
, message_end
);
2828 process_connected(tc
);
2830 case MSG_CONNECT_ERROR
:
2831 process_connect_error(tc
);
2833 case MSG_DISCONNECT_REQ
:
2834 process_disconnect_req(tc
);
2836 case MSG_DISCONNECTED
:
2837 process_disconnected(tc
);
2840 process_map_req(tc
);
2846 process_unmap_req(tc
);
2849 process_unmapped(tc
);
2853 // these messages can be received only from the MTC
2854 switch (message_type
) {
2855 case MSG_TESTCASE_STARTED
:
2856 process_testcase_started();
2858 case MSG_TESTCASE_FINISHED
:
2859 process_testcase_finished();
2862 process_mtc_ready();
2865 error("Invalid message type (%d) was received "
2866 "from the MTC at %s [%s].", message_type
,
2867 mtc
->comp_location
->hostname
,
2868 mtc
->comp_location
->ip_addr
->get_addr_str());
2869 close_connection
= TRUE
;
2872 // these messages can be received only from PTCs
2873 switch (message_type
) {
2875 process_stopped(tc
, message_end
);
2877 case MSG_STOPPED_KILLED
:
2878 process_stopped_killed(tc
, message_end
);
2884 notify("Invalid message type (%d) was received from "
2885 "PTC %d at %s [%s].", message_type
,
2886 tc
->comp_ref
, tc
->comp_location
->hostname
,
2887 tc
->comp_location
->ip_addr
->get_addr_str());
2888 close_connection
= TRUE
;
2892 if (close_connection
) break;
2893 text_buf
.cut_message();
2895 } catch (const TC_Error
& tc_error
) {
2897 error("Malformed message was received from the MTC at %s "
2898 "[%s].", mtc
->comp_location
->hostname
,
2899 mtc
->comp_location
->ip_addr
->get_addr_str());
2901 notify("Malformed message was received from PTC %d at %s [%s].",
2902 tc
->comp_ref
, tc
->comp_location
->hostname
,
2903 tc
->comp_location
->ip_addr
->get_addr_str());
2905 close_connection
= TRUE
;
2907 if (close_connection
) {
2908 send_error_str(tc
->tc_fd
, "The received message was not understood "
2911 } else if (recv_len
== 0) {
2912 // TCP connection is closed by peer
2913 if (tc
->tc_state
!= TC_EXITING
&& !tc
->process_killed
) {
2915 error("Unexpected end of MTC connection from %s [%s].",
2916 mtc
->comp_location
->hostname
,
2917 mtc
->comp_location
->ip_addr
->get_addr_str());
2919 notify("Unexpected end of PTC connection (%d) from %s [%s].",
2920 tc
->comp_ref
, tc
->comp_location
->hostname
,
2921 tc
->comp_location
->ip_addr
->get_addr_str());
2924 close_connection
= TRUE
;
2926 if (tc
->process_killed
&& errno
== ECONNRESET
) {
2927 // ignore TCP resets if the process was killed
2928 // because the last STOP or KILL message can stuck in TCP buffers
2929 // if the process did not receive any data
2932 error("Receiving of data failed from the MTC at %s [%s]: %s",
2933 mtc
->comp_location
->hostname
,
2934 mtc
->comp_location
->ip_addr
->get_addr_str(), strerror(errno
));
2936 notify("Receiving of data failed from PTC %d at %s [%s]: %s",
2937 tc
->comp_ref
, tc
->comp_location
->hostname
,
2938 tc
->comp_location
->ip_addr
->get_addr_str(), strerror(errno
));
2941 close_connection
= TRUE
;
2943 if (close_connection
) {
2944 close_tc_connection(tc
);
2945 remove_component_from_host(tc
);
2947 if (mc_state
!= MC_TERMINATING_MTC
) {
2948 notify("The control connection to MTC is lost. "
2949 "Destroying all PTC connections.");
2951 destroy_all_components();
2952 notify("MTC terminated.");
2953 if (is_hc_in_state(HC_CONFIGURING
)) mc_state
= MC_CONFIGURING
;
2954 else if (is_hc_in_state(HC_IDLE
)) mc_state
= MC_HC_CONNECTED
;
2955 else if (is_hc_in_state(HC_ACTIVE
) ||
2956 is_hc_in_state(HC_OVERLOADED
)) mc_state
= MC_ACTIVE
;
2957 else mc_state
= MC_LISTENING_CONFIGURED
;
2958 stop_requested
= FALSE
;
2960 if (tc
->tc_state
!= TC_EXITING
) {
2961 // we have no idea about the final verdict of the PTC
2962 tc
->local_verdict
= ERROR
;
2963 component_terminated(tc
);
2965 tc
->tc_state
= TC_EXITED
;
2966 if (mc_state
== MC_TERMINATING_TESTCASE
&&
2967 ready_to_finish_testcase()) finish_testcase();
2973 void MainController::unlink_unix_socket(int socket_fd
) {
2974 struct sockaddr_un local_addr
;
2975 // querying the local pathname used by socket_fd
2976 socklen_type addr_len
= sizeof(local_addr
);
2977 if (getsockname(socket_fd
, (struct sockaddr
*)&local_addr
, &addr_len
)) {
2978 } else if (local_addr
.sun_family
!= AF_UNIX
) {
2979 } else if (unlink(local_addr
.sun_path
)) {
2984 void MainController::shutdown_server()
2986 if (server_fd
>= 0) {
2987 remove_poll_fd(server_fd
);
2988 remove_fd_from_table(server_fd
);
2993 if (server_fd_unix
>= 0) {
2994 unlink_unix_socket(server_fd_unix
);
2995 remove_poll_fd(server_fd_unix
);
2996 remove_fd_from_table(server_fd_unix
);
2997 close(server_fd_unix
);
2998 server_fd_unix
= -1;
3002 void MainController::perform_shutdown()
3004 boolean shutdown_complete
= TRUE
;
3006 case MC_HC_CONNECTED
:
3008 for (int i
= 0; i
< n_hosts
; i
++) {
3009 host_struct
*host
= hosts
[i
];
3010 if (host
->hc_state
!= HC_DOWN
) {
3012 host
->hc_state
= HC_EXITING
;
3013 shutdown_complete
= FALSE
;
3018 case MC_LISTENING_CONFIGURED
:
3020 // don't call status_change() if shutdown is complete
3021 // it will be called from thread_main() later
3022 if (shutdown_complete
) mc_state
= MC_INACTIVE
;
3024 mc_state
= MC_SHUTDOWN
;
3029 fatal_error("MainController::perform_shutdown: called in wrong state.");
3033 void MainController::clean_up()
3037 while (unknown_head
!= NULL
) close_unknown_connection(unknown_head
);
3039 destroy_all_components();
3041 for (int i
= 0; i
< n_hosts
; i
++) {
3042 host_struct
*host
= hosts
[i
];
3043 close_hc_connection(host
);
3044 Free(host
->hostname
);
3045 delete host
->ip_addr
;
3046 delete [] host
->hostname_local
;
3047 delete [] host
->machine_type
;
3048 delete [] host
->system_name
;
3049 delete [] host
->system_release
;
3050 delete [] host
->system_version
;
3051 Free(host
->log_source
);
3052 Free(host
->components
);
3053 free_string_set(&host
->allowed_components
);
3062 while (timer_head
!= NULL
) cancel_timer(timer_head
);
3064 for (int i
= 0; i
< n_modules
; i
++) {
3065 delete [] modules
[i
].module_name
;
3066 delete [] modules
[i
].module_checksum
;
3071 version_known
= FALSE
;
3075 if (close(epfd
) < 0)
3076 error("MainController::clean_up: Error while closing epoll"
3081 epoll_events
= NULL
;
3082 #else // ! defined USE_EPOLL
3089 pollfds_modified
= FALSE
;
3096 mc_state
= MC_INACTIVE
;
3098 if (pipe_fd
[1] >= 0) {
3102 if (pipe_fd
[0] >= 0) {
3108 void MainController::send_configure(host_struct
*hc
, const char *config_file
)
3111 text_buf
.push_int(MSG_CONFIGURE
);
3112 text_buf
.push_string(config_file
);
3113 send_message(hc
->hc_fd
, text_buf
);
3116 void MainController::send_exit_hc(host_struct
*hc
)
3119 text_buf
.push_int(MSG_EXIT_HC
);
3120 send_message(hc
->hc_fd
, text_buf
);
3123 void MainController::send_create_mtc(host_struct
*hc
)
3126 text_buf
.push_int(MSG_CREATE_MTC
);
3127 send_message(hc
->hc_fd
, text_buf
);
3130 void MainController::send_create_ptc(host_struct
*hc
,
3131 component component_reference
, const qualified_name
& component_type
,
3132 const char *component_name
, boolean is_alive
,
3133 const qualified_name
& current_testcase
)
3136 text_buf
.push_int(MSG_CREATE_PTC
);
3137 text_buf
.push_int(component_reference
);
3138 text_buf
.push_qualified_name(component_type
);
3139 text_buf
.push_string(component_name
);
3140 text_buf
.push_int(is_alive
? 1 : 0);
3141 text_buf
.push_qualified_name(current_testcase
);
3142 send_message(hc
->hc_fd
, text_buf
);
3145 void MainController::send_kill_process(host_struct
*hc
,
3146 component component_reference
)
3149 text_buf
.push_int(MSG_KILL_PROCESS
);
3150 text_buf
.push_int(component_reference
);
3151 send_message(hc
->hc_fd
, text_buf
);
3154 void MainController::send_create_ack(component_struct
*tc
,
3155 component component_reference
)
3158 text_buf
.push_int(MSG_CREATE_ACK
);
3159 text_buf
.push_int(component_reference
);
3160 send_message(tc
->tc_fd
, text_buf
);
3163 void MainController::send_start_ack(component_struct
*tc
)
3166 text_buf
.push_int(MSG_START_ACK
);
3167 send_message(tc
->tc_fd
, text_buf
);
3170 void MainController::send_stop(component_struct
*tc
)
3173 text_buf
.push_int(MSG_STOP
);
3174 send_message(tc
->tc_fd
, text_buf
);
3177 void MainController::send_stop_ack(component_struct
*tc
)
3180 text_buf
.push_int(MSG_STOP_ACK
);
3181 send_message(tc
->tc_fd
, text_buf
);
3184 void MainController::send_kill_ack(component_struct
*tc
)
3187 text_buf
.push_int(MSG_KILL_ACK
);
3188 send_message(tc
->tc_fd
, text_buf
);
3191 void MainController::send_running(component_struct
*tc
, boolean answer
)
3194 text_buf
.push_int(MSG_RUNNING
);
3195 text_buf
.push_int(answer
? 1 : 0);
3196 send_message(tc
->tc_fd
, text_buf
);
3199 void MainController::send_alive(component_struct
*tc
, boolean answer
)
3202 text_buf
.push_int(MSG_ALIVE
);
3203 text_buf
.push_int(answer
? 1 : 0);
3204 send_message(tc
->tc_fd
, text_buf
);
3207 void MainController::send_done_ack(component_struct
*tc
, boolean answer
,
3208 const char *return_type
, int return_value_len
, const void *return_value
)
3211 text_buf
.push_int(MSG_DONE_ACK
);
3212 text_buf
.push_int(answer
? 1 : 0);
3213 text_buf
.push_string(return_type
);
3214 text_buf
.push_raw(return_value_len
, return_value
);
3215 send_message(tc
->tc_fd
, text_buf
);
3218 void MainController::send_killed_ack(component_struct
*tc
, boolean answer
)
3221 text_buf
.push_int(MSG_KILLED_ACK
);
3222 text_buf
.push_int(answer
? 1 : 0);
3223 send_message(tc
->tc_fd
, text_buf
);
3226 void MainController::send_connect_listen(component_struct
*tc
,
3227 const char *local_port
, component remote_comp
, const char *remote_comp_name
,
3228 const char *remote_port
, transport_type_enum transport_type
)
3231 text_buf
.push_int(MSG_CONNECT_LISTEN
);
3232 text_buf
.push_string(local_port
);
3233 text_buf
.push_int(remote_comp
);
3234 text_buf
.push_string(remote_comp_name
);
3235 text_buf
.push_string(remote_port
);
3236 text_buf
.push_int(transport_type
);
3237 send_message(tc
->tc_fd
, text_buf
);
3240 void MainController::send_connect(component_struct
*tc
,
3241 const char *local_port
, component remote_comp
, const char *remote_comp_name
,
3242 const char *remote_port
, transport_type_enum transport_type
,
3243 int remote_address_len
, const void *remote_address
)
3246 text_buf
.push_int(MSG_CONNECT
);
3247 text_buf
.push_string(local_port
);
3248 text_buf
.push_int(remote_comp
);
3249 text_buf
.push_string(remote_comp_name
);
3250 text_buf
.push_string(remote_port
);
3251 text_buf
.push_int(transport_type
);
3252 text_buf
.push_raw(remote_address_len
, remote_address
);
3253 send_message(tc
->tc_fd
, text_buf
);
3256 void MainController::send_connect_ack(component_struct
*tc
)
3259 text_buf
.push_int(MSG_CONNECT_ACK
);
3260 send_message(tc
->tc_fd
, text_buf
);
3263 void MainController::send_disconnect(component_struct
*tc
,
3264 const char *local_port
, component remote_comp
, const char *remote_port
)
3267 text_buf
.push_int(MSG_DISCONNECT
);
3268 text_buf
.push_string(local_port
);
3269 text_buf
.push_int(remote_comp
);
3270 text_buf
.push_string(remote_port
);
3271 send_message(tc
->tc_fd
, text_buf
);
3274 void MainController::send_disconnect_ack(component_struct
*tc
)
3277 text_buf
.push_int(MSG_DISCONNECT_ACK
);
3278 send_message(tc
->tc_fd
, text_buf
);
3281 void MainController::send_map(component_struct
*tc
,
3282 const char *local_port
, const char *system_port
)
3285 text_buf
.push_int(MSG_MAP
);
3286 text_buf
.push_string(local_port
);
3287 text_buf
.push_string(system_port
);
3288 send_message(tc
->tc_fd
, text_buf
);
3291 void MainController::send_map_ack(component_struct
*tc
)
3294 text_buf
.push_int(MSG_MAP_ACK
);
3295 send_message(tc
->tc_fd
, text_buf
);
3298 void MainController::send_unmap(component_struct
*tc
,
3299 const char *local_port
, const char *system_port
)
3302 text_buf
.push_int(MSG_UNMAP
);
3303 text_buf
.push_string(local_port
);
3304 text_buf
.push_string(system_port
);
3305 send_message(tc
->tc_fd
, text_buf
);
3308 void MainController::send_unmap_ack(component_struct
*tc
)
3311 text_buf
.push_int(MSG_UNMAP_ACK
);
3312 send_message(tc
->tc_fd
, text_buf
);
3315 void MainController::send_cancel_done_mtc(component component_reference
,
3319 text_buf
.push_int(MSG_CANCEL_DONE
);
3320 text_buf
.push_int(component_reference
);
3321 text_buf
.push_int(cancel_any
? 1 : 0);
3322 send_message(mtc
->tc_fd
, text_buf
);
3325 void MainController::send_component_status_mtc(component component_reference
,
3326 boolean is_done
, boolean is_killed
, boolean is_any_done
,
3327 boolean is_all_done
, boolean is_any_killed
, boolean is_all_killed
,
3328 const char *return_type
, int return_value_len
, const void *return_value
)
3331 text_buf
.push_int(MSG_COMPONENT_STATUS
);
3332 text_buf
.push_int(component_reference
);
3333 text_buf
.push_int(is_done
? 1 : 0);
3334 text_buf
.push_int(is_killed
? 1 : 0);
3335 text_buf
.push_int(is_any_done
? 1 : 0);
3336 text_buf
.push_int(is_all_done
? 1 : 0);
3337 text_buf
.push_int(is_any_killed
? 1 : 0);
3338 text_buf
.push_int(is_all_killed
? 1 : 0);
3339 text_buf
.push_string(return_type
);
3340 text_buf
.push_raw(return_value_len
, return_value
);
3341 send_message(mtc
->tc_fd
, text_buf
);
3344 void MainController::send_execute_control(const char *module_name
)
3347 text_buf
.push_int(MSG_EXECUTE_CONTROL
);
3348 text_buf
.push_string(module_name
);
3349 send_message(mtc
->tc_fd
, text_buf
);
3352 void MainController::send_execute_testcase(const char *module_name
,
3353 const char *testcase_name
)
3356 text_buf
.push_int(MSG_EXECUTE_TESTCASE
);
3357 text_buf
.push_string(module_name
);
3358 text_buf
.push_string(testcase_name
);
3359 send_message(mtc
->tc_fd
, text_buf
);
3362 void MainController::send_ptc_verdict(boolean continue_execution
)
3365 text_buf
.push_int(MSG_PTC_VERDICT
);
3367 for (int i
= tc_first_comp_ref
; i
< n_components
; i
++)
3368 if (components
[i
]->tc_state
!= PTC_STALE
) n_ptcs
++;
3369 text_buf
.push_int(n_ptcs
);
3370 for (int i
= tc_first_comp_ref
; i
< n_components
; i
++) {
3371 if (components
[i
]->tc_state
!= PTC_STALE
) {
3372 text_buf
.push_int(components
[i
]->comp_ref
);
3373 text_buf
.push_string(components
[i
]->comp_name
);
3374 text_buf
.push_int(components
[i
]->local_verdict
);
3375 if (components
[i
]->verdict_reason
!= NULL
)
3376 text_buf
.push_string(components
[i
]->verdict_reason
);
3378 text_buf
.push_string("");
3381 text_buf
.push_int(continue_execution
? 1 : 0);
3382 send_message(mtc
->tc_fd
, text_buf
);
3385 void MainController::send_continue()
3388 text_buf
.push_int(MSG_CONTINUE
);
3389 send_message(mtc
->tc_fd
, text_buf
);
3392 void MainController::send_exit_mtc()
3395 text_buf
.push_int(MSG_EXIT_MTC
);
3396 send_message(mtc
->tc_fd
, text_buf
);
3399 void MainController::send_cancel_done_ptc(component_struct
*tc
,
3400 component component_reference
)
3403 text_buf
.push_int(MSG_CANCEL_DONE
);
3404 text_buf
.push_int(component_reference
);
3405 send_message(tc
->tc_fd
, text_buf
);
3409 void MainController::send_component_status_ptc(component_struct
*tc
,
3410 component component_reference
, boolean is_done
, boolean is_killed
,
3411 const char *return_type
, int return_value_len
, const void *return_value
)
3414 text_buf
.push_int(MSG_COMPONENT_STATUS
);
3415 text_buf
.push_int(component_reference
);
3416 text_buf
.push_int(is_done
? 1 : 0);
3417 text_buf
.push_int(is_killed
? 1 : 0);
3418 text_buf
.push_string(return_type
);
3419 text_buf
.push_raw(return_value_len
, return_value
);
3420 send_message(tc
->tc_fd
, text_buf
);
3423 void MainController::send_start(component_struct
*tc
,
3424 const qualified_name
& function_name
, int arg_len
, const void *arg_ptr
)
3427 text_buf
.push_int(MSG_START
);
3428 text_buf
.push_qualified_name(function_name
);
3429 text_buf
.push_raw(arg_len
, arg_ptr
);
3430 send_message(tc
->tc_fd
, text_buf
);
3433 void MainController::send_kill(component_struct
*tc
)
3436 text_buf
.push_int(MSG_KILL
);
3437 send_message(tc
->tc_fd
, text_buf
);
3440 void MainController::send_error(int fd
, const char *fmt
, ...)
3444 char *reason
= mprintf_va_list(fmt
, ap
);
3446 send_error_str(fd
, reason
);
3450 void MainController::send_error_str(int fd
, const char *reason
)
3453 text_buf
.push_int((RInt
)MSG_ERROR
);
3454 text_buf
.push_string(reason
);
3455 send_message(fd
, text_buf
);
3458 void MainController::send_message(int fd
, Text_Buf
& text_buf
)
3460 text_buf
.calculate_length();
3461 const char *send_ptr
= text_buf
.get_data();
3462 int send_len
= text_buf
.get_len();
3463 int sent_len
= send(fd
, send_ptr
, send_len
, 0);
3464 if (send_len
!= sent_len
) {
3465 error("Sending of message failed: %s", strerror(errno
));
3469 void MainController::process_error(unknown_connection
*conn
)
3471 Text_Buf
& text_buf
= *conn
->text_buf
;
3472 char *reason
= text_buf
.pull_string();
3473 error("Error message was received on an unknown connection from %s [%s]: "
3474 "%s.", conn
->ip_addr
->get_host_str(), conn
->ip_addr
->get_addr_str(), reason
);
3476 text_buf
.cut_message();
3480 void MainController::process_log(unknown_connection
*conn
)
3482 Text_Buf
& text_buf
= *conn
->text_buf
;
3484 tv
.tv_sec
= text_buf
.pull_int().get_val();
3485 tv
.tv_usec
= text_buf
.pull_int().get_val();
3486 char *source
= mprintf("<unknown>@%s", conn
->ip_addr
->get_host_str());
3487 int severity
= text_buf
.pull_int().get_val();
3488 char *message
= text_buf
.pull_string();
3489 notify(&tv
, source
, severity
, message
);
3494 void MainController::process_version(unknown_connection
*conn
)
3496 if (check_version(conn
)) {
3497 error("HC connection from %s [%s] was refused because of "
3498 "incorrect version.", conn
->ip_addr
->get_host_str(),
3499 conn
->ip_addr
->get_addr_str());
3500 close_unknown_connection(conn
);
3503 host_struct
*hc
= add_new_host(conn
);
3506 mc_state
= MC_HC_CONNECTED
;
3507 case MC_HC_CONNECTED
:
3509 case MC_LISTENING_CONFIGURED
:
3511 configure_host(hc
, TRUE
);
3512 mc_state
= MC_CONFIGURING
;
3516 hc
->hc_state
= HC_EXITING
;
3519 configure_host(hc
, TRUE
);
3521 // handle the remaining messages that are in hc->text_buf
3522 handle_hc_data(hc
, FALSE
);
3526 void MainController::process_mtc_created(unknown_connection
*conn
)
3529 if (mc_state
!= MC_CREATING_MTC
) {
3530 send_error_str(fd
, "Message MTC_CREATED arrived in invalid state.");
3531 close_unknown_connection(conn
);
3534 if (mtc
== NULL
|| mtc
->tc_state
!= TC_INITIAL
)
3535 fatal_error("MainController::process_mtc_created: MTC is in invalid "
3537 if (!conn
->unix_socket
&&
3538 *(mtc
->comp_location
->ip_addr
) != *(conn
->ip_addr
)) {
3539 send_error(fd
, "Message MTC_CREATED arrived from an unexpected "
3540 "IP address. It is accepted only from %s.",
3541 mtc
->comp_location
->ip_addr
->get_addr_str());
3542 close_unknown_connection(conn
);
3546 mc_state
= MC_READY
;
3547 mtc
->tc_state
= TC_IDLE
;
3549 fd_table
[fd
].fd_type
= FD_TC
;
3550 fd_table
[fd
].component_ptr
= mtc
;
3551 Text_Buf
*text_buf
= conn
->text_buf
;
3552 text_buf
->cut_message();
3553 mtc
->text_buf
= text_buf
;
3554 delete [] mtc
->initial
.location_str
;
3556 delete_unknown_connection(conn
);
3558 notify("MTC is created.");
3559 // handle the remaining messages that are in text_buf
3560 handle_tc_data(mtc
, FALSE
);
3564 void MainController::process_ptc_created(unknown_connection
*conn
)
3569 case MC_EXECUTING_TESTCASE
:
3570 case MC_TERMINATING_TESTCASE
:
3573 send_error_str(fd
, "Message PTC_CREATED arrived in invalid state.");
3574 close_unknown_connection(conn
);
3578 Text_Buf
*text_buf
= conn
->text_buf
;
3579 component component_reference
= text_buf
->pull_int().get_val();
3581 switch (component_reference
) {
3583 send_error_str(fd
, "Message PTC_CREATED refers to the null component "
3585 close_unknown_connection(conn
);
3588 send_error_str(fd
, "Message PTC_CREATED refers to the component "
3589 "reference of the MTC.");
3590 close_unknown_connection(conn
);
3592 case SYSTEM_COMPREF
:
3593 send_error_str(fd
, "Message PTC_CREATED refers to the component "
3594 "reference of the system.");
3595 close_unknown_connection(conn
);
3598 send_error_str(fd
, "Message PTC_CREATED refers to 'any component'.");
3599 close_unknown_connection(conn
);
3602 send_error_str(fd
, "Message PTC_CREATED refers to 'all component'.");
3603 close_unknown_connection(conn
);
3607 component_struct
*tc
= lookup_component(component_reference
);
3609 send_error(fd
, "Message PTC_CREATED refers to invalid component "
3610 "reference %d.", component_reference
);
3611 close_unknown_connection(conn
);
3613 } else if (tc
->tc_state
!= TC_INITIAL
) {
3614 send_error(fd
, "Message PTC_CREATED refers to test component "
3615 "%d, which is not being created.", component_reference
);
3616 close_unknown_connection(conn
);
3618 } else if (!conn
->unix_socket
&& *(conn
->ip_addr
) != *(tc
->comp_location
->ip_addr
)) {
3619 char *real_hostname
= mprintf("%s [%s]", conn
->ip_addr
->get_host_str(),
3620 conn
->ip_addr
->get_addr_str());
3621 char *expected_hostname
= mprintf("%s [%s]",
3622 tc
->comp_location
->hostname
, tc
->comp_location
->ip_addr
->get_addr_str());
3623 send_error(fd
, "Invalid source host (%s) for the control "
3624 "connection. Expected: %s.", real_hostname
, expected_hostname
);
3625 error("Connection of PTC %d arrived from an unexpected "
3626 "IP address (%s). Expected: %s.", component_reference
,
3627 real_hostname
, expected_hostname
);
3628 Free(real_hostname
);
3629 Free(expected_hostname
);
3630 close_unknown_connection(conn
);
3634 tc
->tc_state
= TC_IDLE
;
3636 fd_table
[fd
].fd_type
= FD_TC
;
3637 fd_table
[fd
].component_ptr
= tc
;
3638 text_buf
->cut_message();
3639 tc
->text_buf
= text_buf
;
3640 delete [] tc
->initial
.location_str
;
3642 delete_unknown_connection(conn
);
3644 if (mc_state
== MC_TERMINATING_TESTCASE
|| mtc
->stop_requested
||
3645 mtc
->tc_state
== MTC_ALL_COMPONENT_KILL
||
3646 (mtc
->tc_state
== MTC_ALL_COMPONENT_STOP
&& !tc
->is_alive
)) {
3648 tc
->tc_state
= PTC_KILLING
;
3649 if (!tc
->is_alive
) tc
->stop_requested
= TRUE
;
3650 init_requestors(&tc
->stopping_killing
.stop_requestors
, NULL
);
3651 init_requestors(&tc
->stopping_killing
.kill_requestors
, NULL
);
3652 start_kill_timer(tc
);
3654 component_struct
*create_requestor
= tc
->initial
.create_requestor
;
3655 if (create_requestor
->tc_state
== TC_CREATE
) {
3656 send_create_ack(create_requestor
, component_reference
);
3657 if (create_requestor
== mtc
)
3658 create_requestor
->tc_state
= MTC_TESTCASE
;
3659 else create_requestor
->tc_state
= PTC_FUNCTION
;
3662 // handle the remaining messages that are in text_buf
3663 handle_tc_data(tc
, FALSE
);
3667 void MainController::process_error(host_struct
*hc
)
3669 char *reason
= hc
->text_buf
->pull_string();
3670 error("Error message was received from HC at %s [%s]: %s",
3671 hc
->hostname
, hc
->ip_addr
->get_addr_str(), reason
);
3675 void MainController::process_log(host_struct
*hc
)
3677 Text_Buf
& text_buf
= *hc
->text_buf
;
3679 tv
.tv_sec
= text_buf
.pull_int().get_val();
3680 tv
.tv_usec
= text_buf
.pull_int().get_val();
3681 int severity
= text_buf
.pull_int().get_val();
3682 char *message
= text_buf
.pull_string();
3683 notify(&tv
, hc
->log_source
, severity
, message
);
3687 void MainController::process_configure_ack(host_struct
*hc
)
3689 switch (hc
->hc_state
) {
3690 case HC_CONFIGURING
:
3691 hc
->hc_state
= HC_ACTIVE
;
3693 case HC_CONFIGURING_OVERLOADED
:
3694 hc
->hc_state
= HC_OVERLOADED
;
3697 send_error_str(hc
->hc_fd
, "Unexpected message CONFIGURE_ACK was "
3701 if (mc_state
== MC_CONFIGURING
) check_all_hc_configured();
3702 else notify("Host %s was configured successfully.", hc
->hostname
);
3706 void MainController::process_configure_nak(host_struct
*hc
)
3708 switch (hc
->hc_state
) {
3709 case HC_CONFIGURING
:
3710 case HC_CONFIGURING_OVERLOADED
:
3711 hc
->hc_state
= HC_IDLE
;
3714 send_error_str(hc
->hc_fd
, "Unexpected message CONFIGURE_NAK was "
3718 if (mc_state
== MC_CONFIGURING
) check_all_hc_configured();
3719 else notify("Processing of configuration file failed on host %s.",
3724 void MainController::process_create_nak(host_struct
*hc
)
3727 case MC_CREATING_MTC
:
3728 case MC_EXECUTING_TESTCASE
:
3729 case MC_TERMINATING_TESTCASE
:
3732 send_error_str(hc
->hc_fd
, "Message CREATE_NAK arrived in invalid "
3737 switch (hc
->hc_state
) {
3739 notify("Host %s is overloaded. New components will not be created "
3740 "there until further notice.", hc
->hostname
);
3741 hc
->hc_state
= HC_OVERLOADED
;
3746 send_error_str(hc
->hc_fd
, "Unexpected message CREATE_NAK was received: "
3747 "the sender is in invalid state.");
3751 Text_Buf
& text_buf
= *hc
->text_buf
;
3752 component component_reference
= text_buf
.pull_int().get_val();
3754 switch (component_reference
) {
3756 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to the null "
3757 "component reference.");
3759 case SYSTEM_COMPREF
:
3760 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to the component "
3761 "reference of the system.");
3764 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to "
3765 "'any component'.");
3768 send_error_str(hc
->hc_fd
, "Message CREATE_NAK refers to "
3769 "'all component'.");
3773 component_struct
*tc
= lookup_component(component_reference
);
3775 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to invalid component "
3776 "reference %d.", component_reference
);
3779 if (tc
->tc_state
!= TC_INITIAL
) {
3780 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to test component "
3781 "%d, which is not being created.", component_reference
);
3784 if (tc
->comp_location
!= hc
) {
3785 send_error(hc
->hc_fd
, "Message CREATE_NAK refers to test component "
3786 "%d, which was assigned to a different host (%s).",
3787 component_reference
, tc
->comp_location
->hostname
);
3791 remove_component_from_host(tc
);
3792 hc
->n_active_components
--;
3794 char *reason
= text_buf
.pull_string();
3797 if (mc_state
!= MC_CREATING_MTC
)
3798 fatal_error("MainController::process_create_nak: MC is in "
3799 "unexpected state when CREATE_NAK refers to MTC.");
3800 error("Creation of MTC failed on host %s: %s.", hc
->hostname
, reason
);
3801 destroy_all_components();
3802 mc_state
= MC_ACTIVE
;
3804 host_struct
*new_host
= choose_ptc_location(
3805 tc
->comp_type
.definition_name
, tc
->comp_name
,
3806 tc
->initial
.location_str
);
3807 if (new_host
!= NULL
) {
3808 send_create_ptc(new_host
, component_reference
, tc
->comp_type
,
3809 tc
->comp_name
, tc
->is_alive
, mtc
->tc_fn_name
);
3810 notify("PTC with component reference %d was relocated from host "
3811 "%s to %s because of overload: %s.", component_reference
,
3812 hc
->hostname
, new_host
->hostname
, reason
);
3813 add_component_to_host(new_host
, tc
);
3814 new_host
->n_active_components
++;
3816 char *comp_data
= mprintf("component type: %s.%s",
3817 tc
->comp_type
.module_name
, tc
->comp_type
.definition_name
);
3818 if (tc
->comp_name
!= NULL
)
3819 comp_data
= mputprintf(comp_data
, ", name: %s", tc
->comp_name
);
3820 if (tc
->initial
.location_str
!= NULL
&&
3821 tc
->initial
.location_str
[0] != '\0')
3822 comp_data
= mputprintf(comp_data
, ", location: %s",
3823 tc
->initial
.location_str
);
3824 component_struct
*create_requestor
= tc
->initial
.create_requestor
;
3825 if (create_requestor
->tc_state
== TC_CREATE
) {
3826 send_error(create_requestor
->tc_fd
, "Creation of the new PTC "
3827 "(%s) failed on host %s: %s. Other suitable hosts to "
3828 "relocate the component are not available.", comp_data
,
3829 hc
->hostname
, reason
);
3830 if (create_requestor
== mtc
)
3831 create_requestor
->tc_state
= MTC_TESTCASE
;
3832 else create_requestor
->tc_state
= PTC_FUNCTION
;
3834 delete [] tc
->initial
.location_str
;
3835 tc
->tc_state
= PTC_STALE
;
3837 switch (mtc
->tc_state
) {
3838 case MTC_TERMINATING_TESTCASE
:
3839 if (ready_to_finish_testcase()) finish_testcase();
3841 case MTC_ALL_COMPONENT_KILL
:
3842 check_all_component_kill();
3844 case MTC_ALL_COMPONENT_STOP
:
3845 check_all_component_stop();
3850 notify("Creation of a PTC (%s) failed on host %s: %s. "
3851 "Relocation to other suitable host is not possible.",
3852 comp_data
, hc
->hostname
, reason
);
3862 void MainController::process_hc_ready(host_struct
*hc
)
3864 switch(hc
->hc_state
) {
3866 hc
->hc_state
= HC_ACTIVE
;
3868 case HC_CONFIGURING_OVERLOADED
:
3869 hc
->hc_state
= HC_CONFIGURING
;
3872 send_error_str(hc
->hc_fd
, "Unexpected message HC_READY was received.");
3875 notify("Host %s is no more overloaded.", hc
->hostname
);
3879 void MainController::process_error(component_struct
*tc
)
3881 char *reason
= tc
->text_buf
->pull_string();
3883 error("Error message was received from the MTC at %s [%s]: %s",
3884 mtc
->comp_location
->hostname
,
3885 mtc
->comp_location
->ip_addr
->get_addr_str(), reason
);
3887 notify("Error message was received from PTC %d at %s [%s]: %s",
3888 tc
->comp_ref
, tc
->comp_location
->hostname
,
3889 tc
->comp_location
->ip_addr
->get_addr_str(), reason
);
3894 void MainController::process_log(component_struct
*tc
)
3896 Text_Buf
& text_buf
= *tc
->text_buf
;
3898 tv
.tv_sec
= text_buf
.pull_int().get_val();
3899 tv
.tv_usec
= text_buf
.pull_int().get_val();
3900 int severity
= text_buf
.pull_int().get_val();
3901 char *message
= text_buf
.pull_string();
3902 notify(&tv
, tc
->log_source
, severity
, message
);
3906 void MainController::process_create_req(component_struct
*tc
)
3908 if (!request_allowed(tc
, "CREATE_REQ")) return;
3910 if (max_ptcs
>= 0 && n_active_ptcs
>= max_ptcs
) {
3911 send_error(tc
->tc_fd
, "The license key does not allow more than %d "
3912 "simultaneously active PTCs.", max_ptcs
);
3916 Text_Buf
& text_buf
= *tc
->text_buf
;
3917 qualified_name component_type
;
3918 text_buf
.pull_qualified_name(component_type
);
3919 char *component_name
= text_buf
.pull_string();
3920 if (component_name
[0] == '\0') {
3921 delete [] component_name
;
3922 component_name
= NULL
;
3924 char *component_location
= text_buf
.pull_string();
3925 if (component_location
[0] == '\0') {
3926 delete [] component_location
;
3927 component_location
= NULL
;
3929 boolean is_alive
= text_buf
.pull_int().get_val();
3931 host_struct
*host
= choose_ptc_location(component_type
.definition_name
,
3932 component_name
, component_location
);
3935 if (!is_hc_in_state(HC_ACTIVE
)) {
3936 send_error_str(tc
->tc_fd
, "There is no active HC connection. "
3937 "Create operation cannot be performed.");
3939 char *comp_data
= mprintf("component type: %s.%s",
3940 component_type
.module_name
, component_type
.definition_name
);
3941 if (component_name
!= NULL
)
3942 comp_data
= mputprintf(comp_data
, ", name: %s", component_name
);
3943 if (component_location
!= NULL
)
3944 comp_data
= mputprintf(comp_data
, ", location: %s",
3945 component_location
);
3946 send_error(tc
->tc_fd
, "No suitable host was found to create a "
3947 "new PTC (%s).", comp_data
);
3950 free_qualified_name(&component_type
);
3951 delete [] component_name
;
3952 delete [] component_location
;
3956 component comp_ref
= next_comp_ref
++;
3957 send_create_ptc(host
, comp_ref
, component_type
, component_name
, is_alive
,
3960 tc
->tc_state
= TC_CREATE
;
3962 component_struct
*new_ptc
= new component_struct
;
3963 new_ptc
->comp_ref
= comp_ref
;
3964 new_ptc
->comp_type
= component_type
;
3965 new_ptc
->comp_name
= component_name
;
3966 new_ptc
->tc_state
= TC_INITIAL
;
3967 new_ptc
->local_verdict
= NONE
;
3968 new_ptc
->verdict_reason
= NULL
;
3969 new_ptc
->tc_fd
= -1;
3970 new_ptc
->text_buf
= NULL
;
3971 init_qualified_name(&new_ptc
->tc_fn_name
);
3972 new_ptc
->return_type
= NULL
;
3973 new_ptc
->return_value_len
= 0;
3974 new_ptc
->return_value
= NULL
;
3975 new_ptc
->is_alive
= is_alive
;
3976 new_ptc
->stop_requested
= FALSE
;
3977 new_ptc
->process_killed
= FALSE
;
3978 new_ptc
->initial
.create_requestor
= tc
;
3979 new_ptc
->initial
.location_str
= component_location
;
3980 init_requestors(&new_ptc
->done_requestors
, NULL
);
3981 init_requestors(&new_ptc
->killed_requestors
, NULL
);
3982 init_requestors(&new_ptc
->cancel_done_sent_for
, NULL
);
3983 new_ptc
->kill_timer
= NULL
;
3984 init_connections(new_ptc
);
3986 add_component(new_ptc
);
3987 add_component_to_host(host
, new_ptc
);
3988 host
->n_active_components
++;
3994 void MainController::process_start_req(component_struct
*tc
, int message_end
)
3996 if (!request_allowed(tc
, "START_REQ")) return;
3998 Text_Buf
& text_buf
= *tc
->text_buf
;
3999 component component_reference
= text_buf
.pull_int().get_val();
4000 switch (component_reference
) {
4002 send_error_str(tc
->tc_fd
, "Start operation was requested on the null "
4003 "component reference.");
4006 send_error_str(tc
->tc_fd
, "Start operation was requested on the "
4007 "component reference of the MTC.");
4009 case SYSTEM_COMPREF
:
4010 send_error_str(tc
->tc_fd
, "Start operation was requested on the "
4011 "component reference of the system.");
4014 send_error_str(tc
->tc_fd
, "Start operation was requested on "
4015 "'any component'.");
4018 send_error_str(tc
->tc_fd
, "Start operation was requested on "
4019 "'all component'.");
4022 component_struct
*target
= lookup_component(component_reference
);
4023 if (target
== NULL
) {
4024 send_error(tc
->tc_fd
, "Start operation was requested on invalid "
4025 "component reference: %d.", component_reference
);
4028 switch (target
->tc_state
) {
4031 // these states are correct
4043 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4044 "started because it is already executing function %s.%s.",
4045 component_reference
, target
->tc_fn_name
.module_name
,
4046 target
->tc_fn_name
.definition_name
);
4049 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4050 "started because it function %s.%s is currently being stopped on "
4051 "it.", component_reference
, target
->tc_fn_name
.module_name
,
4052 target
->tc_fn_name
.definition_name
);
4055 case PTC_STOPPING_KILLING
:
4056 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4057 "started because it is currently being killed.",
4058 component_reference
);
4062 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4063 "started because it is not alive anymore.", component_reference
);
4066 send_error(tc
->tc_fd
, "The argument of start operation (%d) is a "
4067 "component reference that belongs to an earlier testcase.",
4068 component_reference
);
4071 send_error(tc
->tc_fd
, "Start operation was requested on component "
4072 "reference %d, which is in invalid state.",
4073 component_reference
);
4076 text_buf
.pull_qualified_name(target
->tc_fn_name
);
4077 target
->stop_requested
= FALSE
;
4078 int arg_begin
= text_buf
.get_pos();
4079 int arg_len
= message_end
- arg_begin
;
4080 const void *arg_ptr
= text_buf
.get_data() + arg_begin
;
4081 boolean send_cancel_done
= FALSE
, cancel_any_component_done
= FALSE
;
4082 if (target
->tc_state
== PTC_STOPPED
) {
4083 // updating the state of target because 'any component.done' cannot
4084 // consider this component anymore
4085 target
->tc_state
= PTC_STARTING
;
4086 // cleaning up the previous return value
4087 delete [] target
->return_type
;
4088 target
->return_type
= NULL
;
4089 target
->return_value_len
= 0;
4090 Free(target
->return_value
);
4091 target
->return_value
= NULL
;
4092 // determining which components we need to send CANCEL_DONE to
4093 init_requestors(&target
->starting
.cancel_done_sent_to
, NULL
);
4094 for (int i
= 0; ; i
++) {
4095 component_struct
*comp
= get_requestor(&target
->done_requestors
, i
);
4096 if (comp
== NULL
) break;
4097 else if (comp
== tc
) {
4098 // the start requestor shall cancel the done status locally
4102 switch (comp
->tc_state
) {
4116 // a CANCEL_DONE message shall be sent to comp
4117 send_cancel_done
= TRUE
;
4118 add_requestor(&target
->starting
.cancel_done_sent_to
, comp
);
4123 case PTC_STOPPING_KILLING
:
4124 // CANCEL_DONE will not be sent to comp
4127 error("Test Component %d is in invalid state when starting "
4128 "PTC %d.", comp
->comp_ref
, component_reference
);
4131 // check whether 'any component.done' needs to be cancelled
4132 if (any_component_done_sent
&& !is_any_component_done()) {
4133 send_cancel_done
= TRUE
;
4134 cancel_any_component_done
= TRUE
;
4135 any_component_done_sent
= FALSE
;
4136 add_requestor(&target
->starting
.cancel_done_sent_to
, mtc
);
4138 free_requestors(&target
->done_requestors
);
4140 if (send_cancel_done
) {
4141 for (int i
= 0; ; i
++) {
4142 component_struct
*comp
=
4143 get_requestor(&target
->starting
.cancel_done_sent_to
, i
);
4144 if (comp
== NULL
) break;
4145 else if (comp
== mtc
) send_cancel_done_mtc(component_reference
,
4146 cancel_any_component_done
);
4147 else send_cancel_done_ptc(comp
, component_reference
);
4148 add_requestor(&comp
->cancel_done_sent_for
, target
);
4150 target
->starting
.start_requestor
= tc
;
4151 target
->starting
.arguments_len
= arg_len
;
4152 target
->starting
.arguments_ptr
= Malloc(arg_len
);
4153 memcpy(target
->starting
.arguments_ptr
, arg_ptr
, arg_len
);
4154 tc
->tc_state
= TC_START
;
4156 send_start(target
, target
->tc_fn_name
, arg_len
, arg_ptr
);
4158 target
->tc_state
= PTC_FUNCTION
;
4163 void MainController::process_stop_req(component_struct
*tc
)
4165 if (!request_allowed(tc
, "STOP_REQ")) return;
4167 component component_reference
= tc
->text_buf
->pull_int().get_val();
4168 switch (component_reference
) {
4170 send_error_str(tc
->tc_fd
, "Stop operation was requested on the null "
4171 "component reference.");
4174 // 'mtc.stop' initiated by a PTC terminates the current testcase
4176 if (!mtc
->stop_requested
) {
4178 kill_all_components(TRUE
);
4179 mtc
->stop_requested
= TRUE
;
4180 start_kill_timer(mtc
);
4181 notify("Test Component %d has requested to stop MTC. "
4182 "Terminating current testcase execution.", tc
->comp_ref
);
4185 } else send_error_str(tc
->tc_fd
, "MTC has requested to stop itself.");
4187 case SYSTEM_COMPREF
:
4188 send_error_str(tc
->tc_fd
, "Stop operation was requested on the "
4189 "component reference of the system.");
4192 send_error_str(tc
->tc_fd
, "Stop operation was requested on "
4193 "'any component'.");
4197 if (stop_all_components()) send_stop_ack(mtc
);
4199 mtc
->tc_state
= MTC_ALL_COMPONENT_STOP
;
4202 } else send_error_str(tc
->tc_fd
, "Operation 'all component.stop' can "
4203 "only be performed on the MTC.");
4208 // the operation refers to a specific PTC
4209 component_struct
*target
= lookup_component(component_reference
);
4210 if (target
== NULL
) {
4211 send_error(tc
->tc_fd
, "The argument of stop operation is an "
4212 "invalid component reference: %d.", component_reference
);
4214 } else if (target
== tc
) {
4215 send_error_str(tc
->tc_fd
, "Stop operation was requested on the "
4216 "requestor component itself.");
4219 boolean target_inactive
= FALSE
;
4220 switch (target
->tc_state
) {
4222 if (!target
->is_alive
) error("PTC %d cannot be in state STOPPED "
4223 "because it is not an alive type PTC.", component_reference
);
4226 target_inactive
= TRUE
;
4237 if (target
->is_alive
) {
4238 if (target_inactive
) {
4239 // do nothing, just send a STOP_ACK to tc
4244 target
->tc_state
= TC_STOPPING
;
4247 // the target is not an alive type PTC: stop operation means kill
4249 if (target_inactive
) target
->tc_state
= PTC_KILLING
;
4250 else target
->tc_state
= PTC_STOPPING_KILLING
;
4252 // a STOP or KILL message was sent out
4253 target
->stop_requested
= TRUE
;
4254 init_requestors(&target
->stopping_killing
.stop_requestors
, tc
);
4255 init_requestors(&target
->stopping_killing
.kill_requestors
, NULL
);
4256 start_kill_timer(target
);
4257 tc
->tc_state
= TC_STOP
;
4261 if (target
->is_alive
) {
4262 // do nothing if the PTC is alive
4268 case PTC_STOPPING_KILLING
:
4269 // the PTC is currently being stopped
4270 add_requestor(&target
->stopping_killing
.stop_requestors
, tc
);
4271 tc
->tc_state
= TC_STOP
;
4276 // the PTC is already terminated, do nothing
4280 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4281 "stopped because it is currently being started.",
4282 component_reference
);
4285 send_error(tc
->tc_fd
, "The argument of stop operation (%d) is a "
4286 "component reference that belongs to an earlier testcase.",
4287 component_reference
);
4290 send_error(tc
->tc_fd
, "The test component that the stop operation "
4291 "refers to (%d) is in invalid state.", component_reference
);
4295 void MainController::process_kill_req(component_struct
*tc
)
4297 if (!request_allowed(tc
, "KILL_REQ")) return;
4299 component component_reference
= tc
->text_buf
->pull_int().get_val();
4300 switch (component_reference
) {
4302 send_error_str(tc
->tc_fd
, "Kill operation was requested on the null "
4303 "component reference.");
4306 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4307 "component reference of the MTC.");
4309 case SYSTEM_COMPREF
:
4310 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4311 "component reference of the system.");
4314 send_error_str(tc
->tc_fd
, "Kill operation was requested on "
4315 "'any component'.");
4319 if (kill_all_components(FALSE
)) send_kill_ack(mtc
);
4321 mtc
->tc_state
= MTC_ALL_COMPONENT_KILL
;
4324 } else send_error_str(tc
->tc_fd
, "Operation 'all component.kill' can "
4325 "only be performed on the MTC.");
4330 // the operation refers to a specific PTC
4331 component_struct
*target
= lookup_component(component_reference
);
4332 if (target
== NULL
) {
4333 send_error(tc
->tc_fd
, "The argument of kill operation is an "
4334 "invalid component reference: %d.", component_reference
);
4336 } else if (target
== tc
) {
4337 send_error_str(tc
->tc_fd
, "Kill operation was requested on the "
4338 "requestor component itself.");
4341 boolean target_inactive
= FALSE
;
4342 switch (target
->tc_state
) {
4344 // the done status of this PTC is already sent out
4345 // and it will not be cancelled in the future
4346 free_requestors(&target
->done_requestors
);
4349 target_inactive
= TRUE
;
4361 if (target_inactive
) {
4362 // the PTC was inactive
4363 target
->tc_state
= PTC_KILLING
;
4364 if (!target
->is_alive
) target
->stop_requested
= TRUE
;
4366 // the PTC was active
4367 target
->tc_state
= PTC_STOPPING_KILLING
;
4368 target
->stop_requested
= TRUE
;
4370 init_requestors(&target
->stopping_killing
.stop_requestors
, NULL
);
4371 init_requestors(&target
->stopping_killing
.kill_requestors
, tc
);
4372 start_kill_timer(target
);
4373 tc
->tc_state
= TC_KILL
;
4377 // the PTC is currently being stopped
4379 target
->tc_state
= PTC_STOPPING_KILLING
;
4380 if (target
->kill_timer
!= NULL
) cancel_timer(target
->kill_timer
);
4381 start_kill_timer(target
);
4384 case PTC_STOPPING_KILLING
:
4385 // the PTC is currently being terminated
4386 add_requestor(&target
->stopping_killing
.kill_requestors
, tc
);
4387 tc
->tc_state
= TC_KILL
;
4392 // the PTC is already terminated
4396 send_error(tc
->tc_fd
, "PTC with component reference %d cannot be "
4397 "killed because it is currently being started.",
4398 component_reference
);
4401 send_error(tc
->tc_fd
, "The argument of kill operation (%d) is a "
4402 "component reference that belongs to an earlier testcase.",
4403 component_reference
);
4406 send_error(tc
->tc_fd
, "The test component that the kill operation "
4407 "refers to (%d) is in invalid state.", component_reference
);
4411 void MainController::process_is_running(component_struct
*tc
)
4413 if (!request_allowed(tc
, "IS_RUNNING")) return;
4415 component component_reference
= tc
->text_buf
->pull_int().get_val();
4416 switch (component_reference
) {
4418 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4419 "null component reference.");
4422 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4423 "component reference of the MTC.");
4425 case SYSTEM_COMPREF
:
4426 send_error_str(tc
->tc_fd
, "Running operation was requested on the "
4427 "component reference of the system.");
4430 if (tc
== mtc
) send_running(mtc
, is_any_component_running());
4431 else send_error_str(tc
->tc_fd
, "Operation 'any component.running' "
4432 "can only be performed on the MTC.");
4435 if (tc
== mtc
) send_running(mtc
, is_all_component_running());
4436 else send_error_str(tc
->tc_fd
, "Operation 'all component.running' "
4437 "can only be performed on the MTC.");
4442 // the operation refers to a specific PTC
4443 component_struct
*comp
= lookup_component(component_reference
);
4445 send_error(tc
->tc_fd
, "The argument of running operation is an "
4446 "invalid component reference: %d.", component_reference
);
4449 switch (comp
->tc_state
) {
4461 case PTC_STOPPING_KILLING
:
4462 send_running(tc
, TRUE
);
4469 send_running(tc
, FALSE
);
4472 send_error(tc
->tc_fd
, "The argument of running operation (%d) is a "
4473 "component reference that belongs to an earlier testcase.",
4474 component_reference
);
4477 send_error(tc
->tc_fd
, "The test component that the running operation "
4478 "refers to (%d) is in invalid state.", component_reference
);
4482 void MainController::process_is_alive(component_struct
*tc
)
4484 if (!request_allowed(tc
, "IS_ALIVE")) return;
4486 component component_reference
= tc
->text_buf
->pull_int().get_val();
4487 switch (component_reference
) {
4489 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4490 "null component reference.");
4493 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4494 "component reference of the MTC.");
4496 case SYSTEM_COMPREF
:
4497 send_error_str(tc
->tc_fd
, "Alive operation was requested on the "
4498 "component reference of the system.");
4501 if (tc
== mtc
) send_alive(mtc
, is_any_component_alive());
4502 else send_error_str(tc
->tc_fd
, "Operation 'any component.alive' "
4503 "can only be performed on the MTC.");
4506 if (tc
== mtc
) send_alive(mtc
, is_all_component_alive());
4507 else send_error_str(tc
->tc_fd
, "Operation 'all component.alive' "
4508 "can only be performed on the MTC.");
4513 // the operation refers to a specific PTC
4514 component_struct
*comp
= lookup_component(component_reference
);
4516 send_error(tc
->tc_fd
, "The argument of alive operation is an "
4517 "invalid component reference: %d.", component_reference
);
4520 switch (comp
->tc_state
) {
4535 case PTC_STOPPING_KILLING
:
4536 send_alive(tc
, TRUE
);
4540 send_alive(tc
, FALSE
);
4543 send_error(tc
->tc_fd
, "The argument of alive operation (%d) is a "
4544 "component reference that belongs to an earlier testcase.",
4545 component_reference
);
4548 send_error(tc
->tc_fd
, "The test component that the alive operation "
4549 "refers to (%d) is in invalid state.", component_reference
);
4553 void MainController::process_done_req(component_struct
*tc
)
4555 if (!request_allowed(tc
, "DONE_REQ")) return;
4557 component component_reference
= tc
->text_buf
->pull_int().get_val();
4558 switch (component_reference
) {
4560 send_error_str(tc
->tc_fd
, "Done operation was requested on the null "
4561 "component reference.");
4564 send_error_str(tc
->tc_fd
, "Done operation was requested on the "
4565 "component reference of the MTC.");
4567 case SYSTEM_COMPREF
:
4568 send_error_str(tc
->tc_fd
, "Done operation was requested on the "
4569 "component reference of the system.");
4573 boolean answer
= is_any_component_done();
4574 send_done_ack(mtc
, answer
, NULL
, 0, NULL
);
4575 if (answer
) any_component_done_sent
= TRUE
;
4576 else any_component_done_requested
= TRUE
;
4577 } else send_error_str(tc
->tc_fd
, "Operation 'any component.done' can "
4578 "only be performed on the MTC.");
4582 boolean answer
= !is_any_component_running();
4583 send_done_ack(mtc
, answer
, NULL
, 0, NULL
);
4584 if (!answer
) all_component_done_requested
= TRUE
;
4585 } else send_error_str(tc
->tc_fd
, "Operation 'all component.done' can "
4586 "only be performed on the MTC.");
4591 // the operation refers to a specific PTC
4592 component_struct
*comp
= lookup_component(component_reference
);
4594 send_error(tc
->tc_fd
, "The argument of done operation is an "
4595 "invalid component reference: %d.", component_reference
);
4598 switch (comp
->tc_state
) {
4600 // this answer has to be cancelled when the component is re-started
4601 add_requestor(&comp
->done_requestors
, tc
);
4606 send_done_ack(tc
, TRUE
, comp
->return_type
, comp
->return_value_len
,
4607 comp
->return_value
);
4621 case PTC_STOPPING_KILLING
:
4622 send_done_ack(tc
, FALSE
, NULL
, 0, NULL
);
4623 add_requestor(&comp
->done_requestors
, tc
);
4626 send_error(tc
->tc_fd
, "The argument of done operation (%d) is a "
4627 "component reference that belongs to an earlier testcase.",
4628 component_reference
);
4631 send_error(tc
->tc_fd
, "The test component that the done operation "
4632 "refers to (%d) is in invalid state.", component_reference
);
4636 void MainController::process_killed_req(component_struct
*tc
)
4638 if (!request_allowed(tc
, "KILLED_REQ")) return;
4640 component component_reference
= tc
->text_buf
->pull_int().get_val();
4641 switch (component_reference
) {
4643 send_error_str(tc
->tc_fd
, "Killed operation was requested on the null "
4644 "component reference.");
4647 send_error_str(tc
->tc_fd
, "Killed operation was requested on the "
4648 "component reference of the MTC.");
4650 case SYSTEM_COMPREF
:
4651 send_error_str(tc
->tc_fd
, "Killed operation was requested on the "
4652 "component reference of the system.");
4656 boolean answer
= !is_all_component_alive();
4657 send_killed_ack(mtc
, answer
);
4658 if (!answer
) any_component_killed_requested
= TRUE
;
4659 } else send_error_str(tc
->tc_fd
, "Operation 'any component.killed' can "
4660 "only be performed on the MTC.");
4664 boolean answer
= !is_any_component_alive();
4665 send_killed_ack(mtc
, answer
);
4666 if (!answer
) all_component_killed_requested
= TRUE
;
4667 } else send_error_str(tc
->tc_fd
, "Operation 'all component.killed' can "
4668 "only be performed on the MTC.");
4673 // the operation refers to a specific PTC
4674 component_struct
*comp
= lookup_component(component_reference
);
4676 send_error(tc
->tc_fd
, "The argument of killed operation is an "
4677 "invalid component reference: %d.", component_reference
);
4680 switch (comp
->tc_state
) {
4683 send_killed_ack(tc
, TRUE
);
4699 case PTC_STOPPING_KILLING
:
4700 send_killed_ack(tc
, FALSE
);
4701 add_requestor(&comp
->killed_requestors
, tc
);
4704 send_error(tc
->tc_fd
, "The argument of killed operation (%d) is a "
4705 "component reference that belongs to an earlier testcase.",
4706 component_reference
);
4709 send_error(tc
->tc_fd
, "The test component that the killed operation "
4710 "refers to (%d) is in invalid state.", component_reference
);
4714 void MainController::process_cancel_done_ack(component_struct
*tc
)
4716 component component_reference
= tc
->text_buf
->pull_int().get_val();
4717 switch (component_reference
) {
4719 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the null "
4720 "component reference.");
4723 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the "
4724 "component reference of the MTC.");
4726 case SYSTEM_COMPREF
:
4727 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to the "
4728 "component reference of the system.");
4731 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to "
4732 "'any component'.");
4735 send_error_str(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to "
4736 "'all component'.");
4741 component_struct
*started_tc
= lookup_component(component_reference
);
4742 if (started_tc
== NULL
) {
4743 send_error(tc
->tc_fd
, "Message CANCEL_DONE_ACK refers to an invalid "
4744 "component reference: %d.", component_reference
);
4747 done_cancelled(tc
, started_tc
);
4748 remove_requestor(&tc
->cancel_done_sent_for
, started_tc
);
4751 void MainController::process_connect_req(component_struct
*tc
)
4753 if (!request_allowed(tc
, "CONNECT_REQ")) return;
4755 Text_Buf
& text_buf
= *tc
->text_buf
;
4756 component src_compref
= text_buf
.pull_int().get_val();
4757 char *src_port
= text_buf
.pull_string();
4758 component dst_compref
= text_buf
.pull_int().get_val();
4759 char *dst_port
= text_buf
.pull_string();
4761 if (!valid_endpoint(src_compref
, TRUE
, tc
, "connect") ||
4762 !valid_endpoint(dst_compref
, TRUE
, tc
, "connect")) {
4768 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4771 conn
= new port_connection
;
4772 conn
->transport_type
=
4773 choose_port_connection_transport(src_compref
, dst_compref
);
4774 conn
->head
.comp_ref
= src_compref
;
4775 conn
->head
.port_name
= src_port
;
4776 conn
->tail
.comp_ref
= dst_compref
;
4777 conn
->tail
.port_name
= dst_port
;
4778 init_requestors(&conn
->requestors
, tc
);
4779 add_connection(conn
);
4780 // conn->head and tail is now in canonical order
4781 switch (conn
->transport_type
) {
4782 case TRANSPORT_LOCAL
:
4783 // send an empty string instead of component name
4784 // the component should already know its own name
4785 send_connect(components
[conn
->head
.comp_ref
], conn
->head
.port_name
,
4786 conn
->tail
.comp_ref
, NULL
, conn
->tail
.port_name
,
4787 conn
->transport_type
, 0, NULL
);
4788 conn
->conn_state
= CONN_CONNECTING
;
4790 case TRANSPORT_UNIX_STREAM
:
4791 case TRANSPORT_INET_STREAM
:
4792 // conn->head will be the server side
4793 if (conn
->tail
.comp_ref
!= MTC_COMPREF
&&
4794 conn
->tail
.comp_ref
!= conn
->head
.comp_ref
) {
4795 // send the name of conn->tail
4796 send_connect_listen(components
[conn
->head
.comp_ref
],
4797 conn
->head
.port_name
, conn
->tail
.comp_ref
,
4798 components
[conn
->tail
.comp_ref
]->comp_name
,
4799 conn
->tail
.port_name
, conn
->transport_type
);
4801 // send an empty string instead of the name of conn->tail if
4802 // it is known by conn->head
4803 send_connect_listen(components
[conn
->head
.comp_ref
],
4804 conn
->head
.port_name
, conn
->tail
.comp_ref
, NULL
,
4805 conn
->tail
.port_name
, conn
->transport_type
);
4807 conn
->conn_state
= CONN_LISTENING
;
4810 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4811 "be established because no suitable transport mechanism is "
4812 "available on the corresponding host(s).", src_compref
,
4813 src_port
, dst_compref
, dst_port
);
4814 remove_connection(conn
);
4817 tc
->tc_state
= TC_CONNECT
;
4820 switch (conn
->conn_state
) {
4821 case CONN_LISTENING
:
4822 case CONN_CONNECTING
:
4823 add_requestor(&conn
->requestors
, tc
);
4824 tc
->tc_state
= TC_CONNECT
;
4827 case CONN_CONNECTED
:
4828 send_connect_ack(tc
);
4830 case CONN_DISCONNECTING
:
4831 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4832 "be established because a disconnect operation is in progress "
4833 "on it.", src_compref
, src_port
, dst_compref
, dst_port
);
4836 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
4837 "be established due to an internal error in the MC.",
4838 src_compref
, src_port
, dst_compref
, dst_port
);
4839 error("The port connection %d:%s - %d:%s is in invalid state "
4840 "when a connect operation was requested on it.", src_compref
,
4841 src_port
, dst_compref
, dst_port
);
4848 void MainController::process_connect_listen_ack(component_struct
*tc
,
4851 if (!message_expected(tc
, "CONNECT_LISTEN_ACK")) return;
4853 Text_Buf
& text_buf
= *tc
->text_buf
;
4854 component src_compref
= tc
->comp_ref
;
4855 char *src_port
= text_buf
.pull_string();
4856 component dst_compref
= text_buf
.pull_int().get_val();
4857 char *dst_port
= text_buf
.pull_string();
4858 transport_type_enum transport_type
=
4859 (transport_type_enum
)text_buf
.pull_int().get_val();
4860 int local_addr_begin
= text_buf
.get_pos();
4861 int local_addr_len
= message_end
- local_addr_begin
;
4862 const void *local_addr_ptr
= text_buf
.get_data() + local_addr_begin
;
4864 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4867 // this message must arrive in the right state
4868 // and from the server side (head)
4869 if (conn
->conn_state
!= CONN_LISTENING
||
4870 conn
->head
.comp_ref
!= src_compref
||
4871 strcmp(conn
->head
.port_name
, src_port
)) {
4872 send_error(tc
->tc_fd
, "Unexpected message CONNECT_LISTEN_ACK was "
4873 "received for port connection %d:%s - %d:%s.",
4874 src_compref
, src_port
, dst_compref
, dst_port
);
4878 } else if (conn
->transport_type
!= transport_type
) {
4879 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4880 "connection %d:%s - %d:%s contains wrong transport type: %s "
4881 "was expected instead of %s.", src_compref
, src_port
,
4882 dst_compref
, dst_port
, get_transport_name(conn
->transport_type
),
4883 get_transport_name(transport_type
));
4888 component_struct
*dst_comp
= components
[dst_compref
];
4889 switch (dst_comp
->tc_state
) {
4904 if (src_compref
!= MTC_COMPREF
&& src_compref
!= dst_compref
) {
4905 // send the name of tc
4906 send_connect(dst_comp
, dst_port
, src_compref
, tc
->comp_name
,
4907 src_port
, transport_type
, local_addr_len
, local_addr_ptr
);
4909 // send an empty string instead of the name of tc if it is
4910 // known by dst_comp
4911 send_connect(dst_comp
, dst_port
, src_compref
, NULL
, src_port
,
4912 transport_type
, local_addr_len
, local_addr_ptr
);
4914 conn
->conn_state
= CONN_CONNECTING
;
4917 send_disconnect_to_server(conn
);
4918 send_error_to_connect_requestors(conn
, "test component %d has "
4919 "terminated during connection setup.", dst_compref
);
4920 remove_connection(conn
);
4924 // the connection does not exist anymore
4925 // check whether the transport type is valid
4926 switch (transport_type
) {
4927 case TRANSPORT_LOCAL
:
4928 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4929 "connection %d:%s - %d:%s cannot refer to transport type %s.",
4930 src_compref
, src_port
, dst_compref
, dst_port
,
4931 get_transport_name(transport_type
));
4933 case TRANSPORT_INET_STREAM
:
4934 case TRANSPORT_UNIX_STREAM
:
4937 send_error(tc
->tc_fd
, "Message CONNECT_LISTEN_ACK for port "
4938 "connection %d:%s - %d:%s refers to invalid transport type %d.",
4939 src_compref
, src_port
, dst_compref
, dst_port
, transport_type
);
4947 void MainController::process_connected(component_struct
*tc
)
4949 if (!message_expected(tc
, "CONNECTED")) return;
4951 Text_Buf
& text_buf
= *tc
->text_buf
;
4952 component src_compref
= tc
->comp_ref
;
4953 char *src_port
= text_buf
.pull_string();
4954 component dst_compref
= text_buf
.pull_int().get_val();
4955 char *dst_port
= text_buf
.pull_string();
4957 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4960 // this message must arrive in the right state
4961 // and from the server side (head)
4962 if (conn
->conn_state
== CONN_CONNECTING
&&
4963 conn
->head
.comp_ref
== src_compref
&&
4964 !strcmp(conn
->head
.port_name
, src_port
)) {
4965 send_connect_ack_to_requestors(conn
);
4966 conn
->conn_state
= CONN_CONNECTED
;
4969 send_error(tc
->tc_fd
, "Unexpected CONNECTED message was "
4970 "received for port connection %d:%s - %d:%s.",
4971 src_compref
, src_port
, dst_compref
, dst_port
);
4974 // do nothing if the connection does not exist anymore
4980 void MainController::process_connect_error(component_struct
*tc
)
4982 if (!message_expected(tc
, "CONNECT_ERROR")) return;
4984 Text_Buf
& text_buf
= *tc
->text_buf
;
4985 component src_compref
= tc
->comp_ref
;
4986 char *src_port
= text_buf
.pull_string();
4987 component dst_compref
= text_buf
.pull_int().get_val();
4988 char *dst_port
= text_buf
.pull_string();
4989 char *reason
= text_buf
.pull_string();
4991 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
4994 switch (conn
->conn_state
) {
4995 case CONN_CONNECTING
:
4996 // in this state both endpoints can report error
4997 if (conn
->transport_type
!= TRANSPORT_LOCAL
&&
4998 conn
->tail
.comp_ref
== src_compref
&&
4999 !strcmp(conn
->tail
.port_name
, src_port
)) {
5000 // shut down the server side (head) only if the error was reported
5001 // by the client side (tail)
5002 send_disconnect_to_server(conn
);
5005 case CONN_LISTENING
:
5006 // in this state only the server side (head) can report the error
5007 if (conn
->head
.comp_ref
== src_compref
&&
5008 !strcmp(conn
->head
.port_name
, src_port
)) break;
5010 send_error(tc
->tc_fd
, "Unexpected message CONNECT_ERROR was "
5011 "received for port connection %d:%s - %d:%s.",
5012 src_compref
, src_port
, dst_compref
, dst_port
);
5018 send_error_to_connect_requestors(conn
, "test component %d reported "
5019 "error: %s", src_compref
, reason
);
5020 remove_connection(conn
);
5023 // do nothing if the connection does not exist anymore
5030 void MainController::process_disconnect_req(component_struct
*tc
)
5032 if (!request_allowed(tc
, "DISCONNECT_REQ")) return;
5034 Text_Buf
& text_buf
= *tc
->text_buf
;
5035 component src_compref
= text_buf
.pull_int().get_val();
5036 char *src_port
= text_buf
.pull_string();
5037 component dst_compref
= text_buf
.pull_int().get_val();
5038 char *dst_port
= text_buf
.pull_string();
5040 if (!valid_endpoint(src_compref
, FALSE
, tc
, "disconnect") ||
5041 !valid_endpoint(dst_compref
, FALSE
, tc
, "disconnect")) {
5047 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
5050 switch (conn
->conn_state
) {
5051 case CONN_LISTENING
:
5052 case CONN_CONNECTING
:
5053 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
5054 "be destroyed because a connect operation is in progress "
5055 "on it.", src_compref
, src_port
, dst_compref
, dst_port
);
5057 case CONN_CONNECTED
:
5058 send_disconnect(components
[conn
->tail
.comp_ref
],
5059 conn
->tail
.port_name
, conn
->head
.comp_ref
,
5060 conn
->head
.port_name
);
5061 conn
->conn_state
= CONN_DISCONNECTING
;
5063 case CONN_DISCONNECTING
:
5064 add_requestor(&conn
->requestors
, tc
);
5065 tc
->tc_state
= TC_DISCONNECT
;
5069 send_error(tc
->tc_fd
, "The port connection %d:%s - %d:%s cannot "
5070 "be destroyed due to an internal error in the MC.",
5071 src_compref
, src_port
, dst_compref
, dst_port
);
5072 error("The port connection %d:%s - %d:%s is in invalid state when "
5073 "a disconnect operation was requested on it.", src_compref
,
5074 src_port
, dst_compref
, dst_port
);
5077 // the connection is already terminated
5078 // send the acknowledgement immediately
5079 send_disconnect_ack(tc
);
5086 void MainController::process_disconnected(component_struct
*tc
)
5088 if (!message_expected(tc
, "DISCONNECTED")) return;
5090 Text_Buf
& text_buf
= *tc
->text_buf
;
5091 component src_compref
= tc
->comp_ref
;
5092 char *src_port
= text_buf
.pull_string();
5093 component dst_compref
= text_buf
.pull_int().get_val();
5094 char *dst_port
= text_buf
.pull_string();
5096 port_connection
*conn
= find_connection(src_compref
, src_port
, dst_compref
,
5099 switch (conn
->conn_state
) {
5100 case CONN_LISTENING
:
5101 // in this state only the server side (head) can report the end of
5103 if (conn
->head
.comp_ref
!= src_compref
||
5104 strcmp(conn
->head
.port_name
, src_port
)) {
5105 send_error(tc
->tc_fd
, "Unexpected message DISCONNECTED was "
5106 "received for port connection %d:%s - %d:%s.",
5107 src_compref
, src_port
, dst_compref
, dst_port
);
5111 case CONN_CONNECTING
:
5112 // in this state both ends can report the end of the connection
5113 send_error_to_connect_requestors(conn
, "test component %d "
5114 "reported end of the connection during connection setup.",
5116 remove_connection(conn
);
5119 case CONN_CONNECTED
:
5120 remove_connection(conn
);
5123 case CONN_DISCONNECTING
:
5124 send_disconnect_ack_to_requestors(conn
);
5125 remove_connection(conn
);
5129 error("The port connection %d:%s - %d:%s is in invalid state when "
5130 "MC was notified about its termination.", src_compref
, src_port
,
5131 dst_compref
, dst_port
);
5140 void MainController::process_map_req(component_struct
*tc
)
5142 if (!request_allowed(tc
, "MAP_REQ")) return;
5144 Text_Buf
& text_buf
= *tc
->text_buf
;
5145 component src_compref
= text_buf
.pull_int().get_val();
5146 char *src_port
= text_buf
.pull_string();
5147 char *system_port
= text_buf
.pull_string();
5149 if (!valid_endpoint(src_compref
, TRUE
, tc
, "map")) {
5151 delete [] system_port
;
5155 port_connection
*conn
= find_connection(src_compref
, src_port
,
5156 SYSTEM_COMPREF
, system_port
);
5158 send_map(components
[src_compref
], src_port
, system_port
);
5159 conn
= new port_connection
;
5160 conn
->head
.comp_ref
= src_compref
;
5161 conn
->head
.port_name
= src_port
;
5162 conn
->tail
.comp_ref
= SYSTEM_COMPREF
;
5163 conn
->tail
.port_name
= system_port
;
5164 conn
->conn_state
= CONN_MAPPING
;
5165 init_requestors(&conn
->requestors
, tc
);
5166 add_connection(conn
);
5167 tc
->tc_state
= TC_MAP
;
5170 switch (conn
->conn_state
) {
5172 add_requestor(&conn
->requestors
, tc
);
5173 tc
->tc_state
= TC_MAP
;
5179 case CONN_UNMAPPING
:
5180 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s cannot "
5181 "be established because an unmap operation is in progress "
5182 "on it.", src_compref
, src_port
, system_port
);
5185 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s is in "
5186 "invalid state.", src_compref
, src_port
, system_port
);
5189 delete [] system_port
;
5193 void MainController::process_mapped(component_struct
*tc
)
5195 if (!message_expected(tc
, "MAPPED")) return;
5197 Text_Buf
& text_buf
= *tc
->text_buf
;
5198 component src_compref
= tc
->comp_ref
;
5199 char *src_port
= text_buf
.pull_string();
5200 char *system_port
= text_buf
.pull_string();
5202 port_connection
*conn
= find_connection(src_compref
, src_port
,
5203 SYSTEM_COMPREF
, system_port
);
5205 send_error(tc
->tc_fd
, "The MAPPED message refers to a "
5206 "non-existent port mapping %d:%s - system:%s.",
5207 src_compref
, src_port
, system_port
);
5208 } else if (conn
->conn_state
!= CONN_MAPPING
) {
5209 send_error(tc
->tc_fd
, "Unexpected MAPPED message was "
5210 "received for port mapping %d:%s - system:%s.",
5211 src_compref
, src_port
, system_port
);
5213 for (int i
= 0; ; i
++) {
5214 component_struct
*comp
= get_requestor(&conn
->requestors
, i
);
5215 if (comp
== NULL
) break;
5216 if (comp
->tc_state
== TC_MAP
) {
5218 if (comp
== mtc
) comp
->tc_state
= MTC_TESTCASE
;
5219 else comp
->tc_state
= PTC_FUNCTION
;
5222 free_requestors(&conn
->requestors
);
5223 conn
->conn_state
= CONN_MAPPED
;
5228 delete [] system_port
;
5231 void MainController::process_unmap_req(component_struct
*tc
)
5233 if (!request_allowed(tc
, "UNMAP_REQ")) return;
5235 Text_Buf
& text_buf
= *tc
->text_buf
;
5236 component src_compref
= text_buf
.pull_int().get_val();
5237 char *src_port
= text_buf
.pull_string();
5238 char *system_port
= text_buf
.pull_string();
5240 if (!valid_endpoint(src_compref
, FALSE
, tc
, "unmap")) {
5242 delete [] system_port
;
5246 port_connection
*conn
= find_connection(src_compref
, src_port
,
5247 SYSTEM_COMPREF
, system_port
);
5251 switch (conn
->conn_state
) {
5253 send_unmap(components
[src_compref
], src_port
, system_port
);
5254 conn
->conn_state
= CONN_UNMAPPING
;
5255 case CONN_UNMAPPING
:
5256 add_requestor(&conn
->requestors
, tc
);
5257 tc
->tc_state
= TC_UNMAP
;
5261 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s cannot "
5262 "be destroyed because a map operation is in progress "
5263 "on it.", src_compref
, src_port
, system_port
);
5266 send_error(tc
->tc_fd
, "The port mapping %d:%s - system:%s is in "
5267 "invalid state.", src_compref
, src_port
, system_port
);
5272 delete [] system_port
;
5275 void MainController::process_unmapped(component_struct
*tc
)
5277 if (!message_expected(tc
, "UNMAPPED")) return;
5279 Text_Buf
& text_buf
= *tc
->text_buf
;
5280 component src_compref
= tc
->comp_ref
;
5281 char *src_port
= text_buf
.pull_string();
5282 char *system_port
= text_buf
.pull_string();
5284 port_connection
*conn
= find_connection(src_compref
, src_port
,
5285 SYSTEM_COMPREF
, system_port
);
5287 switch (conn
->conn_state
) {
5290 case CONN_UNMAPPING
:
5291 destroy_mapping(conn
);
5294 send_error(tc
->tc_fd
, "Unexpected UNMAPPED message was "
5295 "received for port mapping %d:%s - system:%s.",
5296 src_compref
, src_port
, system_port
);
5301 delete [] system_port
;
5305 void MainController::process_testcase_started()
5307 if (mc_state
!= MC_EXECUTING_CONTROL
) {
5308 send_error_str(mtc
->tc_fd
, "Unexpected message TESTCASE_STARTED "
5313 Text_Buf
& text_buf
= *mtc
->text_buf
;
5314 text_buf
.pull_qualified_name(mtc
->tc_fn_name
);
5315 text_buf
.pull_qualified_name(mtc
->comp_type
);
5316 text_buf
.pull_qualified_name(system
->comp_type
);
5318 mtc
->tc_state
= MTC_TESTCASE
;
5319 mc_state
= MC_EXECUTING_TESTCASE
;
5320 tc_first_comp_ref
= next_comp_ref
;
5321 any_component_done_requested
= FALSE
;
5322 any_component_done_sent
= FALSE
;
5323 all_component_done_requested
= FALSE
;
5324 any_component_killed_requested
= FALSE
;
5325 all_component_killed_requested
= FALSE
;
5330 void MainController::process_testcase_finished()
5332 if (mc_state
!= MC_EXECUTING_TESTCASE
) {
5333 send_error_str(mtc
->tc_fd
, "Unexpected message TESTCASE_FINISHED "
5338 boolean ready_to_finish
= kill_all_components(TRUE
);
5340 mc_state
= MC_TERMINATING_TESTCASE
;
5341 mtc
->tc_state
= MTC_TERMINATING_TESTCASE
;
5342 mtc
->local_verdict
= (verdicttype
)mtc
->text_buf
->pull_int().get_val();
5343 mtc
->verdict_reason
= mtc
->text_buf
->pull_string();
5344 mtc
->stop_requested
= FALSE
;
5345 if (mtc
->kill_timer
!= NULL
) {
5346 cancel_timer(mtc
->kill_timer
);
5347 mtc
->kill_timer
= NULL
;
5349 any_component_done_requested
= FALSE
;
5350 any_component_done_sent
= FALSE
;
5351 all_component_done_requested
= FALSE
;
5352 any_component_killed_requested
= FALSE
;
5353 all_component_killed_requested
= FALSE
;
5355 if (ready_to_finish
) finish_testcase();
5360 void MainController::process_mtc_ready()
5362 if (mc_state
!= MC_EXECUTING_CONTROL
|| mtc
->tc_state
!= MTC_CONTROLPART
) {
5363 send_error_str(mtc
->tc_fd
, "Unexpected message MTC_READY was "
5367 mc_state
= MC_READY
;
5368 mtc
->tc_state
= TC_IDLE
;
5369 mtc
->stop_requested
= FALSE
;
5370 if (mtc
->kill_timer
!= NULL
) {
5371 cancel_timer(mtc
->kill_timer
);
5372 mtc
->kill_timer
= NULL
;
5374 stop_requested
= FALSE
;
5375 notify("Test execution finished.");
5379 void MainController::process_stopped(component_struct
*tc
, int message_end
)
5381 switch (tc
->tc_state
) {
5384 case PTC_STOPPING_KILLING
:
5385 // only alive PTCs are allowed to send STOPPED
5386 if (tc
->is_alive
) break;
5388 send_error_str(tc
->tc_fd
, "Unexpected message STOPPED was received.");
5391 Text_Buf
& text_buf
= *tc
->text_buf
;
5392 delete [] tc
->return_type
;
5393 tc
->return_type
= text_buf
.pull_string();
5394 tc
->return_value_len
= message_end
- text_buf
.get_pos();
5395 Free(tc
->return_value
);
5396 tc
->return_value
= Malloc(tc
->return_value_len
);
5397 text_buf
.pull_raw(tc
->return_value_len
, tc
->return_value
);
5398 free_qualified_name(&tc
->tc_fn_name
);
5399 component_stopped(tc
);
5403 void MainController::process_stopped_killed(component_struct
*tc
,
5406 switch (tc
->tc_state
) {
5417 case PTC_STOPPING_KILLING
:
5420 send_error_str(tc
->tc_fd
, "Unexpected message STOPPED_KILLED was "
5422 // also notify the user because the above message may get lost
5423 notify("Unexpected message STOPPED_KILLED was received from PTC %d.",
5427 Text_Buf
& text_buf
= *tc
->text_buf
;
5428 tc
->local_verdict
= (verdicttype
)text_buf
.pull_int().get_val();
5429 tc
->verdict_reason
= text_buf
.pull_string();
5430 tc
->return_type
= text_buf
.pull_string();
5431 tc
->return_value_len
= message_end
- text_buf
.get_pos();
5432 tc
->return_value
= Malloc(tc
->return_value_len
);
5433 text_buf
.pull_raw(tc
->return_value_len
, tc
->return_value
);
5434 // start a guard timer to detect whether the control connection is closed
5436 if (tc
->tc_state
!= PTC_STOPPING_KILLING
) start_kill_timer(tc
);
5437 component_terminated(tc
);
5441 void MainController::process_killed(component_struct
*tc
)
5443 switch (tc
->tc_state
) {
5449 send_error_str(tc
->tc_fd
, "Unexpected message KILLED was received.");
5450 // also notify the user because the above message may get lost
5451 notify("Unexpected message KILLED was received from PTC %d.",
5455 tc
->local_verdict
= (verdicttype
)tc
->text_buf
->pull_int().get_val();
5456 tc
->verdict_reason
= tc
->text_buf
->pull_string();
5457 // start a guard timer to detect whether the control connection is closed
5459 if (tc
->tc_state
!= PTC_KILLING
) start_kill_timer(tc
);
5460 component_terminated(tc
);
5464 void MainController::initialize(UserInterface
& par_ui
, int par_max_ptcs
)
5468 max_ptcs
= par_max_ptcs
;
5470 mc_state
= MC_INACTIVE
;
5473 if (uname(&buf
) < 0) fatal_error("MainController::initialize: "
5474 "uname() system call failed.");
5475 mc_hostname
= mprintf("MC@%s", buf
.nodename
);
5479 if (pthread_mutex_init(&mutex
, NULL
))
5480 fatal_error("MainController::initialize: pthread_mutex_init failed.");
5483 epoll_events
= NULL
;
5490 pollfds_modified
= FALSE
;
5496 unknown_head
= NULL
;
5497 unknown_tail
= NULL
;
5501 init_string_set(&assigned_components
);
5502 all_components_assigned
= FALSE
;
5508 version_known
= FALSE
;
5517 next_comp_ref
= FIRST_PTC_COMPREF
;
5519 stop_after_tc
= FALSE
;
5520 stop_requested
= FALSE
;
5529 wakeup_reason
= REASON_NOTHING
;
5531 register_termination_handlers();
5534 void MainController::terminate()
5537 destroy_host_groups();
5539 pthread_mutex_destroy(&mutex
);
5542 void MainController::add_host(const char *group_name
, const char *host_name
)
5545 if (mc_state
!= MC_INACTIVE
) {
5546 error("MainController::add_host: called in wrong state.");
5550 host_group_struct
*group
= add_host_group(group_name
);
5551 if (host_name
!= NULL
) {
5552 if (group
->has_all_hosts
) error("Redundant member `%s' was ignored in "
5553 "host group `%s'. All hosts (`*') are already the members of the "
5554 "group.", host_name
, group_name
);
5556 if (set_has_string(&group
->host_members
, host_name
)) {
5557 error("Duplicate member `%s' was ignored in host group "
5558 "`%s'.", host_name
, group_name
);
5559 } else add_string_to_set(&group
->host_members
, host_name
);
5562 if (group
->has_all_hosts
) error("Duplicate member `*' was ignored in "
5563 "host group `%s'.", group_name
);
5565 for (int i
= 0; ; i
++) {
5566 const char *group_member
=
5567 get_string_from_set(&group
->host_members
, i
);
5568 if (group_member
== NULL
) break;
5569 error("Redundant member `%s' was ignored in host group `%s'. "
5570 "All hosts (`*') are already the members of the group.",
5571 group_member
, group_name
);
5573 free_string_set(&group
->host_members
);
5574 group
->has_all_hosts
= TRUE
;
5580 void MainController::assign_component(const char *host_or_group
,
5581 const char *component_id
)
5584 if (mc_state
!= MC_INACTIVE
) {
5585 error("MainController::assign_component: called in wrong state.");
5589 host_group_struct
*group
= add_host_group(host_or_group
);
5590 if (component_id
== NULL
) {
5591 if (all_components_assigned
) {
5592 for (int i
= 0; i
< n_host_groups
; i
++) {
5593 if (host_groups
[i
].has_all_components
) {
5594 error("Duplicate assignment of all components (*) to host "
5595 "group `%s'. Previous assignment to group `%s' is "
5596 "ignored.", host_or_group
, host_groups
[i
].group_name
);
5597 host_groups
[i
].has_all_components
= FALSE
;
5600 } else all_components_assigned
= TRUE
;
5601 group
->has_all_components
= TRUE
;
5603 if (set_has_string(&assigned_components
, component_id
)) {
5604 for (int i
= 0; i
< n_host_groups
; i
++) {
5605 if (set_has_string(&host_groups
[i
].assigned_components
,
5607 error("Duplicate assignment of component `%s' to host "
5608 "group `%s'. Previous assignment to group `%s' is "
5609 "ignored.", component_id
, host_or_group
,
5610 host_groups
[i
].group_name
);
5611 remove_string_from_set(&host_groups
[i
].assigned_components
,
5615 } else add_string_to_set(&assigned_components
, component_id
);
5616 add_string_to_set(&group
->assigned_components
, component_id
);
5621 void MainController::destroy_host_groups()
5624 if (mc_state
!= MC_INACTIVE
)
5625 error("MainController::destroy_host_groups: called in wrong state.");
5627 for (int i
= 0; i
< n_host_groups
; i
++) {
5628 host_group_struct
*group
= host_groups
+ i
;
5629 Free(group
->group_name
);
5630 free_string_set(&group
->host_members
);
5631 free_string_set(&group
->assigned_components
);
5636 free_string_set(&assigned_components
);
5637 all_components_assigned
= FALSE
;
5642 void MainController::set_kill_timer(double timer_val
)
5645 if (mc_state
!= MC_INACTIVE
)
5646 error("MainController::set_kill_timer: called in wrong state.");
5647 else if (timer_val
< 0.0)
5648 error("MainController::set_kill_timer: setting a negative kill timer "
5650 else kill_timer
= timer_val
;
5654 unsigned short MainController::start_session(const char *local_address
,
5655 unsigned short tcp_port
, bool unix_sockets_enabled
)
5659 if (mc_state
!= MC_INACTIVE
) {
5660 error("MainController::start_session: called in wrong state.");
5666 epoll_events
= (epoll_event
*)Malloc(EPOLL_MAX_EVENTS
* sizeof(*epoll_events
));
5667 epfd
= epoll_create(EPOLL_SIZE_HINT
);
5669 error("System call epoll_create failed: %s", strerror(errno
));
5674 set_close_on_exec(epfd
);
5677 nh
.set_family(local_address
);
5678 server_fd
= nh
.socket();
5679 if (server_fd
< 0) {
5680 error("Server socket creation failed: %s", strerror(errno
));
5687 if (setsockopt(server_fd
, SOL_SOCKET
, SO_REUSEADDR
, (const char*)&on
,
5689 error("System call setsockopt (SO_REUSEADDR) failed on server socket: "
5690 "%s", strerror(errno
));
5696 if (setsockopt(server_fd
, IPPROTO_TCP
, TCP_NODELAY
, (const char*)&on
,
5698 error("System call setsockopt (TCP_NODELAY) failed on server socket: "
5699 "%s", strerror(errno
));
5705 IPAddress
*localaddr
= IPAddress::create_addr(nh
.get_family());
5706 if (localaddr
) localaddr
->set_port(tcp_port
);
5708 if (local_address
!= NULL
) {
5709 if (!localaddr
|| !localaddr
->set_addr(local_address
, tcp_port
)) {
5710 error("Cannot resolve host name `%s' to a local IP address: "
5711 "Host name lookup failure", local_address
);
5719 if (bind(server_fd
, localaddr
->get_addr(), localaddr
->get_addr_len())) {
5720 if (local_address
!= NULL
) {
5721 if (tcp_port
!= 0) error("Binding server socket to IP address "
5722 "%s and TCP port %d failed: %s", localaddr
->get_addr_str(),
5723 tcp_port
, strerror(errno
));
5724 else error("Binding server socket to IP address %s failed: %s",
5725 localaddr
->get_addr_str(), strerror(errno
));
5727 if (tcp_port
!= 0) error("Binding server socket to TCP port %d "
5728 "failed: %s", tcp_port
, strerror(errno
));
5729 else error("Binding server socket to an ephemeral TCP port "
5730 "failed: %s", strerror(errno
));
5738 if (listen(server_fd
, 10)) {
5739 if (local_address
!= NULL
) {
5740 if (tcp_port
!= 0) error("Listening on IP address %s and TCP port "
5741 "%d failed: %s", localaddr
->get_addr_str(), tcp_port
,
5743 else error("Listening on IP address %s failed: %s",
5744 localaddr
->get_addr_str(), strerror(errno
));
5746 if (tcp_port
!= 0) error("Listening on TCP port %d failed: %s",
5747 tcp_port
, strerror(errno
));
5748 else error("Listening on an ephemeral TCP port failed: %s",
5757 if (localaddr
->getsockname(server_fd
)) {
5758 error("System call getsockname() failed on server socket: %s",
5765 tcp_port
= localaddr
->get_port();
5767 set_close_on_exec(server_fd
);
5769 // Trying to open a unix socket for local communication
5770 if (unix_sockets_enabled
) {
5772 server_fd_unix
= socket(PF_UNIX
, SOCK_STREAM
, 0);
5773 if (server_fd_unix
< 0) {
5774 notify("Unix server socket creation failed: %s", strerror(errno
));
5779 struct sockaddr_un localaddr_unix
;
5780 memset(&localaddr_unix
, 0, sizeof(localaddr_unix
));
5781 localaddr_unix
.sun_family
= AF_UNIX
;
5782 snprintf(localaddr_unix
.sun_path
, sizeof(localaddr_unix
.sun_path
),
5783 "/tmp/ttcn3-mctr-%u", tcp_port
);
5784 if (unlink(localaddr_unix
.sun_path
))
5785 errno
= 0; // silently ignore, error handling below
5787 if (bind(server_fd_unix
, (struct sockaddr
*)&localaddr_unix
,
5788 sizeof(localaddr_unix
)) != 0) {
5789 if (errno
== EADDRINUSE
) {
5790 // the temporary file name is already used by someone else
5791 close(server_fd_unix
);
5792 notify("Could not create Unix server socket: '%s' is already existed "
5793 "and cannot be removed.", localaddr_unix
.sun_path
);
5797 close(server_fd_unix
);
5798 notify("Binding of Unix server socket to pathname %s failed. (%s)",
5799 localaddr_unix
.sun_path
, strerror(errno
));
5805 if (listen(server_fd_unix
, 10)) {
5806 notify("Could not listen on the given socket. Unix domain socket "
5807 "communication will not be used.");
5808 close(server_fd_unix
);
5813 set_close_on_exec(server_fd_unix
);
5815 add_fd_to_table(server_fd_unix
);
5816 fd_table
[server_fd_unix
].fd_type
= FD_SERVER
;
5817 add_poll_fd(server_fd_unix
);
5819 notify("Unix server socket created successfully.");
5823 if (pipe(pipe_fd
) < 0) {
5824 error("System call pipe failed: %s", strerror(errno
));
5830 set_close_on_exec(pipe_fd
[0]);
5831 set_close_on_exec(pipe_fd
[1]);
5833 wakeup_reason
= REASON_NOTHING
;
5835 mc_state
= MC_LISTENING
;
5837 add_fd_to_table(server_fd
);
5838 fd_table
[server_fd
].fd_type
= FD_SERVER
;
5839 add_poll_fd(server_fd
);
5840 server_fd_disabled
= FALSE
;
5842 add_fd_to_table(pipe_fd
[0]);
5843 fd_table
[pipe_fd
[0]].fd_type
= FD_PIPE
;
5844 add_poll_fd(pipe_fd
[0]);
5846 pthread_attr_t attr
;
5847 if (pthread_attr_init(&attr
))
5848 fatal_error("MainController::start_session: pthread_attr_init failed.");
5849 if (pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
))
5850 fatal_error("MainController::start_session: "
5851 "pthread_attr_setdetachstate failed.");
5854 if (pthread_create(&thread
, &attr
, thread_main
, NULL
))
5855 fatal_error("MainController::start_session: pthread_create failed.");
5857 if (pthread_attr_destroy(&attr
))
5858 fatal_error("MainController::start_session: pthread_attr_destroy "
5860 if (local_address
!= NULL
)
5861 notify("Listening on IP address %s and TCP port %d.", localaddr
->get_addr_str(), tcp_port
);
5862 else notify("Listening on TCP port %d.", tcp_port
);
5869 void MainController::shutdown_session()
5879 case MC_LISTENING_CONFIGURED
:
5880 case MC_HC_CONNECTED
:
5882 notify("Shutting down session.");
5883 wakeup_thread(REASON_SHUTDOWN
);
5886 error("MainController::shutdown_session: called in wrong state.");
5891 char *MainController::config_str
;
5893 void MainController::configure(const char *config_file
)
5897 case MC_HC_CONNECTED
:
5899 mc_state
= MC_CONFIGURING
;
5902 case MC_LISTENING_CONFIGURED
:
5903 mc_state
= MC_LISTENING_CONFIGURED
;
5906 error("MainController::configure: called in wrong state.");
5911 config_str
= mcopystr(config_file
);
5912 if(mc_state
== MC_CONFIGURING
) {
5913 notify("Downloading configuration file to all HCs.");
5914 for (int i
= 0; i
< n_hosts
; i
++) configure_host(hosts
[i
], FALSE
);
5920 void MainController::create_mtc(int host_index
)
5923 if (mc_state
!= MC_ACTIVE
) {
5924 error("MainController::create_mtc: called in wrong state.");
5928 if (host_index
< 0 || host_index
>= n_hosts
) {
5929 error("MainController::create_mtc: host index (%d) is out of range.",
5934 host_struct
*host
= hosts
[host_index
];
5935 switch (host
->hc_state
) {
5937 notify("HC on host %s reported overload. Trying to create MTC there "
5938 "anyway.", host
->hostname
);
5942 error("MTC cannot be created on %s: HC is not active.", host
->hostname
);
5946 notify("Creating MTC on host %s.", host
->hostname
);
5947 send_create_mtc(host
);
5949 mtc
= new component_struct
;
5950 mtc
->comp_ref
= MTC_COMPREF
;
5951 init_qualified_name(&mtc
->comp_type
);
5952 mtc
->comp_name
= new char[4];
5953 strcpy(mtc
->comp_name
, "MTC");
5954 mtc
->tc_state
= TC_INITIAL
;
5955 mtc
->local_verdict
= NONE
;
5956 mtc
->verdict_reason
= NULL
;
5958 mtc
->text_buf
= NULL
;
5959 init_qualified_name(&mtc
->tc_fn_name
);
5960 mtc
->return_type
= NULL
;
5961 mtc
->return_value_len
= 0;
5962 mtc
->return_value
= NULL
;
5963 mtc
->is_alive
= FALSE
;
5964 mtc
->stop_requested
= FALSE
;
5965 mtc
->process_killed
= FALSE
;
5966 mtc
->initial
.create_requestor
= NULL
;
5967 mtc
->initial
.location_str
= NULL
;
5968 init_requestors(&mtc
->done_requestors
, NULL
);
5969 init_requestors(&mtc
->killed_requestors
, NULL
);
5970 init_requestors(&mtc
->cancel_done_sent_for
, NULL
);
5971 mtc
->kill_timer
= NULL
;
5972 init_connections(mtc
);
5974 add_component_to_host(host
, mtc
);
5975 host
->n_active_components
++;
5977 system
= new component_struct
;
5978 system
->comp_ref
= SYSTEM_COMPREF
;
5979 init_qualified_name(&system
->comp_type
);
5980 system
->comp_name
= new char[7];
5981 strcpy(system
->comp_name
, "SYSTEM");
5982 system
->log_source
= NULL
;
5983 system
->comp_location
= NULL
;
5984 system
->tc_state
= TC_SYSTEM
;
5985 system
->local_verdict
= NONE
;
5986 system
->verdict_reason
= NULL
;
5988 system
->text_buf
= NULL
;
5989 init_qualified_name(&system
->tc_fn_name
);
5990 system
->return_type
= NULL
;
5991 system
->return_value_len
= 0;
5992 system
->return_value
= NULL
;
5993 system
->is_alive
= FALSE
;
5994 system
->stop_requested
= FALSE
;
5995 system
->process_killed
= FALSE
;
5996 init_requestors(&system
->done_requestors
, NULL
);
5997 init_requestors(&system
->killed_requestors
, NULL
);
5998 init_requestors(&system
->cancel_done_sent_for
, NULL
);
5999 system
->kill_timer
= NULL
;
6000 init_connections(system
);
6001 add_component(system
);
6003 mc_state
= MC_CREATING_MTC
;
6008 void MainController::exit_mtc()
6011 if (mc_state
!= MC_READY
) {
6012 error("MainController::exit_mtc: called in wrong state.");
6016 notify("Terminating MTC.");
6018 mtc
->tc_state
= TC_EXITING
;
6019 mtc
->comp_location
->n_active_components
--;
6020 mc_state
= MC_TERMINATING_MTC
;
6021 start_kill_timer(mtc
);
6026 void MainController::execute_control(const char *module_name
)
6029 if (mc_state
!= MC_READY
) {
6030 error("MainController::execute_control: called in wrong state.");
6034 send_execute_control(module_name
);
6035 mtc
->tc_state
= MTC_CONTROLPART
;
6036 mc_state
= MC_EXECUTING_CONTROL
;
6041 void MainController::execute_testcase(const char *module_name
,
6042 const char *testcase_name
)
6045 if (mc_state
!= MC_READY
) {
6046 error("MainController::execute_testcase: called in wrong state.");
6050 send_execute_testcase(module_name
, testcase_name
);
6051 mtc
->tc_state
= MTC_CONTROLPART
;
6052 mc_state
= MC_EXECUTING_CONTROL
;
6057 void MainController::stop_after_testcase(boolean new_state
)
6060 stop_after_tc
= new_state
;
6061 if (mc_state
== MC_PAUSED
&& !stop_after_tc
) {
6063 continue_testcase();
6067 void MainController::continue_testcase()
6070 if (mc_state
== MC_PAUSED
) {
6071 notify("Resuming execution.");
6073 mtc
->tc_state
= MTC_CONTROLPART
;
6074 mc_state
= MC_EXECUTING_CONTROL
;
6076 } else error("MainController::continue_testcase: called in wrong state.");
6080 void MainController::stop_execution()
6083 if (!stop_requested
) {
6084 notify("Stopping execution.");
6087 mc_state
= MC_EXECUTING_CONTROL
;
6088 mtc
->tc_state
= MTC_CONTROLPART
;
6089 case MC_EXECUTING_CONTROL
:
6091 mtc
->stop_requested
= TRUE
;
6092 start_kill_timer(mtc
);
6093 wakeup_thread(REASON_MTC_KILL_TIMER
);
6095 case MC_EXECUTING_TESTCASE
:
6096 if (!mtc
->stop_requested
) {
6098 kill_all_components(TRUE
);
6099 mtc
->stop_requested
= TRUE
;
6100 start_kill_timer(mtc
);
6101 wakeup_thread(REASON_MTC_KILL_TIMER
);
6103 case MC_TERMINATING_TESTCASE
:
6104 // MTC will be stopped later in finish_testcase()
6109 error("MainController::stop_execution: called in wrong state.");
6113 stop_requested
= TRUE
;
6115 } else notify("Stop was already requested. Operation ignored.");
6119 mc_state_enum
MainController::get_state()
6122 mc_state_enum ret_val
= mc_state
;
6127 boolean
MainController::get_stop_after_testcase()
6130 boolean ret_val
= stop_after_tc
;
6135 int MainController::get_nof_hosts()
6138 int ret_val
= n_hosts
;
6143 host_struct
*MainController::get_host_data(int host_index
)
6146 if (host_index
>= 0 && host_index
< n_hosts
) return hosts
[host_index
];
6150 component_struct
*MainController::get_component_data(int component_reference
)
6153 return lookup_component(component_reference
);
6156 void MainController::release_data()
6161 const char *MainController::get_mc_state_name(mc_state_enum state
)
6168 case MC_LISTENING_CONFIGURED
:
6169 return "listening (configured)";
6170 case MC_HC_CONNECTED
:
6171 return "HC connected";
6172 case MC_CONFIGURING
:
6173 return "configuring...";
6176 case MC_CREATING_MTC
:
6177 return "creating MTC...";
6178 case MC_TERMINATING_MTC
:
6179 return "terminating MTC...";
6182 case MC_EXECUTING_CONTROL
:
6183 return "executing control part";
6184 case MC_EXECUTING_TESTCASE
:
6185 return "executing testcase";
6186 case MC_TERMINATING_TESTCASE
:
6187 return "terminating testcase...";
6189 return "paused after testcase";
6191 return "shutting down...";
6193 return "unknown/transient";
6197 const char *MainController::get_hc_state_name(hc_state_enum state
)
6201 return "not configured";
6202 case HC_CONFIGURING
:
6203 case HC_CONFIGURING_OVERLOADED
:
6204 return "being configured";
6208 return "overloaded";
6212 return "unknown/transient";
6216 const char *MainController::get_tc_state_name(tc_state_enum state
)
6220 return "being created";
6222 return "inactive - waiting for start";
6224 return "executing create operation";
6226 return "executing component start operation";
6228 case MTC_ALL_COMPONENT_STOP
:
6229 return "executing component stop operation";
6231 case MTC_ALL_COMPONENT_KILL
:
6232 return "executing kill operation";
6234 return "executing connect operation";
6236 return "executing disconnect operation";
6238 return "executing map operation";
6240 return "executing unmap operation";
6242 return "being stopped";
6244 return "terminated";
6247 case MTC_CONTROLPART
:
6248 return "executing control part";
6250 return "executing testcase";
6251 case MTC_TERMINATING_TESTCASE
:
6252 return "terminating testcase";
6256 return "executing function";
6258 return "being started";
6260 return "stopped - waiting for re-start";
6262 case PTC_STOPPING_KILLING
:
6263 return "being killed";
6265 return "unknown/transient";
6269 const char *MainController::get_transport_name(transport_type_enum transport
)
6271 switch (transport
) {
6272 case TRANSPORT_LOCAL
:
6273 return "LOCAL (software loop)";
6274 case TRANSPORT_INET_STREAM
:
6275 return "INET_STREAM (TCP over IPv4)";
6276 case TRANSPORT_UNIX_STREAM
:
6277 return "UNIX_STREAM (UNIX domain socket)";
6283 //----------------------------------------------------------------------------
6285 } /* namespace mctr */
6287 //----------------------------------------------------------------------------
6291 // indent-tabs-mode: nil
6292 // c-basic-offset: 2