Use avahi for network, share config over network, use unique for shared random

This commit is contained in:
Stefan Bühler 2009-08-07 14:15:42 +02:00
parent d1fe907235
commit 0c61d8a25a
9 changed files with 978 additions and 800 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
bomber
matcher

View File

@ -2,3 +2,6 @@ David Ashley
dashxdr@gmail.com
http://www.xdr.com/dash
http://www.linuxmotors.com
Stefan Bühler
http://stbuehler.de/

View File

View File

@ -1,37 +1,23 @@
#DBG = -g
CC = gcc
CFLAGS = -O2 -Wall $(shell sdl-config --cflags) $(DBG)
WARNFLAGS = -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wformat-security
CFLAGS = -g -D_REENTRANT -O2 -Wall $(shell sdl-config --cflags) $(DBG) $(WARNFLAGS)
all: bomber matcher
.PHONY: all clean
all: bomber
bomber: bomber.o gfx.o sound.o matcher
gcc -o bomber bomber.o gfx.o sound.o $(shell sdl-config --libs) $(DBG)
bomber: bomber.o gfx.o sound.o announce.o matcher
gcc -o bomber bomber.o gfx.o sound.o announce.o $(shell sdl-config --libs) -lavahi-common -lavahi-client $(DBG)
matcher: matcher.c
bomber.o: bomber.c bomber.h gfx.h
bomber.o: bomber.c bomber.h gfx.h announce.h
gfx.o: gfx.c gfx.h bomber.h
gfx.o: gfx.c gfx.h bomber.h
sound.o: sound.c
sound.o: sound.c
announce.o: announce.c announce.h
clean:
rm -f *.o matcher bomber
test: all
./bomber
WORK = /ram
VER = 1.0.3
DDIR = SDL_bomber-$(VER)
package: clean
rm -rf $(WORK)/$(DDIR)
mkdir $(WORK)/$(DDIR)
cp *.c *.h Makefile* README INSTALL COPYING AUTHORS TODO $(WORK)/$(DDIR)
cp -a data $(WORK)/$(DDIR)
cp ChangeLog $(WORK)/$(DDIR)
cd $(WORK) && tar czf $(DDIR).tgz $(DDIR)

408
announce.c Normal file
View File

@ -0,0 +1,408 @@
#include "announce.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <avahi-client/client.h>
#include <avahi-client/lookup.h>
#include <avahi-client/publish.h>
#include <avahi-common/alternative.h>
#include <avahi-common/error.h>
#include <avahi-common/malloc.h>
#include <avahi-common/thread-watch.h>
#define SERVICE_TYPE "_sdlbomber._udp"
static AvahiClient *client = NULL;
static AvahiThreadedPoll *threaded_poll = NULL;
static AvahiEntryGroup *group = NULL;
static char* name = NULL;
static uint16_t port = 0;
static uint32_t unique = 0, version = 0;
static volatile int all_for_now;
gamelistentry gamelistentries[10];
int gamelistsize = 0;
static void myerror(AvahiClient *c, const char *s) {
fprintf(stderr, "Error in: %s\n (%s)", s, avahi_strerror(avahi_client_errno(client)));
}
static void create_services(AvahiClient *c);
static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
group = g;
switch (state) {
case AVAHI_ENTRY_GROUP_ESTABLISHED :
break;
case AVAHI_ENTRY_GROUP_COLLISION :
{
char *n = avahi_alternative_service_name(name);
avahi_free(name);
name = n;
}
/* And recreate the services */
avahi_entry_group_reset(group);
create_services(avahi_entry_group_get_client(g));
break;
case AVAHI_ENTRY_GROUP_FAILURE :
fprintf(stderr, "Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
avahi_threaded_poll_quit(threaded_poll);
break;
case AVAHI_ENTRY_GROUP_UNCOMMITED:
case AVAHI_ENTRY_GROUP_REGISTERING:
break;
}
}
static void create_services(AvahiClient *c) {
int ret;
if (!group) {
if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) {
myerror(c, "avahi_entry_group_new");
goto fail;
}
}
again:
if (avahi_entry_group_is_empty(group)) {
char buf_unique[128], buf_version[128];
snprintf(buf_unique, sizeof(buf_unique), "unique=%X", (unsigned int) unique);
snprintf(buf_version, sizeof(buf_version), "version=%X", (unsigned int) version);
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, SERVICE_TYPE, NULL, NULL, port, buf_unique, buf_version, NULL)) < 0) {
if (ret == AVAHI_ERR_COLLISION)
goto collision;
fprintf(stderr, "Failed to add "SERVICE_TYPE": %s\n", avahi_strerror(ret));
goto fail;
}
if ((ret = avahi_entry_group_commit(group)) < 0) {
fprintf(stderr, "Failed to commit entry group: %s\n", avahi_strerror(ret));
goto fail;
}
}
return;
collision:
{
char *n = avahi_alternative_service_name(name);
avahi_free(name);
name = n;
}
avahi_entry_group_reset(group);
goto again;
fail:
avahi_threaded_poll_quit(threaded_poll);
}
static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) {
client = c;
switch (state) {
case AVAHI_CLIENT_S_RUNNING:
if (port != 0) create_services(c);
break;
case AVAHI_CLIENT_FAILURE:
myerror(c, "client failure");
avahi_threaded_poll_quit(threaded_poll);
break;
case AVAHI_CLIENT_S_COLLISION:
case AVAHI_CLIENT_S_REGISTERING:
if (group) {
avahi_entry_group_reset(group);
}
break;
case AVAHI_CLIENT_CONNECTING:
break;
}
}
int registergame(char *playername, uint16_t p, uint32_t uniq, unsigned char v[4]) {
if (name) avahi_free(name);
name = avahi_strdup(playername);
port = p;
unique = htonl(uniq);
memcpy(&version, v, 4);
version = htonl(version);
avahi_threaded_poll_lock(threaded_poll);
create_services(client);
avahi_threaded_poll_unlock(threaded_poll);
return 1;
}
void unregistergame() {
port = 0;
avahi_threaded_poll_lock(threaded_poll);
if (group) avahi_entry_group_reset(group);
group = NULL;
avahi_threaded_poll_unlock(threaded_poll);
}
static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event,
const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address,
uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata) {
int i;
uint32_t want_version = *(uint32_t*) userdata;
assert(r);
if (protocol != AVAHI_PROTO_INET) goto done; /* ignore non IPv4 for now */
if (gamelistsize >= GAMELIST_MAXSIZE) goto done;
/* Called whenever a service has been resolved successfully or timed out */
switch (event) {
case AVAHI_RESOLVER_FAILURE:
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
break;
case AVAHI_RESOLVER_FOUND: {
gamelistentry *ge;
unsigned int uniq, version;
int have_unique = 0, have_version = 0;
AvahiStringList *psl;
for (psl = txt ; psl ; psl = psl->next) {
if (0 == strncmp("unique=", (const char*) psl->text, 7)) {
sscanf((const char*) psl->text, "unique=%X", &uniq);
have_unique = 1;
} else if (0 == strncmp("version=", (const char*) psl->text, 8)) {
sscanf((const char*) psl->text, "version=%X", &version);
if (version != want_version) goto done; /* version mismatch */
have_version = 1;
}
}
if (!have_unique || !have_version) goto done;
i = gamelistsize++;
ge = &gamelistentries[i];
memset(ge, 0, sizeof(*ge));
ge->netname.sin_addr.s_addr = address->data.ipv4.address;
ge->netname.sin_family = AF_INET;
ge->netname.sin_port = port;
ge->name = avahi_strdup(name);
ge->unique = ntohl(uniq);
}
}
done:
avahi_service_resolver_free(r);
}
static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event,
const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata) {
assert(b);
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
switch (event) {
case AVAHI_BROWSER_FAILURE:
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(client)));
avahi_threaded_poll_quit(threaded_poll);
return;
case AVAHI_BROWSER_NEW:
/* fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); */
/* We ignore the returned resolver object. In the callback
function we free it. If the server is terminated before
the callback function is called the server will free
the resolver for us. */
if (!(avahi_service_resolver_new(client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(client)));
break;
case AVAHI_BROWSER_REMOVE:
break;
case AVAHI_BROWSER_ALL_FOR_NOW:
all_for_now = 1;
break;
case AVAHI_BROWSER_CACHE_EXHAUSTED:
all_for_now = 1;
break;
}
}
static void freefoundgames() {
int i;
for (i = 0; i < gamelistsize; i++) {
avahi_free(gamelistentries[i].name);
}
gamelistsize = 0;
}
int searchgames(unsigned char version[4]) {
int i;
AvahiServiceBrowser *sb = NULL;
uint32_t gameversion;
memcpy(&gameversion, version, 4);
gameversion = htonl(gameversion);
freefoundgames();
avahi_threaded_poll_lock(threaded_poll);
all_for_now = 0;
if (NULL == (sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, SERVICE_TYPE, NULL, 0, browse_callback, &gameversion))) {
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
avahi_threaded_poll_unlock(threaded_poll);
return 0;
}
avahi_threaded_poll_unlock(threaded_poll);
for (i = 0; i < 10; i++) {
usleep(200000);
avahi_threaded_poll_lock(threaded_poll);
if (all_for_now) {
avahi_service_browser_free(sb);
avahi_threaded_poll_unlock(threaded_poll);
return 1;
}
avahi_threaded_poll_unlock(threaded_poll);
}
avahi_threaded_poll_lock(threaded_poll);
avahi_service_browser_free(sb);
avahi_threaded_poll_unlock(threaded_poll);
return 1;
}
int initannouncer() {
if (!(threaded_poll = avahi_threaded_poll_new())) {
fprintf(stderr, "avahi_threaded_poll_new failed\n");
return 0;
}
if (!(client = avahi_client_new(avahi_threaded_poll_get(threaded_poll), 0, client_callback, NULL, NULL))) {
fprintf(stderr, "avahi_client_new failed\n");
avahi_threaded_poll_free(threaded_poll);
threaded_poll = NULL;
return 0;
}
if (avahi_threaded_poll_start(threaded_poll) < 0) {
fprintf(stderr, "avahi_threaded_poll_start failed\n");
avahi_client_free(client);
avahi_threaded_poll_free(threaded_poll);
client = NULL;
threaded_poll = NULL;
return 0;
}
return 1;
}
void freeannouncer() {
freefoundgames();
avahi_threaded_poll_stop(threaded_poll);
if (client) avahi_client_free(client);
if (threaded_poll) avahi_threaded_poll_free(threaded_poll);
client = NULL;
threaded_poll = NULL;
avahi_free(name);
name = NULL;
}
#if 0
int openmatcher()
{
struct hostent *hostptr;
if(matcheropened) return 1;
hostptr=gethostbyname(mname);
if(!hostptr)
{
hostptr=gethostbyaddr(mname,strlen(mname),AF_INET);
if(!hostptr)
return 0;
}
memset(&matchername,0,sizeof(matchername));
matchername.sin_family=AF_INET;
matchername.sin_port=htons(PORT);
memcpy(&matchername.sin_addr,hostptr->h_addr,hostptr->h_length);
matcheropened=1;
return 1;
}
int registergame()
{
long now;
int size;
long lastreg;
if(!openmatcher()) return 0;
pulseoff();
now=longtime();
lastreg=now-1;
while(longtime()-now<10)
{
if(longtime()-lastreg>=1)
{
lastreg=longtime();
putmsg(&matchername,regpacket,REGISTERLEN);
}
size=getmsg(1000);
if(size<REGISTERLEN+1) continue;
if(mesg[0]!=PKT_ACK) continue;
if(memcmp(regpacket,mesg+1,REGISTERLEN)) continue;
return 1;
}
return 0;
}
int unregistergame()
{
long now;
int size;
if(!openmatcher()) return 0;
pulseoff();
now=longtime();
clearreg();
while(longtime()-now<10)
{
putmsg(&matchername,regpacket,REGISTERLEN);
size=getmsg(1000);
if(size<REGISTERLEN+1) continue;
if(mesg[0]!=PKT_ACK) continue;
if(memcmp(regpacket,mesg+1,REGISTERLEN)) continue;
return 1;
}
return 0;
}
#endif

25
announce.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef ANNOUNCE_H
#define ANNOUNCE_H
#include <netinet/in.h>
typedef struct gamelistentry gamelistentry;
struct gamelistentry {
struct sockaddr_in netname;
char *name;
uint32_t unique;
};
int registergame(char *playername, uint16_t port, uint32_t unique, unsigned char version[4]);
void unregistergame();
int searchgames(unsigned char version[4]);
int initannouncer();
void freeannouncer();
#define GAMELIST_MAXSIZE 10
extern gamelistentry gamelistentries[GAMELIST_MAXSIZE];
extern int gamelistsize;
#endif

1266
bomber.c

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,7 @@ typedef struct player
int flags;
int abilities;
int speed;
int speedturtle_timeout;
int bombsused;
int bombsavailable;
int flamelength;
@ -164,6 +165,7 @@ typedef struct bonustile
int px,py;
int type;
}bonustile;
#define TILE_NONE -1
#define TILE_BOMB 5
#define TILE_FLAME 2

35
gfx.c
View File

@ -29,7 +29,7 @@ void dumpgfx()
{
usedcolors = 0;
}
int bestmatch(int red,int green,int blue)
static int bestmatch(int red,int green,int blue)
{
int i;
int bestcolor,bestdelta=0;
@ -61,7 +61,7 @@ int delta;
return bestcolor;
}
void updatemap(void)
static void updatemap(void)
{
SDL_SetColors(thescreen, themap, 0, 256);
}
@ -117,7 +117,7 @@ int cnt;
updatemap();
}
uchar *compressfig(uchar *put,gfxset *gs,
static uchar *compressfig(uchar *put,gfxset *gs,
int sourcex,int sourcey,int sizex,int sizey)
{
int j,gswidth;
@ -154,7 +154,7 @@ int dx,dy;
*put++=0;
return put;
}
void gfxfetchsingle(figure *fig,gfxset *gs,int sourcex,int sourcey,int sizex,int sizey)
static void gfxfetchsingle(figure *fig,gfxset *gs,int sourcex,int sourcey,int sizex,int sizey)
{
uchar *p,*p2;
int dx,dy;
@ -401,16 +401,14 @@ void copyupxysize(int x,int y,int xsize,int ysize)
}
void set_color(int color, int red, int green, int blue)
{
themap[color].r=red;
themap[color].g=green;
themap[color].b=blue;
// static void set_color(int color, int red, int green, int blue) {
// themap[color].r=red;
// themap[color].g=green;
// themap[color].b=blue;
// }
}
void opengfx(int argc, char **argv)
{
unsigned long videoflags;
void opengfx(int argc, char **argv) {
unsigned long videoflags;
themap[0].r=0;
themap[0].g=0;
@ -657,17 +655,16 @@ SDLK_LALT,MYALTL,
SDLK_RALT,MYALTR,
ENDMARK
};
int looklist(int code,int *list)
static int looklist(int code,int *list)
{
while(*list!=ENDMARK)
{
while((unsigned int)*list!=ENDMARK) {
if(*list==code)
return list[1];
list+=2;
}
return -1;
}
int mapkey(int code,int qual)
static int mapkey(int code,int qual)
{
if(qual & KMOD_SHIFT)
@ -681,7 +678,7 @@ int mapkey(int code,int qual)
return code;
}
void markkey(int code,int status)
static void markkey(int code,int status)
{
int i;
int *ip;
@ -818,7 +815,7 @@ int i,*ip,code;
}
*/
void drawrect(int x,int y,int xs,int ys,int c)
static void drawrect(int x,int y,int xs,int ys,int c)
{
uchar *p;