Question

Fsockopen UDP connection problem

I am currently developing an APP that makes A UDP connection to another host to send commands (old quake3 engine game server) so you can moderate your gameserver without having to boot the game up on your pc.

I’m using laravel (overkill, but I’m learning the framework as well) and locally it works just fine, I can send the command and retrieve the message just as i want it to be. Now when deploying, the app doesn’t seem to work anymore, it doesn’t send any commands and I can’t seem to debug that, udp doesn’t have status (sometimes shows it connected even though the host is dead) so I’m running out of ideas, the firewall is set-up to allow outgoing UDP/TCP connections(I’ve tried with the firewall disabled as well) to the port I’m sending commands to (29070) and when asking the support about any possible blocking they said no. As you guys are probably way more experienced than me, is this a PHP problem or a VPS one?

$this->fp = fsockopen($this->host, $this->port, $this->errno, $this->errstr, 5);
        socket_set_timeout($this->fp, 5);   

and if I do

if ($this->fp)
    echo 'sucess';

It echoes out sucess, but you can’t really trust that when it comes to UDP connections.

How should I proceed?

Thanks.

ps used lemp and lamp on ubuntu 16.04

also I’ve looked around for another laravel host service and none of them accept outgoing and/or incoming UDP connection, which kill’s my application, so if any of you have any ideas please share, i’m desperate.


Submit an answer

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Sign In or Sign Up to Answer

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in Q&A, subscribe to topics of interest, and get courses and tools that will help you grow as a developer and scale your project or business.

@Vanker

I would deploy a basic AWS instance for testing purposes. I wouldn’t use that script on a production game server since you’d need to install PHP on the server to run it.

On the AWS test instance, you’d run the server.php script and test the connection to it as well as it’s response from a DigitalOcean Droplet that has the client.php file. That way you’re testing across both networks.

Without setting up a test instance on AWS and testing the connection between DigitalOcean and the AWS instance, the only conclusion I can come to is that the issue is on the game server. The cause is hard to determine since I don’t know anything about the game server or how it was setup.

@jtittle For some reason I couldn’t reply to your last comment.

I got your point now, will test with the code you specified although I already destroyed the second droplet (was just testing anyways) so it will take some time.

Let’s say it work the way we expect it to, what could be the case then?

Is there any chance that the game host (amazon) could block certain ips or range of ips or anything like that?

It’s been a week now since I’m trying to figure this problem out and even my hair is turning gray already.

Also, I’d try to deploy on another hosting service to check if it works there, I’m just a programmer so I don’t know a lot about setting up a server from ground, so I MAY have fucked up somewhere (read tutorials on how to set-up) but every host that I found does not allow incoming and/or outgoing udp connections.

@Vanker

As another test, we could use something like this to bounce between two servers.

client.php

<?php
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);

$msg = "Ping!" . PHP_EOL;
$len = strlen($msg);

if ( ! socket_sendto( $sock, $msg, $len, 0, 'REMOTE_IP', 29070 ) )
{
    $errorcode = socket_last_error();
    $errormsg  = socket_strerror( $errorcode );

    die( "Could not send data: [$errorcode] $errormsg" . PHP_EOL );
}

if ( socket_recv( $sock , $reply , 2045 , MSG_WAITALL ) === FALSE )
{
    $errorcode = socket_last_error();
    $errormsg  = socket_strerror( $errorcode );

    die( "Could not receive data: [$errorcode] $errormsg" . PHP_EOL );
}

echo "Reply: $reply";

socket_close($sock);

server.php

<?php
/**
 * Create UDP Socket
 */
if( ! ( $sock = socket_create( AF_INET, SOCK_DGRAM, 0 ) ) )
{
    $errorcode = socket_last_error();
    $errormsg  = socket_strerror( $errorcode );

    die( "Couldn't create socket: [$errorcode] $errormsg" . PHP_EOL );
}

echo 'Socket created' . PHP_EOL;

/**
 * Bind to Source Address
 */
if( ! socket_bind( $sock, '0.0.0.0' , 29070 ) )
{
    $errorcode = socket_last_error();
    $errormsg  = socket_strerror( $errorcode );

    die( "Could not bind socket : [$errorcode] $errormsg" . PHP_EOL );
}

echo 'Socket Bind: OK' . PHP_EOL;

while(1)
{
    echo "Waiting for data ..." . PHP_EOL;

    /**
     * Receive Data
     */
    $r = socket_recvfrom( $sock, $buf, 512, 0, $remote_ip, $remote_port );

    echo "$remote_ip : $remote_port -- " . $buf;

    /**
     * Send Data Back to Client
     */
    socket_sendto( $sock, "OK " . $buf , 100 , 0 , $remote_ip , $remote_port );
}

socket_close( $sock );

You’ll want to change REMOTE_IP on line 7 of client.php to match the IP you’re trying to connect to.

On the remote server, we would run php server.php. Then on the client, we’ll run php client.php.

client.php sends Ping! and server.php responds with OK Ping! which shows on the client server.

This is confirmation of sorts when it comes to whether the message was actually sent. Now, in this example, if the server you’re trying to send to has the port blocked, it will hang, but there’s way around that as well.

We can use socket_set_option, like so:

socket_set_option( $sock, SOL_SOCKET, SO_RCVTIMEO, [ "sec" => 10, "usec" => 0 ] );

You’d change sec from 10 to however many seconds you want to allow the connection attempt to run. So our new client.php script would look like:

<?php
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);

socket_set_option( $sock, SOL_SOCKET, SO_RCVTIMEO, [ "sec" => 10, "usec" => 0 ] );

$msg = "Ping!" . PHP_EOL;
$len = strlen($msg);

if ( ! socket_sendto( $sock, $msg, $len, 0, 'REMOTE_IP', 29070 ) )
{
    $errorcode = socket_last_error();
    $errormsg  = socket_strerror( $errorcode );

    die( "Could not send data: [$errorcode] $errormsg" . PHP_EOL );
}

if ( socket_recv( $sock , $reply , 2045 , MSG_WAITALL ) === FALSE )
{
    $errorcode = socket_last_error();
    $errormsg  = socket_strerror( $errorcode );

    die( "Could not receive data: [$errorcode] $errormsg" . PHP_EOL );
}

echo "Reply: $reply";

socket_close($sock);

In the above, if it doesn’t connect and send in 10 seconds, you’ll receive something like:

Could not receive data: [11] Resource temporarily unavailable