void CNet::FlushNet(void) { for (int a=0; a<gs->activePlayers; a++) { Connection* c=&connections[a]; if(c->active && c->outgoingLength>0) { FlushConnection(a); } } }
void CNet::Update(void) { Uint64 t; t = SDL_GetTicks(); curTime=float(t)/1000.f; if(playbackDemo) ReadDemoFile(); if(onlyLocal) { return; } sockaddr_in from; socklen_t fromsize; fromsize=sizeof(from); int r; unsigned char inbuf[16000]; if(connected) while(true) { if((r=recvfrom(mySocket,(char*)inbuf,16000,0,(sockaddr*)&from,&fromsize))==SOCKET_ERROR) { if (IsFakeError()) break; char test[500]; sprintf(test,"Error receiving data. %i %d",(int)imServer,WSAGetLastError()); handleerror(NULL,test,"SHUTDOWN ERROR",MBF_OK | MBF_INFO); exit(0); } int conn=ResolveConnection(&from); if(conn==-1) { if(waitOnCon && r>=12 && (*(int*)inbuf)==0 && (*(int*)&inbuf[4])==-1 && inbuf[8]==0 && inbuf[9]==NETMSG_ATTEMPTCONNECT && inbuf[11]==NETWORK_VERSION) { conn=InitNewConn(&from,false,inbuf[10]); } else { continue; } } inInitialConnect=false; int packetNum=(*(int*)inbuf); ProcessRawPacket(inbuf,r,conn); } for(int a=0; a<gs->activePlayers; ++a) { Connection* c=&connections[a]; if(c->localConnection || !c->active) continue; std::map<int,Packet*>::iterator wpi; while((wpi=c->waitingPackets.find(c->lastInOrder+1))!=c->waitingPackets.end()) { //process all in order packets that we have waiting if(c->readyLength+wpi->second->length>=NETWORK_BUFFER_SIZE) { logOutput.Print("Overflow in incoming network buffer"); break; } memcpy(&c->readyData[c->readyLength],wpi->second->data,wpi->second->length); c->readyLength+=wpi->second->length; delete wpi->second; c->waitingPackets.erase(wpi); c->lastInOrder++; } if(inInitialConnect && c->lastSendTime<curTime-1) { //server hasnt responded so try to send the connection attempt again SendRawPacket(a,c->unackedPackets[0]->data,c->unackedPackets[0]->length,0); c->lastSendTime=curTime; } if(c->lastSendTime<curTime-5 && !inInitialConnect) { //we havent sent anything for a while so send something to prevent timeout SendData(NETMSG_HELLO); } if(c->lastSendTime<curTime-0.2f && !c->waitingPackets.empty()) { //we have at least one missing incomming packet lying around so send a packet to ensure the other side get a nak SendData(NETMSG_HELLO); } if(c->lastReceiveTime < curTime-(inInitialConnect ? 40 : 30)) { //other side has timed out c->active=false; } if(c->outgoingLength>0 && (c->lastSendTime < (curTime-0.2f+c->outgoingLength*0.01f) || c->lastSendFrame < gs->frameNum-1)) { FlushConnection(a); } } }
/** * This is the main routine responsible for replicating our GL state * for a new VNC viewer. Called when we detect that a new VNC viewer * has been started. * \param ipaddress the IP address where the new viewer is running. */ void replicatespuReplicate(int ipaddress) { GET_THREAD(thread); struct in_addr addr; char *hosturl; char *ipstring; int i, r_slot; int serverPort; crDebug("Replicate SPU: Enter replicatespuReplicate(ipaddress=0x%x)", ipaddress); replicatespuFlushAll( (void *)thread ); #ifdef CHROMIUM_THREADSAFE_notyet crLockMutex(&_ReplicateMutex); #endif /* * Find empty slot. * Slot 0 is the dummy slot (a non-existant server on devnull connection) */ for (r_slot = 1; r_slot < CR_MAX_REPLICANTS; r_slot++) { if (!IS_CONNECTED(replicate_spu.rserver[r_slot].conn)) break; } if (r_slot == CR_MAX_REPLICANTS) { crWarning("Replicate SPU: no more replicant slots available"); return; } /** ** OK, now rserver[r_slot] is free for use. **/ /* * At this time, we can only support one VNC viewer per host. * Check for that here. */ for (i = 1; i < CR_MAX_REPLICANTS; i++) { if (replicate_spu.ipnumbers[i] == ipaddress) { CRConnection *conn = replicate_spu.rserver[i].conn; /* If the connection appears to be active, it may actually be a dangling * connection. Try flushing it now. If flushing fails, the connection * type will definitely be CR_NO_CONNECTION (which we test below). */ if (conn) { if (conn->type != CR_NO_CONNECTION) { FlushConnection(i); } if (conn->type != CR_NO_CONNECTION) { crWarning("Replicate SPU: Can't connect to multiple VNC viewers on one host."); #if 0 /* The above test isn't 100% reliable and can prevent successful * restart of a viewer on a host. For now, just print warning and * continue. */ return; #endif } } } } replicate_spu.ipnumbers[r_slot] = ipaddress; serverPort = replicate_spu.chromium_start_port + r_slot; if (replicate_spu.vncAvailable) { /* Send a ChromiumStart message to the VNC Server. The VNC Server will * in turn send a ChromiumStart message to all the attached VNC viewers. * The VNC Viewer/Chromium module will tell its crserver that there's * a new OpenGL client. * We pass the mothership port and crserver port in this message. */ char protocol[100], hostname[1000]; const char *mothershipURL; unsigned short mothershipPort; mothershipURL = crGetenv("CRMOTHERSHIP"); crDebug("Replicate SPU: CRMOTHERSHIP env var = %s", mothershipURL); if (mothershipURL) crParseURL(mothershipURL, protocol, hostname, &mothershipPort, DEFAULT_MOTHERSHIP_PORT); else mothershipPort = DEFAULT_MOTHERSHIP_PORT; crDebug("Replicate SPU: Sending ChromiumStart msg to VNC server, port=%d", serverPort); if (!XVncChromiumStart(replicate_spu.glx_display, ipaddress, serverPort, mothershipPort)) { crWarning("Replicate SPU: XVncChromiumStart() call failed"); } } addr.s_addr = ipaddress; ipstring = inet_ntoa(addr); hosturl = crAlloc(crStrlen(ipstring) + 9); sprintf(hosturl, "tcpip://%s", ipstring); crDebug("Replicate SPU attaching to %s on port %d", hosturl, serverPort); /* connect to the remote VNC server */ replicate_spu.rserver[r_slot].name = crStrdup( replicate_spu.name ); replicate_spu.rserver[r_slot].buffer_size = replicate_spu.buffer_size; replicate_spu.rserver[r_slot].conn = crNetConnectToServer( hosturl, serverPort, replicate_spu.rserver[r_slot].buffer_size, 1); if (!replicate_spu.rserver[r_slot].conn) { crWarning("Replicate SPU: failed to connect to %s", hosturl); return; } CRASSERT(replicate_spu.rserver[r_slot].conn); /* * Setup the the packer flush function. While replicating state to * a particular server we definitely don't want to do any broadcast * flushing! */ crPackFlushFunc( thread->packer, replicatespuFlushOnePacker ); crPackSendHugeFunc( thread->packer, replicatespuHugeOnePacker ); NewServerIndex = r_slot; /* * Create server-side windows and contexts by walking tables of app windows * and contexts. Note that windows can be created in random order, * but contexts must be created in the order they were originally * created, or shared contexts will break. */ crHashtableWalk(replicate_spu.windowTable, replicatespuReplicateWindow, thread); crListApply(replicate_spu.contextList, replicatespuReplicateContext, thread); /* MakeCurrent, the current context */ if (thread->currentContext) { int serverWindow = thread->currentContext->currentWindow->id[r_slot]; int serverContext = thread->currentContext->rserverCtx[r_slot]; if (replicate_spu.swap) crPackMakeCurrentSWAP(serverWindow, 0, serverContext); else crPackMakeCurrent(serverWindow, 0, serverContext); crStateMakeCurrent( thread->currentContext->State ); } /* * Set window sizes */ crHashtableWalk(replicate_spu.windowTable, replicatespuResizeWindows, thread); replicatespuFlushOne(thread, NewServerIndex); /* * restore normal, broadcasting packer flush function now. */ crPackFlushFunc( thread->packer, replicatespuFlush ); crPackSendHugeFunc( thread->packer, replicatespuHuge ); NewServerIndex = -1; crDebug("Replicate SPU: leaving replicatespuReplicate"); #ifdef CHROMIUM_THREADSAFE_notyet crUnlockMutex(&_ReplicateMutex); #endif }