X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_net.pas;h=0f3df0f81f384348afba14eeaa326f3ce4ff6f42;hb=6f6b37c341bc73e5e2a135f355a9891292b8e849;hp=4e2ed9a09f94f868abff12ccccba327c435a3b6d;hpb=510ce208a83791aca610ab38198a9ebbb2ad2bfe;p=d2df-sdl.git diff --git a/src/game/g_net.pas b/src/game/g_net.pas index 4e2ed9a..0f3df0f 100644 --- a/src/game/g_net.pas +++ b/src/game/g_net.pas @@ -22,7 +22,7 @@ uses e_log, e_msg, ENet, Classes, MAPDEF{$IFDEF USE_MINIUPNPC}, miniupnpc;{$ELSE};{$ENDIF} const - NET_PROTOCOL_VER = 173; + NET_PROTOCOL_VER = 180; NET_MAXCLIENTS = 24; NET_CHANS = 11; @@ -44,6 +44,7 @@ const NET_CLIENT = 2; NET_BUFSIZE = $FFFF; + NET_PING_PORT = $DF2D; NET_EVERYONE = -1; @@ -65,6 +66,12 @@ const BANLIST_FILENAME = 'banlist.txt'; NETDUMP_FILENAME = 'netdump'; + {$IFDEF FREEBSD} + NilThreadId = nil; + {$ELSE} + NilThreadId = 0; + {$ENDIF} + type TNetClient = record ID: Byte; @@ -148,6 +155,8 @@ var NetIGDService: TURLStr; {$ENDIF} + NetPortThread: TThreadID = NilThreadId; + NetDumpFile: TStream; function g_Net_Init(): Boolean; @@ -170,7 +179,7 @@ function g_Net_Client_ByName(Name: string): pTNetClient; function g_Net_Client_ByPlayer(PID: Word): pTNetClient; function g_Net_ClientName_ByID(ID: Integer): string; -procedure g_Net_SendData(Data:AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD); +procedure g_Net_SendData(Data: AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD); function g_Net_Wait_Event(msgId: Word): TMemoryStream; function IpToStr(IP: LongWord): string; @@ -197,7 +206,10 @@ implementation uses SysUtils, e_input, g_nethandler, g_netmsg, g_netmaster, g_player, g_window, g_console, - g_main, g_game, g_language, g_weapons, utils; + g_main, g_game, g_language, g_weapons, utils, ctypes; + +var + g_Net_DownloadTimeout: Single; { /// SERVICE FUNCTIONS /// } @@ -316,6 +328,10 @@ begin NetMode := NET_NONE; + if NetPortThread <> NilThreadId then + WaitForThreadTerminate(NetPortThread, 66666); + + NetPortThread := NilThreadId; g_Net_UnforwardPorts(); if NetDump then @@ -334,6 +350,12 @@ end; { /// SERVER FUNCTIONS /// } +function ForwardThread(Param: Pointer): PtrInt; +begin + Result := 0; + if not g_Net_ForwardPorts() then Result := -1; +end; + function g_Net_Host(IPAddr: LongWord; Port: enet_uint16; MaxClients: Cardinal = 16): Boolean; begin if NetMode <> NET_NONE then @@ -361,7 +383,7 @@ begin NetAddr.host := IPAddr; NetAddr.port := Port; - if NetForwardPorts then g_Net_ForwardPorts(); + if NetForwardPorts then NetPortThread := BeginThread(ForwardThread); NetHost := enet_host_create(@NetAddr, NET_MAXCLIENTS, NET_CHANS, 0, 0); @@ -377,7 +399,7 @@ begin if NetPongSock <> ENET_SOCKET_NULL then begin NetPongAddr.host := IPAddr; - NetPongAddr.port := Port + 1; + NetPongAddr.port := NET_PING_PORT; if enet_socket_bind(NetPongSock, @NetPongAddr) < 0 then begin enet_socket_destroy(NetPongSock); @@ -492,6 +514,7 @@ begin NetOut.Clear(); NetOut.Write(Byte(Ord('D'))); NetOut.Write(Byte(Ord('F'))); + NetOut.Write(NetPort); NetOut.Write(ClTime); g_Net_Slist_WriteInfo(); NPl := 0; @@ -520,10 +543,8 @@ begin Result := 0; if NetUseMaster then - begin g_Net_Slist_Check; - g_Net_Host_CheckPings; - end; + g_Net_Host_CheckPings; while (enet_host_service(NetHost, @NetEvent, 0) > 0) do begin @@ -804,7 +825,8 @@ begin ProcessLoading(true); - if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then + if e_KeyPressed(IK_SPACE) or e_KeyPressed(IK_ESCAPE) or e_KeyPressed(VK_ESCAPE) or + e_KeyPressed(JOY0_JUMP) or e_KeyPressed(JOY1_JUMP) or e_KeyPressed(JOY2_JUMP) or e_KeyPressed(JOY3_JUMP) then OuterLoop := False; end; @@ -889,7 +911,7 @@ begin end; end; -procedure g_Net_SendData(Data:AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD); +procedure g_Net_SendData(Data: AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD); var P: pENetPacket; F: enet_uint32; @@ -918,59 +940,71 @@ begin enet_host_flush(NetHost); end; +function UserRequestExit: Boolean; +begin + Result := e_KeyPressed(IK_SPACE) or + e_KeyPressed(IK_ESCAPE) or + e_KeyPressed(VK_ESCAPE) or + e_KeyPressed(JOY0_JUMP) or + e_KeyPressed(JOY1_JUMP) or + e_KeyPressed(JOY2_JUMP) or + e_KeyPressed(JOY3_JUMP) +end; + function g_Net_Wait_Event(msgId: Word): TMemoryStream; -var - downloadEvent: ENetEvent; - OuterLoop: Boolean; - MID: Byte; - Ptr: Pointer; - msgStream: TMemoryStream; + var + ev: ENetEvent; + rMsgId: Byte; + Ptr: Pointer; + stream: TMemoryStream; + status: cint; begin - FillChar(downloadEvent, SizeOf(downloadEvent), 0); - msgStream := nil; - OuterLoop := True; - while OuterLoop do - begin - while (enet_host_service(NetHost, @downloadEvent, 0) > 0) do + FillChar(ev, SizeOf(ev), 0); + stream := nil; + repeat + status := enet_host_service(NetHost, @ev, Trunc(g_Net_DownloadTimeout * 1000)); + if status > 0 then begin - if (downloadEvent.kind = ENET_EVENT_TYPE_RECEIVE) then - begin - Ptr := downloadEvent.packet^.data; - - MID := Byte(Ptr^); - - if (MID = msgId) then + case ev.kind of + ENET_EVENT_TYPE_RECEIVE: + begin + Ptr := ev.packet^.data; + rMsgId := Byte(Ptr^); + if rMsgId = msgId then + begin + stream := TMemoryStream.Create; + stream.SetSize(ev.packet^.dataLength); + stream.WriteBuffer(Ptr^, ev.packet^.dataLength); + stream.Seek(0, soFromBeginning); + status := 1 (* received *) + end + else + begin + (* looks that game state always received, so ignore it *) + e_LogWritefln('g_Net_Wait_Event(%s): skip message %s', [msgId, rMsgId]); + status := 2 (* continue *) + end + end; + ENET_EVENT_TYPE_DISCONNECT: begin - msgStream := TMemoryStream.Create; - msgStream.SetSize(downloadEvent.packet^.dataLength); - msgStream.WriteBuffer(Ptr^, downloadEvent.packet^.dataLength); - msgStream.Seek(0, soFromBeginning); - - OuterLoop := False; - enet_packet_destroy(downloadEvent.packet); - break; - end - else begin - enet_packet_destroy(downloadEvent.packet); + if (ev.data <= NET_DISC_MAX) then + g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' + _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + ev.data)], True); + status := -2 (* error: disconnected *) end; - end else - if (downloadEvent.kind = ENET_EVENT_TYPE_DISCONNECT) then - begin - if (downloadEvent.data <= NET_DISC_MAX) then - g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' + - _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + downloadEvent.data)], True); - OuterLoop := False; - Break; - end; + g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' unknown ENet event ' + IntToStr(Ord(ev.kind)), True); + status := -3 (* error: unknown event *) + end; + enet_packet_destroy(ev.packet) + end + else + begin + g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' timeout reached', True); + status := 0 (* error: timeout *) end; - ProcessLoading(true); - - if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then - break; - end; - Result := msgStream; + until (status <> 2) or UserRequestExit(); + Result := stream end; function g_Net_IsHostBanned(IP: LongWord; Perm: Boolean = False): Boolean; @@ -1119,7 +1153,6 @@ var Urls: TUPNPUrls; Data: TIGDDatas; LanAddr: array [0..255] of Char; - ExtAddr: array [0..40] of Char; StrPort: AnsiString; Err, I: Integer; begin @@ -1131,15 +1164,13 @@ begin exit; end; - conwriteln('trying to forward server ports...'); - NetPongForwarded := False; NetPortForwarded := 0; - DevList := upnpDiscover(2000, nil, nil, 0, 0, Addr(Err)); + DevList := upnpDiscover(1000, nil, nil, 0, 0, 2, Addr(Err)); if DevList = nil then begin - conwritefln(' upnpDiscover() failed: %d', [Err]); + conwritefln('port forwarding failed: upnpDiscover() failed: %d', [Err]); exit; end; @@ -1147,19 +1178,11 @@ begin if I = 0 then begin - conwriteln(' could not find an IGD device on this LAN, aborting'); + conwriteln('port forwarding failed: could not find an IGD device on this LAN'); FreeUPNPDevList(DevList); FreeUPNPUrls(@Urls); exit; - end - else if I = 1 then - conwritefln(' found IGD @ %s', [Urls.controlURL]) - else - conwritefln(' found some kind of UPNP device @ %s, maybe it''ll work', [Urls.controlURL]); - - UPNP_GetExternalIPAddress(Urls.controlURL, Addr(data.first.servicetype[1]), Addr(ExtAddr[0])); - if ExtAddr[0] <> #0 then - conwritefln(' external IP address: %s', [Addr(ExtAddr[0])]); + end; StrPort := IntToStr(NetPort); I := UPNP_AddPortMapping( @@ -1170,7 +1193,7 @@ begin if I <> 0 then begin - conwritefln(' forwarding port %d failed: error %d', [NetPort, I]); + conwritefln('forwarding port %d failed: error %d', [NetPort, I]); FreeUPNPDevList(DevList); FreeUPNPUrls(@Urls); exit; @@ -1178,7 +1201,7 @@ begin if ForwardPongPort then begin - StrPort := IntToStr(NetPort + 1); + StrPort := IntToStr(NET_PING_PORT); I := UPNP_AddPortMapping( Urls.controlURL, Addr(data.first.servicetype[1]), PChar(StrPort), PChar(StrPort), Addr(LanAddr[0]), PChar('D2DF'), @@ -1187,17 +1210,17 @@ begin if I <> 0 then begin - conwritefln(' forwarding port %d failed: error %d', [NetPort + 1, I]); + conwritefln('forwarding port %d failed: error %d', [NetPort + 1, I]); NetPongForwarded := False; end else begin - conwritefln(' forwarded port %d successfully', [NetPort + 1]); + conwritefln('forwarded port %d successfully', [NetPort + 1]); NetPongForwarded := True; end; end; - conwritefln(' forwarded port %d successfully', [NetPort]); + conwritefln('forwarded port %d successfully', [NetPort]); NetIGDControl := AnsiString(Urls.controlURL); NetIGDService := data.first.servicetype; NetPortForwarded := NetPort; @@ -1248,13 +1271,11 @@ end; {$ENDIF} initialization - + conRegVar('cl_downloadtimeout', @g_Net_DownloadTimeout, 0.0, 1000000.0, '', 'timeout in seconds, 0 to disable it'); + g_Net_DownloadTimeout := 60; NetIn.Alloc(NET_BUFSIZE); NetOut.Alloc(NET_BUFSIZE); - finalization - NetIn.Free(); NetOut.Free(); - end.