abisip-find: add -l to list base stations instead of streaming replies

To get an overview of what base stations are present in a network, particularly
with many base stations being present, it is particularly useful to get a list
of connected base stations instead of just output of received replies.

Keep a sorted list of known base stations, which time out after 10 seconds.
Print additions and removals, and total amount of replies received. On each
change, print the entire list.

Output a running total of replies received, to provide comfort to the reader
that something is still happening, and to confirm that the shown listing is
still up-to-date (updated on the same line by means of '\r').

It looks like:

  ----- Mon Dec 25 18:59:43 2017

    0: MAC_Address='00:02:95:07:dc:bd'  IP_Address='192.168.0.124'  Unit_ID='1/1/1'  Location_1='Unknown'  Location_2='3GAP'  Equipment_Version='237B015_C'  Software_Version='unknown'  Unit_Name='Unknown'  Serial_Number='000295-0000152614'
    1: MAC_Address='00:02:95:07:dd:57'  IP_Address='192.168.0.15'  Unit_ID='1/1/1'  Location_1='Unknown'  Location_2='3GAP'  Equipment_Version='237B015_C'  Software_Version='unknown'  Unit_Name='Unknown'  Serial_Number='000295-0000154153'

  Total: 2
  RX: 11

  ----- Mon Dec 25 19:00:12 2017

  LOST:
  MAC_Address='00:02:95:07:dd:57'  IP_Address='192.168.0.15'  Unit_ID='1/1/1'  Location_1='Unknown'  Location_2='3GAP'  Equipment_Version='237B015_C'  Software_Version='unknown'  Unit_Name='Unknown'  Serial_Number='000295-0000154153'

  ----- Mon Dec 25 19:00:12 2017

    0: MAC_Address='00:02:95:07:dc:bd'  IP_Address='192.168.0.124'  Unit_ID='1/1/1'  Location_1='Unknown'  Location_2='3GAP'  Equipment_Version='237B015_C'  Software_Version='unknown'  Unit_Name='Unknown'  Serial_Number='000295-0000152614'

  Total: 1
  RX: 15

  ----- Mon Dec 25 19:00:28 2017

  New:
  MAC_Address='00:02:95:07:dd:57'  IP_Address='192.168.0.15'  Unit_ID='1/1/1'  Location_1='Unknown'  Location_2='3GAP'  Equipment_Version='237B015_C'  Software_Version='unknown'  Unit_Name='Unknown'  Serial_Number='000295-0000154153'

  ----- Mon Dec 25 19:00:28 2017

    0: MAC_Address='00:02:95:07:dc:bd'  IP_Address='192.168.0.124'  Unit_ID='1/1/1'  Location_1='Unknown'  Location_2='3GAP'  Equipment_Version='237B015_C'  Software_Version='unknown'  Unit_Name='Unknown'  Serial_Number='000295-0000152614'
    1: MAC_Address='00:02:95:07:dd:57'  IP_Address='192.168.0.15'  Unit_ID='1/1/1'  Location_1='Unknown'  Location_2='3GAP'  Equipment_Version='237B015_C'  Software_Version='unknown'  Unit_Name='Unknown'  Serial_Number='000295-0000154153'
  RX: 18

Change-Id: I4201876431029b303dbd10e46492228379c9782a
This commit is contained in:
Neels Hofmeyr 2017-12-25 18:22:18 +01:00
parent 2a9ac19863
commit 5bf1e15c55
1 changed files with 140 additions and 8 deletions

View File

@ -25,17 +25,22 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <time.h>
#include <talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/protocol/ipaccess.h>
#include <osmocom/gsm/ipa.h>
#include <osmocom/bsc/gsm_data.h>
static struct {
const char *ifname;
bool list_view;
} cmdline_opts = {
.ifname = NULL,
.list_view = false,
};
static void print_help()
@ -44,6 +49,9 @@ static void print_help()
printf("Usage: abisip-find [-l] [<interface-name>]\n");
printf(" <interface-name> Specify the outgoing network interface,\n"
" e.g. 'eth0'\n");
printf(" -l --list-view Instead of printing received responses,\n"
" output a sorted list of currently present\n"
" base stations and change events.\n");
}
static void handle_options(int argc, char **argv)
@ -52,10 +60,11 @@ static void handle_options(int argc, char **argv)
int option_index = 0, c;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"list-view", 0, 0, 'l'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "h",
c = getopt_long(argc, argv, "hl",
long_options, &option_index);
if (c == -1)
break;
@ -64,6 +73,9 @@ static void handle_options(int argc, char **argv)
case 'h':
print_help();
exit(EXIT_SUCCESS);
case 'l':
cmdline_opts.list_view = true;
break;
default:
/* catch unknown options *as well as* missing arguments. */
fprintf(stderr, "Error in command line options. Exiting. Try --help.\n");
@ -159,22 +171,137 @@ static int bcast_find(int fd)
return sendto(fd, find_pkt, sizeof(find_pkt), 0, (struct sockaddr *) &sa, sizeof(sa));
}
static int parse_response(unsigned char *buf, int len)
static char *parse_response(void *ctx, unsigned char *buf, int len)
{
uint8_t t_len;
uint8_t t_tag;
uint8_t *cur = buf;
char *out = talloc_zero_size(ctx, 512);
while (cur < buf + len) {
t_len = *cur++;
t_tag = *cur++;
printf("%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
out = talloc_asprintf_append(out, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
cur += t_len;
}
printf("\n");
return 0;
return out;
}
struct base_station {
struct llist_head entry;
char *line;
time_t timestamp;
};
LLIST_HEAD(base_stations);
void *ctx = NULL;
void print_timestamp()
{
time_t now = time(NULL);
printf("\n\n----- %s\n", ctime(&now));
}
struct base_station *base_station_parse(unsigned char *buf, int len)
{
struct base_station *new_bs = talloc_zero(ctx, struct base_station);
new_bs->line = parse_response(new_bs, buf, len);
new_bs->timestamp = time(NULL);
return new_bs;
}
bool base_stations_add(struct base_station *new_bs)
{
struct base_station *bs;
llist_for_each_entry(bs, &base_stations, entry) {
int c = strcmp(new_bs->line, bs->line);
if (!c) {
/* entry already exists. */
bs->timestamp = new_bs->timestamp;
return false;
}
if (c < 0) {
/* found the place to add the entry */
break;
}
}
print_timestamp();
printf("New:\n%s\n", new_bs->line);
llist_add_tail(&new_bs->entry, &bs->entry);
return true;
}
bool base_stations_timeout()
{
struct base_station *bs, *next_bs;
time_t now = time(NULL);
bool changed = false;
llist_for_each_entry_safe(bs, next_bs, &base_stations, entry) {
if (now - bs->timestamp < 10)
continue;
print_timestamp();
printf("LOST:\n%s\n", bs->line);
llist_del(&bs->entry);
talloc_free(bs);
changed = true;
}
return changed;
}
void base_stations_print()
{
struct base_station *bs;
int count = 0;
print_timestamp();
llist_for_each_entry(bs, &base_stations, entry) {
printf("%3d: %s\n", count, bs->line);
count++;
}
printf("\nTotal: %d\n", count);
}
static void base_stations_bump(bool known_changed)
{
bool changed = known_changed;
if (base_stations_timeout())
changed = true;
if (changed)
base_stations_print();
}
static void handle_response(unsigned char *buf, int len)
{
static unsigned int responses = 0;
responses++;
if (cmdline_opts.list_view) {
bool changed = false;
struct base_station *bs = base_station_parse(buf, len);
if (base_stations_add(bs))
changed = true;
else
talloc_free(bs);
base_stations_bump(changed);
printf("RX: %u \r", responses);
fflush(stdout);
} else {
char *line = parse_response(ctx, buf, len);
printf(line);
printf("\n");
talloc_free(line);
}
}
static int read_response(int fd)
@ -195,7 +322,8 @@ static int read_response(int fd)
if (buf[4] != IPAC_MSGT_ID_RESP)
return 0;
return parse_response(buf+6, len-6);
handle_response(buf+6, len-6);
return 0;
}
static int bfd_cb(struct osmo_fd *bfd, unsigned int flags)
@ -217,6 +345,8 @@ static void timer_cb(void *_data)
bfd->when |= BSC_FD_WRITE;
base_stations_bump(false);
osmo_timer_schedule(&timer, 5, 0);
}
@ -231,8 +361,10 @@ int main(int argc, char **argv)
handle_options(argc, argv);
if (!cmdline_opts.ifname)
fprintf(stdout, "you might need to specify the outgoing\n"
" network interface, e.g. ``%s eth0''\n", argv[0]);
fprintf(stdout, "- You might need to specify the outgoing\n"
" network interface, e.g. ``%s eth0''\n", argv[0]);
if (!cmdline_opts.list_view)
fprintf(stdout, "- You may find the --list-view option convenient.\n");
bfd.cb = bfd_cb;
bfd.when = BSC_FD_READ | BSC_FD_WRITE;