Commit 8cca28b3 authored by Cedric Roux's avatar Cedric Roux

put textlog.[ch] in logger/ and rename remote.c to textlog.c

parent 1dea1590
...@@ -11,17 +11,20 @@ OBJS=remote_old.o plot.o database.o gui.o utils.o ...@@ -11,17 +11,20 @@ OBJS=remote_old.o plot.o database.o gui.o utils.o
$(PROG): gui/gui.a $(OBJS) $(PROG): gui/gui.a $(OBJS)
$(CC) $(CFLAGS) -o $(PROG) $(OBJS) gui/gui.a $(LIBS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) gui/gui.a $(LIBS)
textlog: utils.o remote.o database.o event.o handler.o textlog.o \ textlog: utils.o textlog.o database.o event.o handler.o \
event_selector.o view/view.a gui/gui.a event_selector.o view/view.a gui/gui.a logger/logger.a
$(CC) $(CFLAGS) -o textlog $^ $(LIBS) $(CC) $(CFLAGS) -o textlog $^ $(LIBS)
.PHONY: gui/gui.a view/view.a .PHONY: gui/gui.a view/view.a logger/logger.a
gui/gui.a:
cd gui && make
view/view.a: view/view.a:
cd view && make cd view && make
gui/gui.a: logger/logger.a:
cd gui && make cd logger && make
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<
...@@ -30,3 +33,4 @@ clean: ...@@ -30,3 +33,4 @@ clean:
rm -f *.o $(PROG) core textlog rm -f *.o $(PROG) core textlog
cd gui && make clean cd gui && make clean
cd view && make clean cd view && make clean
cd logger && make clean
CC=gcc
CFLAGS=-Wall -g -pthread -I..
OBJS=textlog.o
logger.a: $(OBJS)
ar cr logger.a $(OBJS)
%.o: %.c
$(CC) $(CFLAGS) -o $@ -c $<
clean:
rm -f *.a *.o
#include "textlog.h"
#include "handler.h"
#include "database.h"
#include "view/view.h"
#include "utils.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
enum format_item_type {
INSTRING,
INT, STRING, BUFFER };
struct format_item {
enum format_item_type type;
union {
/* INSTRING */
char *s;
/* others */
int event_arg;
};
};
struct textlog {
char *event_name;
char *format;
void *database;
unsigned long handler_id;
/* parsed format string */
struct format_item *f;
int fsize;
/* list of views */
view **v;
int vsize;
/* local output buffer */
OBUF o;
};
static void _event(void *p, event e)
{
struct textlog *l = p;
int i;
l->o.osize = 0;
for (i = 0; i < l->fsize; i++)
switch(l->f[i].type) {
case INSTRING: PUTS(&l->o, l->f[i].s); break;
case INT: PUTI(&l->o, e.e[l->f[i].event_arg].i); break;
case STRING: PUTS_CLEAN(&l->o, e.e[l->f[i].event_arg].s); break;
case BUFFER:
PUTS(&l->o, "{buffer size:");
PUTI(&l->o, e.e[l->f[i].event_arg].bsize);
PUTS(&l->o, "}");
break;
}
PUTC(&l->o, 0);
for (i = 0; i < l->vsize; i++) l->v[i]->append(l->v[i], l->o.obuf);
}
enum chunk_type { C_ERROR, C_STRING, C_ARG_NAME, C_EVENT_NAME };
struct chunk {
enum chunk_type type;
char *s;
enum format_item_type it;
int event_arg;
};
/* TODO: speed it up? */
static int find_argument(char *name, database_event_format f,
enum format_item_type *it, int *event_arg)
{
int i;
for (i = 0; i < f.count; i++) if (!strcmp(name, f.name[i])) break;
if (i == f.count) return 0;
*event_arg = i;
if (!strcmp(f.type[i], "int")) *it = INT;
else if (!strcmp(f.type[i], "string")) *it = STRING;
else if (!strcmp(f.type[i], "buffer")) *it = BUFFER;
else return 0;
return 1;
}
static struct chunk next_chunk(char **s, database_event_format f)
{
char *cur = *s;
char *name;
enum format_item_type it;
int event_arg;
/* argument in [ ] */
if (*cur == '[') {
*cur = 0;
cur++;
name = cur;
/* no \ allowed there */
while (*cur && *cur != ']' && *cur != '\\') cur++;
if (*cur != ']') goto error;
*cur = 0;
cur++;
*s = cur;
if (find_argument(name, f, &it, &event_arg) == 0) goto error;
return (struct chunk){type:C_ARG_NAME, s:name, it:it, event_arg:event_arg};
}
/* { } is name of event (anything in between is smashed) */
if (*cur == '{') {
*cur = 0;
cur++;
while (*cur && *cur != '}') cur++;
if (*cur != '}') goto error;
*cur = 0;
cur++;
*s = cur;
return (struct chunk){type:C_EVENT_NAME};
}
/* anything but [ and { is raw string */
/* TODO: deal with \ */
name = cur;
while (*cur && *cur != '[' && *cur != '{') cur++;
*s = cur;
return (struct chunk){type:C_STRING, s:name};
error:
return (struct chunk){type:C_ERROR};
}
textlog *new_textlog(event_handler *h, void *database,
char *event_name, char *format)
{
struct textlog *ret;
int event_id;
database_event_format f;
char *cur;
ret = calloc(1, sizeof(struct textlog)); if (ret == NULL) abort();
ret->event_name = strdup(event_name); if (ret->event_name == NULL) abort();
ret->format = strdup(format); if (ret->format == NULL) abort();
ret->database = database;
event_id = event_id_from_name(database, event_name);
ret->handler_id = register_handler_function(h, event_id, _event, ret);
f = get_format(database, event_id);
/* we won't get more than strlen(format) "chunks" */
ret->f = malloc(sizeof(struct format_item) * strlen(format));
if (ret->f == NULL) abort();
cur = ret->format;
while (*cur) {
struct chunk c = next_chunk(&cur, f);
switch (c.type) {
case C_ERROR: goto error;
case C_STRING:
ret->f[ret->fsize].type = INSTRING;
ret->f[ret->fsize].s = c.s;
break;
case C_ARG_NAME:
ret->f[ret->fsize].type = c.it;
ret->f[ret->fsize].event_arg = c.event_arg;
break;
case C_EVENT_NAME:
ret->f[ret->fsize].type = INSTRING;
ret->f[ret->fsize].s = ret->event_name;
break;
}
ret->fsize++;
}
return ret;
error:
printf("%s:%d: bad format '%s'\n", __FILE__, __LINE__, format);
abort();
}
void textlog_add_view(textlog *_l, view *v)
{
struct textlog *l = _l;
l->vsize++;
l->v = realloc(l->v, l->vsize * sizeof(view *)); if (l->v == NULL) abort();
l->v[l->vsize-1] = v;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "database.h"
#include "event.h"
#include "handler.h"
#include "textlog.h"
#include "view/view.h"
#include "gui/gui.h"
#include "utils.h"
#include "../T_defs.h"
#include "event_selector.h"
#define DEFAULT_REMOTE_PORT 2021
int get_connection(char *addr, int port)
{
struct sockaddr_in a;
socklen_t alen;
int s, t;
printf("waiting for connection on %s:%d\n", addr, port);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) { perror("socket"); exit(1); }
t = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int)))
{ perror("setsockopt"); exit(1); }
a.sin_family = AF_INET;
a.sin_port = htons(port);
a.sin_addr.s_addr = inet_addr(addr);
if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
if (listen(s, 5)) { perror("bind"); exit(1); }
alen = sizeof(a);
t = accept(s, (struct sockaddr *)&a, &alen);
if (t == -1) { perror("accept"); exit(1); }
close(s);
printf("connected\n");
return t;
}
void usage(void)
{
printf(
"options:\n"
" -d <database file> this option is mandatory\n"
" -on <GROUP or ID> turn log ON for given GROUP or ID\n"
" -off <GROUP or ID> turn log OFF for given GROUP or ID\n"
" -ON turn all logs ON\n"
" -OFF turn all logs OFF\n"
" note: you may pass several -on/-off/-ON/-OFF,\n"
" they will be processed in order\n"
" by default, all is off\n"
" -p <port> use given port (default %d)\n"
" -x GUI output\n"
" -debug-gui activate GUI debug logs\n"
" -no-gui disable GUI entirely\n",
DEFAULT_REMOTE_PORT
);
exit(1);
}
int fullread(int fd, void *_buf, int count)
{
char *buf = _buf;
int ret = 0;
int l;
while (count) {
l = read(fd, buf, count);
if (l <= 0) { printf("read socket problem\n"); abort(); }
count -= l;
buf += l;
ret += l;
}
return ret;
}
event get_event(int s, char *v, void *d)
{
int type;
int32_t length;
fullread(s, &length, 4);
fullread(s, &type, sizeof(int));
length -= sizeof(int);
fullread(s, v, length);
return new_event(type, length, v, d);
}
static void *gui_thread(void *_g)
{
gui *g = _g;
gui_loop(g);
return NULL;
}
int main(int n, char **v)
{
extern int volatile gui_logd;
char *database_filename = NULL;
void *database;
int port = DEFAULT_REMOTE_PORT;
char **on_off_name;
int *on_off_action;
int on_off_n = 0;
int *is_on;
int number_of_events;
int s;
int i;
char t;
int l;
event_handler *h;
textlog *textlog;
gui *g;
int gui_mode = 0;
view *out;
int gui_active = 1;
on_off_name = malloc(n * sizeof(char *)); if (on_off_name == NULL) abort();
on_off_action = malloc(n * sizeof(int)); if (on_off_action == NULL) abort();
for (i = 1; i < n; i++) {
if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
if (!strcmp(v[i], "-d"))
{ if (i > n-2) usage(); database_filename = v[++i]; continue; }
if (!strcmp(v[i], "-p"))
{ if (i > n-2) usage(); port = atoi(v[++i]); continue; }
if (!strcmp(v[i], "-on")) { if (i > n-2) usage();
on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=1; continue; }
if (!strcmp(v[i], "-off")) { if (i > n-2) usage();
on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=0; continue; }
if (!strcmp(v[i], "-ON"))
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; }
if (!strcmp(v[i], "-OFF"))
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; }
if (!strcmp(v[i], "-x")) { gui_mode = 1; continue; }
if (!strcmp(v[i], "-debug-gui")) { gui_logd = 1; continue; }
if (!strcmp(v[i], "-no-gui")) { gui_active = 0; continue; }
usage();
}
if (gui_active == 0) gui_mode = 0;
if (database_filename == NULL) {
printf("ERROR: provide a database file (-d)\n");
exit(1);
}
database = parse_database(database_filename);
number_of_events = number_of_ids(database);
is_on = calloc(number_of_events, sizeof(int));
if (is_on == NULL) abort();
h = new_handler(database);
if (gui_active) {
g = gui_init();
new_thread(gui_thread, g);
}
if (gui_mode) {
widget *w, *win;
// w = new_textlist(g, 600, 20, 0);
w = new_textlist(g, 800, 50, BACKGROUND_COLOR);
win = new_toplevel_window(g, 800, 50*12, "textlog");
widget_add_child(g, win, w, -1);
out = new_view_textlist(1000, 10, g, w);
//tout = new_view_textlist(7, 4, g, w);
} else {
out = new_view_stdout();
}
for (i = 0; i < number_of_events; i++) {
char *name, *desc;
database_get_generic_description(database, i, &name, &desc);
textlog = new_textlog(h, database, name, desc);
// "ENB_UL_CHANNEL_ESTIMATE",
// "ev: {} eNB_id [eNB_ID] frame [frame] subframe [subframe]");
textlog_add_view(textlog, out);
free(name);
free(desc);
}
for (i = 0; i < on_off_n; i++)
on_off(database, on_off_name[i], is_on, on_off_action[i]);
s = get_connection("0.0.0.0", port);
/* send the first message - activate selected traces */
t = 0;
if (write(s, &t, 1) != 1) abort();
l = 0;
for (i = 0; i < number_of_events; i++) if (is_on[i]) l++;
if (write(s, &l, sizeof(int)) != sizeof(int)) abort();
for (l = 0; l < number_of_events; l++)
if (is_on[l])
if (write(s, &l, sizeof(int)) != sizeof(int)) abort();
if (gui_active)
setup_event_selector(g, database, s, is_on);
/* read messages */
while (1) {
char v[T_BUFFER_MAX];
event e;
e = get_event(s, v, database);
handle_event(h, e);
}
return 0;
}
#include "textlog.h" #include <stdio.h>
#include "handler.h" #include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "database.h" #include "database.h"
#include "event.h"
#include "handler.h"
#include "logger/textlog.h"
#include "view/view.h" #include "view/view.h"
#include "gui/gui.h"
#include "utils.h" #include "utils.h"
#include <stdlib.h> #include "../T_defs.h"
#include <string.h> #include "event_selector.h"
#include <stdio.h>
enum format_item_type { #define DEFAULT_REMOTE_PORT 2021
INSTRING,
INT, STRING, BUFFER }; int get_connection(char *addr, int port)
struct format_item {
enum format_item_type type;
union {
/* INSTRING */
char *s;
/* others */
int event_arg;
};
};
struct textlog {
char *event_name;
char *format;
void *database;
unsigned long handler_id;
/* parsed format string */
struct format_item *f;
int fsize;
/* list of views */
view **v;
int vsize;
/* local output buffer */
OBUF o;
};
static void _event(void *p, event e)
{ {
struct textlog *l = p; struct sockaddr_in a;
int i; socklen_t alen;
int s, t;
l->o.osize = 0; printf("waiting for connection on %s:%d\n", addr, port);
for (i = 0; i < l->fsize; i++) s = socket(AF_INET, SOCK_STREAM, 0);
switch(l->f[i].type) { if (s == -1) { perror("socket"); exit(1); }
case INSTRING: PUTS(&l->o, l->f[i].s); break; t = 1;
case INT: PUTI(&l->o, e.e[l->f[i].event_arg].i); break; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(int)))
case STRING: PUTS_CLEAN(&l->o, e.e[l->f[i].event_arg].s); break; { perror("setsockopt"); exit(1); }
case BUFFER:
PUTS(&l->o, "{buffer size:"); a.sin_family = AF_INET;
PUTI(&l->o, e.e[l->f[i].event_arg].bsize); a.sin_port = htons(port);
PUTS(&l->o, "}"); a.sin_addr.s_addr = inet_addr(addr);
break;
} if (bind(s, (struct sockaddr *)&a, sizeof(a))) { perror("bind"); exit(1); }
PUTC(&l->o, 0); if (listen(s, 5)) { perror("bind"); exit(1); }
alen = sizeof(a);
t = accept(s, (struct sockaddr *)&a, &alen);
if (t == -1) { perror("accept"); exit(1); }
close(s);
printf("connected\n");
for (i = 0; i < l->vsize; i++) l->v[i]->append(l->v[i], l->o.obuf); return t;
} }
enum chunk_type { C_ERROR, C_STRING, C_ARG_NAME, C_EVENT_NAME }; void usage(void)
struct chunk {
enum chunk_type type;
char *s;
enum format_item_type it;
int event_arg;
};
/* TODO: speed it up? */
static int find_argument(char *name, database_event_format f,
enum format_item_type *it, int *event_arg)
{ {
int i; printf(
for (i = 0; i < f.count; i++) if (!strcmp(name, f.name[i])) break; "options:\n"
if (i == f.count) return 0; " -d <database file> this option is mandatory\n"
*event_arg = i; " -on <GROUP or ID> turn log ON for given GROUP or ID\n"
if (!strcmp(f.type[i], "int")) *it = INT; " -off <GROUP or ID> turn log OFF for given GROUP or ID\n"
else if (!strcmp(f.type[i], "string")) *it = STRING; " -ON turn all logs ON\n"
else if (!strcmp(f.type[i], "buffer")) *it = BUFFER; " -OFF turn all logs OFF\n"
else return 0; " note: you may pass several -on/-off/-ON/-OFF,\n"
return 1; " they will be processed in order\n"
" by default, all is off\n"
" -p <port> use given port (default %d)\n"
" -x GUI output\n"
" -debug-gui activate GUI debug logs\n"
" -no-gui disable GUI entirely\n",
DEFAULT_REMOTE_PORT
);
exit(1);
} }
static struct chunk next_chunk(char **s, database_event_format f) int fullread(int fd, void *_buf, int count)
{ {
char *cur = *s; char *buf = _buf;
char *name; int ret = 0;
enum format_item_type it; int l;
int event_arg; while (count) {
l = read(fd, buf, count);
/* argument in [ ] */ if (l <= 0) { printf("read socket problem\n"); abort(); }
if (*cur == '[') { count -= l;
*cur = 0; buf += l;
cur++; ret += l;
name = cur;
/* no \ allowed there */
while (*cur && *cur != ']' && *cur != '\\') cur++;
if (*cur != ']') goto error;
*cur = 0;
cur++;
*s = cur;
if (find_argument(name, f, &it, &event_arg) == 0) goto error;
return (struct chunk){type:C_ARG_NAME, s:name, it:it, event_arg:event_arg};
} }
return ret;
}
/* { } is name of event (anything in between is smashed) */ event get_event(int s, char *v, void *d)
if (*cur == '{') { {
*cur = 0; int type;
cur++; int32_t length;
while (*cur && *cur != '}') cur++;
if (*cur != '}') goto error;
*cur = 0;
cur++;
*s = cur;
return (struct chunk){type:C_EVENT_NAME};
}
/* anything but [ and { is raw string */ fullread(s, &length, 4);
/* TODO: deal with \ */ fullread(s, &type, sizeof(int));
name = cur; length -= sizeof(int);
while (*cur && *cur != '[' && *cur != '{') cur++; fullread(s, v, length);
*s = cur;
return (struct chunk){type:C_STRING, s:name};
error: return new_event(type, length, v, d);
return (struct chunk){type:C_ERROR};
} }
textlog *new_textlog(event_handler *h, void *database, static void *gui_thread(void *_g)
char *event_name, char *format)
{ {
struct textlog *ret; gui *g = _g;
int event_id; gui_loop(g);
database_event_format f; return NULL;
char *cur; }
ret = calloc(1, sizeof(struct textlog)); if (ret == NULL) abort(); int main(int n, char **v)
{
ret->event_name = strdup(event_name); if (ret->event_name == NULL) abort(); extern int volatile gui_logd;
ret->format = strdup(format); if (ret->format == NULL) abort(); char *database_filename = NULL;
ret->database = database; void *database;
int port = DEFAULT_REMOTE_PORT;
event_id = event_id_from_name(database, event_name); char **on_off_name;
int *on_off_action;
ret->handler_id = register_handler_function(h, event_id, _event, ret); int on_off_n = 0;
int *is_on;
f = get_format(database, event_id); int number_of_events;
int s;
/* we won't get more than strlen(format) "chunks" */ int i;
ret->f = malloc(sizeof(struct format_item) * strlen(format)); char t;
if (ret->f == NULL) abort(); int l;
event_handler *h;
cur = ret->format; textlog *textlog;
gui *g;
while (*cur) { int gui_mode = 0;
struct chunk c = next_chunk(&cur, f); view *out;
switch (c.type) { int gui_active = 1;
case C_ERROR: goto error;
case C_STRING: on_off_name = malloc(n * sizeof(char *)); if (on_off_name == NULL) abort();
ret->f[ret->fsize].type = INSTRING; on_off_action = malloc(n * sizeof(int)); if (on_off_action == NULL) abort();
ret->f[ret->fsize].s = c.s;
break; for (i = 1; i < n; i++) {
case C_ARG_NAME: if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage();
ret->f[ret->fsize].type = c.it; if (!strcmp(v[i], "-d"))
ret->f[ret->fsize].event_arg = c.event_arg; { if (i > n-2) usage(); database_filename = v[++i]; continue; }
break; if (!strcmp(v[i], "-p"))
case C_EVENT_NAME: { if (i > n-2) usage(); port = atoi(v[++i]); continue; }
ret->f[ret->fsize].type = INSTRING; if (!strcmp(v[i], "-on")) { if (i > n-2) usage();
ret->f[ret->fsize].s = ret->event_name; on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=1; continue; }
break; if (!strcmp(v[i], "-off")) { if (i > n-2) usage();
} on_off_name[on_off_n]=v[++i]; on_off_action[on_off_n++]=0; continue; }
ret->fsize++; if (!strcmp(v[i], "-ON"))
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; }
if (!strcmp(v[i], "-OFF"))
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; }
if (!strcmp(v[i], "-x")) { gui_mode = 1; continue; }
if (!strcmp(v[i], "-debug-gui")) { gui_logd = 1; continue; }
if (!strcmp(v[i], "-no-gui")) { gui_active = 0; continue; }
usage();
} }
return ret; if (gui_active == 0) gui_mode = 0;
error: if (database_filename == NULL) {
printf("%s:%d: bad format '%s'\n", __FILE__, __LINE__, format); printf("ERROR: provide a database file (-d)\n");
abort(); exit(1);
} }
void textlog_add_view(textlog *_l, view *v) database = parse_database(database_filename);
{
struct textlog *l = _l; number_of_events = number_of_ids(database);
l->vsize++; is_on = calloc(number_of_events, sizeof(int));
l->v = realloc(l->v, l->vsize * sizeof(view *)); if (l->v == NULL) abort(); if (is_on == NULL) abort();
l->v[l->vsize-1] = v;
h = new_handler(database);
if (gui_active) {
g = gui_init();
new_thread(gui_thread, g);
}
if (gui_mode) {
widget *w, *win;
// w = new_textlist(g, 600, 20, 0);
w = new_textlist(g, 800, 50, BACKGROUND_COLOR);
win = new_toplevel_window(g, 800, 50*12, "textlog");
widget_add_child(g, win, w, -1);
out = new_view_textlist(1000, 10, g, w);
//tout = new_view_textlist(7, 4, g, w);
} else {
out = new_view_stdout();
}
for (i = 0; i < number_of_events; i++) {
char *name, *desc;
database_get_generic_description(database, i, &name, &desc);
textlog = new_textlog(h, database, name, desc);
// "ENB_UL_CHANNEL_ESTIMATE",
// "ev: {} eNB_id [eNB_ID] frame [frame] subframe [subframe]");
textlog_add_view(textlog, out);
free(name);
free(desc);
}
for (i = 0; i < on_off_n; i++)
on_off(database, on_off_name[i], is_on, on_off_action[i]);
s = get_connection("0.0.0.0", port);
/* send the first message - activate selected traces */
t = 0;
if (write(s, &t, 1) != 1) abort();
l = 0;
for (i = 0; i < number_of_events; i++) if (is_on[i]) l++;
if (write(s, &l, sizeof(int)) != sizeof(int)) abort();
for (l = 0; l < number_of_events; l++)
if (is_on[l])
if (write(s, &l, sizeof(int)) != sizeof(int)) abort();
if (gui_active)
setup_event_selector(g, database, s, is_on);
/* read messages */
while (1) {
char v[T_BUFFER_MAX];
event e;
e = get_event(s, v, database);
handle_event(h, e);
}
return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment