497 util/rx.c
@@ -17,28 +17,28 @@
#define PL_NSIZ 32

struct u_stat_t {
char race;
char gender;
char align;
char have;
short hp, hpmax;
short pow, powmax;
short ac;
short ulevel;
short dlevel;
short wishes;
short prayers;
short deaths;
char class[3];
char status;
long moves; /* 8 bytes */
char plname[PL_NSIZ];
char dungeon_or_death[1024 - 32];
char race;
char gender;
char align;
char have;
short hp, hpmax;
short pow, powmax;
short ac;
short ulevel;
short dlevel;
short wishes;
short prayers;
short deaths;
char class[3];
char status;
long moves; /* 8 bytes */
char plname[PL_NSIZ];
char dungeon_or_death[1024 - 32];
};

struct player_t {
struct u_stat_t stats;
struct timeval updated_at;
struct u_stat_t stats;
struct timeval updated_at;
};

bool done = false;
@@ -47,276 +47,271 @@ bool any_changed = false;
static void
int_handler( int sig )
{
done = true;
done = true;
}

list *players;

static int
cmp_plname( struct u_stat_t *a, struct player_t *b )
{
return strncmp(a->plname, b->stats.plname, PL_NSIZ);
return strncmp(a->plname, b->stats.plname, PL_NSIZ);
}

#define STATUS_ACTIVE 0
#define STATUS_SAVED 1
#define STATUS_ACTIVE 0
#define STATUS_SAVED 1
#define STATUS_INACTIVE 2

#define PLAYER_PLNAME 0
#define PLAYER_ITEMS 1
#define PLAYER_RACE 2
#define PLAYER_ITEMS 1
#define PLAYER_RACE 2
#define PLAYER_GENDER 3
#define PLAYER_ALIGN 4
#define PLAYER_CLASS 5
#define PLAYER_HP 6
#define PLAYER_MAXHP 7
#define PLAYER_ALIGN 4
#define PLAYER_CLASS 5
#define PLAYER_HP 6
#define PLAYER_MAXHP 7
#define PLAYER_ULEVEL 8
#define PLAYER_AC 9
#define PLAYER_AC 9
#define PLAYER_PRAYERS 10
#define PLAYER_WISHES 11
#define PLAYER_DEATHS 12
#define PLAYER_MOVES 13
#define PLAYER_MOVES 13
#define PLAYER_DLEVEL 14
#define PLAYER_DUNGEON 15
#define PLAYER_MAX 16
#define PLAYER_MAX 16

static int player_sorting = PLAYER_PLNAME;
static int player_direction = 1;

static int
cmp_player( struct player_t *pa, struct player_t *pb )
{
struct u_stat_t *a = &pa->stats;
struct u_stat_t *b = &pb->stats;

switch(player_sorting) {
default:
case PLAYER_PLNAME: return cmp_plname(a, pb);
case PLAYER_ITEMS: return b->have - a->have;
case PLAYER_RACE: return b->race - a->race;
case PLAYER_GENDER: return b->gender - a->gender;
case PLAYER_ALIGN: return b->align - a->align;
case PLAYER_CLASS: return strncmp(a->class, b->class, 3);
case PLAYER_HP: return b->hp - a->hp;
case PLAYER_MAXHP: return b->hpmax - a->hpmax;
case PLAYER_ULEVEL: return b->ulevel - a->ulevel;
case PLAYER_AC: return a->ac - b->ac;
case PLAYER_PRAYERS: return b->prayers - a->prayers;
case PLAYER_WISHES: return b->wishes - a->wishes;
case PLAYER_DEATHS: return b->deaths - a->deaths;
case PLAYER_MOVES: return b->moves - a->moves;
case PLAYER_DLEVEL: return b->dlevel - a->dlevel;
case PLAYER_DUNGEON: return strcmp(a->dungeon_or_death, b->dungeon_or_death);
}
struct u_stat_t *a = &pa->stats;
struct u_stat_t *b = &pb->stats;

switch(player_sorting) {
default:
case PLAYER_PLNAME: return cmp_plname(a, pb);
case PLAYER_ITEMS: return b->have - a->have;
case PLAYER_RACE: return b->race - a->race;
case PLAYER_GENDER: return b->gender - a->gender;
case PLAYER_ALIGN: return b->align - a->align;
case PLAYER_CLASS: return strncmp(a->class, b->class, 3);
case PLAYER_HP: return b->hp - a->hp;
case PLAYER_MAXHP: return b->hpmax - a->hpmax;
case PLAYER_ULEVEL: return b->ulevel - a->ulevel;
case PLAYER_AC: return a->ac - b->ac;
case PLAYER_PRAYERS: return b->prayers - a->prayers;
case PLAYER_WISHES: return b->wishes - a->wishes;
case PLAYER_DEATHS: return b->deaths - a->deaths;
case PLAYER_MOVES: return b->moves - a->moves;
case PLAYER_DLEVEL: return b->dlevel - a->dlevel;
case PLAYER_DUNGEON: return strcmp(a->dungeon_or_death, b->dungeon_or_death);
}
}

static void
update( struct u_stat_t *u_stat )
{
struct player_t *existing = list_goto(players, u_stat, (compare) cmp_plname);
if( !existing ) {
existing = (struct player_t *) malloc(sizeof(struct player_t));
list_unshift(players, existing);
}
memcpy(&existing->stats, u_stat, sizeof(struct u_stat_t));
gettimeofday(&existing->updated_at, NULL);
struct player_t *existing = list_goto(players, u_stat, (compare) cmp_plname);
if( !existing ) {
existing = (struct player_t *) malloc(sizeof(struct player_t));
list_unshift(players, existing);
}
memcpy(&existing->stats, u_stat, sizeof(struct u_stat_t));
gettimeofday(&existing->updated_at, NULL);
}

int
main( int argc, char *argv[] )
{
char name[256];
struct u_stat_t u_stat;
struct sockaddr_in addr, from;
socklen_t fromlen;
u_int yes = 1;
bool first_time = true;
int i;

int s = socket(PF_INET, SOCK_DGRAM, 0);
if( s < 0 ) {
perror("socket");
exit(EXIT_FAILURE);
}

gethostname(name, sizeof(name));

if( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) != 0 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
char name[256];
struct u_stat_t u_stat;
struct sockaddr_in addr, from;
socklen_t fromlen;
u_int yes = 1;
bool first_time = true;
int i;

int s = socket(PF_INET, SOCK_DGRAM, 0);
if( s < 0 ) {
perror("socket");
exit(EXIT_FAILURE);
}

gethostname(name, sizeof(name));

if( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) != 0 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}

#ifdef __FreeBSD__
if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) != 0 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) != 0 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
#endif

const struct in_addr localhost_addr = {
.s_addr = htonl(INADDR_LOOPBACK)
};
if( setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &localhost_addr, sizeof(localhost_addr)) == -1 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}

const struct ip_mreq mreq = {
.imr_multiaddr = {
.s_addr = inet_addr("225.0.0.37")
},
.imr_interface = {
.s_addr = htonl(INADDR_LOOPBACK)
}
};
if( setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(12345);

if( bind(s, (struct sockaddr *) &addr, sizeof(addr)) != 0 ) {
perror("bind");
exit(EXIT_FAILURE);
}

players = list_new();
list_set_free(players, (free_function) free, NULL);

signal(SIGINT, int_handler);

while(!done) {
fd_set rfds;
int indl, indr;
char *sline;
struct timeval tv, *tvp;

/* shitty */

list_sort(players, (compare) cmp_player);
if( player_direction < 0 )
list_reverse(players);
switch(player_sorting) {
default:
case PLAYER_PLNAME: indl = 11; indr = 16; break;
case PLAYER_ITEMS: indl = 16; indr = 22; break;
case PLAYER_RACE: indl = -1; indr = -1;
break;
case PLAYER_GENDER: indl = -1; indr = -1;
break;
case PLAYER_ALIGN: indl = -1; indr = -1;
break;
case PLAYER_CLASS: indl = -1; indr = -1;
break;
case PLAYER_HP: indl = 32; indr = 36; break;
case PLAYER_MAXHP: indl = 36; indr = 40; break;
case PLAYER_ULEVEL: indl = 40; indr = 43; break;
case PLAYER_AC: indl = 44; indr = 47; break;
case PLAYER_PRAYERS: indl = 48; indr = 51; break;
case PLAYER_WISHES: indl = 51; indr = 54; break;
case PLAYER_DEATHS: indl = 54; indr = 57; break;
case PLAYER_MOVES: indl = 57; indr = 63; break;
case PLAYER_DLEVEL: indl = 63; indr = 66; break;
case PLAYER_DUNGEON: indl = 66; indr = 79; break;
}
if( indl >= 0 ) {
}
if( indr >= 0 ) {
}
//MAGIC NUMBERS
sline = (char *) malloc(400);

struct timeval now;
gettimeofday(&now, NULL);
//MAGIC NUMBERS++
for( i = 0; i < list_count(players); i++ ) {
const char alignments[3] = "cnl";
struct player_t *player = list_goto_index(players, i);
struct u_stat_t *stats = &player->stats;
// (MAGIC_NUMBER++)++
snprintf(sline, 400,
"%s,%c,%c,%c,%s,%d,%d,%d,%d,%d,%d,%d,%ld,%d,%s\n",
stats->plname,
stats->race, stats->gender, alignments[stats->align + 1],
stats->class, stats->hp, stats->hpmax, stats->ulevel,
stats->ac, stats->prayers, stats->wishes, stats->deaths,
stats->moves, stats->dlevel, stats->dungeon_or_death);
}
printf(sline);
fflush(stdout);
if( first_time ) {
int bsock;
struct sockaddr_in other;
first_time = false;
fprintf(stderr, sline);
free(sline);
bsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if( bsock == -1 ) {
perror("socket");
exit(EXIT_FAILURE);
}

memset(&other, 0, sizeof(other));
other.sin_family = AF_INET;
other.sin_port = htons(12346);
if( inet_aton("127.0.0.1", &other.sin_addr) == 0 ) {
fprintf(stderr, "inet_aton failed\n");
exit(EXIT_FAILURE);
}

if( sendto(bsock, &yes, sizeof(yes), 0,
(struct sockaddr *) &other, sizeof(other)) == -1 ) {
perror("sendto");
exit(EXIT_FAILURE);
}

shutdown(bsock, SHUT_RDWR);
close(bsock);
}
else{
free(sline);
}

FD_ZERO(&rfds);
FD_SET(s, &rfds);
FD_SET(0, &rfds);

if( any_changed ) {
tv.tv_sec = 0;
tv.tv_usec = 100000;
tvp = &tv;
} else {
tvp = NULL;
}

switch( select(s + 1, &rfds, NULL, NULL, tvp) ) {
case 0: continue; /* timeout... shouldn't happen */
case -1:
if( errno == EINTR || errno == ETIMEDOUT )
continue;
perror("select");
exit(EXIT_FAILURE);
default:
if( FD_ISSET(s, &rfds) ) {
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if( recvfrom(s, &u_stat, sizeof(u_stat), 0, (struct sockaddr *) &from, &fromlen) < 0 ) {
perror("recvfrom");
exit(EXIT_FAILURE);
}

update(&u_stat);
}
}

}


list_destroy(players);

exit(EXIT_SUCCESS);
const struct in_addr localhost_addr = {
.s_addr = htonl(INADDR_LOOPBACK)
};
if( setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &localhost_addr, sizeof(localhost_addr)) == -1 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}

const struct ip_mreq mreq = {
.imr_multiaddr = {
.s_addr = inet_addr("225.0.0.37")
},
.imr_interface = {
.s_addr = htonl(INADDR_LOOPBACK)
}
};
if( setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0 ) {
perror("setsockopt");
exit(EXIT_FAILURE);
}

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(12345);

if( bind(s, (struct sockaddr *) &addr, sizeof(addr)) != 0 ) {
perror("bind");
exit(EXIT_FAILURE);
}

players = list_new();
list_set_free(players, (free_function) free, NULL);

signal(SIGINT, int_handler);

while(!done) {
fd_set rfds;
int indl, indr;
char *sline;
struct timeval tv, *tvp;

/* shitty */

list_sort(players, (compare) cmp_player);
if( player_direction < 0 )
list_reverse(players);
switch(player_sorting) {
default:
case PLAYER_PLNAME: indl = 11; indr = 16; break;
case PLAYER_ITEMS: indl = 16; indr = 22; break;
case PLAYER_RACE: indl = -1; indr = -1;
break;
case PLAYER_GENDER: indl = -1; indr = -1;
break;
case PLAYER_ALIGN: indl = -1; indr = -1;
break;
case PLAYER_CLASS: indl = -1; indr = -1;
break;
case PLAYER_HP: indl = 32; indr = 36; break;
case PLAYER_MAXHP: indl = 36; indr = 40; break;
case PLAYER_ULEVEL: indl = 40; indr = 43; break;
case PLAYER_AC: indl = 44; indr = 47; break;
case PLAYER_PRAYERS: indl = 48; indr = 51; break;
case PLAYER_WISHES: indl = 51; indr = 54; break;
case PLAYER_DEATHS: indl = 54; indr = 57; break;
case PLAYER_MOVES: indl = 57; indr = 63; break;
case PLAYER_DLEVEL: indl = 63; indr = 66; break;
case PLAYER_DUNGEON: indl = 66; indr = 79; break;
}
//MAGIC NUMBERS
sline = (char *) malloc(400);

struct timeval now;
gettimeofday(&now, NULL);
//MAGIC NUMBERS++
for( i = 0; i < list_count(players); i++ ) {
const char alignments[3] = "cnl";
struct player_t *player = list_goto_index(players, i);
struct u_stat_t *stats = &player->stats;
// (MAGIC_NUMBER++)++
snprintf(sline, 400,
"%s,%c,%c,%c,%s,%d,%d,%d,%d,%d,%d,%d,%ld,%d,%s\n",
stats->plname,
stats->race, stats->gender, alignments[stats->align + 1],
stats->class, stats->hp, stats->hpmax, stats->ulevel,
stats->ac, stats->prayers, stats->wishes, stats->deaths,
stats->moves, stats->dlevel, stats->dungeon_or_death);
}
printf(sline);
fflush(stdout);
if( first_time ) {
int bsock;
struct sockaddr_in other;
first_time = false;
fprintf(stderr, sline);
free(sline);
bsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if( bsock == -1 ) {
perror("socket");
exit(EXIT_FAILURE);
}

memset(&other, 0, sizeof(other));
other.sin_family = AF_INET;
other.sin_port = htons(12346);
if( inet_aton("127.0.0.1", &other.sin_addr) == 0 ) {
fprintf(stderr, "inet_aton failed\n");
exit(EXIT_FAILURE);
}

if( sendto(bsock, &yes, sizeof(yes), 0,
(struct sockaddr *) &other, sizeof(other)) == -1 ) {
perror("sendto");
exit(EXIT_FAILURE);
}

shutdown(bsock, SHUT_RDWR);
close(bsock);
} else {
free(sline);
}

FD_ZERO(&rfds);
FD_SET(s, &rfds);
FD_SET(0, &rfds);

if( any_changed ) {
tv.tv_sec = 0;
tv.tv_usec = 100000;
tvp = &tv;
} else {
tvp = NULL;
}

switch( select(s + 1, &rfds, NULL, NULL, tvp) ) {
case 0: continue; /* timeout... shouldn't happen */
case -1:
if( errno == EINTR || errno == ETIMEDOUT )
continue;
perror("select");
exit(EXIT_FAILURE);
default:
if( FD_ISSET(s, &rfds) ) {
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
if( recvfrom(s, &u_stat, sizeof(u_stat), 0, (struct sockaddr *) &from, &fromlen) < 0 ) {
perror("recvfrom");
exit(EXIT_FAILURE);
}

update(&u_stat);
}
}

}


list_destroy(players);

exit(EXIT_SUCCESS);
}