|
|
@ -9,7 +9,7 @@ |
|
|
|
#define MAXMSG 4096 |
|
|
|
|
|
|
|
int udpsocket; |
|
|
|
const unsigned char gameversion[4]={0xda,0x01,0x00,0x04}; |
|
|
|
const unsigned char gameversion[4]={0xda,0x01,0x00,0x05}; |
|
|
|
|
|
|
|
struct netnode netnodes[64]; |
|
|
|
|
|
|
@ -36,6 +36,84 @@ unsigned char actions[MAXNETNODES]; |
|
|
|
unsigned char latestactions[MAXNETNODES]; |
|
|
|
long latestcounts[MAXNETNODES]; |
|
|
|
|
|
|
|
enum network_packet_types { |
|
|
|
PKT_ACK, /* perfect copy of packet received */ |
|
|
|
/* join / host game */ |
|
|
|
/* slave -> master packets */ |
|
|
|
PKT_JOIN, /* 4 bytes version #, 4 bytes joinunique #, 16 bytes name */ |
|
|
|
PKT_QUIT, /* 4 bytes unique # */ |
|
|
|
/* master -> slave packets */ |
|
|
|
PKT_INVITE, /* 4 bytes unique #, 1 byte your slot (0xff for kick, no data following it) #, any # of 1:slot,16:name sets (-1 end) */ |
|
|
|
PKT_BEGIN, /* clone of INVITE */ |
|
|
|
PKT_CONFIG, /* 4 bytes unique #, config */ |
|
|
|
PKT_ACCEPT, /* 4 bytes join unique #, 132 bytes seed + unique #, config, slot info (see invite) */ |
|
|
|
PKT_REJECT, /* 4 bytes join unique #, 4 bytes version #, 1: reason */ |
|
|
|
/* ingame actions */ |
|
|
|
/* slave -> master packets */ |
|
|
|
PKT_MYDATA, /* 4 bytes unique #,4 bytes frame #, 1 byte data */ |
|
|
|
/* master -> slave packets */ |
|
|
|
PKT_STEP, /* 4 bytes unique #, 4 bytes frame #, 8 bytes ACT_* */ |
|
|
|
|
|
|
|
PKT_INVALID = 0xff |
|
|
|
}; |
|
|
|
|
|
|
|
enum reject_reason { |
|
|
|
REJECT_FULL, |
|
|
|
REJECT_VERSION |
|
|
|
/* TODO: password? */ |
|
|
|
}; |
|
|
|
|
|
|
|
/* all bytes stored MSB first */ |
|
|
|
|
|
|
|
/* |
|
|
|
game startup: |
|
|
|
<master and matcher> |
|
|
|
Master: send REGISTER to matcher with optional password, wait for ack. If |
|
|
|
timout, resend. |
|
|
|
matcher: Wait for REGISTER packet, when received maintain database. respond |
|
|
|
to sender with ACK. REGISTER packet can close a game also. The REGISTER |
|
|
|
packet sent by the master has a unique word to be used to avoid confusion. |
|
|
|
REGISTER packet also contains a game version # |
|
|
|
|
|
|
|
After master registers game and receives ACK, just waits for slaves to contact. |
|
|
|
|
|
|
|
<slave and matcher> |
|
|
|
slave: send QUERY to matcher with optional password, wait for INFO, if timeout, |
|
|
|
resend. |
|
|
|
matcher: respond to QUERY with INFO packet. matcher need not maintain any |
|
|
|
database for slave requests. INFO packet contains IP addr and port for each |
|
|
|
master machine that matches the QUERY spec (ALL or password). Only a |
|
|
|
certain MAX # of entries are sent if there are too many to choose from. |
|
|
|
|
|
|
|
<slave and master> |
|
|
|
slave: send JOIN to master, wait for INVITE. If timeout, resend. JOIN packet |
|
|
|
contains the unique word the master created. JOIN also contains username. |
|
|
|
master: Respond to JOIN with INVITE. INVITE contains unique word from JOIN |
|
|
|
packet. INVITE either contains NO meaning game no longer exists or is closed |
|
|
|
or player is not invited. IF yes, INVITE contains info on other players |
|
|
|
already in the game (username and slot # for each). Master allocates the |
|
|
|
slots and avoids confusion based on IP addr and port #. INVITE also contains |
|
|
|
game options structure. Whenever a new player JOINS and is admitted, master |
|
|
|
sends updated INVITE packets to everyone already in the JOIN list. Whenever |
|
|
|
master changes game options, master sends out another set of INVITES |
|
|
|
|
|
|
|
Duplicate JOINS are answered with updated INVITE but nothing changes as far |
|
|
|
as allocation. |
|
|
|
|
|
|
|
Master player launches game after he's satisfied everyone has joined. |
|
|
|
|
|
|
|
Master sends BEGIN packet to everyone. BEGIN is identical to INVITE except |
|
|
|
that the data is final. Slave must respond with its first MYDATA packet with |
|
|
|
frame # of 0. If master times out waiting, master sends duplicate BEGIN to |
|
|
|
wayward slaves. Once master has received MYDATA from everyone, game starts. |
|
|
|
|
|
|
|
Within game slave sends MYDATA to master and waits for STEP packet. If |
|
|
|
timeout, slave sends duplicate MYDATA. |
|
|
|
|
|
|
|
If master times out waiting for a slave's MYDATA, slave gets dropped. MYDATAs |
|
|
|
received will be answered with PKT_QUIT. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
/* Network I/O, building/checking packets */ |
|
|
@ -132,17 +210,17 @@ static Uint32 readuint32(unsigned char *p) { |
|
|
|
return (p[0]<<24L) | (p[1]<<16L) | (p[2]<<8) | p[3]; |
|
|
|
} |
|
|
|
|
|
|
|
static unsigned char* writeunique(unsigned char *p) { |
|
|
|
static unsigned char* write_unique(unsigned char *p) { |
|
|
|
memcpy(p, &network_unique, 4); |
|
|
|
return p + 4; |
|
|
|
} |
|
|
|
|
|
|
|
static unsigned char* writeversion(unsigned char *p) { |
|
|
|
static unsigned char* write_version(unsigned char *p) { |
|
|
|
memcpy(p, &gameversion, 4); |
|
|
|
return p + 4; |
|
|
|
} |
|
|
|
|
|
|
|
static int isvalidmsg() { |
|
|
|
static int isvalidmsg_from_slave() { |
|
|
|
int i; |
|
|
|
void *host; |
|
|
|
void *port; |
|
|
@ -158,6 +236,13 @@ static int isvalidmsg() { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
static int isvalidmsg_from_master() { |
|
|
|
if (sender.sin_family != mastername.sin_family |
|
|
|
|| sender.sin_addr.s_addr != mastername.sin_addr.s_addr |
|
|
|
|| sender.sin_port != mastername.sin_port) return 0; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* Handling game actions */ |
|
|
|
|
|
|
|
static void addactions(void) { |
|
|
@ -190,7 +275,7 @@ static void sendactions(int which) { |
|
|
|
unsigned char msg[512]; |
|
|
|
|
|
|
|
msg[0] = PKT_STEP; |
|
|
|
writeunique(msg+1); |
|
|
|
write_unique(msg+1); |
|
|
|
writeuint32(msg+5, actioncount); |
|
|
|
memcpy(msg+9,actionblock,MAXNETNODES*ACTIONHIST); |
|
|
|
putmsg(&netnodes[which].netname,msg,MAXNETNODES*ACTIONHIST+9); |
|
|
@ -200,7 +285,7 @@ static void sendmine(int frame) { |
|
|
|
unsigned char msg[64]; |
|
|
|
|
|
|
|
msg[0] = PKT_MYDATA; |
|
|
|
writeunique(msg+1); |
|
|
|
write_unique(msg+1); |
|
|
|
writeuint32(msg+5, frame); |
|
|
|
msg[9]=myaction; |
|
|
|
putmsg(&mastername,msg,10); |
|
|
@ -229,7 +314,7 @@ int networktraffic(void) { |
|
|
|
// for example JOIN on frame 0, respond with BEGIN if player already in game |
|
|
|
// respond with uninvite INVITE on JOIN from others |
|
|
|
if(length<10) continue; |
|
|
|
whosent=isvalidmsg(); |
|
|
|
whosent = isvalidmsg_from_slave(); |
|
|
|
if(whosent<=0) continue; |
|
|
|
count=readuint32(mesg+5); |
|
|
|
if(count>latestcounts[whosent]) { |
|
|
@ -333,120 +418,86 @@ void freesocket(void) { |
|
|
|
|
|
|
|
/* Join / Host Games */ |
|
|
|
|
|
|
|
static void buildinform(unsigned char type) { |
|
|
|
unsigned char *put; |
|
|
|
/* Master side */ |
|
|
|
|
|
|
|
static unsigned char* write_inform(unsigned char* put) { |
|
|
|
int i; |
|
|
|
|
|
|
|
put=mesg; |
|
|
|
*put++=type; |
|
|
|
put = writeunique(put); |
|
|
|
++put; // slot specific for each slave |
|
|
|
*put++ = 0xff; /* slot specific for each slave */ |
|
|
|
for (i = 0; i < MAXNETNODES; ++i) { |
|
|
|
if(!netnodes[i].used) continue; |
|
|
|
*put++=i; |
|
|
|
memmove(put,netnodes[i].name,16); |
|
|
|
put+=16; |
|
|
|
*put++ = i; |
|
|
|
memmove(put, netnodes[i].name, 16); |
|
|
|
put += 16; |
|
|
|
} |
|
|
|
*put++=0xff; |
|
|
|
memcpy(put, configopts, sizeof(configopts)); |
|
|
|
put += sizeof(configopts); |
|
|
|
informsize=put-mesg; |
|
|
|
} |
|
|
|
|
|
|
|
static void inform1(int which) { |
|
|
|
mesg[5]=which; |
|
|
|
putmsg(&netnodes[which].netname,mesg,informsize); |
|
|
|
*put++ = 0xff; |
|
|
|
return put; |
|
|
|
} |
|
|
|
|
|
|
|
static void inform(unsigned char type) { |
|
|
|
static void send_inform_all(unsigned char type) { |
|
|
|
int i; |
|
|
|
buildinform(type); |
|
|
|
for(i=1;i<MAXNETNODES;++i) |
|
|
|
if(netnodes[i].used) |
|
|
|
inform1(i); |
|
|
|
} |
|
|
|
|
|
|
|
//returns 0=ignore packet,1=we're rejected,2=INVITE,3=BEGIN |
|
|
|
int scaninvite(int msec) { |
|
|
|
int i, size; |
|
|
|
unsigned char *take; |
|
|
|
Uint32 unique = 0; |
|
|
|
|
|
|
|
size = getmsg(msec); |
|
|
|
|
|
|
|
if (size < 6) return 0; |
|
|
|
if (*mesg!=PKT_INVITE && *mesg!=PKT_BEGIN) return 0; |
|
|
|
if (sender.sin_family != mastername.sin_family |
|
|
|
|| sender.sin_addr.s_addr != mastername.sin_addr.s_addr |
|
|
|
|| sender.sin_port != mastername.sin_port) return 0; |
|
|
|
|
|
|
|
myslot=mesg[5]; |
|
|
|
if (6 == size || 0xff == mesg[5] || 0xff == mesg[6]) return 1; |
|
|
|
unsigned char *put = mesg; |
|
|
|
|
|
|
|
/* update unique */ |
|
|
|
memcpy(&unique, mesg+1, 4); |
|
|
|
if (unique != network_unique) |
|
|
|
set_unique(ntohl(unique)); |
|
|
|
*put++ = type; |
|
|
|
put = write_unique(put); |
|
|
|
put = write_inform(put); |
|
|
|
informsize = put-mesg; |
|
|
|
|
|
|
|
memset(netnodes,0,sizeof(netnodes)); |
|
|
|
size-=6; |
|
|
|
take=mesg+6; |
|
|
|
while(*take!=0xff && size>=17) { |
|
|
|
if((i=*take)<MAXNETNODES) { |
|
|
|
netnodes[i].used=1; |
|
|
|
memmove(netnodes[i].name,take+1,16); |
|
|
|
for(i=1;i<MAXNETNODES;++i) { |
|
|
|
if(netnodes[i].used) { |
|
|
|
mesg[5] = i; |
|
|
|
putmsg(&netnodes[i].netname, mesg, informsize); |
|
|
|
} |
|
|
|
take+=17; |
|
|
|
size-=17; |
|
|
|
} |
|
|
|
take++; size--; /* read 0xff */ |
|
|
|
} |
|
|
|
|
|
|
|
if(*mesg==PKT_INVITE) { |
|
|
|
return 2; |
|
|
|
} else { /* BEGIN */ |
|
|
|
if (size != sizeof(configopts)) { |
|
|
|
fprintf(stderr, "PKT_BEGIN has wrong size: %i != %i\n", size, (int) sizeof(configopts)); |
|
|
|
return 1; /* broken packet */ |
|
|
|
} |
|
|
|
set_game_options(take); |
|
|
|
return 3; |
|
|
|
} |
|
|
|
static unsigned char* write_config(unsigned char* put) { |
|
|
|
*put++ = configopts.density; |
|
|
|
*put++ = configopts.flames; |
|
|
|
*put++ = configopts.bombs; |
|
|
|
*put++ = configopts.generosity; |
|
|
|
return put; |
|
|
|
} |
|
|
|
|
|
|
|
int send_join(struct sockaddr_in *netname, char playername[16]) { |
|
|
|
int res = 0; |
|
|
|
long now; |
|
|
|
static void build_config() { |
|
|
|
unsigned char *put; |
|
|
|
|
|
|
|
set_unique(-1); /* reset unique and random */ |
|
|
|
put=mesg; |
|
|
|
*put++=PKT_CONFIG; |
|
|
|
put = write_config(put); |
|
|
|
informsize=put-mesg; |
|
|
|
} |
|
|
|
|
|
|
|
mastername = *netname; |
|
|
|
*regpacket=PKT_JOIN; |
|
|
|
writeversion(regpacket + 1); |
|
|
|
memmove(regpacket+5, playername, 16); |
|
|
|
now=longtime(); |
|
|
|
while(longtime()-now<10) { |
|
|
|
putmsg(&mastername,regpacket,1+4+16); |
|
|
|
if (0 == (res=scaninvite(1000))) continue; |
|
|
|
return res; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
static void send_config1(int which) { |
|
|
|
putmsg(&netnodes[which].netname,mesg,informsize); |
|
|
|
} |
|
|
|
|
|
|
|
void send_quit() { |
|
|
|
long now; |
|
|
|
int size; |
|
|
|
void send_config() { |
|
|
|
int i; |
|
|
|
build_config(); |
|
|
|
for (i = 1; i < MAXNETNODES; ++i) |
|
|
|
if (netnodes[i].used) |
|
|
|
send_config1(i); |
|
|
|
} |
|
|
|
|
|
|
|
*regpacket = PKT_QUIT; |
|
|
|
writeunique(regpacket+1); |
|
|
|
now=longtime(); |
|
|
|
while(longtime()-now<10) { |
|
|
|
putmsg(&mastername,regpacket,5); |
|
|
|
size=getmsg(1000); |
|
|
|
if(size<6) continue; |
|
|
|
if(mesg[0] != PKT_ACK || mesg[1] != PKT_QUIT) continue; |
|
|
|
if (isvalidunique(mesg+2)) |
|
|
|
break; |
|
|
|
} |
|
|
|
static void send_reject(struct sockaddr_in *toname, Uint32 network_join_unique, unsigned char reason) { |
|
|
|
mesg[0] = PKT_REJECT; |
|
|
|
memcpy(mesg+1, &network_join_unique, sizeof(network_join_unique)); |
|
|
|
write_version(mesg+5); |
|
|
|
mesg[9] = reason; |
|
|
|
putmsg(&sender,mesg,10); |
|
|
|
} |
|
|
|
|
|
|
|
static void send_accept(Uint32 network_join_unique) { |
|
|
|
unsigned char *put = mesg; |
|
|
|
|
|
|
|
*put++ = PKT_ACCEPT; |
|
|
|
memcpy(put, &network_join_unique, sizeof(network_join_unique)); |
|
|
|
put += sizeof(network_join_unique); |
|
|
|
put = write_seed_unique(put); |
|
|
|
put = write_config(put); |
|
|
|
put = write_inform(put); |
|
|
|
putmsg(&sender,mesg,put-mesg); |
|
|
|
} |
|
|
|
|
|
|
|
int start_network_game() { |
|
|
@ -459,21 +510,21 @@ int start_network_game() { |
|
|
|
} |
|
|
|
|
|
|
|
int begin_network_game() { |
|
|
|
inform(PKT_BEGIN); |
|
|
|
send_inform_all(PKT_BEGIN); |
|
|
|
network = NETWORK_MASTER; |
|
|
|
/* TODO: wait for ack */ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
void send_invites() { |
|
|
|
inform(PKT_INVITE); |
|
|
|
send_inform_all(PKT_INVITE); |
|
|
|
} |
|
|
|
|
|
|
|
void cancel_network_game() { |
|
|
|
int i; |
|
|
|
|
|
|
|
mesg[0] = PKT_INVITE; |
|
|
|
writeunique(mesg+1); |
|
|
|
write_unique(mesg+1); |
|
|
|
mesg[5] = 0xff; |
|
|
|
|
|
|
|
for(i=1;i<MAXNETNODES;++i) { |
|
|
@ -487,11 +538,17 @@ int handle_joins() { |
|
|
|
int size; |
|
|
|
int i, j; |
|
|
|
unsigned char temp[64]; |
|
|
|
Uint32 network_join_unique; |
|
|
|
|
|
|
|
size=getmsg(40); |
|
|
|
switch (*mesg) { |
|
|
|
case PKT_JOIN: |
|
|
|
if (size < 21 || !isvalidversion(mesg+1)) return 0; |
|
|
|
if (size < 25) return 0; |
|
|
|
memcpy(&network_join_unique, mesg+5, sizeof(network_join_unique)); |
|
|
|
if (!isvalidversion(mesg+1)) { |
|
|
|
send_reject(&sender, network_join_unique, REJECT_VERSION); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
break; |
|
|
|
case PKT_QUIT: |
|
|
|
if (size < 5 || !isvalidunique(mesg+1)) return 0; |
|
|
@ -519,23 +576,21 @@ int handle_joins() { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if(*mesg==PKT_QUIT) { |
|
|
|
switch (*mesg) { |
|
|
|
case PKT_QUIT: |
|
|
|
if(i < MAXNETNODES) /* if host found, reset entry */ |
|
|
|
memset(netnodes+i,0,sizeof(struct netnode)); |
|
|
|
/* send always ACK for QUITs */ |
|
|
|
*temp=PKT_ACK; |
|
|
|
memmove(temp+1,mesg,5); |
|
|
|
putmsg(&sender,temp,6); |
|
|
|
} else { |
|
|
|
break; |
|
|
|
case PKT_JOIN: |
|
|
|
if (i==MAXNETNODES && j==-1) { /* reject */ |
|
|
|
*mesg=PKT_INVITE; |
|
|
|
writeunique(mesg+1); |
|
|
|
mesg[5]=0xff; |
|
|
|
putmsg(&sender,mesg,6); |
|
|
|
send_reject(&sender, network_join_unique, REJECT_FULL); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/* no explicit ack, send invites to all later */ |
|
|
|
if(i==MAXNETNODES) i=j; |
|
|
|
memmove(&netnodes[i].netname.sin_addr.s_addr, |
|
|
|
&sender.sin_addr.s_addr,4); |
|
|
@ -543,8 +598,138 @@ int handle_joins() { |
|
|
|
&sender.sin_port,2); |
|
|
|
netnodes[i].netname.sin_family=AF_INET; |
|
|
|
netnodes[i].used=1; |
|
|
|
memmove(netnodes[i].name,mesg+5,16); |
|
|
|
memcpy(netnodes[i].name,mesg+9,16); |
|
|
|
netnodes[i].name[15] = '\0'; |
|
|
|
|
|
|
|
send_accept(network_join_unique); |
|
|
|
break; |
|
|
|
} |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/* Client side */ |
|
|
|
|
|
|
|
static int read_inform(unsigned char** pbuf, int *psize) { |
|
|
|
unsigned char *buf = *pbuf; |
|
|
|
int size = *psize; |
|
|
|
int i; |
|
|
|
|
|
|
|
if (size < 1) return 0; |
|
|
|
myslot = *buf++; size--; |
|
|
|
if (0xff == myslot) return 1; |
|
|
|
|
|
|
|
if (size < 1) return 0; |
|
|
|
while (0xff != *buf) { |
|
|
|
i = *buf++; size--; |
|
|
|
if (size < 17 || i >= MAXNETNODES) return 0; |
|
|
|
netnodes[i].used = 1; |
|
|
|
memcpy(netnodes[i].name, buf, 16); |
|
|
|
buf += 16; |
|
|
|
size -= 16; |
|
|
|
} |
|
|
|
|
|
|
|
*psize = size; |
|
|
|
*pbuf = buf; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static void read_config(unsigned char* buf) { |
|
|
|
GameOptions opts; |
|
|
|
memset(&opts, 0, sizeof(opts)); |
|
|
|
opts.density = *buf++; |
|
|
|
opts.flames = *buf++; |
|
|
|
opts.bombs = *buf++; |
|
|
|
opts.generosity = *buf++; |
|
|
|
set_game_options(&opts); |
|
|
|
} |
|
|
|
|
|
|
|
/* returns 0=ignore packet,1=we're rejected,2=INVITE/CONFIG,3=BEGIN */ |
|
|
|
int scaninvite(int msec) { |
|
|
|
int size; |
|
|
|
unsigned char *take; |
|
|
|
|
|
|
|
size = getmsg(msec); |
|
|
|
|
|
|
|
if (size < 6) return 0; |
|
|
|
if (*mesg!=PKT_INVITE && *mesg!=PKT_BEGIN && *mesg!=PKT_CONFIG) return 0; |
|
|
|
if (!isvalidmsg_from_master()) return 0; |
|
|
|
if (!isvalidunique(mesg+1)) return 0; |
|
|
|
|
|
|
|
take = mesg+5; |
|
|
|
size -= 5; |
|
|
|
|
|
|
|
switch (*mesg) { |
|
|
|
case PKT_INVITE: |
|
|
|
case PKT_BEGIN: |
|
|
|
if (!read_inform(&take, &size)) return 0; |
|
|
|
if (0xff == myslot) return 1; /* master closed game */ |
|
|
|
break; |
|
|
|
case PKT_CONFIG: |
|
|
|
if (size < 4) return 0; |
|
|
|
read_config(take); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (*mesg == PKT_BEGIN) { |
|
|
|
return 3; |
|
|
|
} else { |
|
|
|
return 2; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int send_join(struct sockaddr_in *netname, char playername[16]) { |
|
|
|
int size; |
|
|
|
long now; |
|
|
|
Uint32 join_unique = gtime(); |
|
|
|
unsigned char *buf; |
|
|
|
|
|
|
|
mastername = *netname; |
|
|
|
*regpacket=PKT_JOIN; |
|
|
|
write_version(regpacket + 1); |
|
|
|
writeuint32(regpacket+5, join_unique); |
|
|
|
memcpy(regpacket+9, playername, 16); |
|
|
|
now=longtime(); |
|
|
|
putmsg(&mastername,regpacket,1+4+4+16); |
|
|
|
while(longtime()-now < 3) { |
|
|
|
if (0 == (size = getmsg(1000))) { |
|
|
|
/* got no message, send join again */ |
|
|
|
putmsg(&mastername,regpacket,1+4+4+16); |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (size < 5) continue; |
|
|
|
if (readuint32(mesg+1) != join_unique) continue; |
|
|
|
switch (*mesg) { |
|
|
|
case PKT_ACCEPT: |
|
|
|
if (size < 1+4+132+4+2) continue; |
|
|
|
read_seed_unique(mesg + 5); |
|
|
|
read_config(mesg+137); |
|
|
|
buf = mesg+141; |
|
|
|
size -= 141; |
|
|
|
if (!read_inform(&buf,&size)) return 0; |
|
|
|
return 2; |
|
|
|
case PKT_REJECT: |
|
|
|
/* TODO: print reject message */ |
|
|
|
return 0; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void send_quit() { |
|
|
|
long now; |
|
|
|
int size; |
|
|
|
|
|
|
|
*regpacket = PKT_QUIT; |
|
|
|
write_unique(regpacket+1); |
|
|
|
now=longtime(); |
|
|
|
while(longtime()-now<10) { |
|
|
|
putmsg(&mastername,regpacket,5); |
|
|
|
size=getmsg(1000); |
|
|
|
if(size<6) continue; |
|
|
|
if(mesg[0] != PKT_ACK || mesg[1] != PKT_QUIT) continue; |
|
|
|
if (isvalidunique(mesg+2)) |
|
|
|
break; |
|
|
|
} |
|
|
|
} |