DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include "dosbox.h" 00021 00022 #if C_IPX 00023 00024 #include "dosbox.h" 00025 #include "ipxserver.h" 00026 #include "timer.h" 00027 #include <stdlib.h> 00028 #include <string.h> 00029 #include "ipx.h" 00030 00031 IPaddress ipxServerIp; // IPAddress for server's listening port 00032 UDPsocket ipxServerSocket; // Listening server socket 00033 00034 packetBuffer connBuffer[SOCKETTABLESIZE]; 00035 00036 Bit8u inBuffer[IPXBUFFERSIZE]; 00037 IPaddress ipconn[SOCKETTABLESIZE]; // Active TCP/IP connection 00038 UDPsocket tcpconn[SOCKETTABLESIZE]; // Active TCP/IP connections 00039 SDLNet_SocketSet serverSocketSet; 00040 TIMER_TickHandler* serverTimer; 00041 00042 Bit8u packetCRC(Bit8u *buffer, Bit16u bufSize) { 00043 Bit8u tmpCRC = 0; 00044 Bit16u i; 00045 for(i=0;i<bufSize;i++) { 00046 tmpCRC ^= *buffer; 00047 buffer++; 00048 } 00049 return tmpCRC; 00050 } 00051 00052 /* 00053 static void closeSocket(Bit16u sockidx) { 00054 Bit32u host; 00055 00056 host = ipconn[sockidx].host; 00057 LOG_MSG("IPXSERVER: %d.%d.%d.%d disconnected", CONVIP(host)); 00058 00059 SDLNet_TCP_DelSocket(serverSocketSet,tcpconn[sockidx]); 00060 SDLNet_TCP_Close(tcpconn[sockidx]); 00061 connBuffer[sockidx].connected = false; 00062 connBuffer[sockidx].waitsize = false; 00063 } 00064 */ 00065 00066 static void sendIPXPacket(Bit8u *buffer, Bit16s bufSize) { 00067 Bit16u srcport, destport; 00068 Bit32u srchost, desthost; 00069 Bit16u i; 00070 Bits result; 00071 UDPpacket outPacket; 00072 outPacket.channel = -1; 00073 outPacket.data = buffer; 00074 outPacket.len = bufSize; 00075 outPacket.maxlen = bufSize; 00076 IPXHeader *tmpHeader; 00077 tmpHeader = (IPXHeader *)buffer; 00078 00079 srchost = tmpHeader->src.addr.byIP.host; 00080 desthost = tmpHeader->dest.addr.byIP.host; 00081 00082 srcport = tmpHeader->src.addr.byIP.port; 00083 destport = tmpHeader->dest.addr.byIP.port; 00084 00085 00086 if(desthost == 0xffffffff) { 00087 // Broadcast 00088 for(i=0;i<SOCKETTABLESIZE;i++) { 00089 if(connBuffer[i].connected && ((ipconn[i].host != srchost)||(ipconn[i].port!=srcport))) { 00090 outPacket.address = ipconn[i]; 00091 result = SDLNet_UDP_Send(ipxServerSocket,-1,&outPacket); 00092 if(result == 0) { 00093 LOG_MSG("IPXSERVER: %s", SDLNet_GetError()); 00094 continue; 00095 } 00096 //LOG_MSG("IPXSERVER: Packet of %d bytes sent from %d.%d.%d.%d to %d.%d.%d.%d (BROADCAST) (%x CRC)", bufSize, CONVIP(srchost), CONVIP(ipconn[i].host), packetCRC(&buffer[30], bufSize-30)); 00097 } 00098 } 00099 } else { 00100 // Specific address 00101 for(i=0;i<SOCKETTABLESIZE;i++) { 00102 if((connBuffer[i].connected) && (ipconn[i].host == desthost) && (ipconn[i].port == destport)) { 00103 outPacket.address = ipconn[i]; 00104 result = SDLNet_UDP_Send(ipxServerSocket,-1,&outPacket); 00105 if(result == 0) { 00106 LOG_MSG("IPXSERVER: %s", SDLNet_GetError()); 00107 continue; 00108 } 00109 //LOG_MSG("IPXSERVER: Packet sent from %d.%d.%d.%d to %d.%d.%d.%d", CONVIP(srchost), CONVIP(desthost)); 00110 } 00111 } 00112 } 00113 00114 00115 00116 00117 } 00118 00119 bool IPX_isConnectedToServer(Bits tableNum, IPaddress ** ptrAddr) { 00120 if(tableNum >= SOCKETTABLESIZE) return false; 00121 *ptrAddr = &ipconn[tableNum]; 00122 return connBuffer[tableNum].connected; 00123 } 00124 00125 static void ackClient(IPaddress clientAddr) { 00126 IPXHeader regHeader; 00127 UDPpacket regPacket; 00128 00129 SDLNet_Write16(0xffff, regHeader.checkSum); 00130 SDLNet_Write16(sizeof(regHeader), regHeader.length); 00131 00132 SDLNet_Write32(0, regHeader.dest.network); 00133 PackIP(clientAddr, ®Header.dest.addr.byIP); 00134 SDLNet_Write16(0x2, regHeader.dest.socket); 00135 00136 SDLNet_Write32(1, regHeader.src.network); 00137 PackIP(ipxServerIp, ®Header.src.addr.byIP); 00138 SDLNet_Write16(0x2, regHeader.src.socket); 00139 regHeader.transControl = 0; 00140 00141 regPacket.data = (Uint8 *)®Header; 00142 regPacket.len = sizeof(regHeader); 00143 regPacket.maxlen = sizeof(regHeader); 00144 regPacket.address = clientAddr; 00145 // Send registration string to client. If client doesn't get this, client will not be registered 00146 SDLNet_UDP_Send(ipxServerSocket,-1,®Packet); 00147 } 00148 00149 static void IPX_ServerLoop() { 00150 UDPpacket inPacket; 00151 IPaddress tmpAddr; 00152 00153 //char regString[] = "IPX Register\0"; 00154 00155 Bit16u i; 00156 Bit32u host; 00157 Bits result; 00158 00159 inPacket.channel = -1; 00160 inPacket.data = &inBuffer[0]; 00161 inPacket.maxlen = IPXBUFFERSIZE; 00162 00163 00164 result = SDLNet_UDP_Recv(ipxServerSocket, &inPacket); 00165 if (result != 0) { 00166 // Check to see if incoming packet is a registration packet 00167 // For this, I just spoofed the echo protocol packet designation 0x02 00168 IPXHeader *tmpHeader; 00169 tmpHeader = (IPXHeader *)&inBuffer[0]; 00170 00171 // Check to see if echo packet 00172 if(SDLNet_Read16(tmpHeader->dest.socket) == 0x2) { 00173 // Null destination node means its a server registration packet 00174 if(tmpHeader->dest.addr.byIP.host == 0x0) { 00175 UnpackIP(tmpHeader->src.addr.byIP, &tmpAddr); 00176 for(i=0;i<SOCKETTABLESIZE;i++) { 00177 if(!connBuffer[i].connected) { 00178 // Use prefered host IP rather than the reported source IP 00179 // It may be better to use the reported source 00180 ipconn[i] = inPacket.address; 00181 00182 connBuffer[i].connected = true; 00183 host = ipconn[i].host; 00184 LOG_MSG("IPXSERVER: Connect from %d.%d.%d.%d", CONVIP(host)); 00185 ackClient(inPacket.address); 00186 return; 00187 } else { 00188 if((ipconn[i].host == tmpAddr.host) && (ipconn[i].port == tmpAddr.port)) { 00189 00190 LOG_MSG("IPXSERVER: Reconnect from %d.%d.%d.%d", CONVIP(tmpAddr.host)); 00191 // Update anonymous port number if changed 00192 ipconn[i].port = inPacket.address.port; 00193 ackClient(inPacket.address); 00194 return; 00195 } 00196 } 00197 00198 } 00199 } 00200 } 00201 00202 // IPX packet is complete. Now interpret IPX header and send to respective IP address 00203 sendIPXPacket((Bit8u *)inPacket.data, inPacket.len); 00204 } 00205 } 00206 00207 void IPX_StopServer() { 00208 TIMER_DelTickHandler(&IPX_ServerLoop); 00209 SDLNet_UDP_Close(ipxServerSocket); 00210 } 00211 00212 bool IPX_StartServer(Bit16u portnum) { 00213 Bit16u i; 00214 00215 if(!SDLNet_ResolveHost(&ipxServerIp, NULL, portnum)) { 00216 00217 //serverSocketSet = SDLNet_AllocSocketSet(SOCKETTABLESIZE); 00218 ipxServerSocket = SDLNet_UDP_Open(portnum); 00219 if(!ipxServerSocket) return false; 00220 00221 for(i=0;i<SOCKETTABLESIZE;i++) connBuffer[i].connected = false; 00222 00223 TIMER_AddTickHandler(&IPX_ServerLoop); 00224 return true; 00225 } 00226 return false; 00227 } 00228 00229 #endif