add IPv4 multicasting support
[btb/d2x.git] / arch / win32 / ipx_win.c
1 /* $Id: ipx_win.c,v 1.7 2003-10-12 09:17:47 btb Exp $ */
2
3 /*
4  *
5  * IPX driver using BSD style sockets
6  * Mostly taken from dosemu
7  *
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include <conf.h>
12 #endif
13
14 #include <string.h>
15 #include <stdlib.h>
16 #include <winsock.h>
17 #include <wsipx.h>
18 #include <errno.h>
19 #include <stdio.h>
20
21 #include "ipx_drv.h"
22
23 #define _do_mprintf(n, format, args...) printf(format, ## args)
24 #define mprintf(args) _do_mprintf args
25
26 //#define n_printf(format, args...) mprintf((1, format, ## args))
27
28 static int ipx_win_GetMyAddress( void )
29 {
30 #if 0
31   int sock;
32   struct sockaddr_ipx ipxs;
33   struct sockaddr_ipx ipxs2;
34   int len;
35   int i;
36   
37 //  sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
38   sock=socket(AF_IPX,SOCK_DGRAM,0);
39
40   if(sock==-1)
41   {
42     mprintf((1,"IPX: could not open socket in GetMyAddress\n"));
43     return(-1);
44   }
45
46   /* bind this socket to network 0 */  
47   ipxs.sa_family=AF_IPX;
48 #ifdef IPX_MANUAL_ADDRESS
49   memcpy(ipxs.sa_netnum, ipx_MyAddress, 4);
50 #else
51   memset(ipxs.sa_netnum, 0, 4);
52 #endif  
53   ipxs.sa_socket=0;
54   
55   if(bind(sock,(struct sockaddr *)&ipxs,sizeof(ipxs))==-1)
56   {
57     mprintf((1,"IPX: could bind to network 0 in GetMyAddress\n"));
58     closesocket( sock );
59     return(-1);
60   }
61   
62   len = sizeof(ipxs2);
63   if (getsockname(sock,(struct sockaddr *)&ipxs2,&len) < 0) {
64     mprintf((1,"IPX: could not get socket name in GetMyAddress\n"));
65     closesocket( sock );
66     return(-1);
67   }
68
69   memcpy(ipx_MyAddress, ipxs2.sa_netnum, 4);
70   for (i = 0; i < 6; i++) {
71     ipx_MyAddress[4+i] = ipxs2.sa_nodenum[i];
72   }
73 /*  printf("My address is 0x%.4X:%.2X.%.2X.%.2X.%.2X.%.2X.%.2X\n", *((int *)ipxs2.sa_netnum), ipxs2.sa_nodenum[0],
74   ipxs2.sa_nodenum[1], ipxs2.sa_nodenum[2], ipxs2.sa_nodenum[3], ipxs2.sa_nodenum[4], ipxs2.sa_nodenum[5]);*/
75
76     closesocket( sock );
77
78 #endif
79   return(0);
80 }
81
82 static int ipx_win_OpenSocket(ipx_socket_t *sk, int port)
83 {
84   int sock;                     /* sock here means Linux socket handle */
85   int opt;
86   struct sockaddr_ipx ipxs;
87   int len;
88   struct sockaddr_ipx ipxs2;
89
90   /* DANG_FIXTHIS - kludge to support broken linux IPX stack */
91   /* need to convert dynamic socket open into a real socket number */
92 /*  if (port == 0) {
93     mprintf((1,"IPX: using socket %x\n", nextDynamicSocket));
94     port = nextDynamicSocket++;
95   }
96 */
97   /* do a socket call, then bind to this port */
98 //  sock = socket(AF_IPX, SOCK_DGRAM, PF_IPX);
99 //  sock = socket(AF_IPX, SOCK_DGRAM, 0);
100   sock = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);//why NSPROTO_IPX?  I looked in the quake source and thats what they used. :) -MPM  (on w2k 0 and PF_IPX don't work)
101   if (sock == -1) {
102     mprintf((1,"IPX: could not open IPX socket.\n"));
103     return -1;
104   }
105
106
107   opt = 1;
108   /* Permit broadcast output */
109   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
110                  (const char *)&opt, sizeof(opt)) == -1) {
111     mprintf((1,"IPX: could not set socket option for broadcast.\n"));
112     return -1;
113   }
114   ipxs.sa_family = AF_IPX;
115   memcpy(ipxs.sa_netnum, ipx_MyAddress, 4);
116 //  *((unsigned int *)&ipxs.sa_netnum[0]) = *((unsigned int *)&ipx_MyAddress[0]);
117 /*  ipxs.sa_netnum = htonl(MyNetwork); */
118   memset(ipxs.sa_nodenum, 0, 6);
119 //  bzero(ipxs.sa_nodenum, 6);  /* Please fill in my node name */
120   ipxs.sa_socket = htons((short)port);
121
122   /* now bind to this port */
123   if (bind(sock, (struct sockaddr *) &ipxs, sizeof(ipxs)) == -1) {
124     mprintf((1,"IPX: could not bind socket to address\n"));
125     closesocket( sock );
126     return -1;
127   }
128   
129 //  if( port==0 ) {
130 //    len = sizeof(ipxs2);
131 //    if (getsockname(sock,(struct sockaddr *)&ipxs2,&len) < 0) {
132 //       //n_printf("IPX: could not get socket name in IPXOpenSocket\n");
133 //     closesocket( sock );
134 //      return -1;
135 //    } else {
136 //      port = htons(ipxs2.sa_socket);
137 //      //n_printf("IPX: opened dynamic socket %04x\n", port);
138 //    }
139   len = sizeof(ipxs2);
140   if (getsockname(sock,(struct sockaddr *)&ipxs2,&len) < 0) {
141     mprintf((1,"IPX: could not get socket name in IPXOpenSocket\n"));
142     closesocket( sock );
143     return -1;
144   } 
145   if (port == 0) {
146     port = htons(ipxs2.sa_socket);
147     mprintf((1,"IPX: opened dynamic socket %04x\n", port));
148   }
149
150   memcpy(ipx_MyAddress, ipxs2.sa_netnum, 4);
151   memcpy(ipx_MyAddress + 4, ipxs2.sa_nodenum, 6);
152
153   sk->fd = sock;
154   sk->socket = port;
155   return 0;
156 }
157
158 static void ipx_win_CloseSocket(ipx_socket_t *mysock) {
159   /* now close the file descriptor for the socket, and free it */
160   mprintf((1,"IPX: closing file descriptor on socket %x\n", mysock->socket));
161   closesocket(mysock->fd);
162 }
163
164 static int ipx_win_SendPacket(ipx_socket_t *mysock, IPXPacket_t *IPXHeader,
165  u_char *data, int dataLen) {
166   struct sockaddr_ipx ipxs;
167  
168   ipxs.sa_family = AF_IPX;
169   /* get destination address from IPX packet header */
170   memcpy(&ipxs.sa_netnum, IPXHeader->Destination.Network, 4);
171   /* if destination address is 0, then send to my net */
172   if ((*(unsigned int *)&ipxs.sa_netnum) == 0) {
173     (*(unsigned int *)&ipxs.sa_netnum)= *((unsigned int *)&ipx_MyAddress[0]);
174 /*  ipxs.sa_netnum = htonl(MyNetwork); */
175   }
176   memcpy(&ipxs.sa_nodenum, IPXHeader->Destination.Node, 6);
177   memcpy(&ipxs.sa_socket, IPXHeader->Destination.Socket, 2);
178 //  ipxs.sa_type = IPXHeader->PacketType;
179   /*    ipxs.sipx_port=htons(0x452); */
180   return sendto(mysock->fd, data, dataLen, 0,
181              (struct sockaddr *) &ipxs, sizeof(ipxs));
182 }
183
184 static int ipx_win_ReceivePacket(ipx_socket_t *s, char *buffer, int bufsize, 
185  struct ipx_recv_data *rd) {
186         int sz, size;
187         struct sockaddr_ipx ipxs;
188  
189         sz = sizeof(ipxs);
190         if ((size = recvfrom(s->fd, buffer, bufsize, 0,
191              (struct sockaddr *) &ipxs, &sz)) <= 0)
192              return size;
193         memcpy(rd->src_network, ipxs.sa_netnum, 4);
194         memcpy(rd->src_node, ipxs.sa_nodenum, 6);
195         rd->src_socket = ipxs.sa_socket;
196         rd->dst_socket = s->socket;
197 //      rd->pkt_type = ipxs.sipx_type;
198   
199         return size;
200 }
201
202 struct ipx_driver ipx_win = {
203         ipx_win_GetMyAddress,
204         ipx_win_OpenSocket,
205         ipx_win_CloseSocket,
206         ipx_win_SendPacket,
207         ipx_win_ReceivePacket,
208         ipx_general_PacketReady,
209         NULL,   // InitNetgameAuxData
210         NULL,   // HandleNetgameAuxData
211         NULL,   // HandleLeaveGame
212         NULL    // SendGamePack
213 };