0

I'm trying to set up a HttpListener for a Server Manager for my Multiplayer Unity Game but I am getting an exception when executing the following code:

using System;
using System.IO;
using System.Net;
using System.Threading;
using WebAPI.Route;
using System.Collections.Generic;
using System.Linq;

namespace WebAPI
{
public class WebListener
{
    private int Port = 4444;

    private HttpListener Listener;
    private Thread ListenerThread;
    private bool Bailout = false;

    private List<IRouteController> Routes;

    public WebListener(int port, List<IRouteController> routes)
    {
        Port = port;
        Routes = routes;

        string ip = Dns.GetHostEntry(Dns.GetHostName())
            .AddressList
            .First(x => x.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            .ToString();

        Listener = new HttpListener();
        Listener.Prefixes.Add("http://localhost:" + Port + "/");
        Listener.Prefixes.Add("http://127.0.0.1:" + Port + "/");
        Listener.Prefixes.Add("http://" + ip + ":" + Port + " /");
        Listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
        Listener.Start();

        ListenerThread = new Thread(Listen);
        ListenerThread.Start();
    }

    ~WebListener()
    {
        Bailout = true;
        if (ListenerThread != null)
            ListenerThread.Join();
    }

    private void Listen()
    {
        while (!Bailout)
        {
            var result = Listener.BeginGetContext(ListenerCallback, Listener);
            result.AsyncWaitHandle.WaitOne();
        }
    }

    private void ListenerCallback(IAsyncResult result)
    {
        var context = Listener.EndGetContext(result);

        if (context.Request.HttpMethod == "POST")
        {
            string route = context.Request.Url.LocalPath.ToLower();

            var controller = Routes.Where(r => route.Contains(r.GetRoute())).FirstOrDefault();
            if (controller != null)
            {
                var json = new StreamReader(context.Request.InputStream,
                                            context.Request.ContentEncoding).ReadToEnd();

                controller.RecieveRequest(json);
            }
            else
            {
                WebLogger.LogWarning("Invalid route, no matching controller found: " + route);
            }
        }

        context.Response.Close();
    }

}
}

This is the exception I receive on line Listener.Start();

Exception thrown: 'System.Net.HttpListenerException' in System.Net.HttpListener.dll The parameter is incorrect.

I'm not sure what I'm doing wrong, any ideas?

dave
  • 25
  • 1
  • 7
  • The address list is an array with usually the first address being a IPV6 and second address being IPV4. You probably need the IPV4 address. – jdweng May 04 '22 at 14:48

1 Answers1

1

The " /" in your last Prefixes.Add leads to your exception.

Listener.Prefixes.Add("http://" + ip + ":" + Port + " /");
//                                                   ^  this space above

But if you change it to

Listener.Prefixes.Add("http://" + ip + ":" + Port + "/");

You may get an Access Denied exception if you run your application without admin privileges and did not already add the access rights to all of your prefixes for your user with netsh. Read here for more information.

Instead of adding the Prefixes one by one, you can use wildcards like "http://*:" + Port + "/" or "http://+:" + Port + "/". With the wildcards you don't need to to get a IPv4 address from your AddressList which may not be the interface you want to bind to.

G Wimpassinger
  • 751
  • 5
  • 18
  • It works fine except that I cannot get netsh to run without administrator privileges which kind of defeats the point :/. Any ideas? – dave May 09 '22 at 12:49
  • @dave: I don't believe `netsh` will run without admin privs. Have a look at [this](https://stackoverflow.com/q/2583347/9393458) SO post. – G Wimpassinger May 09 '22 at 15:33