ref: 373a5aadf3814e5c433787d419a218a9061f5c3d
parent: a4474be05dd2196175875f7333185e7b6c9bd449
author: qwx <>
date: Mon Dec 10 20:40:45 EST 2018
qw: fix networking - better networking implementation, still a few quirks left to fix - fix NET_StringToAdr - announce only when necessary, clean up connections on disconnect - main loop: poll connections and input or sleep
--- a/qw/cl_main.c
+++ b/qw/cl_main.c
@@ -171,15 +171,12 @@
t1 = Sys_DoubleTime ();
- if (!NET_StringToAdr (cls.servername, &adr))
+ if (!NET_StringToAdr (cls.servername, &adr, nil))
{
Con_Printf ("Bad server address\n");
connect_time = -1;
return;
}
-
- if (adr.port == 0)
- adr.port = BigShort (27500);
t2 = Sys_DoubleTime ();
connect_time = realtime+t2-t1; // for retransmit requests
@@ -186,12 +183,12 @@
cls.qport = Cvar_VariableValue("qport");
- Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING);
+ Info_SetValueForStarKey (cls.userinfo, "*ip", adr.addr, MAX_INFO_STRING);
// Con_Printf ("Connecting to %s...\n", cls.servername);
sprintf (data, "%c%c%c%cconnect %i %i %i \"%s\"\n",
255, 255, 255, 255, PROTOCOL_VERSION, cls.qport, cls.challenge, cls.userinfo);
- NET_SendPacket (strlen(data), data, adr);
+ NET_SendPacket (strlen(data), data, &adr);
}
/*
@@ -216,15 +213,12 @@
return;
t1 = Sys_DoubleTime ();
- if (!NET_StringToAdr (cls.servername, &adr))
+ if (!NET_StringToAdr (cls.servername, &adr, nil))
{
Con_Printf ("Bad server address\n");
connect_time = -1;
return;
}
-
- if (adr.port == 0)
- adr.port = BigShort (27500);
t2 = Sys_DoubleTime ();
connect_time = realtime+t2-t1; // for retransmit requests
@@ -231,7 +225,7 @@
Con_Printf ("Connecting to %s...\n", cls.servername);
sprintf (data, "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
- NET_SendPacket (strlen(data), data, adr);
+ NET_SendPacket (strlen(data), data, &adr);
}
void CL_BeginServerConnect(void)
@@ -315,11 +309,10 @@
return;
}
- NET_StringToAdr (rcon_address.string, &to);
+ NET_StringToAdr (rcon_address.string, &to, nil);
}
- NET_SendPacket (strlen(message)+1, message
- , to);
+ NET_SendPacket (strlen(message)+1, message, &to);
}
@@ -392,6 +385,7 @@
Netchan_Transmit (&cls.netchan, 6, final);
Netchan_Transmit (&cls.netchan, 6, final);
Netchan_Transmit (&cls.netchan, 6, final);
+ NET_Close(&cls.netchan.remote_address);
cls.state = ca_disconnected;
@@ -644,7 +638,7 @@
return;
}
- if (!NET_StringToAdr (Cmd_Argv(1), &adr))
+ if (!NET_StringToAdr (Cmd_Argv(1), &adr, nil))
{
Con_Printf ("Bad address\n");
return;
@@ -667,7 +661,7 @@
}
*out = 0;
- NET_SendPacket (out-send, send, adr);
+ NET_SendPacket (out-send, send, &adr);
}
@@ -769,7 +763,7 @@
c = MSG_ReadByte ();
if (!cls.demoplayback)
- Con_Printf ("%s: ", NET_AdrToString (net_from));
+ Con_Printf ("%s: ", net_from->sys);
// Con_DPrintf ("%s", net_message.data + 5);
if (c == S2C_CONNECTION)
{
@@ -794,13 +788,6 @@
char cmdtext[2048];
Con_Printf ("client command\n");
-
- if ((*(unsigned *)net_from.ip != *(unsigned *)laddr.ip
- && *(unsigned *)net_from.ip != Iploopback) )
- {
- Con_Printf ("Command packet from remote host. Ignored.\n");
- return;
- }
s = MSG_ReadString ();
strncpy(cmdtext, s, sizeof(cmdtext) - 1);
@@ -907,7 +894,7 @@
if (net_message.cursize < 8)
{
- Con_Printf ("%s: Runt packet\n",NET_AdrToString(net_from));
+ Con_Printf ("%s: Runt packet\n", net_from->sys);
continue;
}
@@ -915,10 +902,10 @@
// packet from server
//
if (!cls.demoplayback &&
- !NET_CompareAdr (net_from, cls.netchan.remote_address))
+ !NET_CompareAdr (net_from, &cls.netchan.remote_address))
{
Con_DPrintf ("%s:sequenced packet without connection\n"
- ,NET_AdrToString(net_from));
+ , net_from->sys);
continue;
}
if (!Netchan_Process(&cls.netchan))
@@ -1353,8 +1340,6 @@
*/
void Host_Init (quakeparms_t *parms)
{
- int p, port;
-
COM_InitArgv (parms->argc, parms->argv);
COM_AddParm ("-game");
COM_AddParm ("qw");
@@ -1376,14 +1361,7 @@
Host_FixupModelNames();
- port = PORT_CLIENT;
- p = COM_CheckParm ("-cport");
- if (p && p < com_argc)
- {
- port = atoi(com_argv[p+1]);
- Con_Printf ("Client port: %i\n", port);
- }
- NET_Init (port);
+ NET_Init(0);
Netchan_Init ();
W_LoadWadFile ("gfx.wad");
--- a/qw/in.c
+++ b/qw/in.c
@@ -7,8 +7,6 @@
#include <keyboard.h>
#include "quakedef.h"
-extern Channel *fuckchan; /* main fuck receptor */
-
/* vid_9.c */
extern int resized;
extern Point center;
--- a/qw/mkfile
+++ b/qw/mkfile
@@ -6,6 +6,8 @@
qwsv\
CLOBJ=\
+ cd.$O\
+ cl_cam.$O\
cl_demo.$O\
cl_ents.$O\
cl_input.$O\
@@ -13,7 +15,6 @@
cl_parse.$O\
cl_pred.$O\
cl_tent.$O\
- cl_cam.$O\
cmd.$O\
common.$O\
console.$O\
@@ -32,6 +33,7 @@
d_vars.$O\
d_zpoint.$O\
draw.$O\
+ in.$O\
keys.$O\
mathlib.$O\
md4.$O\
@@ -38,9 +40,11 @@
menu.$O\
model.$O\
net_chan.$O\
+ net_udp.$O\
nonintel.$O\
pmove.$O\
pmovetst.$O\
+ qwcl.$O\
r_aclip.$O\
r_alias.$O\
r_bsp.$O\
@@ -58,48 +62,44 @@
sbar.$O\
screen.$O\
skin.$O\
+ snd.$O\
snd_dma.$O\
snd_mem.$O\
snd_mix.$O\
+ sys.$O\
+ vid.$O\
view.$O\
wad.$O\
zone.$O\
- cd.$O\
- vid.$O\
- snd.$O\
- in.$O\
- sys.$O\
- net_udp.$O\
- qwcl.$O\
SVOBJ=\
+ cmd.$O\
+ common.$O\
+ crc.$O\
+ cvar.$O\
+ mathlib.$O\
+ md4.$O\
+ net_chan.$O\
+ net_udp.$O\
+ pmove.$O\
+ pmovetst.$O\
pr_cmds.$O\
pr_edict.$O\
pr_exec.$O\
+ qwsv.$O\
+ sv_ccmds.$O\
+ sv_ents.$O\
sv_init.$O\
sv_main.$O\
- sv_nchan.$O\
- sv_ents.$O\
- sv_send.$O\
sv_move.$O\
+ sv_nchan.$O\
sv_phys.$O\
+ sv_send.$O\
sv_user.$O\
- sv_ccmds.$O\
- world.$O\
svmodel.$O\
- cmd.$O\
- common.$O\
- crc.$O\
- cvar.$O\
- mathlib.$O\
- md4.$O\
- zone.$O\
- pmove.$O\
- pmovetst.$O\
- net_chan.$O\
sys.$O\
- net_udp.$O\
- qwsv.$O\
+ world.$O\
+ zone.$O\
HFILES=\
../adivtab.h\
--- a/qw/net.h
+++ b/qw/net.h
@@ -4,13 +4,13 @@
typedef struct
{
- byte ip[4];
- unsigned short port;
- unsigned short pad;
+ int fd;
+ char sys[72];
+ char addr[64];
+ char srv[8];
} netadr_t;
-extern netadr_t laddr;
-extern netadr_t net_from; // address of who sent the packet
+extern netadr_t *net_from; // address of who sent the packet
extern sizebuf_t net_message;
extern cvar_t hostname;
@@ -20,13 +20,12 @@
void NET_Init (int port);
void NET_Shutdown (void);
qboolean NET_GetPacket (void);
-void NET_SendPacket (int length, void *data, netadr_t to);
+void NET_SendPacket (int length, void *data, netadr_t *to);
+void NET_Close(netadr_t*);
-qboolean NET_CompareAdr (netadr_t a, netadr_t b);
-qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b);
-char *NET_AdrToString (netadr_t a);
-char *NET_BaseAdrToString (netadr_t a);
-qboolean NET_StringToAdr (char *s, netadr_t *a);
+qboolean NET_CompareAdr (netadr_t *a, netadr_t *b);
+qboolean NET_CompareBaseAdr (netadr_t *a, netadr_t *b);
+qboolean NET_StringToAdr(char*, netadr_t*, char*);
//============================================================================
@@ -82,10 +81,10 @@
void Netchan_Init (void);
void Netchan_Transmit (netchan_t *chan, int length, byte *data);
-void Netchan_OutOfBand (netadr_t adr, int length, byte *data);
-void Netchan_OutOfBandPrint (netadr_t adr, char *format, ...);
+void Netchan_OutOfBand (netadr_t *adr, int length, byte *data);
+void Netchan_OutOfBandPrint (netadr_t *adr, char *format, ...);
qboolean Netchan_Process (netchan_t *chan);
-void Netchan_Setup (netchan_t *chan, netadr_t adr, int qport);
+void Netchan_Setup (netchan_t *chan, netadr_t *adr, int qport);
qboolean Netchan_CanPacket (netchan_t *chan);
qboolean Netchan_CanReliable (netchan_t *chan);
--- a/qw/net_chan.c
+++ b/qw/net_chan.c
@@ -85,7 +85,7 @@
Sends an out-of-band datagram
================
*/
-void Netchan_OutOfBand (netadr_t adr, int length, byte *data)
+void Netchan_OutOfBand (netadr_t *adr, int length, byte *data)
{
sizebuf_t send;
byte send_buf[MAX_MSGLEN + PACKET_HEADER];
@@ -111,7 +111,7 @@
Sends a text message in an out-of-band datagram
================
*/
-void Netchan_OutOfBandPrint (netadr_t adr, char *format, ...)
+void Netchan_OutOfBandPrint (netadr_t *adr, char *format, ...)
{
va_list argptr;
static char string[8192]; // ??? why static?
@@ -132,11 +132,12 @@
called to open a channel to a remote system
==============
*/
-void Netchan_Setup (netchan_t *chan, netadr_t adr, int qport)
+void Netchan_Setup (netchan_t *chan, netadr_t *adr, int qport)
{
memset (chan, 0, sizeof(*chan));
-
- chan->remote_address = adr;
+
+ if(adr != nil)
+ memcpy(&chan->remote_address, adr, sizeof *adr);
chan->last_received = realtime;
chan->message.data = chan->message_buf;
@@ -202,7 +203,7 @@
{
chan->fatal_error = true;
Con_Printf ("%s:Outgoing message overflow\n"
- , NET_AdrToString (chan->remote_address));
+ , chan->remote_address.addr);
return;
}
@@ -258,7 +259,7 @@
//zoid, no input in demo playback mode
if(svonly || !cls.demoplayback)
- NET_SendPacket (send.cursize, send.data, chan->remote_address);
+ NET_SendPacket (send.cursize, send.data, &chan->remote_address);
if (chan->cleartime < realtime)
chan->cleartime = realtime + send.cursize*chan->rate;
@@ -291,7 +292,7 @@
unsigned reliable_ack, reliable_message;
int qport;
- if((svonly || !cls.demoplayback) && !NET_CompareAdr(net_from, chan->remote_address))
+ if((svonly || !cls.demoplayback) && !NET_CompareAdr(net_from, &chan->remote_address))
return false;
// get sequence numbers
@@ -319,35 +320,6 @@
, reliable_ack
, net_message.cursize);
-/* get a rate estimation
- if (chan->outgoing_sequence - sequence_ack < MAX_LATENT)
- {
- int i;
- double time, rate;
-
- i = sequence_ack & (MAX_LATENT - 1);
- time = realtime - chan->outgoing_time[i];
- time -= 0.1; // subtract 100 ms
- if (time <= 0)
- { // gotta be a digital link for <100 ms ping
- if (chan->rate > 1.0/5000)
- chan->rate = 1.0/5000;
- }
- else
- {
- if (chan->outgoing_size[i] < 512)
- { // only deal with small messages
- rate = chan->outgoing_size[i]/time;
- if (rate > 5000)
- rate = 5000;
- rate = 1.0/rate;
- if (chan->rate > rate)
- chan->rate = rate;
- }
- }
- }
-*/
-
//
// discard stale or duplicated packets
//
@@ -355,7 +327,7 @@
{
if (showdrop.value)
Con_Printf ("%s:Out of order packet %i at %i\n"
- , NET_AdrToString (chan->remote_address)
+ , chan->remote_address.addr
, sequence
, chan->incoming_sequence);
return false;
@@ -371,7 +343,7 @@
if (showdrop.value)
Con_Printf ("%s:Dropped %i packets at %i\n"
- , NET_AdrToString (chan->remote_address)
+ , chan->remote_address.addr
, sequence-(chan->incoming_sequence+1)
, sequence);
}
@@ -406,4 +378,3 @@
return true;
}
-
--- a/qw/net_udp.c
+++ b/qw/net_udp.c
@@ -2,345 +2,163 @@
#include <libc.h>
#include <stdio.h>
#include <thread.h>
-#include <bio.h>
-#include <ndb.h>
#include <ip.h>
#include "quakedef.h"
-extern Channel *fuckchan; /* main fuck receptor */
-
+Channel *echan, *lchan;
+char *netmtpt = "/net";
sizebuf_t net_message;
-netadr_t laddr = { .ip{ 192, 168, 1, 138} }; /* 0.0.0.0:0 */
-netadr_t net_from;
+netadr_t *net_from;
+netadr_t cons[2*MAX_CLIENTS];
+static uchar netbuf[8192];
+static int afd = -1, lpid;
-typedef struct Conmsg Conmsg;
-typedef struct Conlist Conlist;
-
-enum{
- Nbuf = 64,
- Bufsz = 8192,
- Hdrsz = 16+16+16+2+2, /* sizeof Udphdr w/o padding */
-};
-static int cfd = -1, ufd = -1;
-static char srv[6];
-static uchar netbuf[Bufsz];
-static Channel *udpchan;
-static QLock cnlock;
-
-struct Conlist{
- Conlist *p;
- uchar u[IPaddrlen+2];
- char addr[IPaddrlen*2+8+6]; /* ipv6 + separators + port in decimal */
- int dfd;
- Udphdr h;
-};
-Conlist *cnroot;
-
-struct Conmsg{
- Conlist *p;
- int n;
- uchar buf[Bufsz];
-};
-
-static void uproc(void *);
-static void dproc(void *);
-static void cninit(void);
-static Conlist* cnins(int, char *, uchar *, Udphdr *);
-static Conlist* cnfind(char *);
-static void cndel(Conlist *);
-static void cnnuke(void);
-
-
-netadr_t net_from;
-int net_socket; // non blocking, for receives
-int net_send_socket; // blocking, for sends
-
-
qboolean
-NET_CompareBaseAdr(netadr_t a, netadr_t b)
+NET_CompareBaseAdr(netadr_t *a, netadr_t *b)
{
- return a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3];
+ return strcmp(a->addr, b->addr) == 0;
}
qboolean
-NET_CompareAdr(netadr_t a, netadr_t b)
+NET_CompareAdr(netadr_t *a, netadr_t *b)
{
- return a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port;
+ return strcmp(a->sys, b->sys) == 0;
}
-char *
-NET_AdrToString(netadr_t a)
-{
- static char s[256];
-
- seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud:%hud", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
- return s;
-}
-
-char *
-NET_BaseAdrToString(netadr_t a)
-{
- static char s[256];
-
- seprint(s, s+sizeof s, "%ud.%ud.%ud.%ud", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
- return s;
-}
-
-/*
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-*/
qboolean
-NET_StringToAdr(char *addr, netadr_t *a) /* assumes IPv4 */
+NET_StringToAdr(char *s, netadr_t *a, char *port)
{
- int i;
- char s[256], *p, *pp;
- Ndbtuple *t, *nt;
+ int fd, n;
+ char buf[128], *f[4], *p;
- strncpy(s, addr, sizeof s);
- s[sizeof(s)-1] = 0;
-
- /* FIXME: arbitrary length strings: ip.h limit? */
- if((p = strrchr(s, ':')) != nil){
- *p++ = '\0';
- a->port = BigShort(atoi(p));
+ snprint(buf, sizeof buf, "%s/cs", netmtpt);
+ if((fd = open(buf, ORDWR)) < 0)
+ sysfatal("open: %r");
+ if((p = strrchr(s, '!')) == nil && (p = strrchr(s, ':')) == nil)
+ p = port == nil ? "27500" : port;
+ else
+ p++;
+ snprint(buf, sizeof buf, "udp!%s!%s", s, p);
+ n = strlen(buf);
+ if(write(fd, buf, n) != n){
+ fprint(2, "translating %s: %r\n", s);
+ return -1;
}
-
- /* FIXME: sys */
- if(strcmp(ipattr(s), "dom") == 0){
- if((t = dnsquery(nil, s, "ip")) == nil){
- fprint(2, "NET_StringToAdr:dnsquery %s: %r\n", s);
- return 0;
- }
-
- for(nt = t; nt != nil; nt = nt->entry)
- if(!strcmp(nt->attr, "ip")){
- strncpy(s, nt->val, sizeof(s)-1);
- break;
- }
- ndbfree(t);
+ seek(fd, 0, 0);
+ if((n = read(fd, buf, sizeof(buf)-1)) <= 0){
+ fprint(2, "reading cs tables: %r");
+ return -1;
}
-
- /* FIXMEGASHIT */
- for(i = 0, pp = s; i < IPv4addrlen; i++){
- if((p = strchr(pp, '.')) != nil)
- *p++ = 0;
- a->ip[i] = atoi(pp);
- pp = p;
- }
+ buf[n] = 0;
+ close(fd);
+ if(getfields(buf, f, 4, 0, " !") < 2)
+ goto err;
+ memset(a, 0, sizeof *a);
+ strncpy(a->addr, f[1], sizeof(a->addr)-1);
+ strncpy(a->srv, f[2], sizeof(a->srv)-1);
+ snprint(a->sys, sizeof a->sys, "%s!%s", f[1], f[2]);
return true;
+err:
+ fprint(2, "bad cs entry %s", buf);
+ return false;
}
static void
-cninit(void)
+getinfo(netadr_t *a)
{
- if(cnroot != nil)
- return;
- if((cnroot = malloc(sizeof *cnroot)) == nil)
- sysfatal("cninit:malloc: %r");
- cnroot->p = cnroot;
- memset(cnroot->u, 0, sizeof cnroot->u);
- memset(cnroot->addr, 0, sizeof cnroot->addr);
- cnroot->dfd = -1;
-}
+ NetConnInfo *nc;
-static Conlist *
-cnins(int fd, char *addr, uchar *u, Udphdr *h)
-{
- Conlist *p, *l;
-
- l = cnroot;
- if((p = malloc(sizeof *p)) == nil)
- sysfatal("cnins:malloc: %r");
-
- strncpy(p->addr, addr, sizeof p->addr);
- memcpy(p->u, u, sizeof p->u);
- p->dfd = fd;
- if(h != nil)
- memcpy(&p->h, h, sizeof p->h);
- p->p = l->p;
- l->p = p;
- return p;
-}
-
-static Conlist *
-cnfind(char *raddr)
-{
- Conlist *p = cnroot->p;
-
- while(p != cnroot){
- if(!strncmp(p->addr, raddr, strlen(p->addr)))
- return p;
- p = p->p;
+ if((nc = getnetconninfo(nil, a->fd)) == nil){
+ fprint(2, "getnetconninfo: %r\n");
+ return;
}
- return nil;
+ strncpy(a->addr, nc->raddr, sizeof(a->addr)-1);
+ strncpy(a->srv, nc->rserv, sizeof(a->srv)-1);
+ snprint(a->sys, sizeof a->sys, "%s!%s", a->addr, a->srv);
+ free(nc);
}
-static void
-cndel(Conlist *p)
-{
- Conlist *l = cnroot;
-
- while(l->p != p){
- l = l->p;
- if(l == cnroot)
- sysfatal("cndel: bad unlink: cnroot 0x%p node 0x%p\n", cnroot, p);
- }
- l->p = p->p;
- if(p->dfd != ufd && p->dfd != -1)
- close(p->dfd);
- free(p);
-}
-
-static void
-cnnuke(void)
-{
- Conlist *p, *l = cnroot;
-
- if(cnroot == nil)
- return;
- do{
- p = l;
- l = l->p;
- if(p->dfd != -1)
- close(p->dfd);
- free(p);
- }while(l != cnroot);
- cnroot = nil;
-}
-
qboolean
NET_GetPacket(void)
{
- int n;
- Conmsg m;
+ int n, fd;
+ netadr_t *a;
- if(cfd == -1)
+ if(svonly && nbrecv(lchan, &fd) > 0){
+ for(a=cons; a<cons+nelem(cons); a++)
+ if(a->fd < 0)
+ break;
+ if(a == cons + nelem(cons)){
+ close(fd);
+ return false;
+ }
+ a->fd = fd;
+ getinfo(a);
+ }else{
+ for(a=cons; a<cons+nelem(cons); a++)
+ if(a->fd >= 0 && flen(a->fd) > 0)
+ break;
+ if(a == cons + nelem(cons))
+ return false;
+ }
+ if((n = read(a->fd, netbuf, sizeof netbuf)) <= 0){
+ fprint(2, "read: %r\n");
return false;
-
- if((n = nbrecv(udpchan, &m)) < 0)
- sysfatal("NET_GetPacket:nbrecv: %r");
- if(n == 0)
- return false;
- memcpy(net_from.ip, m.p->u+12, 4);
- net_from.port = m.p->u[17] << 8 | m.p->u[16];
- net_message.cursize = m.n;
- memcpy(netbuf, m.buf, m.n);
-
+ }
+ net_message.cursize = n;
+ net_from = a;
return true;
}
void
-NET_SendPacket(int length, void *data, netadr_t to)
+NET_SendPacket(int length, void *data, netadr_t *to)
{
- int fd;
- char *addr, *s, *lport;
- uchar b[Bufsz+Hdrsz], u[IPaddrlen+2];
- Conlist *p;
+ netadr_t *a;
- if(cfd == -1)
+ for(a=cons; a<cons+nelem(cons); a++)
+ if(strcmp(a->sys, to->sys) == 0 || a->fd < 0)
+ break;
+ if(a == cons + nelem(cons))
return;
-
- addr = NET_AdrToString(to);
- qlock(&cnlock);
- p = cnfind(addr);
- qunlock(&cnlock);
- if(p != nil){
- fd = p->dfd;
- if(fd == ufd){
- memcpy(b, &p->h, Hdrsz);
- memcpy(b+Hdrsz, data, length);
- write(fd, b, length+Hdrsz);
+ else if(a->fd < 0){
+ memcpy(a, to, sizeof *a);
+ if((a->fd = dial(netmkaddr(a->addr, "udp", a->srv), nil, nil, nil)) < 0){
+ fprint(2, "dial: %r\n");
return;
- }else if(write(fd, data, length) != length)
- sysfatal("NET_SendPacket:write: %r");
- }else{
- lport = strrchr(addr, ':');
- *lport++ = '\0';
- s = netmkaddr(addr, "udp", lport);
- if((fd = dial(s, srv, nil, nil)) < 0)
- sysfatal("NET_SendPacket:dial: %r");
-
- memcpy(u, v4prefix, sizeof v4prefix);
- memcpy(u+IPv4off, to.ip, IPv4addrlen);
- u[16] = to.port;
- u[17] = to.port >> 8;
- *(lport-1) = ':';
- qlock(&cnlock);
- p = cnins(fd, addr, u, nil);
- qunlock(&cnlock);
-
- if(proccreate(dproc, p, 8196*4) < 0)
- sysfatal("NET_SendPacket:proccreate: %r");
+ }
}
- if(write(fd, data, length) != length)
- sysfatal("NET_SendPacket:write: %r");
+ if(write(a->fd, data, length) != length)
+ fprint(2, "write: %r\n");
}
-static void
-dproc(void *me)
+void
+NET_Close(netadr_t *to)
{
- int n, fd;
- Conmsg m;
- Conlist *p;
+ netadr_t *a;
- threadsetgrp(THnet);
-
- m.p = p = me;
- fd = p->dfd;
-
- for(;;){
- if((n = read(fd, m.buf, sizeof m.buf)) <= 0)
- break;
- m.n = n;
- if(send(udpchan, &m) < 0)
- sysfatal("uproc:send: %r\n");
- if(svonly && nbsend(fuckchan, nil) < 0)
- sysfatal("fuckchan %r\n");
- }
- fprint(2, "dproc %d: %r\n", threadpid(threadid()));
- cndel(me);
+ for(a=cons; a<cons+nelem(cons); a++)
+ if(strcmp(a->sys, to->sys) == 0){
+ close(a->fd);
+ a->fd = -1;
+ }
}
static void
-uproc(void *)
+lproc(void *port)
{
- int n;
- uchar udpbuf[Bufsz+Hdrsz], u[IPaddrlen+2];
- char a[IPaddrlen*2+8+6];
- Udphdr h;
- Conmsg m;
- Conlist *p;
+ int fd, lfd;
+ char adir[40], ldir[40], data[100];
- threadsetgrp(THnet);
-
+ snprint(data, sizeof data, "%s/udp!*!%d", netmtpt, *(int *)port);
+ if((afd = announce(data, adir)) < 0)
+ sysfatal("announce: %r");
for(;;){
- if((n = read(ufd, udpbuf, sizeof udpbuf)) <= 0)
- sysfatal("uproc:read: %r");
-
- memcpy(&h, udpbuf, Hdrsz);
- memcpy(u, h.raddr, IPaddrlen);
- memcpy(u+IPaddrlen, h.rport, 2);
- snprint(a, sizeof a, "%ud.%ud.%ud.%ud:%hud", u[12], u[13], u[14], u[15], u[16]<<8 | u[17]);
- qlock(&cnlock);
- if((p = cnfind(a)) == nil)
- p = cnins(ufd, a, u, &h);
- qunlock(&cnlock);
- m.p = p;
-
- if(n - Hdrsz < 0){ /* FIXME */
- m.n = n;
- memcpy(m.buf, udpbuf, m.n);
- }else{
- m.n = n - Hdrsz;
- memcpy(m.buf, udpbuf+Hdrsz, m.n);
- }
- if(send(udpchan, &m) < 0)
- sysfatal("uproc:send: %r\n");
- if(svonly && nbsend(fuckchan, nil) < 0)
- sysfatal("fucking chan refused the fuck: %r\n");
+ if((lfd = listen(adir, ldir)) < 0
+ || (fd = accept(lfd, ldir)) < 0)
+ break;
+ close(lfd);
+ send(echan, nil);
+ send(lchan, &fd);
}
}
@@ -347,25 +165,21 @@
void
NET_Init(int port)
{
- char data[64], adir[40];
+ int n;
+ netadr_t *a;
- if(cfd != -1)
- return;
-
- cninit();
- snprint(srv, sizeof srv, "%hud", port);
- if((cfd = announce(netmkaddr("*", "udp", srv), adir)) < 0)
- sysfatal("announce udp!*!%s: %r", srv);
- if(fprint(cfd, "headers") < 0)
- sysfatal("NET_Init: failed to set header mode: %r");
- snprint(data, sizeof data, "%s/data", adir);
- if((ufd = open(data, ORDWR)) < 0)
- sysfatal("open: %r");
- if((udpchan = chancreate(sizeof(Conmsg), Nbuf)) == nil)
- sysfatal("chancreate udpchan: %r");
- if(proccreate(uproc, udpchan, 8192*4) < 0)
- sysfatal("proccreate: %r");
-
+ n = COM_CheckParm("-net");
+ if(n && n < com_argc-1)
+ if((netmtpt = strdup(com_argv[n+1])) == nil)
+ sysfatal("strdup: %r");
+ if(svonly && afd < 0){
+ if((lchan = chancreate(sizeof(int), 0)) == nil)
+ sysfatal("chancreate: %r");
+ if((lpid = proccreate(lproc, &port, 8192)) < 0)
+ sysfatal("proccreate lproc: %r");
+ }
+ for(a=cons; a<cons+nelem(cons); a++)
+ a->fd = -1;
net_message.maxsize = sizeof netbuf;
net_message.data = netbuf;
}
@@ -373,18 +187,16 @@
void
NET_Shutdown(void)
{
- threadkillgrp(THnet);
- cnnuke();
- if(udpchan != nil){
- chanfree(udpchan);
- udpchan = nil;
- }
- if(cfd != -1){
- close(cfd);
- cfd = -1;
- }
- if(ufd != -1){
- close(ufd);
- ufd = -1;
- }
+ netadr_t *a;
+
+ for(a=cons; a<cons+nelem(cons); a++)
+ if(a->fd >= 0){
+ close(a->fd);
+ a->fd = -1;
+ }
+ if(afd < 0)
+ return;
+ close(afd);
+ threadkill(lpid);
+ afd = -1;
}
--- a/qw/pr_cmds.c
+++ b/qw/pr_cmds.c
@@ -1544,7 +1544,7 @@
value = Info_ValueForKey(localinfo, key);
} else if (e1 <= MAX_CLIENTS) {
if (!strcmp(key, "ip"))
- value = strcpy(ov, NET_BaseAdrToString (svs.clients[e1-1].netchan.remote_address));
+ value = strcpy(ov, svs.clients[e1-1].netchan.remote_address.addr);
else if (!strcmp(key, "ping")) {
int ping = SV_CalcPing (&svs.clients[e1-1]);
sprintf(ov, "%d", ping);
--- a/qw/protocol.h
+++ b/qw/protocol.h
@@ -6,8 +6,6 @@
//=========================================
-#define PORT_CLIENT 27001
-#define PORT_MASTER 27000
#define PORT_SERVER 27500
//=========================================
--- a/qw/qwcl.c
+++ b/qw/qwcl.c
@@ -5,14 +5,16 @@
#include "quakedef.h"
mainstacksize = 512*1024;
-Channel *fuckchan;
-
/* FIXME: stupid-ass linking kludges */
server_static_t svs;
-qboolean ServerPaused(void){return 0;}
-void SV_SendServerInfoChange(char *, char *){}
-
+qboolean ServerPaused(void)
+{
+ return 0;
+}
+void SV_SendServerInfoChange(char *, char *)
+{
+}
static void
croak(void *, char *note)
--- a/qw/qwsv.c
+++ b/qw/qwsv.c
@@ -4,14 +4,15 @@
#include <thread.h>
#include "quakedef.h"
-mainstacksize = 512*1024;
-Channel *fuckchan;
+mainstacksize = 256*1024;
+
+extern Channel *echan;
+extern netadr_t cons[MAX_CLIENTS];
+
quakeparms_t q;
-static cvar_t extrasleep = {"extrasleep", "0"}; /* in ms */
static int iop = -1, pfd[2];
-
/* FIXME: stupid-ass linking kludges */
client_static_t cls;
void Draw_BeginDisc(void){}
@@ -18,7 +19,6 @@
void Draw_EndDisc(void){}
void Host_Shutdown(void){}
-
char *
Sys_ConsoleInput(void)
{
@@ -36,6 +36,8 @@
void
killiop(void)
{
+ if(iop < 0)
+ return;
threadkillgrp(THin);
close(pfd[0]);
close(pfd[1]);
@@ -58,52 +60,38 @@
s[n-1] = 0;
if((write(pfd[0], s, n)) != n)
break;
- if(nbsend(fuckchan, nil) < 0)
- sysfatal("chan really wanted to, but it's just too tired. %r");
+ send(echan, nil);
}
- fprint(2, "iproc %d: %r\n", threadpid(threadid()));
iop = -1;
}
-static void
-croak(void *, char *note)
-{
- if(!strncmp(note, "sys:", 4)){
- killiop();
- NET_Shutdown();
- }
- noted(NDFLT);
-}
-
void
threadmain(int argc, char *argv[])
{
double time, oldtime, newtime;
+ netadr_t *a;
svonly = 1;
COM_InitArgv (argc, argv);
initparm(&q);
- notify(croak);
- if((fuckchan = chancreate(sizeof(int), 1)) == nil)
- sysfatal("chancreate fuckchan: %r");
+ if((echan = chancreate(sizeof(int), 1)) == nil)
+ sysfatal("chancreate: %r");
SV_Init(&q);
- Cvar_RegisterVariable(&extrasleep);
if(proccreate(iproc, nil, 8192) < 0)
sysfatal("proccreate iproc: %r");
-
SV_Frame(0.1); /* run one frame immediately for first heartbeat */
-
oldtime = Sys_DoubleTime() - 0.1;
for(;;){
- recv(fuckchan, nil); /* we just don't give any for free */
-
- newtime = Sys_DoubleTime(); /* time since last docking */
+ if(nbrecv(echan, nil) == 0){
+ for(a=cons; a<cons+nelem(cons); a++)
+ if(a->fd >= 0 && flen(a->fd) > 0)
+ break;
+ if(a == cons + nelem(cons))
+ sleep(1);
+ }
+ newtime = Sys_DoubleTime();
time = newtime - oldtime;
oldtime = newtime;
- SV_Frame(time);
-
- /* just a way to screw up fucking conformation on purpose */
- if(extrasleep.value)
- sleep(extrasleep.value);
+ SV_Frame(time);
}
}
--- a/qw/sv_ccmds.c
+++ b/qw/sv_ccmds.c
@@ -36,21 +36,18 @@
for (i=1 ; i<Cmd_Argc() ; i++)
{
- if (!strcmp(Cmd_Argv(i), "none") || !NET_StringToAdr (Cmd_Argv(i), &master_adr[i-1]))
+ if (!strcmp(Cmd_Argv(i), "none") || !NET_StringToAdr (Cmd_Argv(i), &master_adr[i-1], "27000"))
{
Con_Printf ("Setting nomaster mode.\n");
return;
}
- if (master_adr[i-1].port == 0)
- master_adr[i-1].port = BigShort (27000);
+ Con_Printf ("Master server at %s\n", master_adr[i-1].sys);
- Con_Printf ("Master server at %s\n", NET_AdrToString (master_adr[i-1]));
-
Con_Printf ("Sending a ping.\n");
data[0] = A2A_PING;
data[1] = 0;
- NET_SendPacket (2, data, master_adr[i-1]);
+ NET_SendPacket (2, data, &master_adr[i-1]);
}
svs.last_heartbeat = -99999;
@@ -375,7 +372,6 @@
avg = 1000*svs.stats.latched_active / STATFRAMES;
pak = (float)svs.stats.latched_packets/ STATFRAMES;
- Con_Printf ("net address : %s\n",NET_AdrToString (laddr));
Con_Printf ("cpu utilization : %3i%%\n",(int)cpu);
Con_Printf ("avg response time: %i ms\n",(int)avg);
Con_Printf ("packets/frame : %5.2f (%d)\n", pak, num_prstr);
@@ -400,7 +396,7 @@
else
Con_Printf("\n");
- s = NET_BaseAdrToString ( cl->netchan.remote_address);
+ s = cl->netchan.remote_address.addr;
Con_Printf (" %-16.16s", s);
if (cl->state == cs_connected)
{
@@ -426,7 +422,7 @@
continue;
Con_Printf ("%5i %6i ", (int)cl->edict->v.frags, cl->userid);
- s = NET_BaseAdrToString ( cl->netchan.remote_address);
+ s = cl->netchan.remote_address.addr;
Con_Printf ("%s", s);
l = 16 - strlen(s);
for (j=0 ; j<l ; j++)
--- a/qw/sv_main.c
+++ b/qw/sv_main.c
@@ -404,7 +404,7 @@
return;
}
- Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, NET_AdrToString(net_from));
+ Con_DPrintf ("sending log %i to %s\n", svs.logsequence-1, net_from->sys);
sprintf (data, "stdlog %i\n", svs.logsequence-1);
strcat (data, (char *)svs.log_buf[((svs.logsequence-1)&1)]);
@@ -451,7 +451,7 @@
// see if we already have a challenge for this ip
for (i = 0 ; i < MAX_CHALLENGES ; i++)
{
- if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+ if (NET_CompareBaseAdr (net_from, &svs.challenges[i].adr))
break;
if (svs.challenges[i].time < oldestTime)
{
@@ -464,7 +464,7 @@
{
// overwrite the oldest
svs.challenges[oldest].challenge = (rand() << 16) ^ rand();
- svs.challenges[oldest].adr = net_from;
+ svs.challenges[oldest].adr = *net_from;
svs.challenges[oldest].time = realtime;
i = oldest;
}
@@ -517,7 +517,7 @@
// see if the challenge is valid
for (i=0 ; i<MAX_CHALLENGES ; i++)
{
- if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
+ if (NET_CompareBaseAdr (net_from, &svs.challenges[i].adr))
{
if (challenge == svs.challenges[i].challenge)
break; // good
@@ -539,7 +539,7 @@
cistrcmp(spectator_password.string, "none") &&
strcmp(spectator_password.string, s) )
{ // failed
- Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from));
+ Con_Printf ("%s:spectator password failed\n", net_from->sys);
Netchan_OutOfBandPrint (net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT);
return;
}
@@ -554,7 +554,7 @@
cistrcmp(password.string, "none") &&
strcmp(password.string, s) )
{
- Con_Printf ("%s:password failed\n", NET_AdrToString (net_from));
+ Con_Printf ("%s:password failed\n", net_from->sys);
Netchan_OutOfBandPrint (net_from, "%c\nserver requires a password\n\n", A2C_PRINT);
return;
}
@@ -562,7 +562,7 @@
Info_RemoveKey (userinfo, "password"); // remove passwd
}
- adr = net_from;
+ adr = *net_from;
userid++; // so every client gets a unique id
newcl = &temp;
@@ -586,17 +586,17 @@
{
if (cl->state == cs_free)
continue;
- if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
+ if (NET_CompareBaseAdr (&adr, &cl->netchan.remote_address)
&& ( cl->netchan.qport == qport
- || adr.port == cl->netchan.remote_address.port ))
+ || strcmp(adr.srv, cl->netchan.remote_address.srv) == 0))
{
if (cl->state == cs_connected) {
- Con_Printf("%s:dup connect\n", NET_AdrToString (adr));
+ Con_Printf("%s:dup connect\n", adr.sys);
userid--;
return;
}
- Con_Printf ("%s:reconnect\n", NET_AdrToString (adr));
+ Con_Printf ("%s:reconnect\n", adr.sys);
SV_DropClient (cl);
break;
}
@@ -625,8 +625,8 @@
if ( (spectator && spectators >= (int)maxspectators.value)
|| (!spectator && clients >= (int)maxclients.value) )
{
- Con_Printf ("%s:full connect\n", NET_AdrToString (adr));
- Netchan_OutOfBandPrint (adr, "%c\nserver is full\n\n", A2C_PRINT);
+ Con_Printf ("%s:full connect\n", adr.sys);
+ Netchan_OutOfBandPrint (&adr, "%c\nserver is full\n\n", A2C_PRINT);
return;
}
@@ -652,11 +652,11 @@
// this is the only place a client_t is ever initialized
*newcl = temp;
- Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION );
+ Netchan_OutOfBandPrint (&adr, "%c", S2C_CONNECTION );
edictnum = (newcl-svs.clients)+1;
- Netchan_Setup (&newcl->netchan , adr, qport);
+ Netchan_Setup (&newcl->netchan , &adr, qport);
newcl->state = cs_connected;
@@ -719,7 +719,7 @@
if (!Rcon_Validate ()) {
Con_Printf ("Bad rcon from %s:\n%s\n"
- , NET_AdrToString (net_from), net_message.data+4);
+ , net_from->sys, net_message.data+4);
SV_BeginRedirect (RD_PACKET);
@@ -728,7 +728,7 @@
} else {
Con_Printf ("Rcon from %s:\n%s\n"
- , NET_AdrToString (net_from), net_message.data+4);
+ , net_from->sys, net_message.data+4);
SV_BeginRedirect (RD_PACKET);
@@ -779,7 +779,7 @@
}
if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n') )
{
- Con_Printf ("A2A_ACK from %s\n", NET_AdrToString (net_from));
+ Con_Printf ("A2A_ACK from %s\n", net_from->sys);
return;
}
else if (!strcmp(c,"status"))
@@ -806,7 +806,7 @@
SVC_RemoteCommand ();
else
Con_Printf ("bad connectionless packet from %s:\n%s\n"
- , NET_AdrToString (net_from), s);
+ , net_from->sys, s);
}
/*
@@ -840,16 +840,9 @@
==============================================================================
*/
-
-typedef struct
-{
- unsigned mask;
- unsigned compare;
-} ipfilter_t;
-
#define MAX_IPFILTERS 1024
-ipfilter_t ipfilters[MAX_IPFILTERS];
+netadr_t ipfilters[MAX_IPFILTERS];
int numipfilters;
cvar_t filterban = {"filterban", "1"};
@@ -856,53 +849,6 @@
/*
=================
-StringToFilter
-=================
-*/
-qboolean StringToFilter (char *s, ipfilter_t *f)
-{
- char num[128];
- int i, j;
- byte b[4];
- byte m[4];
-
- for (i=0 ; i<4 ; i++)
- {
- b[i] = 0;
- m[i] = 0;
- }
-
- for (i=0 ; i<4 ; i++)
- {
- if (*s < '0' || *s > '9')
- {
- Con_Printf ("Bad filter address: %s\n", s);
- return false;
- }
-
- j = 0;
- while (*s >= '0' && *s <= '9')
- {
- num[j++] = *s++;
- }
- num[j] = 0;
- b[i] = atoi(num);
- if (b[i] != 0)
- m[i] = 255;
-
- if (!*s)
- break;
- s++;
- }
-
- f->mask = *(unsigned *)m;
- f->compare = *(unsigned *)b;
-
- return true;
-}
-
-/*
-=================
SV_AddIP_f
=================
*/
@@ -909,22 +855,14 @@
void SV_AddIP_f (void)
{
int i;
-
- for (i=0 ; i<numipfilters ; i++)
- if (ipfilters[i].compare == 0xffffffff)
- break; // free spot
- if (i == numipfilters)
- {
- if (numipfilters == MAX_IPFILTERS)
- {
- Con_Printf ("IP filter list is full\n");
- return;
- }
- numipfilters++;
+
+ i = numipfilters;
+ if(i == MAX_IPFILTERS){
+ Con_Printf("IP filter list is full\n");
+ return;
}
-
- if (!StringToFilter (Cmd_Argv(1), &ipfilters[i]))
- ipfilters[i].compare = 0xffffffff;
+ numipfilters++;
+ NET_StringToAdr(Cmd_Argv(1), &ipfilters[i], nil);
}
/*
@@ -934,15 +872,13 @@
*/
void SV_RemoveIP_f (void)
{
- ipfilter_t f;
+ netadr_t a;
int i, j;
- if (!StringToFilter (Cmd_Argv(1), &f))
+ if(!NET_StringToAdr(Cmd_Argv(1), &a, nil))
return;
for (i=0 ; i<numipfilters ; i++)
- if (ipfilters[i].mask == f.mask
- && ipfilters[i].compare == f.compare)
- {
+ if(strcmp(a.addr, ipfilters[i].addr) == 0){
for (j=i+1 ; j<numipfilters ; j++)
ipfilters[j-1] = ipfilters[j];
numipfilters--;
@@ -960,14 +896,10 @@
void SV_ListIP_f (void)
{
int i;
- byte b[4];
Con_Printf ("Filter list:\n");
for (i=0 ; i<numipfilters ; i++)
- {
- *(unsigned *)b = ipfilters[i].compare;
- Con_Printf ("%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]);
- }
+ Con_Printf ("%s\n", ipfilters[i].addr);
}
/*
@@ -979,7 +911,6 @@
{
FILE *f;
char name[MAX_OSPATH];
- byte b[4];
int i;
sprintf (name, "%s/listip.cfg", com_gamedir);
@@ -994,10 +925,7 @@
}
for (i=0 ; i<numipfilters ; i++)
- {
- *(unsigned *)b = ipfilters[i].compare;
- fprintf (f, "addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
- }
+ fprintf (f, "addip %s\n", ipfilters[i].addr);
fclose (f);
}
@@ -1027,12 +955,9 @@
qboolean SV_FilterPacket (void)
{
int i;
- unsigned in;
-
- in = *(unsigned *)net_from.ip;
for (i=0 ; i<numipfilters ; i++)
- if ( (in & ipfilters[i].mask) == ipfilters[i].compare)
+ if(strcmp(net_from->addr, ipfilters[i].addr) == 0)
return filterban.value;
return !filterban.value;
@@ -1078,14 +1003,14 @@
{
if (cl->state == cs_free)
continue;
- if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
+ if (!NET_CompareBaseAdr (net_from, &cl->netchan.remote_address))
continue;
if (cl->netchan.qport != qport)
continue;
- if (cl->netchan.remote_address.port != net_from.port)
+ if(strcmp(cl->netchan.remote_address.srv, net_from->srv) != 0)
{
Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n");
- cl->netchan.remote_address.port = net_from.port;
+ strcpy(cl->netchan.remote_address.srv, net_from->srv);
}
if (Netchan_Process(&cl->netchan))
{ // this is a valid, sequenced packet, so process it
@@ -1143,6 +1068,7 @@
realtime - cl->connection_started > zombietime.value)
{
cl->state = cs_free; // can now be reused
+ NET_Close(&cl->netchan.remote_address);
}
}
if (sv.paused && !nclients) {
@@ -1398,10 +1324,10 @@
// send to group master
for (i=0 ; i<MAX_MASTERS ; i++)
- if (master_adr[i].port)
+ if (strlen(master_adr[i].srv) > 0)
{
- Con_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
- NET_SendPacket (strlen(string), string, master_adr[i]);
+ Con_Printf ("Sending heartbeat to %s\n", master_adr[i].sys);
+ NET_SendPacket (strlen(string), string, &master_adr[i]);
}
}
@@ -1421,10 +1347,10 @@
// send to group master
for (i=0 ; i<MAX_MASTERS ; i++)
- if (master_adr[i].port)
+ if(strlen(master_adr[i].srv) > 0)
{
- Con_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
- NET_SendPacket (strlen(string), string, master_adr[i]);
+ Con_Printf ("Sending heartbeat to %s\n", master_adr[i].sys);
+ NET_SendPacket (strlen(string), string, &master_adr[i]);
}
}
@@ -1573,7 +1499,6 @@
// heartbeats will allways be sent to the id master
svs.last_heartbeat = -99999; // send immediately
-// NET_StringToAdr ("192.246.40.70:27000", &idmaster_adr);
}
--- a/qw/sv_user.c
+++ b/qw/sv_user.c
@@ -546,7 +546,7 @@
vsprintf (send+5, fmt, argptr);
va_end (argptr);
- NET_SendPacket (strlen(send)+1, send, where);
+ NET_SendPacket (strlen(send)+1, send, &where);
}
/*