From 0f97e2e0e07d43cfc6cd5717c6bd38694ede6585 Mon Sep 17 00:00:00 2001 From: Bradley Bell Date: Wed, 6 Feb 2002 09:22:42 +0000 Subject: [PATCH] Adding d1x network code --- arch/linux/arch_ip.cpp | 240 ++++++++++++++++++ main/ip_base.cpp | 550 +++++++++++++++++++++++++++++++++++++++++ main/ip_base.h | 416 +++++++++++++++++++++++++++++++ main/ip_basec.h | 32 +++ main/ipclienc.c | 35 +++ main/ipclient.cpp | 312 +++++++++++++++++++++++ main/ipclient.h | 69 ++++++ main/ipserver.cpp | 86 +++++++ 8 files changed, 1740 insertions(+) create mode 100644 arch/linux/arch_ip.cpp create mode 100644 main/ip_base.cpp create mode 100644 main/ip_base.h create mode 100644 main/ip_basec.h create mode 100644 main/ipclienc.c create mode 100644 main/ipclient.cpp create mode 100644 main/ipclient.h create mode 100644 main/ipserver.cpp diff --git a/arch/linux/arch_ip.cpp b/arch/linux/arch_ip.cpp new file mode 100644 index 00000000..d66b881c --- /dev/null +++ b/arch/linux/arch_ip.cpp @@ -0,0 +1,240 @@ +/* + * $Source: /cvs/cvsroot/d2x/arch/linux/arch_ip.cpp,v $ + * $Revision: 1.1 $ + * $Author: bradleyb $ + * $Date: 2002-02-06 09:22:41 $ + * + * arch_ip.cpp - arch specific udp/ip code. (linux ver) + * added 2000/02/07 Matt Mueller (some code borrowed from ipx_udp.c) + * + * $Log: not supported by cvs2svn $ + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include /* for htons & co. */ +#include +#include +#include +#include +#include +#include +extern "C" { +#include "ipx_drv.h" +#include "pstypes.h" +#include "mono.h" +//#include "multi.h" +} + +#include "ip_base.h" +#include "ipclient.h" + +static int mysock=-1; + +/* Do hostname resolve on name "buf" and return the address in buffer "qhbuf". + */ +int arch_ip_queryhost(ip_addr *addr,char *buf,u_short baseport) +{ + struct hostent *he; + char *s; + char c=0; + u_short p; + + if ((s=strrchr(buf,':'))) { + c=*s; + *s='\0'; + p=ip_portshift(baseport,s+1); + } + else p=ip_portshift(baseport,NULL);//memset(qhbuf+4,0,2); + he=gethostbyname((char *)buf); + if (s) *s=c; + if (!he) { + msg("Error resolving my hostname \"%s\"",buf); + return -1; //(NULL); + } + if (he->h_addrtype!=AF_INET || he->h_length!=4) { + msg("Error parsing resolved my hostname \"%s\"",buf); + return -1;//(NULL); + } + if (!*he->h_addr_list) { + msg("My resolved hostname \"%s\" address list empty",buf); + return -1;//(NULL); + } + addr->set(4,(u_char*)*he->h_addr_list,p); +// memcpy(qhbuf,(*he->h_addr_list),4); +// return(qhbuf); + return 0; +} + +#ifdef UDPDEBUG +/* Like dumpraddr() but for structure "sockaddr_in" + */ + +static void dumpaddr(struct sockaddr_in *sin) +{ + unsigned short ports; + u_char qhbuf[6]; + + memcpy(qhbuf+0,&sin->sin_addr,4); + //ports=htons(((short)ntohs(sin->sin_port))-UDP_BASEPORT); + ports=sin->sin_port; + memcpy(qhbuf+4,&ports,2); + dumpraddr(qhbuf); +} +#endif + + +int ip_sendtoca(ip_addr addr,const void *buf,int len){ + struct sockaddr_in toaddr; + if (addr.addrlen()!=4) return 0;//not handled yet + toaddr.sin_family=AF_INET; + memcpy(&toaddr.sin_addr,addr.addr,4); + toaddr.sin_port=*(unsigned short *)(addr.addr+4); +#ifdef UDPDEBUG + printf(MSGHDR "sendtoca((%d) ",len); + //dumpraddr(addr.addr); + addr.dump(); + puts(")."); +#endif + return sendto(mysock,buf,len,0,(struct sockaddr *)&toaddr,sizeof(toaddr)); +} + +/* Find as much as MAX_BRDINTERFACES during local iface autoconfiguration. + * Note that more interfaces can be added during manual configuration + * or host-received-packet autoconfiguration + */ + +#define MAX_BRDINTERFACES 16 + +/* We require the interface to be UP and RUNNING to accept it. + */ + +#define IF_REQFLAGS (IFF_UP|IFF_RUNNING) + +/* We reject any interfaces declared as LOOPBACK type. + */ +#define IF_NOTFLAGS (IFF_LOOPBACK) + +int arch_ip_get_my_addr(u_short myport){ + unsigned cnt=MAX_BRDINTERFACES,i,j; + struct ifconf ifconf; + int sock; + struct sockaddr_in *sinp; + ip_addr addr; + + if ((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))<0) + FAIL("Creating socket() failure during broadcast detection: %m"); + +#ifdef SIOCGIFCOUNT + if (ioctl(sock,SIOCGIFCOUNT,&cnt)) + { /* msg("Getting iterface count error: %m"); */ } + else + cnt=cnt*2+2; +#endif + + chk(ifconf.ifc_req=(struct ifreq *)alloca((ifconf.ifc_len=cnt*sizeof(struct ifreq)))); + if (ioctl(sock,SIOCGIFCONF,&ifconf)||ifconf.ifc_len%sizeof(struct ifreq)) { + close(sock); + FAIL("ioctl(SIOCGIFCONF) failure during broadcast detection: %m"); + } + cnt=ifconf.ifc_len/sizeof(struct ifreq); + // chk(broads=malloc(cnt*sizeof(*broads))); + // broadsize=cnt; + for (i=j=0;isin_family!=AF_INET) continue; + addr.set(4,(ubyte*)&sinp->sin_addr,htons(myport)); +#ifdef UDPDEBUG + printf(MSGHDR"added if "); + addr.dump(); + printf("\n"); +#endif + ip_my_addrs.add(addr); + } + return(0); +} + +/*int arch_ip_get_my_addr(u_short myport){ + char buf[256]; + if (gethostname(buf,sizeof(buf))) FAIL("Error getting my hostname"); + + ip_addr ip; + if (ip.dns(buf,myport)) FAIL("Error querying my own hostname \"%s\"",buf); + ip_my_addrs.add(ip); + return 0; +}*/ +int arch_ip_open_socket(int port){ + struct sockaddr_in sin; + int val_one=1; + if ((mysock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0) { + mysock = -1; + FAIL("socket() creation failed on port %d: %m",port); + } + if (setsockopt(mysock,SOL_SOCKET,SO_BROADCAST,&val_one,sizeof(val_one))) { + if (close(mysock)) msg("close() failed during error recovery: %m"); + mysock=-1; + FAIL("setsockopt(SO_BROADCAST) failed: %m"); + } + sin.sin_family=AF_INET; + sin.sin_addr.s_addr=htonl(INADDR_ANY); + sin.sin_port=htons(port); + + if (bind(mysock,(struct sockaddr *)&sin,sizeof(sin))) { + if (close(mysock)) msg("close() failed during error recovery: %m"); + mysock=-1; + FAIL("bind() to UDP port %d failed: %m",port); + } + + return 0; +} +void arch_ip_close_socket(void) { + if (mysock<0) { + msg("close w/o open"); + return; + } + if (close(mysock)) + msg("close() failed on CloseSocket D1X ip socket %m"); + mysock=-1; +} +int arch_ip_recvfrom(char*outbuf,int outbufsize,struct ipx_recv_data *rd){ + struct sockaddr_in fromaddr; + socklen_t fromaddrsize=sizeof(fromaddr); + int size; + static ip_addr ip_fromaddr; + ip_addr *vptr=&ip_fromaddr; + + if ((size=recvfrom(mysock,outbuf,outbufsize,0,(struct sockaddr *)&fromaddr,&fromaddrsize))<0) + return -1; + + if (fromaddr.sin_family!=AF_INET) return -1; + +#ifdef UDPDEBUG + printf(MSGHDR "recvfrom((%d-2=%d),",size,size-2); + dumpaddr(&fromaddr); + puts(")."); +#endif + + ip_fromaddr.set(4,(u_char*)&fromaddr.sin_addr,fromaddr.sin_port); + + memcpy(rd->src_node,&vptr,sizeof(ip_addr*)); + return size; +} +int arch_ip_PacketReady(void) { + return ipx_general_PacketReady(mysock); +} diff --git a/main/ip_base.cpp b/main/ip_base.cpp new file mode 100644 index 00000000..a0397b11 --- /dev/null +++ b/main/ip_base.cpp @@ -0,0 +1,550 @@ +/* + * $Source: /cvs/cvsroot/d2x/main/ip_base.cpp,v $ + * $Revision: 1.1 $ + * $Author: bradleyb $ + * $Date: 2002-02-06 09:22:41 $ + * + * ip_base.cpp - base for NAT-compatible udp/ip code. + * added 2000/02/07 Matt Mueller + * + * $Log: not supported by cvs2svn $ + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +extern "C" { +#include "timer.h" +#include "mono.h" +#include "args.h" +} +#include +#include "ip_base.h" + +int myport=-1; + +int baseport=UDP_BASEPORT; + +ip_addr_list ip_my_addrs; +ip_peer_list peer_list; + +int ip_handshake_base::fillbuf(ubyte *buf){ + u_int32_t tmp32; + u_int16_t tmp16; + int pos=0; + buf[pos++]=type; + buf[pos++]=state; +// memcpy(buf+pos,id,6);pos+=6; + pos+=id.fillbuf(buf+pos); + tmp16=htons(iver); + memcpy(buf+pos,&tmp16,2);pos+=2; + tmp32=htonl(tryid); + memcpy(buf+pos,&tmp32,4);pos+=4; + return pos; +} +int ip_handshake_base::readbuf(ubyte *buf){ + int pos=0; + nopend=1; + type=buf[pos++]; + state=buf[pos++]; +// memcpy(id,buf+pos,6);pos+=6; + pos+=id.readbuf(buf+pos); + memcpy(&iver,buf+pos,2);pos+=2; + iver=htons(iver); + memcpy(&tryid,buf+pos,4);pos+=4; + tryid=htonl(tryid); + return pos; +} +void ip_handshake_base::setstate(int newstate){ + if (!nopend){ + if (state&STATE_NEED_RESEND){ + if (!(newstate&STATE_NEED_RESEND)) + peer_list.pendinghandshakes--; + }else{ + if (newstate&STATE_NEED_RESEND) + peer_list.pendinghandshakes++; + } + mprintf((0,"peer_list.pendinghandshakes=%i\n",peer_list.pendinghandshakes)); + } + state=newstate;attempts=0;nextsend=0; +} +int ip_handshake_base::addstate(int newstate){ + if (state & STATE_ERR){ + setstate((state | newstate) & ~STATE_ERR); + return 2; + } + if ((state | newstate) != state){ + setstate(state | newstate); + return 1; + } + return 0; +} + +int ip_handshake_info::fillbuf(ubyte *buf){ + int pos=ip_handshake_base::fillbuf(buf); + pos+=addr.fillbuf(buf+pos); +// memcpy(buf+pos,addr,6);pos+=6; + return pos; +} +int ip_handshake_info::readbuf(ubyte *buf){ + int pos=ip_handshake_base::readbuf(buf); + pos+=addr.readbuf(buf+pos); +// memcpy(addr,buf+pos,6);pos+=6; + return pos; +} + +int ip_handshake_relay::fillbuf(ubyte *buf){ + u_int16_t tmp16; + int pos=ip_handshake_base::fillbuf(buf); +// memcpy(buf+pos,r_addr[0],6);pos+=6; +// memcpy(buf+pos,r_addr[1],6);pos+=6; +// memcpy(buf+pos,r_id,6);pos+=6; + pos+=r_id.fillbuf(buf+pos); + tmp16=htons(r_iver); + memcpy(buf+pos,&tmp16,2);pos+=2; + pos+=r_addr.fillbuf(buf+pos); +// pos+=r_addr[1].fillbuf(buf+pos); + return pos; +} +int ip_handshake_relay::readbuf(ubyte *buf){ + int pos=ip_handshake_base::readbuf(buf); +// memcpy(r_addr[0],buf+pos,6);pos+=6; +// memcpy(r_addr[1],buf+pos,6);pos+=6; +// memcpy(r_id,buf+pos,6);pos+=6; + pos+=r_id.readbuf(buf+pos); + memcpy(&r_iver,buf+pos,2);pos+=2; + r_iver=htons(r_iver); + pos+=r_addr.readbuf(buf+pos); +// pos+=r_addr[1].readbuf(buf+pos); + return pos; +} +ip_handshake_relay::ip_handshake_relay(ip_peer *torelay):ip_handshake_base(1){ + type=IP_CFG_RELAY; + r_id=torelay->id; + r_iver=torelay->iver; + r_addr=torelay->addr; +// r_addr[1]=torelay->addr[1]; + setstate(STATE_INEEDINFO); +} + +/*void ip_peer::set_good_addr(ubyte *fraddr){ + int i; + for (i=0;ifillbuf(buf+s); + assert(s<256); + if (addr.goodaddr==NULL){ + ip_addr_list::iterator i; + for (i=addr.begin();i!=addr.end();i++) + ip_sendtoca(*i,buf,s); +// int i; +// for (i=0;inextsend=timer_get_approx_seconds()+IP_HS_RETRYTIME; + hsb->attempts++; +/*#ifdef UDPDEBUG + { + int hj; + printf(MSGHDR"sending handshake %i (t%i state %i(%s)) for (%i)",hsb->attempts,hsb->type,hsb->state,ip_hs_statetoa(hsb->state),addr.goodaddr); + for (hj=0;hj0) + printf(", "); + dumpraddr(addr[hj].addr); + } + printf(" v%i\n",iver); + } +#endif*/ +} +bool ip_peer::verify_addr(ip_addr_list &fraddrs){ + int a1=addr.add(fraddrs); + if (a1) + addr.goodaddr=NULL; +/* a1=(addr[0]!=fraddr0 && addr[1]!=fraddr0); + a2=(addr[0]!=fraddr1 && addr[1]!=fraddr1); + if (a1 || a2 || (numaddr<2 && fraddr0!=fraddr1)) + { + mprintf((0,"verify_peer_addr_hsi %i %i\n",a1,a2)); + addr[0]=fraddr1; + addr[1]=fraddr0; + goodaddr=-1; + numaddr=2; + return 1; + }*/ + return a1>0; +} +ip_peer * ip_peer_list::add_1(ip_addr addr/*,ip_id id*/){ + ip_peer*n=add_unk(); + n->addr.add(addr); +// n->goodaddr=-1; +// n->numaddr=1; +// n->id=id; + return n; +} +ip_peer * ip_peer_list::add_full(ip_id id, u_int16_t iver,ip_addr_list &addrs){ + ip_peer*n=add_id(id); +/* n->addr[0]=addr0; + n->addr[1]=addr1; + n->goodaddr=-1; + if (addr0==addr1){ + n->numaddr=1; + }else{ + n->numaddr=2; + }*/ + n->addr.add(addrs); + n->iver=iver; + mprintf((0,"addfull %i addrs\n",n->addr.naddr)); +// n->id=id; + return n; +} +void ip_peer_list::make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs){ + list::iterator unki=find(unknown_peers.begin(),unknown_peers.end(),p); + if (unki!=unknown_peers.end()) + unknown_peers.erase(unki); + p->id=id; + p->iver=iver; +// p->addr[0]=addr0; +// p->addr[1]=addr1; + p->addr.add(addrs); + peers.insert(peer_map::value_type(p->id,p)); +} +ip_peer * ip_peer_list::find_byid(ip_id id){ + peer_map::iterator i=peers.find(id); + if (i!=peers.end()) + return (*i).second; + return NULL; +} +struct do_find_by_addr : public unary_function { + int j; + ip_addr addr; + bool operator()(ip_peer * p) { +//// bool operator()(pair &) { +// for(j=0;jnumaddr;j++) +// if (addr==p->addr[j]) +// return 1; + if (p->addr.hasaddr(addr)) + return 1; + return 0; + } +}; +template +struct pairkiller { + fo *o; + ret operator()(pair &aoeuaoeu) { + return (*o)(aoeuaoeu.second); + } + pairkiller(fo *no):o(no){} +}; +//template +template +pairkiller pairkill(fo * no){ + return pairkiller(no); +} + +ip_peer * ip_peer_list::find_by_addr(ip_addr addr){ + do_find_by_addr fba; +// pairkiller fbap(&fba); + fba.addr=addr; + peer_map::iterator i=find_if(peers.begin(),peers.end(),pairkill(&fba)); + if (i!=peers.end()) + return (*i).second; + list::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba); + if (j!=unknown_peers.end()) + return (*j); + return NULL; +} +ip_peer * ip_peer_list::find_unk_by_addr(ip_addr addr){ + do_find_by_addr fba; + fba.addr=addr; + list::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba); + if (j!=unknown_peers.end()) + return (*j); + return NULL; +} +struct do_peer_handshake : public unary_function{ + fix mintime; + list::iterator i; + ip_handshake_base *hsb; + void operator() (ip_peer* peer) { + for(i=peer->handshakes.begin();i!=peer->handshakes.end();++i){ + hsb=(*i); + //if (hsb->statenextsendstate & STATE_NEED_RESEND) && hsb->nextsendattempts>IP_MAX_HS_ATTEMPTS){ +/*#ifdef UDPDEBUG + int hj; + printf(MSGHDR"handshake timeout (state %i(%s)) for (%i)",hsb->state,ip_hs_statetoa(hsb->state),peer->goodaddr); + for (hj=0;hjnumaddr;hj++){ + if (hj>0) + printf(", "); + dumpraddr(peer->addr[hj].addr); + } + printf(" v%i\n",peer->iver); +#endif*/ + hsb->setstate(STATE_ERR); + }else{ + // handshake_buf.state=handshakers[i].state; + peer->send_handshake(hsb); + } + } + } + } +}; +void ip_peer_list::handshake_frame(void){ + if(pendinghandshakes){ + fix mintime=timer_get_approx_seconds();//try every X seconds + if (pendinghandshake_lasttime dophp(&doph); + doph.mintime=mintime; + for_each(peers.begin(),peers.end(),pairkill(&doph)); + for_each(unknown_peers.begin(),unknown_peers.end(),doph); +// int i; +// mintime-=IP_HS_RETRYTIME;//try every X seconds +/* for (i=0;i{ + void operator() (ip_peer* peer) { + delete peer; + } +}; +void ip_peer_list::clear(void){ + do_peer_delete dopd; + for_each(peers.begin(),peers.end(),pairkill(&dopd)); + peers.erase(peers.begin(),peers.end()); + for_each(unknown_peers.begin(),unknown_peers.end(),dopd); + unknown_peers.erase(unknown_peers.begin(),unknown_peers.end()); +} +ip_peer_list::~ip_peer_list(){ + clear(); +} + + +#ifdef UDPDEBUG +//000a0oeuaoeu + +static void dumpid(unsigned char *a) +{ + printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]); +} +#endif + +int ip_sendtoid(ubyte *id,const void *buf,int len){ +// ip_handshaker *hsr=find_handshaker_by_id(id); + ip_peer *p=peer_list.find_byid(id); + if (!p || p->addr.goodaddr==NULL){ +#ifdef UDPDEBUG + printf(MSGHDR"send to invalid id("); + dumpid(id); + printf(") %p.",p); +#endif + return -1; + } + return ip_sendtoca(*p->addr.goodaddr,buf,len); +} + +void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr){ + ip_peer *p; + switch(buf[0]){ + case IP_CFG_SORRY: + { +#ifdef UDPDEBUG + printf("ip_receive_cfg: %i %i ",buf[0],buf[1]); + dumprid(buf+2); + printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10))); +#endif + + }break; + case IP_CFG_HANDSHAKE: +#ifdef UDPDEBUG + printf("ip_receive_cfg: %i %i ",buf[0],buf[1]); + dumprid(buf+2); + printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10))); +#endif + { + ip_handshake_info *hsi=new ip_handshake_info(buf); + hsi->addr.add(fromaddr); + ip_handshake_info *lhsi=NULL; + p=peer_list.find_byid(hsi->id); +/*#ifdef UDPDEBUG + printf("hsi %i %i id=",hsi->type,hsi->state); + hsi->id.dump(); + printf(" ver=%i tryid=%u\n",hsi->iver,hsi->tryid); + mprintf((0,"peer_list.find_byid=%p\n",p)); +#endif*/ + if (!p){ + p=peer_list.find_unk_by_addr(fromaddr); +// mprintf((0,"peer_list.find_by_addr=%p\n",p)); + if (p){ + peer_list.make_full(p,hsi->id,hsi->iver,hsi->addr); + } + } + else + p->verify_addr(hsi->addr); + if (!p){ + p=peer_list.add_hsi(hsi); +// mprintf((0,"peer_list.add_hsi=%p\n",p)); + } + lhsi=p->find_handshake(); + lhsi->tryid=hsi->tryid; + if (p->addr.goodaddr==NULL){ + p->addr.setgoodaddr(fromaddr); +// lhsi->state&=STATE_INEEDINFO; + } + if (hsi->state&STATE_INEEDINFO) + lhsi->setstate(STATE_SENDINGINFO); + //lhsi->state&=STATE_SENDINGINFO; + else + lhsi->setstate(0); + +// mprintf((0,"lhsi->state=%i\n",lhsi->state)); +// mprintf((0,"hsi->state=%i\n",hsi->state)); + if (lhsi->state) + p->send_handshake(lhsi); + + delete hsi; + }break; + case IP_CFG_RELAY: + { + ip_peer *rp; + ip_handshake_relay hsr(buf); +#ifdef UDPDEBUG + printf("ip_receive_cfg: %i %i ",buf[0],buf[1]); + dumprid(buf+2); + printf(" v%i r_id ",ntohs(*(unsigned short*)(buf+8))); + hsr.r_id.dump(); + printf(" r_iv%i\n",hsr.r_iver); +#endif + p=peer_list.find_byid(hsr.id); + if (!p) { + mprintf((0,"relay from unknown peer\n")); + break;//hrm. + } + rp=peer_list.find_byid(hsr.r_id); + if (hsr.state&STATE_RELAYREPLY){ + if (!rp) { + mprintf((0,"relay reply for unknown peer\n")); + break;//hrm. + } + ip_handshake_relay *rhsr=p->find_relay(rp->id); + if (!rhsr) + break; + rhsr->setstate(0); +#ifdef UDPDEBUG + printf("**** "); + p->id.dump(); + printf(" is ok with "); + rp->id.dump(); + printf("\n"); +#endif + }else{ + if (!rp) + rp=peer_list.add_full(hsr.r_id,hsr.r_iver,hsr.r_addr); + else + rp->verify_addr(hsr.r_addr); + + if (rp->addr.goodaddr==NULL){ + mprintf((0,"sending relayed handshake\n")); + //handshake with relayed peer + ip_handshake_info *lhsi=rp->find_handshake(); +// lhsi->setstate(STATE_INEEDINFO); + if (lhsi->addstate(STATE_INEEDINFO)); + rp->send_handshake(lhsi); + }else{ + mprintf((0,"sending relayed reply\n")); + //reply to relayer + ip_handshake_relay rhsr(rp); + rhsr.setstate(STATE_RELAYREPLY); + p->send_handshake(&rhsr); + } + } + }break; + } +} + + + +int ipx_ip_GetMyAddress(void) { + + int i; + u_int32_t myhandshakeid; + + d_srand( timer_get_approx_seconds() ); +// printf("set my id to %u\n",myhandshakeid); + + ip_my_addrs.clear(); + + if (!FindArg("-ip_nogetmyaddr")) + arch_ip_get_my_addr(myport);//if we can't get an addr, then we can still probably play, just some NAT configs might not work. +// if (arch_ip_get_my_addr(myport)) return -1; + + if ((i=FindArg("-ip_myaddr"))){ + ip_addr ip; + if (!ip.dns(Args[i+1],myport)){ + ip_my_addrs.add(ip); + } + } + + myhandshakeid=htonl(d_rand32()); + //ipx_MyAddress[4]=qhbuf[2]; + //ipx_MyAddress[5]=qhbuf[3]; + if (ip_my_addrs.naddr){ + ip_addr ip=*ip_my_addrs.begin(); + ipx_MyAddress[4]=ip.addr[2]; + ipx_MyAddress[5]=ip.addr[3]; + }else{ + ipx_MyAddress[4]=d_rand()%255; + ipx_MyAddress[5]=d_rand()%255; + } + //memcpy(ipx_MyAddress+6,&handshake_buf.id,4); + memcpy(ipx_MyAddress+6,&myhandshakeid,4); + +#ifdef UDPDEBUG + printf(MSGHDR "Using TCP/IP id "); + dumprid(ipx_MyAddress+4); + putchar('\n'); +#endif + return 0; +} +/* Parse PORTSHIFT numeric parameter + */ + +unsigned short ip_portshift(unsigned short baseport, const char *cs) +{ + long port; + unsigned short ports=htons(baseport); + if (cs){ + port=atol(cs); + if (cs[0]=='-' || cs[0]=='+')//relative port +// if (port<-PORTSHIFT_TOLERANCE || port>+PORTSHIFT_TOLERANCE) +// msg("Invalid portshift in \"%s\", tolerance is +/-%d",cs,PORTSHIFT_TOLERANCE); +// else + ports=htons(port+baseport); + else + ports=htons(port);//absolute port + } +// memcpy(qhbuf+4,&ports,2); + return ports; +} + diff --git a/main/ip_base.h b/main/ip_base.h new file mode 100644 index 00000000..b242ae57 --- /dev/null +++ b/main/ip_base.h @@ -0,0 +1,416 @@ +/* + * $Source: /cvs/cvsroot/d2x/main/ip_base.h,v $ + * $Revision: 1.1 $ + * $Author: bradleyb $ + * $Date: 2002-02-06 09:22:41 $ + * + * ip_base.h - base for NAT-compatible udp/ip code. + * added 2000/02/07 Matt Mueller + * + * $Log: not supported by cvs2svn $ + * + */ + +#ifndef ___IP_BASE_H +#define ___IP_BASE_H + +#include +#include +#include +extern "C" { +#include "ip_basec.h" +#include "fix.h" +#include "mono.h" +#include "vers_id.h" +//#include "inetc.h" +#include "timer.h" +} + +class ip_addr;//prototype for arch_ip_queryhost + +#include "ipclient.h" +#include + + +//inline u_int32_t d_rand32(void) { return d_rand() + (d_rand()<<16);} +inline u_int32_t d_rand32(void) { return d_rand() + (d_rand()<<15) + (d_rand()<<30);}//d_rand() only returns 15 bits + + +void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr); + +extern unsigned char ipx_MyAddress[10]; + +unsigned short ip_portshift(unsigned short baseport, const char *cs); + +#define UDP_BASEPORT 31017 +#define UDP_SERV_BASEPORT 30817 +#define PORTSHIFT_TOLERANCE 0x100 +#define MAX_PACKETSIZE 8192 + +// Length HAS TO BE 2! +#define D1Xid "\xd1x" +// Length HAS TO BE 4! +#define D1Xcfgid "\xcfg\xd1x" + + +//cfg packet types +#define IP_CFG_BASE 0 +#define IP_CFG_HANDSHAKE 1 +#define IP_CFG_RELAY 2 +//someone giving us an error (ie, outdated version, etc.) ... not handled yet. +#define IP_CFG_SORRY 3 + + +#define STATE_INEEDINFO 1<<0 +#define STATE_SENDINGINFO 1<<1 +//#define STATE_NEED_RESEND (STATE_INEEDINFO | STATE_SENDINGINFO) +#define STATE_NEED_RESEND (STATE_INEEDINFO) +#define STATE_VALID_STATES (STATE_INEEDINFO | STATE_SENDINGINFO) +#define STATE_RELAYREPLY 1<<6 +#define STATE_ERR 1<<7 +/* Dump raw form of IP address/port by fancy output to user + */ + +#ifdef UDPDEBUG +#include +inline char *ip_hs_statetoa(int state){ + if (!state) + return "NOSTATE"; + if (state&STATE_ERR) + return "ERR"; + if ((state&(STATE_INEEDINFO|STATE_SENDINGINFO))==(STATE_INEEDINFO|STATE_SENDINGINFO)) + return "NEED+SEND"; + if (state&STATE_INEEDINFO) + return "NEED"; + if (state&STATE_SENDINGINFO) + return "SEND"; + return "huh?"; +} +inline void dumprid(const unsigned char *a) +{ + printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]); +} +inline void dumpraddr(const unsigned char *addr) +{ + ushort port; + printf("[%u.%u.%u.%u]",addr[0],addr[1],addr[2],addr[3]); + port=(unsigned short)ntohs(*(unsigned short *)(addr+4)); + printf(":%d",port); +} +#endif + + +class ip_id { + public: + ubyte id[6]; + + int fillbuf(ubyte *buf)const {memcpy(buf,id,6);return 6;}; + int readbuf(const ubyte *buf){memcpy(id,buf,6);return 6;}; + bool operator < (const ip_id &a_id)const {return memcmp(id,a_id.id,6)<0;} + bool operator == (const ip_id &a_id)const {return memcmp(id,a_id.id,6)==0;} + bool operator > (const ip_id &a_id)const {return memcmp(id,a_id.id,6)>0;} + ip_id& operator = (const ip_id &a_id){readbuf(a_id.id);return *this;} +#ifdef UDPDEBUG + void dump(void){dumprid(id);} +#endif + ip_id(ubyte*nid){readbuf(nid);} + ip_id(void){}; +}; + +class ip_addr { + protected: + ubyte alen;//alen stuff is to maybe make ipv6 support easier (if the transition ever actually happens) + public: + ubyte addr[6]; + + int fillbuf(ubyte *buf)const {buf[0]=alen;memcpy(buf+1,addr,alen);return alen+1;}; + int readbuf(const ubyte *buf){ + int l=buf[0]; + if (l==6){ + memcpy(addr,buf+1,6);alen=l; + }else{ + mprintf((0,"ip_addr readbuf bad len %i\n",l)); + memset(addr,0,6);alen=0; + } + return l+1; + }; + bool operator < (const ip_addr &a_addr)const { + if (alen!=a_addr.alen) return alen (const ip_addr &a_addr)const { + if (alen!=a_addr.alen) return alen>a_addr.alen; + return memcmp(addr,a_addr.addr,alen)>0; + } + ip_addr& operator = (const ip_addr &a_addr){alen=a_addr.alen;memcpy(addr,a_addr.addr,6);return *this;} +#ifdef UDPDEBUG + void dump(void)const{dumpraddr(addr);} +#endif + void set(int addrsize,ubyte *naddr,ushort port){ + if (addrsize!=4)return;//not handled yet. + alen=addrsize+2; + memcpy(addr,naddr,addrsize); +// port=htons(port); + memcpy(addr+addrsize,&port,2); + } + int dns(char *address,ushort baseport){ + return arch_ip_queryhost(this,address,baseport); + } + bool ok(void)const{return alen>0;} + int addrlen(void)const{return alen-2;} +// ip_addr(ubyte*naddr){readbuf(naddr);} + ip_addr(void){alen=0;}; +}; + +class ip_addr_list { + protected: + list addrs; + public: + typedef list::iterator iterator; + typedef list::const_iterator const_iterator; + int naddr; + ip_addr *goodaddr; + + iterator begin(void){return addrs.begin();} + iterator end(void){return addrs.end();} + const_iterator begin(void)const{return addrs.begin();} + const_iterator end(void)const{return addrs.end();} + bool hasaddr(ip_addr addr){ + iterator i=find(begin(),end(),addr); + return (i!=addrs.end()); + } + int add(ip_addr addr){ + if (hasaddr(addr)) + return 0; + addrs.push_back(addr); + naddr++; + return 1; + } + int add(const ip_addr_list &na){ + int j=0; + const_iterator i=na.begin(); + for (;i!=na.end();++i) + j+=add(*i); + return j; + } + void setgoodaddr(ip_addr addr){ + iterator i=find(begin(),end(),addr); + if (i!=end()){ + goodaddr=&(*i); + return; + } + addrs.push_back(addr); + goodaddr=&(*addrs.end()); + } + int fillbuf(ubyte *buf)const { + int s=0; + const_iterator i; + buf[s++]=naddr; + for (i=begin();i!=end();++i) + s+=(*i).fillbuf(buf+s); + return s; + } + int readbuf(const ubyte *buf){ + int s=1,n; + ip_addr a; + for (n=buf[0];n;--n){ + s+=a.readbuf(buf+s); +// addrs.push_back(a); + if (a.ok()) + add(a); + } + return s; + } + void clear(void){ + naddr=0; + goodaddr=NULL; + addrs.erase(begin(),end()); + } + + ip_addr_list(const ip_addr_list &nl):addrs(nl.addrs),naddr(nl.naddr){setgoodaddr(*nl.goodaddr);} + ip_addr_list(void):naddr(0),goodaddr(NULL){} +// ip_addr_list(const ubyte * buf):naddr(0),goodaddr(NULL){readbuf(buf);} +}; + +extern ip_addr_list ip_my_addrs; + +extern int ip_sendtoca(ip_addr addr,const void *buf,int len); + +class ip_handshake_base { + public: + ubyte type; + ubyte state; + ip_id id; + u_int16_t iver; + u_int32_t tryid; + + fix nextsend; + int attempts; + int nopend; + + virtual int fillbuf(ubyte *buf); + virtual int readbuf(ubyte *buf); + void setrandid(void){tryid=d_rand32() ^ timer_get_approx_seconds();} + void setstate(int newstate); + int addstate(int newstate); + +// ip_handshake_base(void):type(IP_CFG_BASE){setstate(IPNOSTATE);} + ip_handshake_base(bool initme=0):type(IP_CFG_BASE){ + nopend=0; + state=0; + setstate(0); + if(initme){ + // id=ip_my_id; + id=ipx_MyAddress+4; + iver=D2X_IVER; + setrandid(); + } + } + virtual ~ip_handshake_base(){setstate(0);}//decrement pendinghandshakes if needed. +}; +class ip_handshake_info : public ip_handshake_base { + public: + ip_addr_list addr; + + virtual int fillbuf(ubyte *buf); + virtual int readbuf(ubyte *buf); + + ip_handshake_info(ubyte *buf){ + readbuf(buf); + } + ip_handshake_info(void):ip_handshake_base(1){ + type=IP_CFG_HANDSHAKE; + addr=ip_my_addrs; +// setstate(STATE_INEEDINFO); + } +}; +class ip_peer; +class ip_handshake_relay : public ip_handshake_base { + public: + ip_id r_id; + u_int16_t r_iver; + ip_addr_list r_addr; + + virtual int fillbuf(ubyte *buf); + virtual int readbuf(ubyte *buf); + + ip_handshake_relay(ubyte *buf){ + readbuf(buf); + } + ip_handshake_relay(ip_peer *torelay); +}; + +//max number of times to try to handshake a host +#define IP_MAX_HS_ATTEMPTS 10 +//how often to resend a hand-shake (3 seconds) +#define IP_HS_RETRYTIME (F1_0*3) +//how often (max) to search through the resend loop (1 second) +#define IP_HS_FRAME_RETRYTIME (F1_0) + +class ip_peer { + public: + ip_addr_list addr; +// int goodaddr; + ip_id id; + int iver; +// ip_hs_state query; +// ip_hs_state reply; + list handshakes; + +// void set_good_addr(ubyte *fraddr); + void add_hs(ip_handshake_base* hs){ +// mprintf((0,"########## add_hs %p: adding a hs %p %i %i\n",this,hs,hs->type,hs->state)); + handshakes.push_back(hs); + } + ip_handshake_relay* find_relay(ip_id r_id){ + list::iterator i; + ip_handshake_base* hsb; + ip_handshake_relay* hsr; + for (i=handshakes.begin();i!=handshakes.end();++i){ + hsb=(*i); + if (hsb->type==IP_CFG_RELAY){ + hsr=(ip_handshake_relay*)hsb; + if (hsr->r_id==r_id) + return hsr; + } + } + return NULL; + } + ip_handshake_info* find_handshake(void){ + list::iterator i; + ip_handshake_base* hsb; + for (i=handshakes.begin();i!=handshakes.end();++i){ + hsb=(*i); + if (hsb->type==IP_CFG_HANDSHAKE) + return (ip_handshake_info*) hsb; + } + ip_handshake_info *ni=new ip_handshake_info(); +// handshakes.push_back(ni); + add_hs(ni); + return ni; + } +/* ip_handshake_base* find_hs(u_int32_t tryid, ubyte type){ + list::iterator i; + ip_handshake_base* hsb; + for (i=handshakes.begin();i!=handshakes.end();++i){ + hsb=(*i); + if (hsb->tryid==tryid && hsb->type==type) + return hsb; + } + return NULL; + }*/ + void send_handshake(ip_handshake_base*hsb); + bool verify_addr(ip_addr_list &fraddrs); + ip_peer(void){iver=0;} + ~ip_peer(){ + list::iterator i; + for (i=handshakes.begin();i!=handshakes.end();++i){ +/* mprintf((0,"###### ~ip_peer %p: deleting a hs %p %i %i\n",this,(*i),(*i)->type,(*i)->state)); + if (!(*i)) + mprintf((0,"~ip_peer null hs?\n")); + else*/ + delete (*i); + } + } +}; + + +class ip_peer_list { + public: + typedef map > peer_map; + peer_map peers; + list unknown_peers; + int pendinghandshakes; + fix pendinghandshake_lasttime; + + ip_peer * add_id(ip_id id){ + ip_peer*n=new ip_peer(); + n->id=id; + peers.insert(peer_map::value_type(n->id,n)); + return n; + } + ip_peer * add_unk(void){ + ip_peer*n=new ip_peer(); + unknown_peers.push_back(n); + return n; + } + //ip_peer * add_1(ubyte *addr,ip_id id); + ip_peer * add_1(ip_addr addr); + ip_peer * add_full(ip_id id, u_int16_t iver, ip_addr_list &addrs); + void make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs); + ip_peer * add_hsi(ip_handshake_info *hsi){return add_full(hsi->id,hsi->iver,hsi->addr);} + ip_peer * find_byid(ip_id id); + ip_peer * find_by_addr(ip_addr addr); + ip_peer * find_unk_by_addr(ip_addr addr); + void handshake_frame(void); + void clear(void); + ip_peer_list(){ + pendinghandshakes=0; + pendinghandshake_lasttime=0; + } + ~ip_peer_list(); +}; +extern ip_peer_list peer_list; + +#endif diff --git a/main/ip_basec.h b/main/ip_basec.h new file mode 100644 index 00000000..aab6f17f --- /dev/null +++ b/main/ip_basec.h @@ -0,0 +1,32 @@ +/* + * $Source: /cvs/cvsroot/d2x/main/ip_basec.h,v $ + * $Revision: 1.1 $ + * $Author: bradleyb $ + * $Date: 2002-02-06 09:22:41 $ + * + * ip_basec.h - interface from cpp to c funcs + * added 2000/02/07 Matt Mueller + * + * $Log: not supported by cvs2svn $ + * + */ + +#ifndef ___IP_BASEC_H +#define ___IP_BASEC_H + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "pstypes.h" +int ip_sendtoid(ubyte *id,const void *buf,int len); + +int get_MAX_PLAYERS(void); +int get_Netgame_player_connected(int pn); +ubyte * get_Netgame_player_node(int pn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/main/ipclienc.c b/main/ipclienc.c new file mode 100644 index 00000000..23bf3753 --- /dev/null +++ b/main/ipclienc.c @@ -0,0 +1,35 @@ +/* + * $Source: /cvs/cvsroot/d2x/main/ipclienc.c,v $ + * $Revision: 1.1 $ + * $Author: bradleyb $ + * $Date: 2002-02-06 09:22:41 $ + * + * ipclienc.h - interface from cpp to c funcs + * added 2000/02/07 Matt Mueller + * + * $Log: not supported by cvs2svn $ + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ip_basec.h" +#include "ipx.h" +#include "network.h" + +void ip_sendtoall(char *buf,int len) +{ + int j; + for (j=0;j +#endif + +extern "C"{ +#include "mono.h" +#include "key.h" +#include "text.h" +#include "newmenu.h" +#include "args.h" +void network_init(void); +int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address); +} + +#include "ip_base.h" +#include "ipclient.h" + + +extern int Player_num; +extern int Network_send_objects; + +extern int N_players; + +int ip_connect_manual(char *textaddr) { +// ip_handshake_info handshake; +// ip_init_handshake_info(&handshake,0); + int r; + ubyte buf[1500]; + ip_peer *p; + ip_addr addr; + + if (addr.dns(textaddr,UDP_BASEPORT)) { + nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not resolve address"); + return -1; + } +#ifdef UDPDEBUG + printf("connecting to "); + addr.dump(); + printf("\n"); +#endif + + network_init(); + N_players = 0; + + if (!(p=peer_list.find_by_addr(addr))){ + p=peer_list.add_1(addr); + } + ip_handshake_info *hsi=p->find_handshake(); + hsi->setstate(STATE_INEEDINFO); + // p->newhandshake(hsi); +// p->handshakes.push_back(hsi); +// set_hs_state(&hsr->reply,IPHELLO); +// ip_send_handshake(hsr,&hsr->reply); + while(hsi->state&STATE_VALID_STATES){ + r=ipx_get_packet_data(buf); + if (r>0) + mprintf((0,MSGHDR "ip_connect_manual: weird, someone sent us normal data\n")); + if (key_inkey()==KEY_ESC) + return 0; + } + if (hsi->state&STATE_ERR) { + nm_messagebox(TXT_ERROR,1,TXT_OK,"handshake timeout"); + return -1; + } + +// join the Netgame. + + return get_and_show_netgame_info(null_addr,p->id.id,NULL); +} + + +static int ipx_ip_OpenSocket(int oport) { + int i; + if ((i=FindArg("-ip_baseport"))){ + baseport=UDP_BASEPORT+atoi(Args[i+1]); + } + + myport=baseport+(oport - IPX_DEFAULT_SOCKET); + if (arch_ip_open_socket(myport)) return -1; + + if (ipx_ip_GetMyAddress() < 0) FAIL("Error getting my address"); + + // if (!port) + // port = dynamic_socket++; +#ifdef UDPDEBUG + msg("OpenSocket on D1X socket port %d (%d : %+d) : %+d",myport,oport,oport-IPX_DEFAULT_SOCKET,baseport-UDP_BASEPORT); +#endif + //sk->socket = UDP_BASEPORT+(oport - IPX_DEFAULT_SOCKET); +// sk->socket = port; + return 0; +} +static void ipx_ip_CloseSocket(void) { +#ifdef UDPDEBUG + msg("CloseSocket on D1X socket port %d",myport); +#endif + arch_ip_close_socket(); + peer_list.clear(); +} + + + +/* Here we'll send the packet to our host. If it is unicast packet, send + * it to IP address/port as retrieved from IPX address. Otherwise (broadcast) + * we'll repeat the same data to each host in our broadcasting list. + */ + +static int ipx_ip_SendPacket(IPXPacket_t *IPXHeader, + ubyte *data, int dataLen) { +// struct sockaddr_in toaddr; + int i=dataLen; + //int bcast; + char *buf; + + if (dataLen<0 || dataLen>MAX_PACKETSIZE) { +#ifdef UDPDEBUG + msg("SendPacket enter, dataLen=%d out of range",dataLen); +#endif + return -1; + } + chk(buf=(char*)alloca(2+dataLen)); + memcpy(buf+0,D1Xid ,2); + memcpy(buf+2,data,dataLen); + +#ifdef UDPDEBUG + printf(MSGHDR "sendto((%d),Node=[4] %02X %02X,Socket=%02X %02X,s_port=%u,", + dataLen, + IPXHeader->Destination.Node [4],IPXHeader->Destination.Node [5], + IPXHeader->Destination.Socket[0],IPXHeader->Destination.Socket[1], + ntohs(*(unsigned short *)(IPXHeader->Destination.Socket))); + dumprid(IPXHeader->Destination.Node); + puts(")."); +#endif + + //toaddr.sin_family=AF_INET; + if (memcmp(broadcast_addr,IPXHeader->Destination.Node,6)==0){ +// ubyte brbuf[6]; + ip_addr brbuf; +// ushort port=htons(myport); +// //int j; +// memcpy(brbuf+0,IPXHeader->Destination.Node+0,4); +// //memcpy(brbuf+4,IPXHeader->Destination.Socket,2); +// memcpy(brbuf+4,&port,2); + brbuf.set(4,IPXHeader->Destination.Node,htons(myport)); + i=ip_sendtoca(brbuf,buf,2+dataLen); +// memcpy(&toaddr.sin_addr,IPXHeader->Destination.Node+0,4); +// toaddr.sin_port=*(unsigned short *)(IPXHeader->Destination.Socket); + ip_sendtoall(buf,2+dataLen); + }else { + i=ip_sendtoid(IPXHeader->Destination.Node,buf,2+dataLen); +// memcpy(&toaddr.sin_addr,hsr->addr[hsr->goodaddr],4); +// toaddr.sin_port=*(unsigned short *)(hsr->addr[hsr->goodaddr]+4); +//// toaddr.sin_port=*(unsigned short *)(IPXHeader->Destination.Node+4); + } + //toaddr.sin_port=htons(((short)ntohs(*(unsigned short *)(IPXHeader->Destination.Node+4)))+UDP_BASEPORT); +// toaddr.sin_port=*(unsigned short *)(IPXHeader->Destination.Socket); + +// i=sendto(mysock->fd,buf,2+dataLen, +// 0,(struct sockaddr *)&toaddr,sizeof(toaddr)); + return(i<1?-1:i-1); +} + +/* Here we will receive new packet to the given buffer. Both formats of packets + * are supported, we fallback to old format when first obsolete packet is seen. + * If the (valid) packet is received from unknown host, we will add it to our + * broadcasting list. FIXME: For now such autoconfigured hosts are NEVER removed. + */ + +static int ipx_ip_ReceivePacket(char *outbuf, int outbufsize, + struct ipx_recv_data *rd) { + int size; + size_t offs; + ip_addr *fromaddr; + //int i; + + if ((size=arch_ip_recvfrom(outbuf,outbufsize,rd))<0) + return -1; + + if (size<2) return -1; + + memcpy(&fromaddr,rd->src_node,sizeof(ip_addr*)); + + if (memcmp(outbuf+0,D1Xid,2)) { + if (memcmp(outbuf+0,D1Xcfgid,4)) { + mprintf((0,MSGHDR"no valid header\n")); + return -1; + } + { +/* ubyte buf[6]; + memcpy(buf,&fromaddr.sin_addr,4); + *(unsigned short *)(buf+4)=fromaddr.sin_port;*/ + //do stuff. +// fromaddr.set(4,rd->src_node,*(unsigned short*)(rd->src_node+4)); + ip_receive_cfg((ubyte*)outbuf+4,size-4,*fromaddr); + } + return 0; + } + else offs=2; + + /* Lace: (dst_socket & src_socket) should be network-byte-order by comment in include/ipx_drv.h */ + /* This behaviour presented here is broken. It is not used anywhere, so why bother? */ +/* rd->src_socket = ntohs(*(unsigned short *)(outbuf+offs)); + if (rd->src_socket != s->socket) { +#ifdef UDPDEBUG + msg(" - pkt was dropped (dst=%d,my=%d)",rd->src_socket,s->socket); +#endif + return -1; + }*/ +// rd->src_socket = s->socket; +// rd->dst_socket = s->socket; + + memmove(outbuf,outbuf+offs,size-(offs)); + size-=offs; + + rd->src_socket = myport; + rd->dst_socket = myport; + + rd->pkt_type = 0; +#ifdef UDPDEBUG + printf(MSGHDR "ReceivePacket: size=%d,from=",size); +// dumpraddr(rd->src_node); + fromaddr->dump(); + putchar('\n'); +#endif +/* ip_peer *p=peer_list.find_by_addr(*fromaddr); + if(p) + p->id.fillbuf(rd->src_node); + else + memset(rd->src_node,0,6);*/ + if (ip_my_addrs.hasaddr(*fromaddr)) + memcpy(rd->src_node,ipx_MyAddress+4,6); + else + memset(rd->src_node,0,6); + + return size; +} + +static int ipx_ip_general_PacketReady(void) { + //ip_handshake_frame();//handle handshake resending + peer_list.handshake_frame(); + return arch_ip_PacketReady(); +} + +static int ipx_ip_CheckReadyToJoin(ubyte *server, ubyte *node){ + if (Network_send_objects) return 0;//if we are currently letting someone else join, we don't know if this person can join ok. + + ip_peer *p=peer_list.find_byid(node); + if (!p || p->addr.goodaddr==NULL) + return 0; + ip_peer *np; + ip_handshake_relay *hsr; + int j; + int ok,nope=0; + + for (j=0;jid==node)continue;//don't tell them to talk to themselves. + + ok=0; + + hsr=p->find_relay(np->id); + if (!hsr){ + hsr=new ip_handshake_relay(np); + p->add_hs(hsr); + } + if (hsr->state==0) + ok++; + + hsr=np->find_relay(p->id); + if (!hsr){ + hsr=new ip_handshake_relay(p); + np->add_hs(hsr); + } + if (hsr->state==0) + ok++; + if (ok!=2) + nope++; + } + } + if (nope) + return 0; + + return 1; +} + +struct ipx_driver ipx_ip = { +// ipx_ip_GetMyAddress, + ipx_ip_OpenSocket, + ipx_ip_CloseSocket, + ipx_ip_SendPacket, + ipx_ip_ReceivePacket, + ipx_ip_general_PacketReady, + ipx_ip_CheckReadyToJoin, + 0, //save 4 bytes. udp/ip is completely inaccessable by the other methods, so we don't need to worry about compatibility. + NULL, //use the easier ones + NULL, //use the easier ones + NULL //use the easier ones +}; diff --git a/main/ipclient.h b/main/ipclient.h new file mode 100644 index 00000000..b6d1f6a5 --- /dev/null +++ b/main/ipclient.h @@ -0,0 +1,69 @@ +/* + * $Source: /cvs/cvsroot/d2x/main/ipclient.h,v $ + * $Revision: 1.1 $ + * $Author: bradleyb $ + * $Date: 2002-02-06 09:22:42 $ + * + * ipclient.h - udp/ip client code + * added 2000/02/07 Matt Mueller + * + * $Log: not supported by cvs2svn $ + * + */ + +#ifndef __IPCLIENT_H_ +#define __IPCLIENT_H_ + +#include +#include +#ifdef __cplusplus +extern "C"{ +#endif +#include "pstypes.h" +#include "ipx.h" +#include "ipx_drv.h" +void ip_sendtoall(char *buf,int len); +int ip_connect_manual(char *textaddr);//make it extern C so that it can be called from .c files. +//void ip_portshift(ubyte*qhbuf,const char *cs); + +int arch_ip_get_my_addr(ushort myport); +int arch_ip_open_socket(int port); +void arch_ip_close_socket(void); +int arch_ip_recvfrom(char *outbuf,int outbufsize,struct ipx_recv_data *rd); +int arch_ip_PacketReady(void); +int arch_ip_queryhost(ip_addr *addr,char *buf,ushort baseport); + +int ipx_ip_GetMyAddress(void); + +extern int myport; + +extern int baseport; + + +#ifdef __cplusplus +} +#endif + + +#define MSGHDR "IPX_ip: " + +static inline void msg(const char *fmt,...) +{ + va_list ap; + fputs(MSGHDR,stdout); + va_start(ap,fmt); + vprintf(fmt,ap); + va_end(ap); + putchar('\n'); +} + +#define FAIL(m...) do { msg(#m); return -1; } while (0) + +static inline void chk(void *p){ + if (p) return; + msg("FATAL: Virtual memory exhausted!"); + exit(EXIT_FAILURE); +} + + +#endif diff --git a/main/ipserver.cpp b/main/ipserver.cpp new file mode 100644 index 00000000..b538e03c --- /dev/null +++ b/main/ipserver.cpp @@ -0,0 +1,86 @@ +/* + * $Source: /cvs/cvsroot/d2x/main/ipserver.cpp,v $ + * $Revision: 1.1 $ + * $Author: bradleyb $ + * $Date: 2002-02-06 09:22:42 $ + * + * ipserver.cpp - udp/ip dedicated gamelist server + * added 2000/02/07 Matt Mueller + * + * $Log: not supported by cvs2svn $ + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "ip_base.h" + +extern "C"{ +#include "error.h" +#include "args.h" +#include "u_mem.h" +} + +unsigned char ipx_MyAddress[10]; + +int ipx_general_PacketReady(int fd) { + fd_set set; + struct timeval tv; + + FD_ZERO(&set); + FD_SET(fd, &set); + tv.tv_usec = 50000;//50 ms + tv.tv_sec = 0; + if (select(fd + 1, &set, NULL, NULL, &tv) > 0) + return 1; + else + return 0; +} + +void ip_server_mainloop(void){ + struct ipx_recv_data rd; + int size; + char buf[1500]; + ip_addr *fromaddr; +// fix curtime; + while (1){ + while (arch_ip_PacketReady()) { + if ((size = arch_ip_recvfrom(buf, 1500, &rd)) > 4) { + memcpy(&fromaddr,rd.src_node,sizeof(ip_addr*)); + if (memcmp(buf,D1Xcfgid,4)==0){ + ip_receive_cfg((ubyte*)buf+4,size-4,*fromaddr); + } + } + } + peer_list.handshake_frame(); +// curtime=timer_get_approx_seconds(); + } +} + +void int_handler(int s){ + exit(1); +} + +int main(int argc,char **argv){ + error_init(NULL); + signal(SIGINT,int_handler);//make ctrl-c do cleanup stuff. + InitArgs(argc,argv); +#ifndef NDEBUG + if ( FindArg( "-showmeminfo" ) ) + show_mem_info = 1; // Make memory statistics show +#endif + myport=UDP_SERV_BASEPORT; + if(arch_ip_open_socket(myport)) + return 1; + atexit(arch_ip_close_socket); + if (ipx_ip_GetMyAddress()) + return 2; + ip_server_mainloop(); +} -- 2.39.2