Skip to content

Commit 2fd422d

Browse files
committed
Reworked Request Timeout
During timeout, will now call callback and fail the request. Adding new parameter in FileNet_RequestFile to define the timeout period.
1 parent 814ab28 commit 2fd422d

File tree

2 files changed

+108
-83
lines changed

2 files changed

+108
-83
lines changed

scripting/filenetwork.sp

Lines changed: 106 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ enum struct FileEnum
1818
any Data;
1919

2020
int Id;
21+
int Timeout;
2122
}
2223

2324
Handle SDKGetPlayerNetInfo;
@@ -39,7 +40,7 @@ char CurrentlySending[MAXPLAYERS+1][PLATFORM_MAX_PATH];
3940
ArrayList RequestListing;
4041
Handle RequestingTimer[MAXPLAYERS+1];
4142
int CurrentlyRequesting[MAXPLAYERS+1] = {-1, ...};
42-
int StartedRequestingAt[MAXPLAYERS+1];
43+
int FailRequestingAt[MAXPLAYERS+1];
4344

4445
methodmap CNetChan
4546
{
@@ -211,8 +212,6 @@ public void OnPluginStart()
211212
failed = true;
212213
}
213214

214-
//THIS ONLY WORKS ON WINDOWS!!!!!!
215-
//linux uses a different solution, timeout logic.
216215
detour = DynamicDetour.FromConf(gamedata, "CGameClient::FileDenied");
217216
if(detour)
218217
{
@@ -349,121 +348,145 @@ public MRESReturn OnFileReceived(Address address, DHookParam param)
349348

350349
RequestListing.Erase(i);
351350
CallRequestFileFinish(info, true);
352-
353-
if(RequestingTimer[info.Client])
354-
TriggerTimer(RequestingTimer[info.Client]);
351+
352+
delete RequestingTimer[info.Client];
353+
SendNextRequest(info.Client);
355354

356355
break;
357356
}
358357
}
359358
return MRES_Ignored;
360359
}
361360

362-
void StartRequestingClient(int client)
363-
{
364-
if(!RequestingTimer[client])
365-
{
366-
RequestingTimer[client] = CreateTimer(1.0, Timer_RequestingClient, client, TIMER_REPEAT);
367-
TriggerTimer(RequestingTimer[client]);
368-
}
369-
}
370-
371-
public Action Timer_RequestingClient(Handle timer, int client)
361+
public MRESReturn OnFileDenied(Address address, DHookParam param)
372362
{
373-
CNetChan chan = CNetChan(client);
374-
if(!chan)
375-
return Plugin_Continue;
376-
377-
static FileEnum info;
378-
379-
if(CurrentlyRequesting[client] != -1)
380-
{
381-
// Client still giving this file
382-
if((StartedRequestingAt[client] + TIMEOUT_PERIOD) > GetTime())
383-
return Plugin_Continue;
384-
385-
// We timed out, this can be a case of the client getting stuck.
386-
// Request a different file to unstuck the client then try again.
387-
DeleteFile("download/scripts/cheatcodes.txt");
388-
389-
info.Client = client;
390-
strcopy(info.Filename, sizeof(info.Filename), "scripts/cheatcodes.txt");
391-
info.Func = INVALID_FUNCTION;
392-
info.Id = chan.RequestFile(info.Filename);
393-
RequestListing.PushArray(info);
394-
395-
CurrentlyRequesting[client] = info.Id;
396-
StartedRequestingAt[client] += 10;
397-
return Plugin_Continue;
398-
}
363+
int id = param.Get(2);
364+
CNetChan chan = SDKCall(SDKGetNetChannel, address);
399365

400366
int length = RequestListing.Length;
401367
for(int i; i < length; i++)
402368
{
369+
static FileEnum info;
403370
RequestListing.GetArray(i, info);
404-
if(info.Client == client)
371+
if(info.Id == id && chan == CNetChan(info.Client))
405372
{
406-
info.Id = chan.RequestFile(info.Filename);
407-
RequestListing.SetArray(i, info);
408-
409-
CurrentlyRequesting[client] = info.Id;
410-
StartedRequestingAt[client] = GetTime();
411-
float CurrentClientPing = GetClientAvgLatency(client, NetFlow_Outgoing);
412-
CurrentClientPing *= 2.0; //beacuse it has to go bothways.
413-
CurrentClientPing += 0.2; //Little buffer for ping issues and differences
414-
Handle pack;
415-
CreateDataTimer(CurrentClientPing, Timer_DeniedFileCheck, pack);
416-
WritePackCell(pack, client); //Client
417-
WritePackCell(pack, info.Id); //The id that we ask for
418-
return Plugin_Continue;
419-
}
420-
}
373+
if(CurrentlyRequesting[info.Client] == id)
374+
CurrentlyRequesting[info.Client] = -1;
375+
376+
RequestListing.Erase(i);
377+
CallRequestFileFinish(info, false);
421378

422-
// No more files to send
423-
RequestingTimer[client] = null;
424-
return Plugin_Stop;
379+
delete RequestingTimer[info.Client];
380+
SendNextRequest(info.Client);
381+
382+
break;
383+
}
384+
}
385+
return MRES_Ignored;
425386
}
426387

427-
public Action Timer_DeniedFileCheck(Handle timer, DataPack pack)
388+
void StartRequestingClient(int client)
428389
{
429-
pack.Reset();
430-
int client = pack.ReadCell();
431-
int id = pack.ReadCell();
432-
//We can presume the client didnt recieve the file if recieving didnt work out.
433-
OnFileDeniedInternal(CNetChan(client), id);
434-
return Plugin_Stop;
390+
// Small delay between requesting files, Linux Server issue
391+
if(!RequestingTimer[client])
392+
RequestingTimer[client] = CreateTimer(1.5, Timer_RequestingClient, client, TIMER_REPEAT);
435393
}
436394

437-
public MRESReturn OnFileDenied(Address address, DHookParam param)
395+
void SendNextRequest(int client)
438396
{
439-
int id = param.Get(2);
440-
CNetChan chan = SDKCall(SDKGetNetChannel, address);
441-
OnFileDeniedInternal(chan, id);
442-
return MRES_Ignored;
397+
if(CurrentlyRequesting[client] == -1)
398+
{
399+
CNetChan chan = CNetChan(client);
400+
if(chan)
401+
{
402+
int length = RequestListing.Length;
403+
for(int i; i < length; i++)
404+
{
405+
static FileEnum info;
406+
RequestListing.GetArray(i, info);
407+
if(info.Client == client)
408+
{
409+
info.Id = chan.RequestFile(info.Filename);
410+
RequestListing.SetArray(i, info);
411+
412+
CurrentlyRequesting[client] = info.Id;
413+
FailRequestingAt[client] = GetTime() + info.Timeout;
414+
StartRequestingClient(client);
415+
break;
416+
}
417+
}
418+
}
419+
}
420+
else
421+
{
422+
StartRequestingClient(client);
423+
}
443424
}
444425

445-
void OnFileDeniedInternal(CNetChan chan, int id)
426+
public Action Timer_RequestingClient(Handle timer, int client)
446427
{
428+
if(CurrentlyRequesting[client] == -1)
429+
{
430+
SendNextRequest(client);
431+
return Plugin_Continue;
432+
}
433+
434+
// Client still giving this file
435+
if(FailRequestingAt[client] > GetTime())
436+
return Plugin_Continue;
437+
438+
/*
439+
We timed out!
440+
441+
1. This can be a case of the client getting stuck from too many missing file requests.
442+
2. A Linux server may not get the notice that the file was missing on the client.
443+
444+
Request a different file that exists to fix issue 1,
445+
fail and return the callback to fix issue 2.
446+
*/
447+
448+
CNetChan chan = CNetChan(client);
449+
if(!chan)
450+
return Plugin_Continue;
451+
452+
static FileEnum info;
447453
int length = RequestListing.Length;
448454
for(int i; i < length; i++)
449455
{
450-
static FileEnum info;
451456
RequestListing.GetArray(i, info);
452-
if(info.Id == id && chan == CNetChan(info.Client))
457+
if(info.Id == CurrentlyRequesting[client] && info.Client == client)
453458
{
454-
if(CurrentlyRequesting[info.Client] == id)
455-
CurrentlyRequesting[info.Client] = -1;
459+
CurrentlyRequesting[info.Client] = -1;
456460

457461
RequestListing.Erase(i);
458462
CallRequestFileFinish(info, false);
459-
460-
if(RequestingTimer[info.Client])
461-
TriggerTimer(RequestingTimer[info.Client]);
462-
463463
break;
464464
}
465465
}
466+
467+
if(info.Plugin == null)
468+
{
469+
// We already tried unstucking with this method, don't try it again
470+
SendNextRequest(client);
471+
}
472+
else
473+
{
474+
DeleteFile("download/scripts/cheatcodes.txt");
475+
476+
info.Plugin = null;
477+
info.Client = client;
478+
strcopy(info.Filename, sizeof(info.Filename), "scripts/cheatcodes.txt");
479+
info.Func = INVALID_FUNCTION;
480+
info.Id = chan.RequestFile(info.Filename);
481+
info.Timeout = 30;
482+
RequestListing.PushArray(info);
483+
484+
CurrentlyRequesting[client] = info.Id;
485+
FailRequestingAt[client] = GetTime() + info.Timeout;
486+
}
487+
return Plugin_Continue;
466488
}
489+
467490
static void CallRequestFileFinish(const FileEnum info, bool success)
468491
{
469492
if(info.Func && info.Func != INVALID_FUNCTION)
@@ -635,6 +658,7 @@ public any Native_RequestFile(Handle plugin, int params)
635658
info.Plugin = plugin;
636659
info.Func = GetNativeFunction(3);
637660
info.Data = GetNativeCell(4);
661+
info.Timeout = params < 5 ? TIMEOUT_PERIOD : GetNativeCell(5);
638662

639663
RequestListing.PushArray(info);
640664

scripting/include/filenetwork.inc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,13 @@ native bool FileNet_SendFile(int client, const char[] file, FileNet_SendFileResu
9393
* @param file Filepath of requested file
9494
* @param callback Optional callback when file is done
9595
* @param data Optional value to pass to the callback function
96+
* @param timeout Timeout period in seconds
9697
*
9798
* @error Invalid client index, client is not in game, or a fake client
9899
*
99100
* @noreturn
100101
*/
101-
native void FileNet_RequestFile(int client, const char[] file, FileNet_RequestFileResult callback = INVALID_FUNCTION, any data = 0);
102+
native void FileNet_RequestFile(int client, const char[] file, FileNet_RequestFileResult callback = INVALID_FUNCTION, any data = 0, int timeout = 90);
102103

103104
/**
104105
* Gets the CNetChan object of a specific client

0 commit comments

Comments
 (0)