DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/ipxserver.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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, &regHeader.dest.addr.byIP);
00134         SDLNet_Write16(0x2, regHeader.dest.socket);
00135 
00136         SDLNet_Write32(1, regHeader.src.network);
00137         PackIP(ipxServerIp, &regHeader.src.addr.byIP);
00138         SDLNet_Write16(0x2, regHeader.src.socket);
00139         regHeader.transControl = 0;
00140 
00141         regPacket.data = (Uint8 *)&regHeader;
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,&regPacket);
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 
00230 // save state support
00231 void *IPX_ServerLoop_PIC_Timer = (void*)IPX_ServerLoop;
00232 
00233 #endif