moved to main/
[btb/d2x.git] / arch / linux / arch_ip.cpp
1 /*
2  * $Source: /cvs/cvsroot/d2x/arch/linux/arch_ip.cpp,v $
3  * $Revision: 1.2 $
4  * $Author: bradleyb $
5  * $Date: 2002-02-15 06:41:41 $
6  *
7  * arch_ip.cpp - arch specific udp/ip code.  (linux ver)
8  * added 2000/02/07 Matt Mueller (some code borrowed from ipx_udp.c)
9  *
10  * $Log: not supported by cvs2svn $
11  * Revision 1.1  2002/02/06 09:22:41  bradleyb
12  * Adding d1x network code
13  *
14  *
15  */
16
17 #ifdef HAVE_CONFIG_H
18 #include <conf.h>
19 #endif
20
21 #include <string.h>
22 #include <netinet/in.h> /* for htons & co. */
23 #include <unistd.h>
24 #include <netdb.h>
25 #include <stdlib.h>
26 #include <net/if.h>
27 #include <sys/ioctl.h>
28 #include <ctype.h>
29 extern "C" {
30 #include "ipx_drv.h"
31 #include "pstypes.h"
32 #include "mono.h"
33 //#include "multi.h"
34 }
35
36 #include "ip_base.h"
37 #include "ipclient.h"
38
39 static int mysock=-1;
40
41 /* Do hostname resolve on name "buf" and return the address in buffer "qhbuf".
42  */
43 int arch_ip_queryhost(ip_addr *addr,char *buf,u_short baseport)
44 {
45         struct hostent *he;
46         char *s;
47         char c=0;
48         u_short p;
49
50         if ((s=strrchr(buf,':'))) {
51                 c=*s;
52                 *s='\0';
53                 p=ip_portshift(baseport,s+1);
54         }
55         else p=ip_portshift(baseport,NULL);//memset(qhbuf+4,0,2);
56         he=gethostbyname((char *)buf);
57         if (s) *s=c;
58         if (!he) {
59                 msg("Error resolving my hostname \"%s\"",buf);
60                 return -1; //(NULL);
61         }
62         if (he->h_addrtype!=AF_INET || he->h_length!=4) {
63                 msg("Error parsing resolved my hostname \"%s\"",buf);
64                 return -1;//(NULL);
65         }
66         if (!*he->h_addr_list) {
67                 msg("My resolved hostname \"%s\" address list empty",buf);
68                 return -1;//(NULL);
69         }
70         addr->set(4,(u_char*)*he->h_addr_list,p);
71 //      memcpy(qhbuf,(*he->h_addr_list),4);
72 //      return(qhbuf);
73         return 0;
74 }
75
76 #ifdef UDPDEBUG
77 /* Like dumpraddr() but for structure "sockaddr_in"
78  */
79
80 static void dumpaddr(struct sockaddr_in *sin)
81 {
82         unsigned short ports;
83         u_char qhbuf[6];
84
85         memcpy(qhbuf+0,&sin->sin_addr,4);
86         //ports=htons(((short)ntohs(sin->sin_port))-UDP_BASEPORT);
87         ports=sin->sin_port;
88         memcpy(qhbuf+4,&ports,2);
89         dumpraddr(qhbuf);
90 }
91 #endif
92
93
94 int ip_sendtoca(ip_addr addr,const void *buf,int len){
95         struct sockaddr_in toaddr;
96         if (addr.addrlen()!=4) return 0;//not handled yet
97         toaddr.sin_family=AF_INET;
98         memcpy(&toaddr.sin_addr,addr.addr,4);
99         toaddr.sin_port=*(unsigned short *)(addr.addr+4);
100 #ifdef UDPDEBUG
101         con_printf(CON_DEBUG, MSGHDR "sendtoca((%d) ",len);
102         //dumpraddr(addr.addr);
103         addr.dump();
104         con_printf(CON_DEBUG, ").\n");
105 #endif
106         return sendto(mysock,buf,len,0,(struct sockaddr *)&toaddr,sizeof(toaddr));
107 }
108
109 /* Find as much as MAX_BRDINTERFACES during local iface autoconfiguration.
110  * Note that more interfaces can be added during manual configuration
111  * or host-received-packet autoconfiguration
112  */
113
114 #define MAX_BRDINTERFACES 16
115
116 /* We require the interface to be UP and RUNNING to accept it.
117  */
118
119 #define IF_REQFLAGS (IFF_UP|IFF_RUNNING)
120
121 /* We reject any interfaces declared as LOOPBACK type.
122  */
123 #define IF_NOTFLAGS (IFF_LOOPBACK)
124
125 int arch_ip_get_my_addr(u_short myport){
126         unsigned cnt=MAX_BRDINTERFACES,i,j;
127         struct ifconf ifconf;
128         int sock;
129         struct sockaddr_in *sinp;
130         ip_addr addr;
131
132         if ((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))<0)
133                 FAIL("Creating socket() failure during broadcast detection: %m");
134
135 #ifdef SIOCGIFCOUNT
136         if (ioctl(sock,SIOCGIFCOUNT,&cnt))
137         { /* msg("Getting iterface count error: %m"); */ }
138         else
139                 cnt=cnt*2+2;
140 #endif
141
142         chk(ifconf.ifc_req=(struct ifreq *)alloca((ifconf.ifc_len=cnt*sizeof(struct ifreq))));
143         if (ioctl(sock,SIOCGIFCONF,&ifconf)||ifconf.ifc_len%sizeof(struct ifreq)) {
144                 close(sock);
145                 FAIL("ioctl(SIOCGIFCONF) failure during broadcast detection: %m");
146         }
147         cnt=ifconf.ifc_len/sizeof(struct ifreq);
148         //      chk(broads=malloc(cnt*sizeof(*broads)));
149         //      broadsize=cnt;
150         for (i=j=0;i<cnt;i++) {
151                 if (ioctl(sock,SIOCGIFFLAGS,ifconf.ifc_req+i)) {
152                         close(sock);
153                         FAIL("ioctl(udp,\"%s\",SIOCGIFFLAGS) error: %m",ifconf.ifc_req[i].ifr_name);
154                 }
155                 if (((ifconf.ifc_req[i].ifr_flags&IF_REQFLAGS)!=IF_REQFLAGS)||
156                                 (ifconf.ifc_req[i].ifr_flags&IF_NOTFLAGS))
157                         continue;
158                 if (ioctl(sock,SIOCGIFDSTADDR,ifconf.ifc_req+i)) {
159                         close(sock);
160                         FAIL("ioctl(udp,\"%s\",SIOCGIFDSTADDR) error: %m",ifconf.ifc_req[i].ifr_name);
161                 }
162
163                 sinp=(struct sockaddr_in *)&ifconf.ifc_req[i].ifr_netmask  ;
164                 if (sinp->sin_family!=AF_INET) continue;
165                 addr.set(4,(ubyte*)&sinp->sin_addr,htons(myport));
166 #ifdef UDPDEBUG
167                 con_printf(CON_DEBUG, MSGHDR"added if ");
168                 addr.dump();
169                 con_printf(CON_DEBUG, "\n");
170 #endif
171                 ip_my_addrs.add(addr);
172         }
173         return(0);
174 }
175
176 /*int arch_ip_get_my_addr(u_short myport){
177         char buf[256];
178         if (gethostname(buf,sizeof(buf))) FAIL("Error getting my hostname");
179
180         ip_addr ip;
181         if (ip.dns(buf,myport)) FAIL("Error querying my own hostname \"%s\"",buf);
182         ip_my_addrs.add(ip);
183         return 0;
184 }*/
185 int arch_ip_open_socket(int port){
186         struct sockaddr_in sin;
187         int val_one=1;
188         if ((mysock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0) {
189                 mysock = -1;
190                 FAIL("socket() creation failed on port %d: %m",port);
191         }
192         if (setsockopt(mysock,SOL_SOCKET,SO_BROADCAST,&val_one,sizeof(val_one))) {
193                 if (close(mysock)) msg("close() failed during error recovery: %m");
194                 mysock=-1;
195                 FAIL("setsockopt(SO_BROADCAST) failed: %m");
196         }
197         sin.sin_family=AF_INET;
198         sin.sin_addr.s_addr=htonl(INADDR_ANY);
199         sin.sin_port=htons(port);
200
201         if (bind(mysock,(struct sockaddr *)&sin,sizeof(sin))) {
202                 if (close(mysock)) msg("close() failed during error recovery: %m");
203                 mysock=-1;
204                 FAIL("bind() to UDP port %d failed: %m",port);
205         }
206
207         return 0;
208 }
209 void arch_ip_close_socket(void) {
210         if (mysock<0) {
211                 msg("close w/o open");
212                 return;
213         }
214         if (close(mysock))
215                 msg("close() failed on CloseSocket D1X ip socket %m");
216         mysock=-1;
217 }
218 int arch_ip_recvfrom(char*outbuf,int outbufsize,struct ipx_recv_data *rd){
219         struct sockaddr_in fromaddr;
220         socklen_t fromaddrsize=sizeof(fromaddr);
221         int size;
222         static ip_addr ip_fromaddr;
223         ip_addr *vptr=&ip_fromaddr;
224
225         if ((size=recvfrom(mysock,outbuf,outbufsize,0,(struct sockaddr *)&fromaddr,&fromaddrsize))<0)
226                 return -1;
227
228         if (fromaddr.sin_family!=AF_INET) return -1;
229
230 #ifdef UDPDEBUG
231         con_printf(CON_DEBUG, MSGHDR "recvfrom((%d-2=%d),",size,size-2);
232         dumpaddr(&fromaddr);
233         con_printf(CON_DEBUG, ").\n");
234 #endif
235
236         ip_fromaddr.set(4,(u_char*)&fromaddr.sin_addr,fromaddr.sin_port);
237
238         memcpy(rd->src_node,&vptr,sizeof(ip_addr*));
239         return size;
240 }
241 int arch_ip_PacketReady(void) {
242         return ipx_general_PacketReady(mysock);
243 }