Author Topic: Download thread problem  (Read 3134 times)

0 Members and 1 Guest are viewing this topic.

Offline CurryWurst

  • Camper
  • ***
  • Posts: 265
    • Soldat Global Account System
Download thread problem
« on: February 22, 2009, 06:41:16 pm »
ATM I'm playing with the download thread function of the Soldat server and
I encountered a problem...

A PHP server sends a map file request and waits for the explicit response
such as STARTFILES & ENDFILES. The problem is that the Soldat server sends
everthing exempt from the ENDFILES command.

Thanks in advance!
« Last Edit: February 27, 2009, 06:32:44 pm by Markus Quär »
Soldat Global Account System: #soldat.sgas @ quakenet

Offline chrisgbk

  • Inactive Staff
  • Veteran
  • *****
  • Posts: 1739
Re: Download thread problem
« Reply #1 on: February 23, 2009, 03:33:57 pm »
Would help to see the PHP code; since the server is hardcoded to send STARTFILES\r\n and ENDFILES\r\n regardless of what happens with the data in between, I would lean to it being a problem in the PHP code, such as accidently parsing data inside the map file as text and splitting it at a linefeed, or not reading all the data waiting, or some other such thing. However, the file sending code has been rewritten for 1.5.0 so any bugs present will be fixed upon the release of that.

Also check case sensitivity and proper path if the server is running linux; the correct name is (I believe) Maps/Arena.PMS

Offline jrgp

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 5037
Re: Download thread problem
« Reply #2 on: February 23, 2009, 05:00:05 pm »
Also check case sensitivity and proper path if the server is running linux; the correct name is (I believe) Maps/Arena.PMS
Actually the folder "Maps" is all lowercase.
There are other worlds than these

Offline CurryWurst

  • Camper
  • ***
  • Posts: 265
    • Soldat Global Account System
Re: Download thread problem
« Reply #3 on: February 27, 2009, 02:22:09 pm »
Would help to see the PHP code; since the server is hardcoded to send STARTFILES\r\n and ENDFILES\r\n regardless of what happens with the data in between, I would lean to it being a problem in the PHP code, such as accidently parsing data inside the map file as text and splitting it at a linefeed, or not reading all the data waiting, or some other such thing. However, the file sending code has been rewritten for 1.5.0 so any bugs present will be fixed upon the release of that.

Also check case sensitivity and proper path if the server is running linux; the correct name is (I believe) Maps/Arena.PMS

Here we go ...

Soldat_Map_Download_Bot.php
Code: [Select]
<?php
require 'class_Lobby.php';
set_time_limit(0);

$folder 'E:/Map Downloads/';
$timeout 2;

echo 
"\n:::: S.M.D.B. - Soldat Map Download Bot ::::\n";

$lobby = new SoldatLobby();
echo 
"-> " $lobby -> count " server online\n";

for (
$i 0$i $lobby -> count$i++)
{
  if (!
file_exists($folder $lobby -> servers[$i]['Map'] . '.PMS'))
  {
    
$address $lobby -> servers[$i]['IP'];
    
$port $lobby -> servers[$i]['Port'] + 10;

    echo 
"\n-> [$i] Connecting to $address\n";

    if(!
$sock = @fsockopen($address$port$errno$errstr3))
    {
      echo 
"-> Connection failed\n";
      continue;
    }
    else
    {
      echo 
'-> Connection established' ."\n";

      
$newmap $lobby -> servers[$i]['Map'] . '.PMS';
      
fwrite($sock"maps/$newmap\n");
      
      
stream_set_timeout($sock,$timeout);
      
$info stream_get_meta_data($sock);

      
$data '';
      
$map '';
     
      while ((
$data != "ENDFILES\r\n") && (!$info['timed_out']))
      {
        
$data = @fgets($sock2048);
        switch (
$data)
        {
          case 
"STARTFILES\r\n":
               {
                 break;
               }
          case 
"maps/$newmap\r\n":
               {
                 echo 
"<- Receiving $newmap ...";
                 break;
               }
          case 
"ENDFILES\r\n":
               {
                 echo 
" done";
                 break;
               }
          default:
               {
                 
$map .= $data;
               }
        }
        
$info stream_get_meta_data($sock);
      }
    }
    if (
$info['timed_out'])
    {
      echo 
"\n-> Connection timed out\n";
      continue;
    }
    else
    {
      
$newmap preg_replace('/[*:?"<>|\/]/''_'$newmap);
      if (!
$handle fopen($folder $newmap"w")) 
      {
        echo 
"Could not open $newmap to write\n";
      }
      else
      {
        if (
fwrite($handle$map))
        {
          echo 
"-> Map saved to $folder\n";
          
fclose($handle);
        }
      }
      
fclose($sock);
    }
  }
}
?>


class_Lobby.php
Code: [Select]
<?php
class SoldatLobby
{
  private 
$address;
  private 
$port;
  private 
$timeout 5;
  private 
$sock;

  public 
$servers = array();
  public 
$count;
 
  function 
SoldatLobby()
  {
    
$this -> address 'rr.soldat.pl';
    
$this -> port 13073;
    if (!
$this -> connect())
    {
      echo 
" failed\n";
      exit();
    }
    else
    {
      echo 
" success\n";
      
$this -> send_request("e©42©0©0©0©0©0©0©0©0©0©0©-1©0\n");
      
$this -> parse_lobbyinfo();
    }
    
fclose($this -> sock);
  }

  private function 
connect()
  {
    echo 
"-> Setting up lobby connection ...";
    if (
$this -> sock = @fsockopen($this -> address$this -> port))
    {
      return 
TRUE;
    }
  }

  private function 
send_request($req)
  {
    return 
fwrite($this -> sock$req);
  }

  private function 
receive_packet()
  {
    
stream_set_timeout($this -> sock$this -> timeout);
    
$info stream_get_meta_data($this -> sock);

    while ((!
feof($this -> sock)) && (!$info['timed_out']))
    {
      
$packet = @fgets($this -> sock2048);
      
$info stream_get_meta_data($this -> sock); 
      return 
trim($packet);
    }
    if (
$info['timed_out'])
    {
      
fclose($this -> sock);
      exit();
    }
  }
  
  private function 
parse_serverinfo($info)
  {
    
$info explode('©'$info);
    
    if (
$info[0] != 'g')
    {
      return 
NULL;
    }
    else
    {
      
$server['Name'] = $info[8];
      
$server['IP'] = $info[2];
      
$server['Port'] = $info[3];
      
$server['Map'] = $info[7];
      
      return 
$server;
    }
  }

  private function 
parse_lobbyinfo()
  {
    
$packet explode('©'$this -> receive_packet());
    echo 
"-> Parsing lobby info ...";
    if (
$packet[0] != 'f')
    {
      
fclose($this -> sock);
      echo 
" failed\n";
      exit();
    }
    
$this -> count $packet[1];
    for (
$i 0$i $this -> count 1$i++)
    {
      
$info $this -> receive_packet();
      if (
$info == "h©©©©©")
      {
        break;
      }
      
$server $this -> parse_serverinfo($info);
      if (
$server == NULL)
      {
        break;
      }
      else
      {
        
$this -> servers[] = $server;
      }
    }
    echo 
" done\n";
  }
}

This is my very first PHP code. I hope it's possible to comprehend.

Offtopic: Does the soldat server sends the <size> information about a requested file?
I never saw this information.

Thanks for your support guys!
Soldat Global Account System: #soldat.sgas @ quakenet

Offline mar77a

  • Global Moderator
  • Veteran
  • *****
  • Posts: 1295
  • mad
    • random stuffs
Re: Download thread problem
« Reply #4 on: February 27, 2009, 02:51:57 pm »

Offline chrisgbk

  • Inactive Staff
  • Veteran
  • *****
  • Posts: 1739
Re: Download thread problem
« Reply #5 on: February 27, 2009, 06:13:44 pm »
I just looked over the old server side code; it seems that if an exception occurs on the server it will fail out without sending ENDFILES\r\n. The only way I can actually see this happening is if you request a file while it is in use, because theres a check if the file exists before it attempts to open it, that results in

Code: [Select]
STARTFILES\r\n
<map name>\r\n
ENDFILES\r\n

as normal, but only if there is an exception does it end up with just

Code: [Select]
STARTFILES\r\n
<map name>\r\n

although it DOES close the connection in this case.

This has already been rectified in 1.5.0 due to the rewrite of the code, and as of my last check, for reference, the new file transfer format is:

Code: [Select]
To server:

STARTFILES\r\n
<filename 1>\r\n
<filename 2>\r\n
...
<filename n>\r\n
ENDFILES\r\n

From server:

STARTFILES\r\n
<total size of all files as 4 byte integer>
<filename 1>\r\n
<size of file 1 as 4 byte integer>
<file 1 data>
<filename 2>\r\n
<size of file 2 as 4 byte integer>
<file 2 data>
...
<filename n>\r\n
<size of file n as 4 byte integer>
<file n data>
ENDFILES\r\n
« Last Edit: June 20, 2009, 05:43:58 pm by chrisgbk »

Offline CurryWurst

  • Camper
  • ***
  • Posts: 265
    • Soldat Global Account System
Re: Download thread problem
« Reply #6 on: February 27, 2009, 06:27:08 pm »
Many thanks for this obvious information. I'll rewrite my project according to v.1.5.0 and
voice you back later if something still goes wrong.
Soldat Global Account System: #soldat.sgas @ quakenet