int main (int argc, char ** argv) { startGameTimer = -1; if (board == NULL) { board = new TileBoard(); } lastHexbankUpdate = enet_time_get(); lastCooldownUpdate = enet_time_get(); lastLocationUpdate = enet_time_get(); server.Initialize(); // Should only be called once at most server.RegisterHandlers(&HandleConnect, &HandleDisconnect, &HandlePacket, &TimedEvent); // registers the event handlers server.SetupServer(4000); // Can be called multiple times with different ports... say if you wanted to host multiple games with a single server server.RunDedicated(); // Run it as a standalone dedicated server (Note: Does not return!) }
/** Sends any queued packets on the host specified to its designated peers. @param host host to flush @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service(). @ingroup host */ void enet_host_flush (ENetHost * host) { timeCurrent = enet_time_get (); enet_protocol_send_outgoing_commands (host, NULL, 0); }
void TimedEvent() { int curTime = enet_time_get(); // if game has not started if (!board->isStarted()) { // check to see if more than one player and if all players are ready. if (board->getPlayerCount() > 1 && board->getReadyPlayers().size() == board->getPlayerCount()) { if (startGameTimer == -1) { // start game timer startGameTimer = curTime; printf("Game will start in 1 seconds.\n"); } // check to see if 10 seconds have elapsed and start game. else if (curTime - startGameTimer >= 1000) { if (board->startBoard()) { printf ("GAME HAS STARTED.\n"); Broadcast ("SG\0"); } else printf ("Error starting game.\n"); } } else { if (startGameTimer!=-1) printf("Start game timer reset.\n"); // reset timer if players not all ready. startGameTimer = -1; } } // if game has started and not ended else if (!board->isEnded()) { // check for a winner if (board->isWinner()) { board->endBoard(); printf ("Game ended. Winner is Player %d.\n",board->getWinner()->getId()); Broadcast ("W"); } else { if (curTime - lastHexbankUpdate > 5000) { board->incHexBank(); // increment player hexbanks every 5 secs lastHexbankUpdate = curTime; printf ("Hexbanks incremented.\n"); Broadcast ("TH"); } if (curTime - lastCooldownUpdate > 125) { board->minusCooldown(); // run every tic. lastCooldownUpdate = curTime; Broadcast ("TC"); } if (curTime - lastLocationUpdate > 125) { char packet[256]; if (board->updateCharacterLocation(packet)) { Broadcast(packet); } } } } }
u32 CNetServerSession::GetLastReceivedTime() const { if (!m_Peer) return 0; return enet_time_get() - m_Peer->lastReceiveTime; }
static void GetRandomishBytes(u8* buf, size_t size) { // We don't need high quality random numbers (which might not be available), // just non-repeating numbers! srand(enet_time_get()); for (size_t i = 0; i < size; i++) buf[i] = rand() & 0xff; }
int currtime() { #ifdef SERVER return enet_time_get(); #else /* CLIENT */ return SDL_GetTicks() - clockrealbase; #endif }
void TraversalClient::ResendPacket(OutgoingTraversalPacketInfo* info) { info->sendTime = enet_time_get(); info->tries++; ENetBuffer buf; buf.data = &info->packet; buf.dataLength = sizeof(info->packet); if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1) OnFailure(SocketSendError); }
void TraversalClient::HandlePing() { enet_uint32 now = enet_time_get(); if (m_State == Connected && now - m_PingTime >= 500) { TraversalPacket ping = {}; ping.type = TraversalPacketPing; ping.ping.hostId = m_HostId; SendTraversalPacket(ping); m_PingTime = now; } }
void TraversalClient::HandleResends() { enet_uint32 now = enet_time_get(); for (auto& tpi : m_OutgoingTraversalPackets) { if (now - tpi.sendTime >= (u32)(300 * tpi.tries)) { if (tpi.tries >= 5) { OnFailure(ResendTimeout); m_OutgoingTraversalPackets.clear(); break; } else { ResendPacket(&tpi); } } } HandlePing(); }
void enet_host_bandwidth_throttle (ENetHost * host) { enet_uint32 timeCurrent = enet_time_get (), elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch, peersTotal = 0, dataTotal = 0, peersRemaining, bandwidth, throttle = 0, bandwidthLimit = 0; int needsAdjustment; ENetPeer * peer; ENetProtocol command; if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) return; for (peer = host -> peers; peer < & host -> peers [host -> peerCount]; ++ peer) { if (peer -> state != ENET_PEER_STATE_CONNECTED) continue; ++ peersTotal; dataTotal += peer -> outgoingDataTotal; } if (peersTotal == 0) return; peersRemaining = peersTotal; needsAdjustment = 1; if (host -> outgoingBandwidth == 0) bandwidth = ~0; else bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000; while (peersRemaining > 0 && needsAdjustment != 0) { needsAdjustment = 0; if (dataTotal < bandwidth) throttle = ENET_PEER_PACKET_THROTTLE_SCALE; else throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; for (peer = host -> peers; peer < & host -> peers [host -> peerCount]; ++ peer) { enet_uint32 peerBandwidth; if (peer -> state != ENET_PEER_STATE_CONNECTED || peer -> incomingBandwidth == 0 || peer -> outgoingBandwidthThrottleEpoch == timeCurrent) continue; peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000; if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) continue; peer -> packetThrottleLimit = (peerBandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal; if (peer -> packetThrottleLimit == 0) peer -> packetThrottleLimit = 1; if (peer -> packetThrottle > peer -> packetThrottleLimit) peer -> packetThrottle = peer -> packetThrottleLimit; peer -> outgoingBandwidthThrottleEpoch = timeCurrent; needsAdjustment = 1; -- peersRemaining; bandwidth -= peerBandwidth; dataTotal -= peerBandwidth; } } if (peersRemaining > 0) for (peer = host -> peers; peer < & host -> peers [host -> peerCount]; ++ peer) { if (peer -> state != ENET_PEER_STATE_CONNECTED || peer -> outgoingBandwidthThrottleEpoch == timeCurrent) continue; peer -> packetThrottleLimit = throttle; if (peer -> packetThrottle > peer -> packetThrottleLimit) peer -> packetThrottle = peer -> packetThrottleLimit; } if (host -> recalculateBandwidthLimits) { host -> recalculateBandwidthLimits = 0; peersRemaining = peersTotal; bandwidth = host -> incomingBandwidth; needsAdjustment = 1; if (bandwidth == 0) bandwidthLimit = 0; else while (peersRemaining > 0 && needsAdjustment != 0) { needsAdjustment = 0; bandwidthLimit = bandwidth / peersRemaining; for (peer = host -> peers; peer < & host -> peers [host -> peerCount]; ++ peer) { if (peer -> state != ENET_PEER_STATE_CONNECTED || peer -> incomingBandwidthThrottleEpoch == timeCurrent) continue; if (peer -> outgoingBandwidth > 0 && bandwidthLimit > peer -> outgoingBandwidth) continue; peer -> incomingBandwidthThrottleEpoch = timeCurrent; needsAdjustment = 1; -- peersRemaining; bandwidth -= peer -> outgoingBandwidth; } } for (peer = host -> peers; peer < & host -> peers [host -> peerCount]; ++ peer) { if (peer -> state != ENET_PEER_STATE_CONNECTED) continue; command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT; command.header.channelID = 0xFF; command.header.flags = 0; command.header.commandLength = sizeof (ENetProtocolBandwidthLimit); command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); if (peer -> incomingBandwidthThrottleEpoch == timeCurrent) command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth); else command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit); enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); } } host -> bandwidthThrottleEpoch = timeCurrent; for (peer = host -> peers; peer < & host -> peers [host -> peerCount]; ++ peer) { peer -> incomingDataTotal = 0; peer -> outgoingDataTotal = 0; } }
/** Waits for events on the host specified and shuttles packets between the host and its peers. @param host host to service @param event an event structure where event details will be placed if one occurs @param timeout number of milliseconds that ENet should wait for events @retval > 1 if an event occurred within the specified time limit @retval 0 if no event occurred @retval < 1 on failure @remarks enet_host_service should be called fairly regularly for adequate performance @ingroup host */ int enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) { enet_uint32 waitCondition; event -> type = ENET_EVENT_TYPE_NONE; event -> peer = NULL; event -> packet = NULL; switch (enet_protocol_dispatch_incoming_commands (host, event)) { case 1: return 1; case -1: perror ("Error dispatching incoming packets"); return -1; default: break; } timeCurrent = enet_time_get (); timeout += timeCurrent; do { if (ENET_TIME_DIFFERENCE (timeCurrent, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) enet_host_bandwidth_throttle (host); switch (enet_protocol_send_outgoing_commands (host, event, 1)) { case 1: return 1; case -1: perror ("Error sending outgoing packets"); return -1; default: break; } switch (enet_protocol_receive_incoming_commands (host, event)) { case 1: return 1; case -1: perror ("Error receiving incoming packets"); return -1; default: break; } switch (enet_protocol_send_outgoing_commands (host, event, 1)) { case 1: return 1; case -1: perror ("Error sending outgoing packets"); return -1; default: break; } switch (enet_protocol_dispatch_incoming_commands (host, event)) { case 1: return 1; case -1: perror ("Error dispatching incoming packets"); return -1; default: break; } timeCurrent = enet_time_get (); if (ENET_TIME_GREATER_EQUAL (timeCurrent, timeout)) return 0; waitCondition = ENET_SOCKET_WAIT_RECEIVE; if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, timeCurrent)) != 0) return -1; timeCurrent = enet_time_get (); } while (waitCondition == ENET_SOCKET_WAIT_RECEIVE); return 0; }
void Tunneld::promiseChannelCleanup(ToxTunChannel *chan) { qDebug()<<chan<<sender(); QObject *snderobj = (QObject*)sender(); QTimer *repeat_timer = NULL; qDebug()<<snderobj->objectName()<<snderobj->metaObject()->className(); if (chan == NULL) { repeat_timer = (QTimer*)snderobj; assert(repeat_timer != NULL); int conid = repeat_timer->property("conid").toInt(); if (!m_conid_chans.contains(conid)) { qDebug()<<"maybe too late repeat check self sock close timer event"; repeat_timer->deleteLater(); return; } chan = m_conid_chans[conid]; assert(chan != NULL); } else { // snderobj is ENetPoll or QTcpSocket } QTcpSocket *sock = chan->m_sock; ENetPeer *enpeer = chan->m_enpeer; ////////// QHash<QString, bool> promise_results; promise_results["sock_closed"] = chan->sock_closed; // promise_results["enet_closed"] = chan->enet_closed; promise_results["peer_sock_closed"] = chan->peer_sock_closed; bool promise_result = true; for (auto it = promise_results.begin(); it != promise_results.end(); it ++) { QString key = it.key(); bool val = it.value(); promise_result = promise_result && val; } if (true) { // 检测对方最近的回包情况 if (!promise_result && repeat_timer == NULL && promise_results["peer_sock_closed"] && !promise_results["sock_closed"]) { qDebug()<<"here"; if (chan->last_recv_peer_pkt_time == QDateTime()) { qDebug()<<"maybe can close socket right now, because recv nothing forever"; } QTimer *t = new QTimer(); t->setInterval(500); t->setSingleShot(true); t->setProperty("conid", QVariant(chan->m_conid)); // // QObject::connect(t, &QTimer::timeout, this, &Tunneld::promiseChannelCleanup, Qt::QueuedConnection); QObject::connect(t, SIGNAL(timeout()), this, SLOT(promiseChannelCleanup()), Qt::QueuedConnection); qDebug()<<"start repeat check sock close timer:"; t->start(); } if (!promise_result && repeat_timer != NULL && promise_results["peer_sock_closed"] && !promise_results["sock_closed"]) { // QDateTime now_time = QDateTime::currentDateTime(); uint32_t last_recv_to_now_time = chan->last_recv_peer_pkt_time.msecsTo(now_time); qDebug()<<"here:"<<last_recv_to_now_time<<enpeer->lastReceiveTime; if (last_recv_to_now_time > 7000) { qDebug()<<"last recv to now, force close self socket:"<<last_recv_to_now_time <<enpeer->incomingPeerID<<enpeer->outgoingPeerID; // 不能直接关闭,要在当前函数执行完后,即下一次事件的时候开始执行。 QTimer::singleShot(1, sock, &QTcpSocket::close); // QTimer *t = new QTimer(); // t->setSingleShot(true); // QObject::connect(t, &QTimer::timeout, sock, &QTcpSocket::close, Qt::QueuedConnection); // t->start(1); repeat_timer->deleteLater(); } else { repeat_timer->start(); } } } if (!promise_result) { qDebug()<<"promise nooooot satisfied:"<<promise_results<<chan->m_conid; return; } chan->promise_close_time = QDateTime::currentDateTime(); qDebug()<<"promise satisfied."<<chan->m_conid; ///// do cleanup bool force_closed = chan->force_closed; // enpeer->toxchan = NULL; // cleanup peerRemoveChan(enpeer, chan); this->m_sock_chans.remove(sock); // this->m_enpeer_chans.remove(enpeer); this->m_conid_chans.remove(chan->m_conid); delete chan; sock->disconnect(); sock->deleteLater(); if (repeat_timer != NULL) repeat_timer->deleteLater(); qDebug()<<"curr chan size:"<<this->m_sock_chans.count()<<this->m_conid_chans.count(); if (force_closed) { return; } // 延时关闭enet_peer QTimer *t = new QTimer(); auto later_close_timeout = [enpeer, t]() { qDebug()<<enpeer<<enpeer->state; if (enpeer->state != ENET_PEER_STATE_CONNECTED) { qDebug()<<"warning, peer currently not connected:"<<enpeer->incomingPeerID; } if (! (enet_list_empty (& enpeer -> outgoingReliableCommands) && enet_list_empty (& enpeer -> outgoingUnreliableCommands) && enet_list_empty (& enpeer -> sentReliableCommands))) { qDebug()<<"warning, maybe has unsent packet:"<<enpeer->incomingPeerID; } qDebug()<<"last recv time:"<<enpeer->incomingPeerID <<enetx_time_diff(enpeer->lastReceiveTime, enet_time_get()); qDebug()<<"restore peer timeout, ping interval"; enet_peer_timeout(enpeer, ENET_PEER_TIMEOUT_LIMIT*2, ENET_PEER_TIMEOUT_MINIMUM*2, ENET_PEER_TIMEOUT_MAXIMUM*2); enet_peer_ping_interval(enpeer, ENET_PEER_PING_INTERVAL*2); // enet_peer_disconnect_now(enpeer, qrand()); enet_peer_disconnect_later(enpeer, qrand()); t->deleteLater(); }; qDebug()<<"last recv time:"<<enpeer->incomingPeerID <<enetx_time_diff(enpeer->lastReceiveTime, enet_time_get()); // QTimer::singleShot(5678, later_close_timeout); t->setInterval(5678); t->setSingleShot(true); QObject::connect(t, &QTimer::timeout, later_close_timeout); t->start(); }