|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Copyright (c) 2010-2011, Red Hat, Inc.
|
|
Packit |
61cb5a |
*
|
|
Packit |
61cb5a |
* Permission to use, copy, modify, and/or distribute this software for any
|
|
Packit |
61cb5a |
* purpose with or without fee is hereby granted, provided that the above
|
|
Packit |
61cb5a |
* copyright notice and this permission notice appear in all copies.
|
|
Packit |
61cb5a |
*
|
|
Packit |
61cb5a |
* THE SOFTWARE IS PROVIDED "AS IS" AND RED HAT, INC. DISCLAIMS ALL WARRANTIES
|
|
Packit |
61cb5a |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
|
Packit |
61cb5a |
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RED HAT, INC. BE LIABLE
|
|
Packit |
61cb5a |
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
Packit |
61cb5a |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
Packit |
61cb5a |
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
Packit |
61cb5a |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Author: Jan Friesse <jfriesse@redhat.com>
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include <sys/types.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#define __STDC_FORMAT_MACROS
|
|
Packit |
61cb5a |
#define __STDC_LIMIT_MACROS
|
|
Packit |
61cb5a |
#include <inttypes.h>
|
|
Packit |
61cb5a |
#include <err.h>
|
|
Packit |
61cb5a |
#include <signal.h>
|
|
Packit |
61cb5a |
#include <stdio.h>
|
|
Packit |
61cb5a |
#include <stdint.h>
|
|
Packit |
61cb5a |
#include <stdlib.h>
|
|
Packit |
61cb5a |
#include <string.h>
|
|
Packit |
61cb5a |
#include <unistd.h>
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#include "addrfunc.h"
|
|
Packit |
61cb5a |
#include "cli.h"
|
|
Packit |
61cb5a |
#include "logging.h"
|
|
Packit |
61cb5a |
#include "msg.h"
|
|
Packit |
61cb5a |
#include "msgsend.h"
|
|
Packit |
61cb5a |
#include "omping.h"
|
|
Packit |
61cb5a |
#include "rhfunc.h"
|
|
Packit |
61cb5a |
#include "rsfunc.h"
|
|
Packit |
61cb5a |
#include "sockfunc.h"
|
|
Packit |
61cb5a |
#include "tlv.h"
|
|
Packit |
61cb5a |
#include "util.h"
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
#define MAX_EXIT_REQUESTS 2
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Structure with internal omping data
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
struct omping_instance {
|
|
Packit |
61cb5a |
struct ai_item local_addr;
|
|
Packit |
61cb5a |
struct ai_item mcast_addr;
|
|
Packit |
61cb5a |
struct rh_list remote_hosts;
|
|
Packit |
61cb5a |
struct ai_list remote_addrs;
|
|
Packit |
61cb5a |
enum omping_op_mode op_mode;
|
|
Packit |
61cb5a |
enum sf_transport_method transport_method;
|
|
Packit |
61cb5a |
char *local_ifname;
|
|
Packit |
61cb5a |
uint64_t send_count_queries;
|
|
Packit |
61cb5a |
int auto_exit;
|
|
Packit |
61cb5a |
int cont_stat;
|
|
Packit |
61cb5a |
int dup_buf_items;
|
|
Packit |
61cb5a |
int hn_max_len;
|
|
Packit |
61cb5a |
int ip_ver;
|
|
Packit |
61cb5a |
int mcast_socket;
|
|
Packit |
61cb5a |
int quiet;
|
|
Packit |
61cb5a |
int rate_limit_time;
|
|
Packit |
61cb5a |
int rcvbuf_size;
|
|
Packit |
61cb5a |
int single_addr;
|
|
Packit |
61cb5a |
int sndbuf_size;
|
|
Packit |
61cb5a |
int timeout_time;
|
|
Packit |
61cb5a |
int ucast_socket;
|
|
Packit |
61cb5a |
int wait_for_finish_time;
|
|
Packit |
61cb5a |
int wait_time;
|
|
Packit |
61cb5a |
unsigned int rh_no_active;
|
|
Packit |
61cb5a |
uint16_t port;
|
|
Packit |
61cb5a |
uint8_t ttl;
|
|
Packit |
61cb5a |
};
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* User requested exit of application (usually with SIGINT)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int exit_requested;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* User requested to display overall statistics (SIGINT/SIGUSR1)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int display_stats_requested;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Function prototypes
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int get_packet_loss_percent(uint64_t packet_sent, uint64_t packet_received);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_check_msg_common(const struct msg_decoded *msg_decoded);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void omping_client_move_to_stop(struct omping_instance *instance,
|
|
Packit |
61cb5a |
struct rh_item *ri, enum rh_client_stop_reason stop_reason);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void omping_instance_create(struct omping_instance *instance, int argc,
|
|
Packit |
61cb5a |
char *argv[]);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void omping_instance_free(struct omping_instance *instance);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_poll_receive_loop(struct omping_instance *instance, int timeout_time);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_poll_timeout(struct omping_instance *instance, struct timeval *old_tstamp,
|
|
Packit |
61cb5a |
int timeout_time);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_process_msg(struct omping_instance *instance, const char *msg,
|
|
Packit |
61cb5a |
size_t msg_len, const struct sockaddr_storage *from, uint8_t ttl, enum sf_cast_type cast_type,
|
|
Packit |
61cb5a |
struct timeval rp_timestamp);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_process_answer_msg(struct omping_instance *instance, const char *msg,
|
|
Packit |
61cb5a |
size_t msg_len, const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from,
|
|
Packit |
61cb5a |
uint8_t ttl, enum sf_cast_type cast_type, struct timeval rp_timestamp);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_process_init_msg(struct omping_instance *instance, const char *msg,
|
|
Packit |
61cb5a |
size_t msg_len, const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from,
|
|
Packit |
61cb5a |
struct timeval rp_timestamp);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_process_query_msg(struct omping_instance *instance, const char *msg,
|
|
Packit |
61cb5a |
size_t msg_len, const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from,
|
|
Packit |
61cb5a |
struct timeval rp_timestamp);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_process_response_msg(struct omping_instance *instance, const char *msg,
|
|
Packit |
61cb5a |
size_t msg_len, const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_send_client_query(struct omping_instance *instance, struct rh_item *ri,
|
|
Packit |
61cb5a |
int increase);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static int omping_send_client_msgs(struct omping_instance *instance);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void omping_send_receive_loop(struct omping_instance *instance, int timeout_time,
|
|
Packit |
61cb5a |
int final_stats, int allow_auto_exit);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void print_client_state(const char *host_name, int host_name_len,
|
|
Packit |
61cb5a |
enum sf_transport_method transport_method, const struct sockaddr_storage *mcast_addr,
|
|
Packit |
61cb5a |
const struct sockaddr_storage *remote_addr, enum rh_client_state state,
|
|
Packit |
61cb5a |
enum rh_client_stop_reason stop_reason);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void print_final_remote_version(const struct rh_list *remote_hosts, int host_name_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void print_final_stats(const struct rh_list *remote_hosts, int host_name_len,
|
|
Packit |
61cb5a |
enum sf_transport_method transport_method);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void print_packet_stats(const char *host_name, int host_name_len, uint32_t seq,
|
|
Packit |
61cb5a |
int is_dup, size_t msg_len, int dist_set, uint8_t dist, int rtt_set, double rtt,
|
|
Packit |
61cb5a |
double avg_rtt, int loss, enum sf_cast_type cast_type, int cont_stat);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void siginfo_handler(int sig);
|
|
Packit |
61cb5a |
static void sigint_handler(int sig);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
static void register_signal_handlers(void);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Functions implementation
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Entry point of omping
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
int
|
|
Packit |
61cb5a |
main(int argc, char *argv[])
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct omping_instance instance;
|
|
Packit |
61cb5a |
int allow_auto_exit;
|
|
Packit |
61cb5a |
int final_stats;
|
|
Packit |
61cb5a |
int wait_for_finish_time;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
omping_instance_create(&instance, argc, argv);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
register_signal_handlers();
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance.op_mode == OMPING_OP_MODE_SERVER) {
|
|
Packit |
61cb5a |
final_stats = allow_auto_exit = 0;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
final_stats = allow_auto_exit = 1;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
omping_send_receive_loop(&instance, instance.timeout_time, final_stats, allow_auto_exit);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!instance.single_addr && instance.wait_for_finish_time != 0 &&
|
|
Packit |
61cb5a |
instance.op_mode != OMPING_OP_MODE_CLIENT) {
|
|
Packit |
61cb5a |
exit_requested = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Moving all clients to stop state and server to finishing state");
|
|
Packit |
61cb5a |
rh_list_put_to_finish_state(&instance.remote_hosts, RH_LFS_BOTH);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance.wait_for_finish_time == -1) {
|
|
Packit |
61cb5a |
wait_for_finish_time = 0;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
wait_for_finish_time = instance.wait_for_finish_time;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
VERBOSE_PRINTF("Waiting for %d ms to inform other nodes about instance exit",
|
|
Packit |
61cb5a |
instance.wait_for_finish_time);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
omping_send_receive_loop(&instance, wait_for_finish_time, 0, 0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
omping_instance_free(&instance);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return 0;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Compute packet loss in percent from number of send and received packets
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
get_packet_loss_percent(uint64_t packet_sent, uint64_t packet_received)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
int loss;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (packet_received > packet_sent) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("packet_received > packet_sent");
|
|
Packit |
61cb5a |
loss = 0;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
loss = (int)((1.0 - (double)packet_received / (double)packet_sent) * 100.0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (loss);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Test basic message characteristics. Return 0 on success, and -1 on fail.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_check_msg_common(const struct msg_decoded *msg_decoded)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
if (msg_decoded->msg_type != MSG_TYPE_INIT && msg_decoded->msg_type != MSG_TYPE_RESPONSE &&
|
|
Packit |
61cb5a |
msg_decoded->msg_type != MSG_TYPE_QUERY && msg_decoded->msg_type != MSG_TYPE_ANSWER) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Unknown type %c (0x%X) of message", msg_decoded->msg_type,
|
|
Packit |
61cb5a |
msg_decoded->msg_type);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->version != 2) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message version %d is not supported", msg_decoded->version);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Move client to stop state. Instance is omping instance, ri is pointer to remote host item from
|
|
Packit |
61cb5a |
* remote hosts list and stop_reason is reason to stop.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
omping_client_move_to_stop(struct omping_instance *instance, struct rh_item *ri,
|
|
Packit |
61cb5a |
enum rh_client_stop_reason stop_reason)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
ri->client_info.state = RH_CS_STOP;
|
|
Packit |
61cb5a |
instance->rh_no_active--;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->quiet < 2) {
|
|
Packit |
61cb5a |
print_client_state(ri->addr->host_name, instance->hn_max_len,
|
|
Packit |
61cb5a |
instance->transport_method, NULL, &ri->addr->sas,
|
|
Packit |
61cb5a |
RH_CS_STOP, stop_reason);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Create instance of omping. argc and argv are taken form main function. Result is stored in
|
|
Packit |
61cb5a |
* instance parameter
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
omping_instance_create(struct omping_instance *instance, int argc, char *argv[])
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
uint16_t bind_port;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
bind_port = 0;
|
|
Packit |
61cb5a |
memset(instance, 0, sizeof(struct omping_instance));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
cli_parse(&instance->remote_addrs, argc, argv, &instance->local_ifname, &instance->ip_ver,
|
|
Packit |
61cb5a |
&instance->local_addr, &instance->wait_time, &instance->transport_method,
|
|
Packit |
61cb5a |
&instance->mcast_addr, &instance->port, &instance->ttl, &instance->single_addr,
|
|
Packit |
61cb5a |
&instance->quiet, &instance->cont_stat, &instance->timeout_time,
|
|
Packit |
61cb5a |
&instance->wait_for_finish_time, &instance->dup_buf_items, &instance->rate_limit_time,
|
|
Packit |
61cb5a |
&instance->sndbuf_size, &instance->rcvbuf_size, &instance->send_count_queries,
|
|
Packit |
61cb5a |
&instance->auto_exit, &instance->op_mode);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_list_create(&instance->remote_hosts, &instance->remote_addrs, instance->dup_buf_items,
|
|
Packit |
61cb5a |
instance->rate_limit_time);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
instance->rh_no_active = rh_list_length(&instance->remote_hosts);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
instance->ucast_socket =
|
|
Packit |
61cb5a |
sf_create_unicast_socket(AF_CAST_SA(&instance->local_addr.sas), instance->ttl, 1,
|
|
Packit |
61cb5a |
instance->single_addr, instance->local_ifname, instance->transport_method, 1, 0,
|
|
Packit |
61cb5a |
instance->sndbuf_size, instance->rcvbuf_size,
|
|
Packit |
61cb5a |
(instance->op_mode == OMPING_OP_MODE_CLIENT ? &bind_port : NULL));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->ucast_socket == -1) {
|
|
Packit |
61cb5a |
err(1, "Can't create/bind unicast socket");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (instance->op_mode) {
|
|
Packit |
61cb5a |
case OMPING_OP_MODE_SERVER:
|
|
Packit |
61cb5a |
instance->mcast_socket = -1;
|
|
Packit |
61cb5a |
rh_list_put_to_finish_state(&instance->remote_hosts, RH_LFS_CLIENT);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case OMPING_OP_MODE_SHOW_VERSION:
|
|
Packit |
61cb5a |
rh_list_put_to_finish_state(&instance->remote_hosts, RH_LFS_SERVER);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case OMPING_OP_MODE_CLIENT:
|
|
Packit |
61cb5a |
rh_list_put_to_finish_state(&instance->remote_hosts, RH_LFS_SERVER);
|
|
Packit |
61cb5a |
case OMPING_OP_MODE_NORMAL:
|
|
Packit |
61cb5a |
instance->mcast_socket =
|
|
Packit |
61cb5a |
sf_create_multicast_socket((struct sockaddr *)&instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
AF_CAST_SA(&instance->local_addr.sas), instance->local_ifname,
|
|
Packit |
61cb5a |
instance->ttl, instance->single_addr, instance->transport_method,
|
|
Packit |
61cb5a |
&instance->remote_addrs, 1, 0, instance->sndbuf_size,
|
|
Packit |
61cb5a |
instance->rcvbuf_size,
|
|
Packit |
61cb5a |
(instance->op_mode == OMPING_OP_MODE_CLIENT ? bind_port : 0));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->mcast_socket == -1) {
|
|
Packit |
61cb5a |
err(1, "Can't create/bind multicast socket");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
util_random_init(&instance->local_addr.sas);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_list_gen_cid(&instance->remote_hosts, &instance->local_addr);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
instance->hn_max_len = rh_list_hn_max_len(&instance->remote_hosts);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Free allocated memory of omping instance.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
omping_instance_free(struct omping_instance *instance)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
af_ai_list_free(&instance->remote_addrs);
|
|
Packit |
61cb5a |
rh_list_free(&instance->remote_hosts);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
free(instance->local_addr.host_name);
|
|
Packit |
61cb5a |
free(instance->mcast_addr.host_name);
|
|
Packit |
61cb5a |
free(instance->local_ifname);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Loop for receiving messages for given time (instance->wait_time) and process them. Instance is
|
|
Packit |
61cb5a |
* omping instance. timeout_time is maximum time to wait.
|
|
Packit |
61cb5a |
* Function returns 0 on success, or -2 on EINTR.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_poll_receive_loop(struct omping_instance *instance, int timeout_time)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
char msg[MAX_MSG_SIZE];
|
|
Packit |
61cb5a |
struct sockaddr_storage from;
|
|
Packit |
61cb5a |
struct timeval old_tstamp;
|
|
Packit |
61cb5a |
struct timeval rp_timestamp;
|
|
Packit |
61cb5a |
enum sf_cast_type cast_type;
|
|
Packit |
61cb5a |
int i;
|
|
Packit |
61cb5a |
int poll_res;
|
|
Packit |
61cb5a |
int receive_res;
|
|
Packit |
61cb5a |
uint8_t ttl;
|
|
Packit |
61cb5a |
int res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memset(&old_tstamp, 0, sizeof(old_tstamp));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
do {
|
|
Packit |
61cb5a |
poll_res = omping_poll_timeout(instance, &old_tstamp, timeout_time);
|
|
Packit |
61cb5a |
if (poll_res == -2) {
|
|
Packit |
61cb5a |
return (-2);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
for (i = 0; i < 2; i++) {
|
|
Packit |
61cb5a |
receive_res = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (i == 0 && poll_res & 1) {
|
|
Packit |
61cb5a |
receive_res = rs_receive_msg(instance->ucast_socket, &from, msg,
|
|
Packit |
61cb5a |
sizeof(msg), &ttl, &rp_timestamp);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (i == 1 && poll_res & 2) {
|
|
Packit |
61cb5a |
receive_res = rs_receive_msg(instance->mcast_socket, &from, msg,
|
|
Packit |
61cb5a |
sizeof(msg), &ttl, &rp_timestamp);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (receive_res) {
|
|
Packit |
61cb5a |
case -1:
|
|
Packit |
61cb5a |
err(2, "Cannot receive message");
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -2:
|
|
Packit |
61cb5a |
return (-2);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -3:
|
|
Packit |
61cb5a |
warn("Cannot receive message");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -4:
|
|
Packit |
61cb5a |
VERBOSE_PRINTF("Received message too long");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (receive_res > 0) {
|
|
Packit |
61cb5a |
if (i == 0) {
|
|
Packit |
61cb5a |
cast_type = SF_CT_UNI;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
switch (instance->transport_method) {
|
|
Packit |
61cb5a |
case SF_TM_ASM:
|
|
Packit |
61cb5a |
case SF_TM_SSM:
|
|
Packit |
61cb5a |
cast_type = SF_CT_MULTI;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case SF_TM_IPBC:
|
|
Packit |
61cb5a |
cast_type = SF_CT_BROAD;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
default:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Internal error - unknown tm");
|
|
Packit |
61cb5a |
errx(1, "Internal error - unknown tm");
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
res = omping_process_msg(instance, msg, receive_res, &from, ttl,
|
|
Packit |
61cb5a |
cast_type, rp_timestamp);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (res == -2) {
|
|
Packit |
61cb5a |
return (-2);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
} while (poll_res > 0);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Wait for messages on sockets. instance is omping_instance and old_tstamp is temporary variable
|
|
Packit |
61cb5a |
* which must be set to zero on first call. Function handles EINTR for display statistics.
|
|
Packit |
61cb5a |
* Function is wrapper on top of rs_poll_timeout, but handles -1 error code. Other return values
|
|
Packit |
61cb5a |
* have same meaning. timeout_time is maximum time to wait
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_poll_timeout(struct omping_instance *instance, struct timeval *old_tstamp, int timeout_time)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
int poll_res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
do {
|
|
Packit |
61cb5a |
poll_res = rs_poll_timeout(instance->ucast_socket, instance->mcast_socket,
|
|
Packit |
61cb5a |
timeout_time, old_tstamp);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (poll_res) {
|
|
Packit |
61cb5a |
case -1:
|
|
Packit |
61cb5a |
err(2, "Cannot poll on sockets");
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -2:
|
|
Packit |
61cb5a |
if (display_stats_requested) {
|
|
Packit |
61cb5a |
display_stats_requested = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->op_mode == OMPING_OP_MODE_SHOW_VERSION) {
|
|
Packit |
61cb5a |
print_final_remote_version(&instance->remote_hosts,
|
|
Packit |
61cb5a |
instance->hn_max_len);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
print_final_stats(&instance->remote_hosts,
|
|
Packit |
61cb5a |
instance->hn_max_len, instance->transport_method);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("\n");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!exit_requested) {
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-2);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
} while (poll_res < 0);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (poll_res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Process received message. Instance is omping instance, msg is received message with msg_len
|
|
Packit |
61cb5a |
* length, from is source of message. ttl is packet Time-To-Live or 0, if that information was not
|
|
Packit |
61cb5a |
* available. cast_type is type of packet received (unicast/multicast/broadcast). rp_timestamp
|
|
Packit |
61cb5a |
* is receiving time of packet.
|
|
Packit |
61cb5a |
* Function returns 0 on success or -2 on EINTR.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_process_msg(struct omping_instance *instance, const char *msg, size_t msg_len,
|
|
Packit |
61cb5a |
const struct sockaddr_storage *from, uint8_t ttl, enum sf_cast_type cast_type,
|
|
Packit |
61cb5a |
struct timeval rp_timestamp)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
char addr_str[INET6_ADDRSTRLEN];
|
|
Packit |
61cb5a |
struct msg_decoded msg_decoded;
|
|
Packit |
61cb5a |
const char *cast_str;
|
|
Packit |
61cb5a |
struct rh_item *rh_item;
|
|
Packit |
61cb5a |
int res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
res = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
msg_decode(msg, msg_len, &msg_decoded);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
cast_str = sf_cast_type_to_str(cast_type);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
af_sa_to_str((struct sockaddr *)from, addr_str);
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received %scast message from %s type %c (0x%X), len %zu", cast_str, addr_str,
|
|
Packit |
61cb5a |
msg_decoded.msg_type, msg_decoded.msg_type, msg_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (omping_check_msg_common(&msg_decoded) == -1) {
|
|
Packit |
61cb5a |
res = ms_stop(instance->ucast_socket, &instance->mcast_addr.sas, &msg_decoded,
|
|
Packit |
61cb5a |
from);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
switch (msg_decoded.msg_type) {
|
|
Packit |
61cb5a |
case MSG_TYPE_INIT:
|
|
Packit |
61cb5a |
if (cast_type != SF_CT_UNI)
|
|
Packit |
61cb5a |
goto error_unknown_mcast;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->op_mode == OMPING_OP_MODE_CLIENT)
|
|
Packit |
61cb5a |
goto error_unknown_msg_type;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
res = omping_process_init_msg(instance, msg, msg_len, &msg_decoded, from,
|
|
Packit |
61cb5a |
rp_timestamp);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case MSG_TYPE_RESPONSE:
|
|
Packit |
61cb5a |
if (cast_type != SF_CT_UNI)
|
|
Packit |
61cb5a |
goto error_unknown_mcast;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->op_mode == OMPING_OP_MODE_SERVER)
|
|
Packit |
61cb5a |
goto error_unknown_msg_type;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
res = omping_process_response_msg(instance, msg, msg_len, &msg_decoded,
|
|
Packit |
61cb5a |
from);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case MSG_TYPE_QUERY:
|
|
Packit |
61cb5a |
if (cast_type != SF_CT_UNI)
|
|
Packit |
61cb5a |
goto error_unknown_mcast;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->op_mode == OMPING_OP_MODE_CLIENT)
|
|
Packit |
61cb5a |
goto error_unknown_msg_type;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
res = omping_process_query_msg(instance, msg, msg_len, &msg_decoded, from,
|
|
Packit |
61cb5a |
rp_timestamp);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case MSG_TYPE_ANSWER:
|
|
Packit |
61cb5a |
if (instance->op_mode == OMPING_OP_MODE_SERVER && cast_type == SF_CT_UNI)
|
|
Packit |
61cb5a |
goto error_unknown_msg_type;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
res = omping_process_answer_msg(instance, msg, msg_len, &msg_decoded, from,
|
|
Packit |
61cb5a |
ttl, cast_type, rp_timestamp);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (res) {
|
|
Packit |
61cb5a |
case -1:
|
|
Packit |
61cb5a |
err(2, "Cannot send message");
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -2:
|
|
Packit |
61cb5a |
return (-2);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -3:
|
|
Packit |
61cb5a |
warn("Send message error");
|
|
Packit |
61cb5a |
rh_item = rh_list_find(&instance->remote_hosts, (const struct sockaddr *)from);
|
|
Packit |
61cb5a |
if (rh_item == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message from unknown address");
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
rh_item->client_info.no_err_msgs++;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -4:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Cannot send message. Buffer too small");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
error_unknown_mcast:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received multicast message with invalid type %c (0x%X)",
|
|
Packit |
61cb5a |
msg_decoded.msg_type, msg_decoded.msg_type);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
error_unknown_msg_type:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message type %c (0x%X) which is not supported in given "
|
|
Packit |
61cb5a |
"operational mode", msg_decoded.msg_type, msg_decoded.msg_type);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Function to test if packet is duplicate. ci is client item information, seq is sequential number
|
|
Packit |
61cb5a |
* and cast_type is type of packet received (unicast/multicast/broadcast).
|
|
Packit |
61cb5a |
* Function returns 0 if packet is not duplicate, otherwise 1.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
is_dup_packet(const struct rh_item_ci *ci, uint32_t seq, enum sf_cast_type cast_type)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
int cast_index;
|
|
Packit |
61cb5a |
int res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
cast_index = (cast_type == SF_CT_UNI ? 0 : 1);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ci->dup_buffer[cast_index][seq % ci->dup_buf_items] == seq) {
|
|
Packit |
61cb5a |
res = 1;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
ci->dup_buffer[cast_index][seq % ci->dup_buf_items] = seq;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
res = 0;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Process answer message. Instance is omping instance, msg is received message with msg_len length,
|
|
Packit |
61cb5a |
* msg_decoded is decoded message, from is address of sender. ttl is Time-To-Live of packet. If ttl
|
|
Packit |
61cb5a |
* is 0, it means that it was not possible to find out ttl. cast_type is type of packet received
|
|
Packit |
61cb5a |
* (unicast/multicast/broadcast). rp_timestamp is receiving time of packet.
|
|
Packit |
61cb5a |
* Function returns 0 on sucess, otherwise same error as rs_sendto or -4 if message cannot be
|
|
Packit |
61cb5a |
* created (usually due to small message buffer), or -5 if message is invalid (not for us, message
|
|
Packit |
61cb5a |
* without client_id, ...).
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_process_answer_msg(struct omping_instance *instance, const char *msg, size_t msg_len,
|
|
Packit |
61cb5a |
const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from, uint8_t ttl,
|
|
Packit |
61cb5a |
enum sf_cast_type cast_type, struct timeval rp_timestamp)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct rh_item *rh_item;
|
|
Packit |
61cb5a |
double avg_rtt;
|
|
Packit |
61cb5a |
double rtt;
|
|
Packit |
61cb5a |
uint64_t received;
|
|
Packit |
61cb5a |
uint64_t sent;
|
|
Packit |
61cb5a |
int cast_index;
|
|
Packit |
61cb5a |
int dist_set;
|
|
Packit |
61cb5a |
int first_packet;
|
|
Packit |
61cb5a |
int is_dup;
|
|
Packit |
61cb5a |
int rtt_set;
|
|
Packit |
61cb5a |
int loss;
|
|
Packit |
61cb5a |
uint8_t dist;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_item = rh_list_find(&instance->remote_hosts, (const struct sockaddr *)from);
|
|
Packit |
61cb5a |
if (rh_item == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message from unknown address");
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->client_id == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message doesn't contain client id");
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->client_id_len != CLIENTID_LEN ||
|
|
Packit |
61cb5a |
memcmp(msg_decoded->client_id, rh_item->client_info.client_id, CLIENTID_LEN) != 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message doesn't contain our client id");
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!msg_decoded->seq_num_isset) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message doesn't contain seq num");
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rh_item->client_info.state != RH_CS_QUERY) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Client is not in query state. Ignoring message");
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ttl > 0 && msg_decoded->ttl > 0) {
|
|
Packit |
61cb5a |
dist_set = 1;
|
|
Packit |
61cb5a |
dist = msg_decoded->ttl - ttl;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
dist_set = dist = 0;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->client_tstamp_isset) {
|
|
Packit |
61cb5a |
rtt_set = 1;
|
|
Packit |
61cb5a |
rtt = util_time_double_absdiff_ns(msg_decoded->client_tstamp, rp_timestamp);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
rtt_set = 0;
|
|
Packit |
61cb5a |
rtt = 0;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
avg_rtt = 0;
|
|
Packit |
61cb5a |
cast_index = (cast_type == SF_CT_UNI ? 0 : 1);
|
|
Packit |
61cb5a |
is_dup = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->dup_buf_items > 0) {
|
|
Packit |
61cb5a |
is_dup = is_dup_packet(&rh_item->client_info, msg_decoded->seq_num, cast_type);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (is_dup) {
|
|
Packit |
61cb5a |
if (rh_item->client_info.no_dups[cast_index] == ((uint64_t)~0)) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Number of received duplicates for %s exhausted.",
|
|
Packit |
61cb5a |
rh_item->addr->host_name);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
rh_item->client_info.no_dups[cast_index]++;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
received = rh_item->client_info.no_received[cast_index];
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
first_packet = (rh_item->client_info.no_received[cast_index] == 0);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
received = ++rh_item->client_info.no_received[cast_index];
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (cast_index == 0) {
|
|
Packit |
61cb5a |
rh_item->client_info.lru_seq_num = msg_decoded->seq_num;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (cast_type != SF_CT_UNI && first_packet &&
|
|
Packit |
61cb5a |
!rh_item->client_info.seq_num_overflow) {
|
|
Packit |
61cb5a |
rh_item->client_info.first_mcast_seq = msg_decoded->seq_num;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rtt_set) {
|
|
Packit |
61cb5a |
util_ov_update(&rh_item->client_info.avg_rtt[cast_index],
|
|
Packit |
61cb5a |
&rh_item->client_info.m2_rtt[cast_index], rtt, received);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (first_packet) {
|
|
Packit |
61cb5a |
rh_item->client_info.rtt_max[cast_index] = rtt;
|
|
Packit |
61cb5a |
rh_item->client_info.rtt_min[cast_index] = rtt;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
if (rtt > rh_item->client_info.rtt_max[cast_index]) {
|
|
Packit |
61cb5a |
rh_item->client_info.rtt_max[cast_index] = rtt;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rtt < rh_item->client_info.rtt_min[cast_index]) {
|
|
Packit |
61cb5a |
rh_item->client_info.rtt_min[cast_index] = rtt;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->cont_stat) {
|
|
Packit |
61cb5a |
sent = rh_item->client_info.no_sent;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (cast_type != SF_CT_UNI && rh_item->client_info.first_mcast_seq > 0) {
|
|
Packit |
61cb5a |
sent = sent - rh_item->client_info.first_mcast_seq + 1;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
loss = get_packet_loss_percent(sent, received);
|
|
Packit |
61cb5a |
avg_rtt = rh_item->client_info.avg_rtt[cast_index] / UTIL_NSINMS;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
loss = 0;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->quiet == 0) {
|
|
Packit |
61cb5a |
print_packet_stats(rh_item->addr->host_name, instance->hn_max_len,
|
|
Packit |
61cb5a |
msg_decoded->seq_num, is_dup, msg_len, dist_set, dist, rtt_set,
|
|
Packit |
61cb5a |
rtt / UTIL_NSINMS, avg_rtt, loss, cast_type, instance->cont_stat);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Process init messge. instance is omping_instance, msg is received message with msg_len length,
|
|
Packit |
61cb5a |
* msg_decoded is decoded message and from is sockaddr of sender. rp_timestamp is receiving time
|
|
Packit |
61cb5a |
* of packet.
|
|
Packit |
61cb5a |
* Function returns 0 on sucess, otherwise same error as rs_sendto or -4 if message cannot be
|
|
Packit |
61cb5a |
* created (usually due to small message buffer)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_process_init_msg(struct omping_instance *instance, const char *msg, size_t msg_len,
|
|
Packit |
61cb5a |
const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from,
|
|
Packit |
61cb5a |
struct timeval rp_timestamp)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct rh_item *rh_item;
|
|
Packit |
61cb5a |
struct tlv_iterator tlv_iter;
|
|
Packit |
61cb5a |
int pref_found;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_item = rh_list_find(&instance->remote_hosts, (const struct sockaddr *)from);
|
|
Packit |
61cb5a |
if (rh_item == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message from unknown address");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_stop(instance->ucast_socket, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
msg_decoded, from));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rh_item->server_info.state == RH_SS_FINISHING) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("We are in finishing state. Sending request to stop.");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_stop(instance->ucast_socket, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
msg_decoded, from));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!msg_decoded->mcast_prefix_isset) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Mcast prefix is not set");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_response(instance->ucast_socket, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
msg_decoded, from, 0, 1, NULL, 0));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
pref_found = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
tlv_iter_init(msg, msg_len, &tlv_iter);
|
|
Packit |
61cb5a |
while (tlv_iter_next(&tlv_iter) == 0) {
|
|
Packit |
61cb5a |
if (tlv_iter_get_type(&tlv_iter) == TLV_OPT_TYPE_MCAST_PREFIX) {
|
|
Packit |
61cb5a |
if (tlv_iter_pref_eq(&tlv_iter, &instance->mcast_addr.sas)) {
|
|
Packit |
61cb5a |
pref_found = 1;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!pref_found) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Can't find required prefix");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_response(instance->ucast_socket, &instance->mcast_addr.sas, msg_decoded,
|
|
Packit |
61cb5a |
from, 0, 1, NULL, 0));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (util_time_absdiff(rh_item->server_info.last_init_ts, rp_timestamp) <
|
|
Packit |
61cb5a |
DEFAULT_WAIT_TIME) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Time diff between two init messages too short. Ignoring message.");
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
util_gen_sid(rh_item->server_info.ses_id);
|
|
Packit |
61cb5a |
rh_item->server_info.state = RH_SS_ANSWER;
|
|
Packit |
61cb5a |
rh_item->server_info.last_init_ts = rp_timestamp;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_response(instance->ucast_socket, &instance->mcast_addr.sas, msg_decoded, from,
|
|
Packit |
61cb5a |
1, 0, rh_item->server_info.ses_id, SESSIONID_LEN));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Process query msg. instance is omping instance, msg is received message with msg_len length,
|
|
Packit |
61cb5a |
* msg_decoded is decoded message and from is sender of message. rp_timestamp is receiving time
|
|
Packit |
61cb5a |
* of packet.
|
|
Packit |
61cb5a |
* Function returns 0 on sucess, otherwise same error as rs_sendto or -4 if message cannot be
|
|
Packit |
61cb5a |
* created (usually due to small message buffer)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_process_query_msg(struct omping_instance *instance, const char *msg, size_t msg_len,
|
|
Packit |
61cb5a |
const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from,
|
|
Packit |
61cb5a |
struct timeval rp_timestamp)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct rh_item *rh_item;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_item = rh_list_find(&instance->remote_hosts, (const struct sockaddr *)from);
|
|
Packit |
61cb5a |
if (rh_item == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message from unknown address");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_stop(instance->ucast_socket, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
msg_decoded, from));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rh_item->server_info.state != RH_SS_ANSWER) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Server is not in answer state");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_stop(instance->ucast_socket, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
msg_decoded, from));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!msg_decoded->seq_num_isset || msg_decoded->mcast_grp == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message doesn't have mcast group set");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_stop(instance->ucast_socket, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
msg_decoded, from));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->ses_id_len != SESSIONID_LEN ||
|
|
Packit |
61cb5a |
memcmp(msg_decoded->ses_id, rh_item->server_info.ses_id, SESSIONID_LEN) != 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message session id isn't expected");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (ms_stop(instance->ucast_socket, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
msg_decoded, from));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Rate limiting
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (instance->rate_limit_time > 0) {
|
|
Packit |
61cb5a |
if (gcra_rl(&rh_item->server_info.gcra, rp_timestamp) == 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message rate limited");
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Answer to query message
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
return (ms_answer(instance->ucast_socket, &instance->mcast_addr.sas, msg, msg_len,
|
|
Packit |
61cb5a |
msg_decoded, from, instance->ttl, MS_ANSWER_BOTH));
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Process response message. Instance is omping instance, msg is received message with msg_len
|
|
Packit |
61cb5a |
* length, msg_decoded is decoded message and from is address of sender.
|
|
Packit |
61cb5a |
* Function returns 0 on sucess, otherwise same error as rs_sendto or -4 if message cannot be
|
|
Packit |
61cb5a |
* created (usually due to small message buffer), or -5 if message is invalid (not for us, message
|
|
Packit |
61cb5a |
* without client_id, ...).
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_process_response_msg(struct omping_instance *instance, const char *msg, size_t msg_len,
|
|
Packit |
61cb5a |
const struct msg_decoded *msg_decoded, const struct sockaddr_storage *from)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct rh_item *rh_item;
|
|
Packit |
61cb5a |
enum rh_client_state old_cstate;
|
|
Packit |
61cb5a |
const char *ci_ses_id;
|
|
Packit |
61cb5a |
const char *msg_ses_id;
|
|
Packit |
61cb5a |
int send_res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_item = rh_list_find(&instance->remote_hosts, (const struct sockaddr *)from);
|
|
Packit |
61cb5a |
if (rh_item == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Received message from unknown address");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rh_item->client_info.state == RH_CS_STOP) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Client is in stop state. Ignoring message.");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->client_id == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message doesn't contain client id");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->client_id_len != CLIENTID_LEN ||
|
|
Packit |
61cb5a |
memcmp(msg_decoded->client_id, rh_item->client_info.client_id, CLIENTID_LEN) != 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message doesn't contain our client id");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->op_mode == OMPING_OP_MODE_SHOW_VERSION) {
|
|
Packit |
61cb5a |
if (msg_decoded->server_info_len > 0) {
|
|
Packit |
61cb5a |
rh_item->client_info.server_info_len = msg_decoded->server_info_len;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
free(rh_item->client_info.server_info);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_item->client_info.server_info =
|
|
Packit |
61cb5a |
(char *)malloc(rh_item->client_info.server_info_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rh_item->client_info.server_info == NULL) {
|
|
Packit |
61cb5a |
errx(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(rh_item->client_info.server_info, msg_decoded->server_info,
|
|
Packit |
61cb5a |
rh_item->client_info.server_info_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
omping_client_move_to_stop(instance, rh_item,
|
|
Packit |
61cb5a |
RH_CSR_REMOTE_VERSION_RECEIVED);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message doesn't contain server information");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->mcast_grp == NULL || msg_decoded->mcast_grp_len == 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Server doesn't send us multicast group");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rh_item->client_info.state == RH_CS_QUERY) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Client was in query state. Put to initial state");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_item->client_info.state = RH_CS_INITIAL;
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Technically, packet was sent and also received so no lost at all
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
rh_item->client_info.no_sent--;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
util_gen_cid(rh_item->client_info.client_id, &instance->local_addr);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Client was not in query state. Put it to stop state");
|
|
Packit |
61cb5a |
omping_client_move_to_stop(instance, rh_item, RH_CSR_SERVER);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (!(tlv_mcast_grp_eq(&instance->mcast_addr.sas, msg_decoded->mcast_grp,
|
|
Packit |
61cb5a |
msg_decoded->mcast_grp_len))) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Server send us different multicast group then expected");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (msg_decoded->ses_id == NULL) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Message doesn't contain session id");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rh_item->client_info.ses_id_len == msg_decoded->ses_id_len) {
|
|
Packit |
61cb5a |
ci_ses_id = rh_item->client_info.ses_id;
|
|
Packit |
61cb5a |
msg_ses_id = msg_decoded->ses_id;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (memcmp(ci_ses_id, msg_ses_id, msg_decoded->ses_id_len) == 0) {
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Duplicate server response");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (-5);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
old_cstate = rh_item->client_info.state;
|
|
Packit |
61cb5a |
rh_item->client_info.state = RH_CS_QUERY;
|
|
Packit |
61cb5a |
rh_item->client_info.ses_id_len = msg_decoded->ses_id_len;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
free(rh_item->client_info.ses_id);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
rh_item->client_info.ses_id = (char *)malloc(rh_item->client_info.ses_id_len);
|
|
Packit |
61cb5a |
if (rh_item->client_info.ses_id == NULL) {
|
|
Packit |
61cb5a |
errx(1, "Can't alloc memory");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
memcpy(rh_item->client_info.ses_id, msg_decoded->ses_id, rh_item->client_info.ses_id_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (old_cstate == RH_CS_INITIAL) {
|
|
Packit |
61cb5a |
if (instance->quiet < 2) {
|
|
Packit |
61cb5a |
print_client_state(rh_item->addr->host_name, instance->hn_max_len,
|
|
Packit |
61cb5a |
instance->transport_method, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
&rh_item->addr->sas, RH_CS_QUERY, RH_CSR_NONE);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
send_res = omping_send_client_query(instance, rh_item, (old_cstate == RH_CS_INITIAL));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (send_res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Send client query message. instance is omping instance. ri is one item fro rh_list and it's
|
|
Packit |
61cb5a |
* client to process. increase is boolean variable. If set, seq_num and no_sent packets are
|
|
Packit |
61cb5a |
* increased.
|
|
Packit |
61cb5a |
* Function return 0 on success, otherwise same error as rs_sendto or -4 if message cannot be
|
|
Packit |
61cb5a |
* created (usually due to small message buffer)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_send_client_query(struct omping_instance *instance, struct rh_item *ri, int increase)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct rh_item_ci *ci;
|
|
Packit |
61cb5a |
int send_res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ci = &ri->client_info;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (increase) {
|
|
Packit |
61cb5a |
if (ci->no_sent + 1 == ((uint64_t)~0)) {
|
|
Packit |
61cb5a |
omping_client_move_to_stop(instance, ri, RH_CSR_SEND_MAXIMUM);
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Maximum number of sent messages for %s exhausted. "
|
|
Packit |
61cb5a |
"Moving to stop state.", ri->addr->host_name);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (instance->send_count_queries > 0 &&
|
|
Packit |
61cb5a |
ci->no_sent + 1 > instance->send_count_queries) {
|
|
Packit |
61cb5a |
omping_client_move_to_stop(instance, ri, RH_CSR_TO_SEND_EXHAUSTED);
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Number of messages to be sent by %s exhausted. "
|
|
Packit |
61cb5a |
"Moving to stop state.", ri->addr->host_name);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ci->seq_num++;
|
|
Packit |
61cb5a |
ci->no_sent++;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ci->seq_num == 0) {
|
|
Packit |
61cb5a |
ci->seq_num_overflow = 1;
|
|
Packit |
61cb5a |
ci->seq_num++;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
send_res = ms_query(instance->ucast_socket, &ri->addr->sas, &instance->mcast_addr.sas,
|
|
Packit |
61cb5a |
ci->seq_num, ci->client_id, ci->ses_id, ci->ses_id_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (send_res);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Send client init or request messages to all of remote hosts. instance is omping instance.
|
|
Packit |
61cb5a |
* Function return 0 on success, or -2 on EINTR.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static int
|
|
Packit |
61cb5a |
omping_send_client_msgs(struct omping_instance *instance)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct rh_item *remote_host;
|
|
Packit |
61cb5a |
struct rh_item_ci *ci;
|
|
Packit |
61cb5a |
int send_res;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
TAILQ_FOREACH(remote_host, &instance->remote_hosts, entries) {
|
|
Packit |
61cb5a |
send_res = 0;
|
|
Packit |
61cb5a |
ci = &remote_host->client_info;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (ci->state) {
|
|
Packit |
61cb5a |
case RH_CS_INITIAL:
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Initial message is send at most after DEFAULT_WAIT_TIME
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (util_time_absdiff(ci->last_init_ts, util_get_time()) >
|
|
Packit |
61cb5a |
DEFAULT_WAIT_TIME) {
|
|
Packit |
61cb5a |
if (instance->quiet < 2) {
|
|
Packit |
61cb5a |
print_client_state(remote_host->addr->host_name,
|
|
Packit |
61cb5a |
instance->hn_max_len, instance->transport_method, NULL,
|
|
Packit |
61cb5a |
&remote_host->addr->sas, RH_CS_INITIAL, RH_CSR_NONE);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
send_res = ms_init(instance->ucast_socket, &remote_host->addr->sas,
|
|
Packit |
61cb5a |
&instance->mcast_addr.sas, ci->client_id,
|
|
Packit |
61cb5a |
(instance->op_mode == OMPING_OP_MODE_SHOW_VERSION ? 1 : 0));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ci->last_init_ts = util_get_time();
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CS_QUERY:
|
|
Packit |
61cb5a |
if (instance->wait_time == 0) {
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Handle wait time zero specifically. Send query if answer for
|
|
Packit |
61cb5a |
* previous query received or after 1ms.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
if (ci->lru_seq_num == ci->seq_num ||
|
|
Packit |
61cb5a |
util_time_absdiff(ci->last_query_ts, util_get_time()) >= 1) {
|
|
Packit |
61cb5a |
send_res = omping_send_client_query(instance, remote_host,
|
|
Packit |
61cb5a |
1);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
ci->last_query_ts = util_get_time();
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
send_res = omping_send_client_query(instance, remote_host, 1);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CS_STOP:
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Do nothing
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (send_res) {
|
|
Packit |
61cb5a |
case -1:
|
|
Packit |
61cb5a |
err(2, "Cannot send message");
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -2:
|
|
Packit |
61cb5a |
return (-2);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -3:
|
|
Packit |
61cb5a |
warn("Send message error");
|
|
Packit |
61cb5a |
ci->no_err_msgs++;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case -4:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Cannot send message. Buffer too small");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
return (0);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Main loop of omping. It is used for receiving and sending messages. On the end, it prints final
|
|
Packit |
61cb5a |
* statistics. instance is omping instance. timeout_time is maximum amount of time to keep loop
|
|
Packit |
61cb5a |
* running (after this time, loop is ended). final_stats is boolean flag which determines if final
|
|
Packit |
61cb5a |
* statistics should be displayed or not. allow_auto_exit is boolean which if set, allows auto exit
|
|
Packit |
61cb5a |
* if every client is in STOP state.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
omping_send_receive_loop(struct omping_instance *instance, int timeout_time, int final_stats,
|
|
Packit |
61cb5a |
int allow_auto_exit)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct timeval start_time;
|
|
Packit |
61cb5a |
int clients_res;
|
|
Packit |
61cb5a |
int loop_end;
|
|
Packit |
61cb5a |
int poll_rec_res;
|
|
Packit |
61cb5a |
int receive_timeout;
|
|
Packit |
61cb5a |
uint64_t time_diff;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (timeout_time != 0) {
|
|
Packit |
61cb5a |
start_time = util_get_time();
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
loop_end = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
do {
|
|
Packit |
61cb5a |
clients_res = omping_send_client_msgs(instance);
|
|
Packit |
61cb5a |
if (clients_res != 0 && clients_res != -2) {
|
|
Packit |
61cb5a |
err(3, "unknown value of clients_res %u", clients_res);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (clients_res == -2) {
|
|
Packit |
61cb5a |
if (exit_requested) {
|
|
Packit |
61cb5a |
loop_end = 1;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
continue;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (timeout_time != 0) {
|
|
Packit |
61cb5a |
time_diff = util_time_absdiff(start_time, util_get_time());
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if ((int)time_diff + instance->wait_time > timeout_time) {
|
|
Packit |
61cb5a |
receive_timeout = timeout_time - time_diff;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
receive_timeout = instance->wait_time;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
receive_timeout = instance->wait_time;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
poll_rec_res = omping_poll_receive_loop(instance, receive_timeout);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (poll_rec_res != 0 && poll_rec_res != -2) {
|
|
Packit |
61cb5a |
err(3, "unknown value of poll_rec_res %u", poll_rec_res);
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (exit_requested) {
|
|
Packit |
61cb5a |
loop_end = 1;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (timeout_time != 0 &&
|
|
Packit |
61cb5a |
(int)util_time_absdiff(start_time, util_get_time()) >= timeout_time) {
|
|
Packit |
61cb5a |
loop_end = 1;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (allow_auto_exit && instance->auto_exit && instance->rh_no_active == 0) {
|
|
Packit |
61cb5a |
loop_end = 1;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
} while (!loop_end);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (final_stats) {
|
|
Packit |
61cb5a |
if (instance->op_mode == OMPING_OP_MODE_SHOW_VERSION) {
|
|
Packit |
61cb5a |
print_final_remote_version(&instance->remote_hosts, instance->hn_max_len);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
print_final_stats(&instance->remote_hosts, instance->hn_max_len,
|
|
Packit |
61cb5a |
instance->transport_method);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Print status of client with host_name (maximum length of host_name_len). transport_method is
|
|
Packit |
61cb5a |
* transport method to be used, mcast_addr is current multicast address to be used by client.
|
|
Packit |
61cb5a |
* remote_addr is address of client and state is current state of client.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
print_client_state(const char *host_name, int host_name_len,
|
|
Packit |
61cb5a |
enum sf_transport_method transport_method, const struct sockaddr_storage *mcast_addr,
|
|
Packit |
61cb5a |
const struct sockaddr_storage *remote_addr, enum rh_client_state state,
|
|
Packit |
61cb5a |
enum rh_client_stop_reason stop_reason)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
char mcast_addr_str[INET6_ADDRSTRLEN];
|
|
Packit |
61cb5a |
char rh_addr_str[INET6_ADDRSTRLEN];
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("%-*s : ", host_name_len, host_name);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (state) {
|
|
Packit |
61cb5a |
case RH_CS_INITIAL:
|
|
Packit |
61cb5a |
printf("waiting for response msg");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CS_QUERY:
|
|
Packit |
61cb5a |
memset(mcast_addr_str, 0, sizeof(mcast_addr_str));
|
|
Packit |
61cb5a |
memset(rh_addr_str, 0, sizeof(rh_addr_str));
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (mcast_addr != NULL) {
|
|
Packit |
61cb5a |
af_sa_to_str(AF_CAST_SA(mcast_addr), mcast_addr_str);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (remote_addr != NULL) {
|
|
Packit |
61cb5a |
af_sa_to_str(AF_CAST_SA(remote_addr), rh_addr_str);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
switch (transport_method) {
|
|
Packit |
61cb5a |
case SF_TM_ASM:
|
|
Packit |
61cb5a |
printf("joined (S,G) = (*, %s), pinging", mcast_addr_str);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case SF_TM_SSM:
|
|
Packit |
61cb5a |
printf("joined (S,G) = (%s, %s), pinging", rh_addr_str, mcast_addr_str);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case SF_TM_IPBC:
|
|
Packit |
61cb5a |
printf("joined (S,G) = (*, %s), pinging", mcast_addr_str);
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CS_STOP:
|
|
Packit |
61cb5a |
switch (stop_reason) {
|
|
Packit |
61cb5a |
case RH_CSR_NONE:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("internal program error.");
|
|
Packit |
61cb5a |
errx(1, "Internal program error");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CSR_SERVER:
|
|
Packit |
61cb5a |
printf("server told us to stop");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CSR_SEND_MAXIMUM:
|
|
Packit |
61cb5a |
printf("maximum number of query messages exhausted");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CSR_TO_SEND_EXHAUSTED:
|
|
Packit |
61cb5a |
printf("given amount of query messages was sent");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case RH_CSR_REMOTE_VERSION_RECEIVED:
|
|
Packit |
61cb5a |
printf("remote version received");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
printf("\n");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Print final remote versions. remote_hosts is list with all remote hosts and host_name_len is
|
|
Packit |
61cb5a |
* maximal length of host name in list.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
print_final_remote_version(const struct rh_list *remote_hosts, int host_name_len)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct rh_item *rh_item;
|
|
Packit |
61cb5a |
struct rh_item_ci *ci;
|
|
Packit |
61cb5a |
size_t i;
|
|
Packit |
61cb5a |
unsigned char ch;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("\n");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
TAILQ_FOREACH(rh_item, remote_hosts, entries) {
|
|
Packit |
61cb5a |
ci = &rh_item->client_info;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("%-*s : ", host_name_len, rh_item->addr->host_name);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ci->server_info_len == 0) {
|
|
Packit |
61cb5a |
printf("response message not received\n");
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
for (i = 0; i < ci->server_info_len; i++) {
|
|
Packit |
61cb5a |
ch = ci->server_info[i];
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ch >= ' ' && ch < 0x7f && ch != '\\') {
|
|
Packit |
61cb5a |
fputc(ch, stdout);
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
if (ch == '\\') {
|
|
Packit |
61cb5a |
printf("\\\\");
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
printf("\\x%02X", ch);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("\n");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Print final statistics. remote_hosts is list with all remote hosts and host_name_len is maximal
|
|
Packit |
61cb5a |
* length of host name in list. transport_method is transport method (SF_TM_ASM/SSM/IPBC) from
|
|
Packit |
61cb5a |
* omping instance.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
print_final_stats(const struct rh_list *remote_hosts, int host_name_len,
|
|
Packit |
61cb5a |
enum sf_transport_method transport_method)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
const char *cast_str;
|
|
Packit |
61cb5a |
struct rh_item *rh_item;
|
|
Packit |
61cb5a |
struct rh_item_ci *ci;
|
|
Packit |
61cb5a |
enum sf_cast_type cast_type;
|
|
Packit |
61cb5a |
double avg_rtt;
|
|
Packit |
61cb5a |
int i;
|
|
Packit |
61cb5a |
int loss;
|
|
Packit |
61cb5a |
int loss_adj;
|
|
Packit |
61cb5a |
uint64_t received;
|
|
Packit |
61cb5a |
uint64_t sent;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("\n");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
loss_adj = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
TAILQ_FOREACH(rh_item, remote_hosts, entries) {
|
|
Packit |
61cb5a |
for (i = 0; i < 2; i++) {
|
|
Packit |
61cb5a |
if (i == 0) {
|
|
Packit |
61cb5a |
cast_type = SF_CT_UNI;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
switch (transport_method) {
|
|
Packit |
61cb5a |
case SF_TM_ASM:
|
|
Packit |
61cb5a |
case SF_TM_SSM:
|
|
Packit |
61cb5a |
cast_type = SF_CT_MULTI;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
case SF_TM_IPBC:
|
|
Packit |
61cb5a |
cast_type = SF_CT_BROAD;
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
default:
|
|
Packit |
61cb5a |
DEBUG_PRINTF("Internal error - unknown transport method");
|
|
Packit |
61cb5a |
errx(1, "Internal error - unknown transport method");
|
|
Packit |
61cb5a |
/* NOTREACHED */
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
cast_str = sf_cast_type_to_str(cast_type);
|
|
Packit |
61cb5a |
ci = &rh_item->client_info;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
received = ci->no_received[i];
|
|
Packit |
61cb5a |
sent = ci->no_sent;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("%-*s : ", host_name_len, rh_item->addr->host_name);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (received == 0 && i == 0) {
|
|
Packit |
61cb5a |
printf("response message never received\n");
|
|
Packit |
61cb5a |
break;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (i != 0) {
|
|
Packit |
61cb5a |
loss_adj = get_packet_loss_percent(sent - ci->first_mcast_seq + 1,
|
|
Packit |
61cb5a |
received);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
loss = get_packet_loss_percent(sent, received);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (received == 0) {
|
|
Packit |
61cb5a |
avg_rtt = 0;
|
|
Packit |
61cb5a |
} else {
|
|
Packit |
61cb5a |
avg_rtt = ci->avg_rtt[i] / UTIL_NSINMS;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("%5scast, ", cast_str);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("xmt/rcv/%%loss = ");
|
|
Packit |
61cb5a |
printf("%"PRIu64"/%"PRIu64, sent, received);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (ci->no_dups[i] > 0) {
|
|
Packit |
61cb5a |
printf("+%"PRIu64, ci->no_dups[i]);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("/%d%%", loss);
|
|
Packit |
61cb5a |
if (i != 0 && ci->first_mcast_seq > 1) {
|
|
Packit |
61cb5a |
printf(" (seq>=%"PRIu32" %d%%)", ci->first_mcast_seq, loss_adj);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf(", min/avg/max/std-dev = ");
|
|
Packit |
61cb5a |
printf("%.3f/%.3f/%.3f/%.3f", ci->rtt_min[i] / UTIL_NSINMS, avg_rtt,
|
|
Packit |
61cb5a |
ci->rtt_max[i] / UTIL_NSINMS,
|
|
Packit |
61cb5a |
util_ov_std_dev(ci->m2_rtt[i], ci->no_received[i]) / UTIL_NSINMS);
|
|
Packit |
61cb5a |
printf("\n");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Print packet statistics. host_name is remote host name with maximal host_name_len length. seq is
|
|
Packit |
61cb5a |
* sequence number of packet, is_dup is boolean with information if packet is duplicate or not,
|
|
Packit |
61cb5a |
* msg_len is length of message, dist_set is boolean variable with information if dist is set or
|
|
Packit |
61cb5a |
* not. dist is distance of packet (how TTL was changed). rtt_set is boolean variable with
|
|
Packit |
61cb5a |
* information if rtt (current round trip time) and avg_rtt (average round trip time) is set and
|
|
Packit |
61cb5a |
* computed or not. loss is number of lost packets. cast_type is type of packet received
|
|
Packit |
61cb5a |
* (unicast/multicast/broadcast). cont_stat is boolean variable saying, if to display
|
|
Packit |
61cb5a |
* continuous statistic or not.
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
print_packet_stats(const char *host_name, int host_name_len, uint32_t seq, int is_dup,
|
|
Packit |
61cb5a |
size_t msg_len, int dist_set, uint8_t dist, int rtt_set, double rtt, double avg_rtt, int loss,
|
|
Packit |
61cb5a |
enum sf_cast_type cast_type, int cont_stat)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
const char *cast_str;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
cast_str = sf_cast_type_to_str(cast_type);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("%-*s : ", host_name_len, host_name);
|
|
Packit |
61cb5a |
printf("%5scast, ", cast_str);
|
|
Packit |
61cb5a |
printf("seq=%"PRIu32, seq);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (is_dup) {
|
|
Packit |
61cb5a |
printf(" (dup)");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf(", ");
|
|
Packit |
61cb5a |
printf("size=%zu bytes", msg_len);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (dist_set) {
|
|
Packit |
61cb5a |
printf(", dist=%"PRIu8, dist);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rtt_set) {
|
|
Packit |
61cb5a |
printf(", time=%.3fms", rtt);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (cont_stat) {
|
|
Packit |
61cb5a |
printf(" (");
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (rtt_set) {
|
|
Packit |
61cb5a |
printf("%.3f avg, ", avg_rtt);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("%d%% loss)", loss);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
printf("\n");
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Register global signal handlers for application. sigaction is used to allow *BSD behavior, where
|
|
Packit |
61cb5a |
* recvmsg, sendto, ... can return EINTR, what signal (Linux) doesn't do (functions are restarted
|
|
Packit |
61cb5a |
* automatically)
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
register_signal_handlers(void)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
struct sigaction act;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
act.sa_handler = sigint_handler;
|
|
Packit |
61cb5a |
sigemptyset(&act.sa_mask);
|
|
Packit |
61cb5a |
act.sa_flags = 0;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
sigaction(SIGINT, &act, NULL);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
act.sa_handler = siginfo_handler;
|
|
Packit |
61cb5a |
#ifdef SIGINFO
|
|
Packit |
61cb5a |
sigaction(SIGINFO, &act, NULL);
|
|
Packit |
61cb5a |
#endif
|
|
Packit |
61cb5a |
sigaction(SIGUSR1, &act, NULL);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Handler for SIGINFO signal
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
siginfo_handler(int sig)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
display_stats_requested++;
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
/*
|
|
Packit |
61cb5a |
* Handler for SIGINT signal
|
|
Packit |
61cb5a |
*/
|
|
Packit |
61cb5a |
static void
|
|
Packit |
61cb5a |
sigint_handler(int sig)
|
|
Packit |
61cb5a |
{
|
|
Packit |
61cb5a |
exit_requested++;
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
DEBUG2_PRINTF("Exit requested %d times", exit_requested);
|
|
Packit |
61cb5a |
|
|
Packit |
61cb5a |
if (exit_requested > MAX_EXIT_REQUESTS) {
|
|
Packit |
61cb5a |
signal(SIGINT, SIG_DFL);
|
|
Packit |
61cb5a |
kill(getpid(), SIGINT);
|
|
Packit |
61cb5a |
}
|
|
Packit |
61cb5a |
}
|