// heartbeat master servers. // send a message to the master every few minutes. static void QRY_HeartbeatMasters(void) { char string[128]; int i, len; master_t *m; time_t current_time = time(NULL); char buf[] = "xxx.xxx.xxx.xxx:xxxxx"; // do we need heartbeat masters? if (!masters_heartbeat->integer) return; if (current_time < masters.last_heartbeat + QW_MASTER_HEARTBEAT_SECONDS) return; // not yet masters.last_heartbeat = current_time; masters.heartbeat_sequence++; snprintf(string, sizeof(string), "%c\n%i\n%i\n", S2M_HEARTBEAT, masters.heartbeat_sequence, FWD_peers_count()); len = strlen(string); if (developer->integer > 1) Sys_DPrintf("heartbeat:\n%s\n", string); for (i = 0, m = masters.master; i < MAX_MASTERS; i++, m++) { if (m->state != ms_used) continue; // master slot not used Sys_DPrintf("heartbeat master: %s\n", NET_AdrToString(&m->addr, buf, sizeof(buf))); NET_SendPacket(net_socket, len, string, &m->addr); } }
void SVC_QRY_ParseMasterReply(void) { int i, c; master_t *m; int ret = net_message.cursize; unsigned char *answer = net_message.data; // not the smartest way, but why copy from one place to another... // no point to parse it, we do not query masters if (!masters_query->integer) { Sys_DPrintf("master server reply ignored\n"); return; } Sys_DPrintf ("master server reply from %s:%d\n", inet_ntoa(net_from.sin_addr), (int)ntohs(net_from.sin_port)); // is it reply from registered master server or someone trying to do some evil things? for (i = 0, m = masters.master; i < MAX_MASTERS; i++, m++) { if (m->state != ms_used) continue; // master slot not used if (NET_CompareAddress(&net_from, &m->addr)) { // OK - it is reply from registered master server m->next_query = time(NULL) + QW_MASTER_QUERY_TIME; // delay next query for some time break; } } if (i >= MAX_MASTERS) { Sys_Printf("Reply from not registered master server\n"); return; } Sys_DPrintf("master server returned %d bytes\n", ret); for (c = 0, i = 6; i + 5 < ret; i += 6, c++) { char ip[64]; int port = 256 * (int)answer[i+4] + (int)answer[i+5]; snprintf(ip, sizeof(ip), "%u.%u.%u.%u", (int)answer[i+0], (int)answer[i+1], (int)answer[i+2], (int)answer[i+3]); if (developer->integer > 1) Sys_DPrintf("SERVER: %4d %s:%d\n", c, ip, port); QRY_SV_new(ip, port, true); } }
static server_t *QRY_SV_new(const char *remote_host, int remote_port, qbool link) { server_t *sv; struct sockaddr_in addr; if (QRY_SV_Count() >= MAX_SERVERS) return NULL; if (!NET_GetSockAddrIn_ByHostAndPort(&addr, remote_host, remote_port)) return NULL; // failed to resolve host name? if ((sv = QRY_SV_ByAddr(&addr))) return NULL; // we already have such server on list if (QRY_FL_Filtered(&addr)) { char buf[] = "xxx.xxx.xxx.xxx:xxxxx"; Sys_DPrintf("filtered: %s\n", NET_AdrToString(&addr, buf, sizeof(buf))); return NULL; // filtered } sv_count++; sv = Sys_malloc(sizeof(*sv)); sv->addr = addr; sv->ping = 0xFFFF; // mark as unreachable if (link) { sv->next = servers; servers = sv; } return sv; }
// check if "masters" or "masters_query" cvar changed and do appropriate action static void QRY_CheckMastersModified(void) { char *mlist; // for fix issues with DNS and such force masters re-init time to time if (time(NULL) - masters.init_time > QW_MASTERS_FORCE_RE_INIT) { Sys_DPrintf("forcing masters re-init\n"); masters_list->modified = true; } // "masters" and "masters_query" was not modified, do nothing if (!masters_list->modified && !masters_query->modified) return; // clear masters QRY_MastersInit(); // add all masters for ( mlist = masters_list->string; (mlist = COM_Parse(mlist)); ) { QRY_AddMaster(com_token); } masters_list->modified = masters_query->modified = false; }
// query master servers static void QRY_QueryMasters(void) { int i; master_t *m; time_t current_time = time(NULL); char buf[] = "xxx.xxx.xxx.xxx:xxxxx"; // do we need query masters? if (!masters_query->integer) return; for (i = 0, m = masters.master; i < MAX_MASTERS; i++, m++) { if (m->state != ms_used) continue; // master slot not used if (current_time <= m->next_query) continue; // not yet Sys_DPrintf("query master: %s\n", NET_AdrToString(&m->addr, buf, sizeof(buf))); NET_SendPacket(net_socket, sizeof(QW_MASTER_QUERY), QW_MASTER_QUERY, &m->addr); m->next_query = current_time + QW_MASTER_QUERY_TIME_SHORT; // delay next query for some time } }
void QRY_SV_PingReply(void) { server_t *sv = NULL; // ignore server ping reply since we do not query masters and can't keep server list up2date if (!masters_query->integer) { Sys_DPrintf("server reply ignored\n"); return; } sv = QRY_SV_ByAddr(&net_from); if (sv) { double current = Sys_DoubleTime(); double ping = current - sv->ping_sent_at; sv->ping = (int)max(0, 1000.0 * ping); sv->ping_reply_at = current; sv->reply = true; // Sys_Printf("ping <- %s:%d, %d\n", inet_ntoa(net_from.sin_addr), (int)ntohs(net_from.sin_port), sv->ping); } else { // Sys_Printf("ping <- %s:%d, not registered server\n", inet_ntoa(net_from.sin_addr), (int)ntohs(net_from.sin_port)); } }
/* ==================== NET_Init ==================== */ void NET_Init (void) { char *ip = (*ps.params.ip) ? ps.params.ip : "0.0.0.0"; char port[64] = {0}; snprintf(port, sizeof(port), "%d", ps.params.port ? ps.params.port : QWFWD_DEFAULT_PORT); if (*ps.params.ip) // if cmd line - force it, so we have priority over cfg net_ip = Cvar_FullSet("net_ip", ip, CVAR_NOSET); else net_ip = Cvar_Get("net_ip", ip, CVAR_NOSET); if (ps.params.port) // if cmd line - force it, so we have priority over cfg net_port = Cvar_FullSet("net_port", port, CVAR_NOSET); else net_port = Cvar_Get("net_port", port, CVAR_NOSET); #ifdef _WIN32 { WSADATA winsockdata; if (WSAStartup(MAKEWORD (2, 1), &winsockdata)) Sys_Error("WinSock initialization failed"); } #endif if ((net_socket = NET_UDP_OpenSocket(net_ip->string, net_port->integer, true)) == INVALID_SOCKET) Sys_Error("NET_Init: failed to initialize socket"); // init the message buffer SZ_InitEx(&net_message, net_message_buffer, sizeof(net_message_buffer), false); Sys_DPrintf("UDP Initialized\n"); }
void dnLoadSnapshot( const snapshot_t *snapshot ) { Sys_DPrintf( "[DUKEMP] dnLoadSnapshot: loading snapshot\n" ); dnRestoreSnapshot( snapshot ); resetinterpolations(); show_shareware = 0; everyothertime = 0; resetmys(); ready2send = 1; // waitforeverybody(); resettimevars(); }
static void FWD_check_drop(void) { peer_t *p, *next; for (p = peers; p; p = next) { next = p->next; if (p->ps != ps_drop) continue; Sys_DPrintf("peer %s:%d dropped\n", inet_ntoa(p->from.sin_addr), (int)ntohs(p->from.sin_port)); FWD_peer_free(p, true); // NOTE: 'p' is not valid after this function, so we remember 'next' before this function } }
static void QRY_FL_RemoveFilteredServers(void) { int i; server_t *sv; for (i = 0; i < server_filter.count; i++) { if ((sv = QRY_SV_ByAddrEx(&server_filter.addr[i], true))) { char buf[] = "xxx.xxx.xxx.xxx:xxxxx"; Sys_DPrintf("filtered: %s\n", NET_AdrToString(&sv->addr, buf, sizeof(buf))); QRY_SV_free(sv, true); } } }
static void QRY_SV_PingServers(void) { static int idx; static double last; double current = Sys_DoubleTime(); // we need double time for ping measurement server_t *sv; // do not ping servers since we do not query masters if (!masters_query->integer) return; if (!servers) return; // nothing to do if (current - last < QW_SERVER_RATE) return; // do not ping servers too fast last = current; idx = (int)max(0, idx); sv = QRY_SV_ByIndex(idx++); if (!sv) sv = QRY_SV_ByIndex(idx = 0); // can't find server by index, try with index 0 if (!sv) return; // hm, should not be the case... // check for dead server if (!sv->reply && sv->ping_sent_at - sv->ping_reply_at > QW_SERVER_DEAD_TIME) { Sys_DPrintf("dead -> %s:%d\n", inet_ntoa(sv->addr.sin_addr), (int)ntohs(sv->addr.sin_port)); QRY_SV_free(sv, true); // remove damn server, however master server may add it back... idx--; // step back index return; } if (sv->ping_sent_at && current - sv->ping_sent_at < QW_SERVER_MIN_PING_REQUEST_TIME) return; // do not spam server sv->ping_sent_at = current; // remember when we sent ping sv->reply = false; // reset reply flag NET_SendPacket(net_socket, sizeof(QW_SERVER_PING_QUERY)-1, QW_SERVER_PING_QUERY, &sv->addr); // Sys_Printf("ping(%3d) -> %s:%d\n", idx, inet_ntoa(sv->addr.sin_addr), (int)ntohs(sv->addr.sin_port)); }
int Net_GetPacket(cluster_t *cluster, netmsg_t *msg) { int ret; socklen_t fromlen = sizeof (cluster->net_from); ClearNetMsg(msg); if (cluster->udpsocket == INVALID_SOCKET) return false; ret = recvfrom(cluster->udpsocket, (char *)msg->data, msg->maxsize, 0, (struct sockaddr *) &cluster->net_from, &fromlen); if (ret == -1) { if (qerrno == EWOULDBLOCK) return false; if (qerrno == EMSGSIZE) { Sys_Printf ("NET_GetPacket: Oversize packet from %s\n", inet_ntoa(cluster->net_from.sin_addr)); return false; } if (qerrno == ECONNRESET) { Sys_DPrintf ("NET_GetPacket: Connection was forcibly closed by %s\n", inet_ntoa(cluster->net_from.sin_addr)); return false; } Sys_Printf ("NET_GetPacket: recvfrom: (%i): %s\n", qerrno, strerror (qerrno)); return false; } if (ret >= msg->maxsize) { Sys_Printf ("NET_GetPacket: Oversize packet from %s\n", inet_ntoa(cluster->net_from.sin_addr)); return false; } msg->cursize = ret; msg->data[ret] = 0; return ret; }
int NET_GetPacket(int s, sizebuf_t *msg) { int ret; socklen_t fromlen = sizeof (net_from); SZ_Clear(msg); net_from_socket = s; ret = recvfrom(s, (char *)msg->data, msg->maxsize, 0, (struct sockaddr *) &net_from, &fromlen); if (ret == SOCKET_ERROR) { if (qerrno == EWOULDBLOCK) return false; if (qerrno == EMSGSIZE) { Sys_Printf ("NET_GetPacket: Oversize packet from %s\n", inet_ntoa(net_from.sin_addr)); return false; } if (qerrno == ECONNRESET) { Sys_DPrintf ("NET_GetPacket: Connection was forcibly closed by %s\n", inet_ntoa(net_from.sin_addr)); return false; } Sys_Error ("NET_GetPacket: recvfrom: (%i): %s", qerrno, strerror (qerrno)); } if (ret >= msg->maxsize) { Sys_Printf ("NET_GetPacket: Oversize packet from %s\n", inet_ntoa(net_from.sin_addr)); return false; } msg->cursize = ret; msg->data[ret] = 0; return ret; }
qbool Net_StringToAddr(struct sockaddr_in *address, const char *host, int defaultport) { struct hostent *phe; struct sockaddr_in sin = {0}; char *colon; char copy[128]; // copy host name without port here. memset (address, 0, sizeof(*address)); sin.sin_family = AF_INET; sin.sin_port = htons(defaultport); strlcpy (copy, host, sizeof(copy)); // strip off a trailing :port if present for (colon = copy ; *colon ; colon++) { if (*colon == ':') { *colon = 0; sin.sin_port = htons((short)atoi(colon+1)); } } /* Map host name to IP address, allowing for dotted decimal */ if((phe = gethostbyname(copy))) { memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length); } else if((sin.sin_addr.s_addr = inet_addr(copy)) == INADDR_NONE) { Sys_DPrintf("Net_StringToAddr: wrong host: %s\n", copy); return false; } *address = sin; return true; }
static void FWD_check_timeout(void) { byte msg_data[6]; sizebuf_t msg; time_t cur_time; double d_cur_time; peer_t *p; SZ_InitEx(&msg, msg_data, sizeof(msg_data), true); cur_time = time(NULL); d_cur_time = Sys_DoubleTime(); for (p = peers; p; p = p->next) { // this is helper for q3 to guess disconnect asap if (p->proto == pr_q3) { if (cur_time - p->last > 1 && d_cur_time - p->q3_disconnect_check > 0.05 && p->ps == ps_connected) { p->q3_disconnect_check = d_cur_time; SZ_Clear(&msg); MSG_WriteLong(&msg, 0); MSG_WriteShort(&msg, p->qport); NET_SendPacket(p->s, msg.cursize, msg.data, &p->to); } } if (cur_time - p->last < 15) // few seconds timeout continue; Sys_DPrintf("peer %s:%d timed out\n", inet_ntoa(p->from.sin_addr), (int)ntohs(p->from.sin_port)); p->ps = ps_drop; } }
// Responses to broadcasts, etc static qbool CL_ConnectionlessPacket_QW (peer_t *p) { qbool need_forward = false; int c; MSG_BeginReading(); MSG_ReadLong(); // Skip the -1 c = MSG_ReadByte(); if (MSG_BadRead()) return need_forward; // Runt packet switch(c) { case S2C_CHALLENGE: { Sys_DPrintf("%s: challenge\n", inet_ntoa(net_from.sin_addr)); p->challenge = atoi(MSG_ReadString()); CL_SendConnectPacket_QW(p); break; } case S2C_CONNECTION: { Sys_DPrintf("%s: connection\n", inet_ntoa(net_from.sin_addr)); if (p->ps >= ps_connected) { Sys_DPrintf("Dup connect received. Ignored.\n"); break; } p->ps = ps_connected; break; } case A2C_CLIENT_COMMAND: { // Remote command from gui front end Sys_DPrintf("%s: client command\n", inet_ntoa(net_from.sin_addr)); break; } case A2C_PRINT: { // Print command from somewhere. #ifdef FTE_PEXT_CHUNKEDDOWNLOADS if (net_message.cursize > 100 && !strncmp((char *)net_message.data + 5, "\\chunk", sizeof("\\chunk")-1)) { CL_Parse_OOB_ChunkedDownload(); return; } #endif // FTE_PEXT_CHUNKEDDOWNLOADS // Sys_Printf("%s: print\n", inet_ntoa(net_from.sin_addr)); // Sys_Printf("%s", MSG_ReadString()); need_forward = true; // so client have chance to see what server trying to say break; } case svc_disconnect: { Sys_DPrintf("%s: svc_disconnect\n", inet_ntoa(net_from.sin_addr)); break; } default: { Sys_DPrintf("CL CL_ConnectionlessPacket %s:\n%c%s\n", inet_ntoa(net_from.sin_addr), c, MSG_ReadString()); break; } } return need_forward; }
static qbool CL_ConnectionlessPacket_Q3 (peer_t *p) { char *s, buf[] = "xxx.xxx.xxx.xxx:xxxxx"; char *c; qbool need_forward = false; MSG_BeginReading(); MSG_ReadLong(); // Skip the -1 s = MSG_ReadStringLine(); Cmd_TokenizeString( s ); c = Cmd_Argv(0); if ( developer->integer ) { Sys_DPrintf ("CL packet %s: %s\n", NET_AdrToString(&net_from, buf, sizeof(buf)), s); } // challenge from the server we are connecting to if ( !stricmp(c, "challengeResponse") ) { if ( p->ps != ps_challenge ) { Sys_DPrintf( "Unwanted challenge response received. Ignored.\n" ); } else { // start sending connect requests instead of challenge request packets p->challenge = atoi(Cmd_Argv(1)); // take this address as the new server address. This allows // a server proxy to hand off connections to multiple servers // clc.serverAddress = from; Sys_DPrintf ("challengeResponse: %d\n", p->challenge); CL_SendConnectPacket_Q3( p ); } return need_forward; } // server connection if ( !stricmp(c, "connectResponse") ) { if ( p->ps >= ps_connected ) { Sys_DPrintf ("Dup connect received. Ignored.\n"); return need_forward; } if ( p->ps != ps_challenge ) { Sys_DPrintf ("connectResponse packet while not connecting. Ignored.\n"); return need_forward; } Sys_DPrintf ("connectResponse\n"); // we are connected now p->ps = ps_connected; // possibile to lost this message, so moved to the other place where it sended time to time // Netchan_OutOfBandPrint(net_socket, &p->from, "print\n" "/reconnect ASAP!\n"); return need_forward; } // a disconnect message from the server, which will happen if the server // dropped the connection but it is still getting packets from us if ( !stricmp(c, "disconnect") ) { // CL_DisconnectPacket( from ); p->ps = ps_drop; // drop this peer return need_forward = true; // so client have chance to see what server trying to say } // echo request from server if ( !stricmp(c, "print") ) { Sys_DPrintf( "%s", MSG_ReadString() ); return need_forward = true; // so client have chance to see what server trying to say } return need_forward; }