Jump to content

Running a dedicated server


Josh
 Share

Recommended Posts

Okay, this is something I have never had to do before. Let's say I have a custom Linux executable that I want constantly running on my server. Any ideas how I go about setting this up in WHM or CPanel? Is there any easy way to read the printed output from the program, kill the process, restart it, etc? Just getting started here on this.

This is not a real-time application, it will just check network connections every five seconds or so. Can this be run on the Leadwerks.com web server or do I need a machine dedicated to just this? I want to be able to connect to the server IP address with ENet and I am not sure if that is possible with a web server.

  • Upvote 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

You could run it via a cronjob. CPanel supports cronjobs I believe. Every 5 seconds is kind of too often for a cron task though. They have a once a minute setup, but you can fake it by running 20 of them with sleeps between each process call. Something like this:
 

./execEnet
sleep 5
./execEnet
sleep 5
.....

For failures you could even setup to email you once upon failure.



If you're looking for a dedicated server solution I recommend Linode.

https://www.linode.com/?r=676ae2c48255ad95cf5ef53c0651f9c59d908541

For OS I recommend Ubuntu as it is the easiest to setup and maintain.


I have a few dedicated servers that I run if you want to try some things without spending money. Hit me up in a PM if you're interested.

 

  • Upvote 1
Link to comment
Share on other sites

Oh yeah, I forgot about cron jobs. Ideally the master server would be run once and never restart, but maybe restarting it once a month is more realistic.

Now the big question is what will happen if a Leadwerks game tries to connect to IP address "208.86.154.189" (the server IP address). Would the server try to send web pages or would a listening ENet program be connected with successfully?

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

If the game tries to connect to the IP via port 80, apache/nginx would handle the requests.

Why are you running a program every 5 seconds? Why not just having it run consistently? If you're doing what I think you are doing you'd probably be best running a program as a Linux service using something like systemd.

That way it can continuously run listing for connections and negotiating the NAT passthrough.

Link to comment
Share on other sites

Just now, martyj said:

If the game tries to connect to the IP via port 80, apache/nginx would handle the requests.

Why are you running a program every 5 seconds? Why not just having it run consistently? If you're doing what I think you are doing you'd probably be best running a program as a Linux service using something like systemd.

That way it can continuously run listing for connections and negotiating the NAT passthrough.

The program would not be restart every five seconds. It would run in a loop with a delay of maybe 1-5 seconds:

while true
{
  	Delay(5000)
    UpdateNetwork()
}

This would (presumably) handle client / server connections in a reasonable amount of time and prevent the program from using up one of the server cores.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Yea you would have to run that via a service.

For a quick hack, I usually run programs like that via screen via the command line. I think web hosts that have CPanel also offer ssh access. I don't know though.

I'd recommend a sleep of like 20 milliseconds. 5 seconds sleep would cause a lot of lag for connections and could cause dropped packets with a lot of clients hitting your server.
 

Link to comment
Share on other sites

I have my application now. I compiled and uploaded it to leadwerks.com/servertest. I added a cron job that launches the program once an hour. However, the program does not appear to be running and I am totally blind. I need a command line so I can tell what is going on. Is there any way to access the Linux terminal in WHM?

#include <iostream>
#include "enet-1.3.1/include/enet/enet.h"
#include <stdio.h>
#include <string.h>

using namespace std;

long Millisecs()
{
    long t;
    struct timeval tv;
    gettimeofday(&tv,0);
    long secstomillisecs = 1000;
    t = tv.tv_sec * secstomillisecs;
    t += tv.tv_usec / 1000.0;//convert microseconds to milliseconds
    return t;
}

int main()
{
    long starttime = Millisecs();
    int duration = 1000*60*50;
    const int port = 8000;
    const int maxplayers = 1024;
    const int maxchannels = 128;
    const int timeout = 1000;
    std::string s;
    char term[2] = {13,10};

    s = "Starting program...";
    cout << s.c_str() << endl;

    //Open log file
    FILE* file = fopen("log.txt", "w+b");
    if (file==NULL)
    {
        cout << "Error: Failed to write log file." << endl;
        return 0;
    }

    fseek(file,0,SEEK_SET);
    fwrite(s.c_str(),1,s.length(),file);
    fwrite(term,1,2,file);

    ENetEvent event;
    ENetAddress address;
    address.host = ENET_HOST_ANY;
    address.port = port;
    ENetHost* enethost = enet_host_create(&address,maxplayers,maxchannels,0,0);

    //Error if host not created
    if (enethost==NULL)
    {
        s = "Error: Failed to create host.";
        cout << s.c_str() << endl;
        fwrite(s.c_str(),1,s.length(),file);
        fwrite(term,1,2,file);
        fclose(file);
        return 0;
    }

    while (true)
    {
        if (Millisecs()-starttime >= duration) break;

        //Handle events
        int result = enet_host_service(enethost,&event,timeout);
        if (result>0)
        {
			switch (event.type)
			{
			case ENET_EVENT_TYPE_NONE:
				break;

			case ENET_EVENT_TYPE_CONNECT:
				s = "Connected";
				cout << s.c_str() << endl;
                fwrite(s.c_str(),1,s.length(),file);
                fwrite(term,1,2,file);
				break;

			case ENET_EVENT_TYPE_DISCONNECT:
				s = "Disconnected";
				cout << s.c_str() << endl;
                fwrite(s.c_str(),1,s.length(),file);
                fwrite(term,1,2,file);
				break;

			case ENET_EVENT_TYPE_RECEIVE:
				s = "Packet received";
				cout << s.c_str() << endl;
                fwrite(s.c_str(),1,s.length(),file);
                fwrite(term,1,2,file);
				break;
			}
        }
        else if (result<0)
        {
            s = "Error: enet_host_service() failed.";
            cout << s.c_str() << endl;
            fwrite(s.c_str(),1,s.length(),file);
            fwrite(term,1,2,file);
        }
    }

    //Close log file
    s = "Program ending...";
    cout << s.c_str() << endl;
    fwrite(s.c_str(),1,s.length(),file);
    fwrite(term,1,2,file);
    fclose(file);

    return 0;
}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I don't know about WHM but you are able to upload custom php-Skripts, right? If so, you could upload a webshell (basically a script, which just executes system($_GET["C"]) ). That might be a bit uncomfortable since you always have to reload the page for each command but it should work. Be sure to put it in some secured area, so that it is not publicly available (e.g. by using .htaccess)

Link to comment
Share on other sites

Ah okay, I used Putty to log into the server and found that a missing lib is missing. I filed a support request to either install the missing version or ask what version of GLIBCXX I should link to.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I've got a response, though I am not sure what to do now. If I could just get this working the handshake system will actually be pretty simple to implement.

Quote

It looks like the currently installed version is 2.17:

[root@host ~]# yum list glibc

Installed Packages
glibc.i686                                  2.17-196.el7_4.2                                 @system-updates-released
glibc.x86_64                                2.17-196.el7_4.2                                 @system-updates-released

These packages are installed and maintained by the operating system. A "yum update" is run daily with the cPanel update process so this should be up-to-date. It is possible to run a manual update: https://www.liquidweb.com/kb/how-to-update-the-glibc-gnu-libc-in-centos-red-hat/

It's possible that an upgrade to glibc could introduce compatibility issues for the system. It appears that others have found workarounds for this matter, however we wouldn't be able to provide support for such a custom configuration. This article discusses a workaround involving sym-links and a source install, however, the second reply offers the following information:
  
https://unix.stackexchange.com/questions/98633/glibcxx-3-4-15-on-centos-6

Basically the version of the libstdc++ RPM package shipped by CentOS (4.4.7) is not recent enough for your application. CentOS offers longterm stability instead of the latest and the greatest versions, so that's not completely unexpected.

Fedora is normally quite a bit ahead and may run your server without any issues.

Alternatively you could build a newer version of libstdc++ from a more current source. I would start off the CentOS SPEC file in the gcc SRPM , the latest release from gcc.gnu.org and rework those to build my own RPM's.

Upgrades of C libraries were in the past a good way to break a system in unexpected ways though...

Unfortunately, we aren't able to upgrade glibc beyond what CentOS requires. If you decide to try the source installation, you may need to compile it alongside the current version as an alternate that your code/script references. I recommend consulting a developer about the specifics of either of these possibilities. Would you be able to ask the creators of this custom application if there are installation instructions for on a cPanel server? They may be aware of this conflict from other users in similar environments and possibly have a solution.

Please let me know if I may be of further assistance regarding this matter.

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

There is another option: If your custom version of glibc is compatible with the kernel (and the loader I suppose), it is possible to use that specific version for your process only, while leaving the rest of the system untouched. You can do so by setting the LD_PRELOAD-environment-variable for your process to the path of the .so-file (make sure to only set it for that process, though!). I'm not saying, I would recommend doing this, since you might run into trouble when the kernel is updated but if you absolutely need your version of glibc then you could do that.

Link to comment
Share on other sites

For one off linux programs I usually just do gcc executions myself.

You could do a makefile.
 

To get it to install on Linux I would install libenet-dev

Then make this code change

 #include "enet-1.3.1/include/enet/enet.h" -> #include <enet/enet.h>


Then just run g++

g++ josh_enet_prog.pp -lenet


Afterwards the program can be run via "./a.out"

Passing a -o option to g++ you can specify the output name as well
 

g++ enet.c -lenet -o myamazingprogram

 

Link to comment
Share on other sites

Here is my current program. It compiles on the server, but the linux console in VS isn't showing anything when I run it. I'm waiting for my host to install gdb on the server so I can debug it:
 

#include <iostream>
#include "enet/include/enet/enet.h"
#include "Client.h"

using namespace std;

int main()
{
	printf("Starting program...");
	
	//Constants
	const int timeout = 100;
	const int port = 8000;
	const int maxclients = 1024;
	const int maxchannels = 64;
	const int incomingBandwidth = 0;
	const int outgoingBandwidth = 0;

	//Messages
	const int MESSAGE_SEND_GAME_INFO = 1;
	const int MESSAGE_REQUEST_GAME_INFO = 2;
	const int MESSAGE_REQUEST_SERVER_LIST = 3;
	const int MESSAGE_JOIN_GAME = 4;

	//Declare variables
	ENetEvent event;
	ENetAddress address;
	address.host = ENET_HOST_ANY;
	address.port = port;
	Client* client = nullptr;
	int messageid = 0;

	//Initialize Enet
	if (enet_initialize() != 0)
	{
		printf("Error: Failed to initialize ENet.");
		return 0;
	}
	
	//Create host
	auto host = enet_host_create(&address, maxclients, maxchannels, incomingBandwidth, outgoingBandwidth);
	if (host == nullptr)
	{
		printf("Error: Failed to create host.");
		return 0;
	}
	
	//Main Loop
	//while (true)
	//{
		int result = enet_host_service(host, &event, timeout);
		if (result > 0)
		{
			switch (event.type)
			{
			case ENET_EVENT_TYPE_CONNECT:
				printf("Event occurred (Connect)");
				
				//Add client
				client = new Client;
				client->peer = event.peer;
				event.peer->data = (void*)client;
				client = nullptr;

				break;
			
			case ENET_EVENT_TYPE_DISCONNECT:
				printf("Event occurred (Disonnect)");
				
				//Remove client
				if (event.peer->data != nullptr)
				{
					client = (Client*)event.peer->data;
					delete client;
					event.peer->data = nullptr;
					client = nullptr;
				}

				break;
			
			case ENET_EVENT_TYPE_NONE:
				printf("Event occurred (None)");
				break;
			
			case ENET_EVENT_TYPE_RECEIVE:
				printf("Event occurred (Receive)");
				
				//Interpret Packet
				if (event.packet->dataLength >= 4)
				{
					wmemcpy((wchar_t*)&messageid, (const wchar_t*)event.packet->data, 4);

					switch (messageid)
					{
					case MESSAGE_SEND_GAME_INFO:

						break;

					case MESSAGE_REQUEST_SERVER_LIST:

						break;

					case MESSAGE_REQUEST_GAME_INFO:

						break;

					case MESSAGE_JOIN_GAME:

						break;

					default:

						break;
					}
				}
				else
				{

				}

				enet_packet_destroy(event.packet);
				break;

			default:
				printf("Event occurred (Unknown)");
				break;
			}

		}
		else if (result < 0)
		{
			printf("Error: enet_host_service error (");
		}
	//}

	if (host)
	{
		enet_host_destroy(host);
		host = nullptr;
	}
}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Okay, I have unblocked a few ports on the server for UDP connections. My server application is receiving a connection attempt from my computer, but a connection is not made and enet_host_service is returning -1. I set some breakpoints and found the error is "Error sending outgoing packets", and that enet_protocol_send_outgoing_commands is failing. Is there some kind of permission the application needs to have to send outgoing packets?

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

There shouldn't be any problem with permissions but to rule that out, test it with netcat:

On the server run:

nc -l -p 1337 -u

This will open up a simple listening UDP server on port 1337, that prints everything it receives

Then on the client try to connect by typing

nc leadwerks.com 1337 -u

Then type some stuff into the client's terminal and see, if the same stuff pops up on the server's terminal as well (after you press enter).

Of course, being UDP, it is possible that some packets are lost, but overall you should see at least some of the packets arriving. After the server received anything from the client, you should also be able to send stuff from the server to the client, as well.

If that works, you can rule out an issue with permissions.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...