예제 #1
0
void EncodeClassName( char *name, char *identifier )
{
    RakNet::BitStream bitStream;
    int index = 0;
    unsigned char byte;

    while ( index < MAXIMUM_CLASS_IDENTIFIER_LENGTH - 1 )
    {
        if ( name[ index ] == 0 )
            break;

        // This should generate a unique identifier for any realistic class name that is 5/8th the length of the actual name and weakly encrypts and compresses it
        if ( name[ index ] >= 'a' && name[ index ] <= 'z' )
            byte = name[ index ] - 'a';
        else if ( name[ index ] >= 'A' && name[ index ] <= 'Z' )
            byte = name[ index ] - 'A';
        else if ( name[ index ] >= '0' && name[ index ] <= '9' )
            byte = name[ index ] - '0';
        else
            byte = name[ index ] << 3;

        bitStream.WriteBits( ( unsigned char* ) & byte, 5 );

        index++;
    }

#ifdef _DEBUG
    memset( identifier, 0, MAXIMUM_CLASS_IDENTIFIER_LENGTH );

#endif

    identifier[ 0 ] = ( char ) ( bitStream.GetNumberOfBytesUsed() );

    memcpy( identifier + 1, bitStream.GetData(), bitStream.GetNumberOfBytesUsed() );
}
예제 #2
0
void Server::initialSync(const RakNet::SystemAddress &sa,running_machine *machine)
{
    unsigned char checksum = 0;

    waitingForClientCatchup=true;
    machine->osd().pauseAudio(true);

    int syncBytes;
    {
    RakNet::BitStream uncompressedStream;

    uncompressedStream.Write(startupTime);

    uncompressedStream.Write(globalCurtime);

    if(getSecondsBetweenSync())
    {
        while(memoryBlocksLocked)
        {
            ;
        }
        memoryBlocksLocked=true;
        cout << "IN CRITICAL SECTION\n";
        cout << "SERVER: Sending initial snapshot\n";

        int numBlocks = int(blocks.size());
        cout << "NUMBLOCKS: " << numBlocks << endl;
        uncompressedStream.Write(numBlocks);

        // NOTE: The server must send stale data to the client for the first time
        // So that future syncs will be accurate
        for(int blockIndex=0; blockIndex<int(initialBlocks.size()); blockIndex++)
        {
            //cout << "BLOCK SIZE FOR INDEX " << blockIndex << ": " << staleBlocks[blockIndex].size << endl;
            uncompressedStream.Write(initialBlocks[blockIndex].size);

            cout << "BLOCK " << blockIndex << ": ";
            for(int a=0; a<staleBlocks[blockIndex].size; a++)
            {
                checksum = checksum ^ staleBlocks[blockIndex].data[a];
                //cout << int(staleBlocks[blockIndex].data[a]) << ' ';
                unsigned char value = initialBlocks[blockIndex].data[a] ^ staleBlocks[blockIndex].data[a];
                uncompressedStream.WriteBits(&value,8);
            }
            cout << int(checksum) << endl;
        }
    }

    for(
        map<int,vector< string > >::iterator it = peerInputs.begin();
        it != peerInputs.end();
        it++
    )
    {
        uncompressedStream.Write(it->first);
        uncompressedStream.Write(int(oldPeerInputs[it->first].size()) + int(it->second.size()));
        for(int a=0; a<(int)it->second.size(); a++)
        {
            uncompressedStream.Write(int(it->second[a].length()));
            uncompressedStream.WriteBits((const unsigned char*)it->second[a].c_str(),it->second[a].length()*8);

            for(int b=0;b<it->second[a].length();b++)
            {
                checksum = checksum ^ it->second[a][b];
            }
        }
        for(int a=0; a<int(oldPeerInputs[it->first].size()); a++)
        {
            uncompressedStream.Write(int(oldPeerInputs[it->first][a].length()));
            uncompressedStream.WriteBits((const unsigned char*)oldPeerInputs[it->first][a].c_str(),oldPeerInputs[it->first][a].length()*8);

            for(int b=0;b<oldPeerInputs[it->first][a].length();b++)
            {
                checksum = checksum ^ oldPeerInputs[it->first][a][b];
            }
        }
    }
    uncompressedStream.Write(int(-1));
    uncompressedStream.Write(checksum);
    cout << "CHECKSUM: " << int(checksum) << endl;

    if(uncompressedBufferSize<uncompressedStream.GetNumberOfBytesUsed()+sizeof(int))
    {
        uncompressedBufferSize = uncompressedStream.GetNumberOfBytesUsed()+sizeof(int);
	free(uncompressedBuffer);
        uncompressedBuffer = (unsigned char*)malloc(uncompressedBufferSize);
        if(!uncompressedBuffer)
        {
            cout << __FILE__ << ":" << __LINE__ << " OUT OF MEMORY\n";
            exit(1);
        }
    }
    syncBytes = uncompressedStream.GetNumberOfBytesUsed();
    memcpy(uncompressedBuffer,uncompressedStream.GetData(),uncompressedStream.GetNumberOfBytesUsed());

    int uncompressedStateSize = (int)uncompressedStream.GetNumberOfBytesUsed();
    printf("INITIAL UNCOMPRESSED STATE SIZE: %d\n",uncompressedStateSize);
    }

    cout << "PUTTING NVRAM AT LOCATION " << syncBytes << endl;

	// open the file; if it exists, call everyone to read from it
	emu_file file(machine->options().nvram_directory(), OPEN_FLAG_READ);
	if (file.open(machine->basename(), ".nv") == FILERR_NONE && file.size()<=1024*1024*64) //Don't bother sending huge NVRAM's
    {
        int nvramSize = file.size();
        if(uncompressedBufferSize<syncBytes+sizeof(int)+nvramSize)
        {
            uncompressedBufferSize = syncBytes+sizeof(int)+nvramSize;
	    free(uncompressedBuffer);
            uncompressedBuffer = (unsigned char*)malloc(uncompressedBufferSize);
            if(!uncompressedBuffer)
            {
                cout << __FILE__ << ":" << __LINE__ << " OUT OF MEMORY\n";
                exit(1);
            }
        }
        cout << "SENDING NVRAM OF SIZE: " << nvramSize << endl;
        memcpy(uncompressedBuffer+syncBytes,&nvramSize,sizeof(int));
        file.read(uncompressedBuffer+syncBytes+sizeof(int),nvramSize);
        file.close();
        syncBytes += sizeof(int) + nvramSize;
    }
	else
	{
	    int dummy=0;
        memcpy(uncompressedBuffer+syncBytes,&dummy,sizeof(int));
        syncBytes += sizeof(int);
	}

    cout << "BYTES USED: " << syncBytes << endl;

    //The application should ensure that this value be at least (sourceLen 1.001) + 12.
    //JJG: Doing more than that to account for header and provide some padding
    //vector<unsigned char> compressedInitialSyncBuffer(
            //sizeof(int)*2 + lzmaGetMaxCompressedSize(uncompressedStream.GetNumberOfBytesUsed()), '\0');

    //JJG: Take a risk and assume the compressed size will be smaller than the uncompressed size
    int newCompressedSize = max(1024*1024,int(sizeof(int)*2 + lzmaGetMaxCompressedSize(syncBytes)));
    if(compressedBufferSize < newCompressedSize )
    {
        compressedBufferSize = newCompressedSize;
        cout << "NEW COMPRESSED BUFFER SIZE: " << compressedBufferSize << endl;
	free(compressedBuffer);
        compressedBuffer = (unsigned char*)malloc(compressedBufferSize);
        if(!compressedBuffer)
        {
            cout << __FILE__ << ":" << __LINE__ << " OUT OF MEMORY\n";
            exit(1);
        }
    }

    int compressedSizeLong = compressedBufferSize;

    //FILE *stateptr = fopen("initialState.dat","wb");
    //fwrite(uncompressedStream.GetData(),uncompressedStream.GetNumberOfBytesUsed(),1,stateptr);
    //fclose(stateptr);

    lzmaCompress(
        compressedBuffer+sizeof(int)+sizeof(int),
        compressedSizeLong,
        uncompressedBuffer,
        syncBytes,
        6
    );

    int uncompressedSize = (int)syncBytes;
    memcpy(compressedBuffer,&uncompressedSize,sizeof(int));

    int compressedSize = (int)compressedSizeLong;
    memcpy(compressedBuffer+sizeof(int),&compressedSize,sizeof(int));

    printf("INITIAL UNCOMPRESSED SIZE: %d\n",uncompressedSize);
    printf("INITIAL COMPRESSED SIZE: %d\n",compressedSize);

    /*
    rakInterface->Send(
    	(char*)(&compressedInitialSyncBuffer[0]),
    	compressedSize+1+sizeof(int),
    	HIGH_PRIORITY,
    	RELIABLE_ORDERED,
    	ORDERING_CHANNEL_SYNC,
    	guid,
    	false
           );
    */

    //
    unsigned char *sendPtr = compressedBuffer;
    int sizeRemaining = compressedSize+sizeof(int)+sizeof(int);
    printf("INITIAL COMPRESSED SIZE: %dKB\n",sizeRemaining/1024);
    int packetSize = max(256,min(1024,sizeRemaining/100));

    oldInputTime.seconds = oldInputTime.attoseconds = 0;

    while(sizeRemaining>packetSize)
    {
        RakNet::BitStream bitStreamPart(65536);
        unsigned char header = ID_INITIAL_SYNC_PARTIAL;
        bitStreamPart.WriteBits((const unsigned char*)&header,8*sizeof(unsigned char));
        bitStreamPart.WriteBits((const unsigned char*)sendPtr,8*packetSize);
        sizeRemaining -= packetSize;
        sendPtr += packetSize;
        rakInterface->Send(
            &bitStreamPart,
            HIGH_PRIORITY,
            RELIABLE_ORDERED,
            ORDERING_CHANNEL_SYNC,
            sa,
            false
        );
        ui_update_and_render(*machine, &machine->render().ui_container());
        machine->osd().update(false);
        RakSleep(10);
    }
    {
        RakNet::BitStream bitStreamPart(65536);
        unsigned char header = ID_INITIAL_SYNC_COMPLETE;
        bitStreamPart.WriteBits((const unsigned char*)&header,8*sizeof(unsigned char));
        bitStreamPart.WriteBits((const unsigned char*)sendPtr,8*sizeRemaining);
        rakInterface->Send(
            &bitStreamPart,
            HIGH_PRIORITY,
            RELIABLE_ORDERED,
            ORDERING_CHANNEL_SYNC,
            sa,
            false
        );
        ui_update_and_render(*machine, &machine->render().ui_container());
        machine->osd().update(false);
        RakSleep(10);
    }
    //

    cout << "FINISHED SENDING BLOCKS TO CLIENT\n";
    cout << "SERVER: Done with initial snapshot\n";
    cout << "OUT OF CRITICAL AREA\n";
    cout.flush();
    memoryBlocksLocked=false;
}