Пример #1
0
        /// <summary>deals with methods of the router class</summary>
        private void AcceptClientThread(IAsyncResult result)
        {
            TcpClient client = _listener.EndAcceptTcpClient(result);

            _processed_connection.Set();

            EndPoint?endpoint = client.Client.RemoteEndPoint;              // we put it right here to make things easier later on (gwyneth 20220107)

            string ip = String.Empty;

            // more stupid checks to deal with the many, many ways this can become null... (gwyneth 20220214)
            if (endpoint != null)
            {
                string?endpointToString = endpoint.ToString();
                if (endpointToString != null)
                {
                    ip = endpointToString.Split(':')[0];
                    DebugUtilities
                    .WriteInfo($"Processing Connection from {IPAddress.Parse(((IPEndPoint) endpoint).Address.ToString())} (ip: {ip})!");                             // new syntax, since this is now nullable (gwyneth 20220207)
                }
                else
                {
                    DebugUtilities.WriteError("No IP address received (?) or couldn't parse IP address for connection");
                }
            }

            NetworkStream stream = client.GetStream();

            DebugUtilities.WriteSpecial("Reading Stream");
            string request = "";

            byte[] buffer = new byte[512];
            int    i      = 0;

            do
            {
                i = stream.Read(buffer, 0, buffer.Length);        //add the next set of data into the buffer..
                DebugUtilities.WriteSpecial("Read chunk from the stream");
                request += Encoding.UTF8.GetString(buffer, 0, i); //append it to the overall request
            }while (stream.DataAvailable);                        //and repeat :)

            DebugUtilities
            .WriteInfo($"Got request, totalling {request.Length} characters");
            string[] split =
                request
                .Split(new string[] { "\r\n\r\n" },
                       StringSplitOptions.RemoveEmptyEntries);

            string hostname = "unknown";                // if we can't resolve IP address to a hostname...

            try
            {
                DebugUtilities.WriteDebug("ip: " + ip ?? "nothing");                    // may be an empty string (gwyneth 20220214)
                if (ip != null)
                {
                    IPHostEntry host = Dns.GetHostEntry(IPAddress.Parse(ip));
                    hostname = host.HostName;
                }
                DebugUtilities.WriteDebug($"ENDPOINT HOSTNAME: {hostname}");
            }
            catch
            {
                DebugUtilities
                .WriteWarning("Could not parse ip address to get the hostname (ipv6?) -  hostname is set as 'unknown'");
            }

            /// <value>get request headers into the appropriate class</value>
            RequestHeaders _request_headers = new RequestHeaders(split[0], hostname);

            string body = "";

            /// <value>
            /// For some reason, the RESTbot HTTP server takes pleasure in waiting for 100-continue,
            /// so we set a flag here.
            /// </value>
            bool foundExpectContinue = false;

            foreach (HeaderLine line in _request_headers.HeaderLines)
            {
                if (line.ToString() == "Expect: 100-continue")
                {
                    foundExpectContinue = true;
                    DebugUtilities.WriteSpecial("Found 100 continue!");
                }
            }

            if (foundExpectContinue)
            {
                try
                {
                    ResponseHeaders continue_response =
                        new ResponseHeaders(100, "Continue");
                    byte[] byte_continue_response =
                        System.Text.Encoding.UTF8.GetBytes(continue_response.ToString());

                    //send the 100 continue message and then go back to the above.
                    DebugUtilities.WriteSpecial("Writing 100 continue response");
                    stream.Write(byte_continue_response, 0, byte_continue_response.Length);
                    DebugUtilities.WriteSpecial($"Finished writing - {byte_continue_response.Length} bytes total sent");

                    request = "";
                    buffer  = new byte[512];
                    /// <value>stream chunk counter</value>
                    i = 0;
                    if (stream.DataAvailable)
                    {
                        DebugUtilities.WriteSpecial("DATA AVALIABLE!!");
                    }
                    else
                    {
                        DebugUtilities.WriteWarning("NO DATA AVALIABLE? Hurr");
                    }
                    do
                    {
                        i = stream.Read(buffer, 0, buffer.Length);        //add the next set of data into the buffer..
                        DebugUtilities.WriteSpecial("Read continued chunk from the stream");
                        request += Encoding.UTF8.GetString(buffer, 0, i); //append it to the overall request
                    }while (stream.DataAvailable);                        //and repeat :)

                    DebugUtilities.WriteInfo($"Got continued request, totalling {request.Length} characters");
                    DebugUtilities.WriteDebug($"Here's what I got: {request}");
                    body = request;
                }
                catch (Exception e)
                {
                    DebugUtilities.WriteError("An error occured while trying to talk to the client (100 expectation response): " + e.Message);
                }
            }
            else
            {
                if (split.Length > 1)
                {
                    body = split[1];
                }
            }
            /// <value>Status message to return to the client that made the request</value>
            /// <remarks>Likely XML-formatted (there are very few exceptions)</remarks>
            string to_return = Program.DoProcessing(_request_headers, body);

            // The next line is DELIBERATELY not using interpolated strings, because there might have
            // been some issues with those. (gwyneth 20220426)
            to_return = "<restbot>" + to_return + "</restbot>";
            // commented out until I figure out how to write a DebugUtilities.WriteTrace() method. (gwyneth 20220426)
            // DebugUtilities.WriteDebug($"What I should return to the client: {to_return}");

            ResponseHeaders response_headers = new ResponseHeaders(200, "OK");
            string          response         = response_headers.ToString() + to_return;

            try
            {
                /// <value>stream of bytes to send over the HTTP stream as response</value>
                /// <remarks>TODO(gwyneth): This comes as XML, but we might wish to convert it first to JSON or
                /// something else. Note: this would require changing the headers, too</remarks>
                byte[] the_buffer = System.Text.Encoding.UTF8.GetBytes(response);
                response = "";                 //unset for the hell of it
                stream.Write(the_buffer, 0, the_buffer.Length);
            }
            catch (Exception e)
            {
                DebugUtilities.WriteError("Could not write to the network stream, error was: " + e.Message);
                //see below
            }

            try
            {
                stream.Close();
                client.Close();
            }
            catch
            {
                DebugUtilities.WriteWarning("An error occured while closing the stream");
                // ignore, sometimes the connection was closed by the client
                // if it's to be ignored, I've downgraded it to a warning. (gwyneth 20220426)
            }
        }
Пример #2
0
        private void AcceptClientThread(IAsyncResult result)
        {
            TcpClient client = _listener.EndAcceptTcpClient(result);
            _proccessed_connection.Set();

            DebugUtilities.WriteInfo("Processing Connection from " + client.Client.RemoteEndPoint.ToString() + "!");
            NetworkStream stream = client.GetStream();

            DebugUtilities.WriteSpecial("Reading Stream");
            string request = "";
            byte[] buffer = new byte[512];
            int i = 0;
            do
            {

                i = stream.Read(buffer, 0, buffer.Length); //add the next set of data into the buffer..
                DebugUtilities.WriteSpecial("Read chunk from the stream");
               request += Encoding.UTF8.GetString(buffer, 0, i); //append it to the overall request
            }
            while (stream.DataAvailable); //and repeat :)

            DebugUtilities.WriteInfo("Got request, totalling " + request.Length + " characters");
            string[] split = request.Split(new string[] { "\r\n\r\n" }, StringSplitOptions.RemoveEmptyEntries);

            string hostname = "unknown";
            try
            {
                EndPoint endpoint = client.Client.RemoteEndPoint;
                DebugUtilities.WriteDebug("ip: " + endpoint.ToString());
                string ip = (endpoint.ToString().Split(':'))[0];
                IPHostEntry host = Dns.GetHostEntry(IPAddress.Parse(ip));
                hostname = host.HostName;
                DebugUtilities.WriteDebug("ENDPOINT HOSTNAME: " + hostname);
            }
            catch
            {
                DebugUtilities.WriteWarning("Could not parse ip address to get the hostname (ipv6?) -  hostname is set as 'unknown'");
            }

            RequestHeaders x = new RequestHeaders(split[0], hostname);

            string body = "";

            bool foundExpectContinue = false;
            foreach(HeaderLine line in x.HeaderLines)
            {
                if(line.ToString() == "Expect: 100-continue")
                {
                    foundExpectContinue = true;
                    DebugUtilities.WriteSpecial("Found 100 continue!");
                }
            }

            if(foundExpectContinue)
            {
                try
                {
                    ResponseHeaders continue_response = new ResponseHeaders(100, "Continue");
                    byte[] byte_continue_response = System.Text.Encoding.UTF8.GetBytes(continue_response.ToString());

                    //send the 100 continue message and then go back to the above.
                    DebugUtilities.WriteSpecial("Writing 100 continue response");
                    stream.Write(byte_continue_response,0,byte_continue_response.Length);
                    DebugUtilities.WriteSpecial("Finished writing - " + byte_continue_response.Length + " bytes total sent");

                    request = "";
                    buffer = new byte[512];
                    i = 0;
                    if (stream.DataAvailable) DebugUtilities.WriteSpecial("DATA AVALIABLE!!");
                    else DebugUtilities.WriteWarning("NO DATA AVALIABLE? Hurr");

                    do
                    {
                        i = stream.Read(buffer, 0, buffer.Length); //add the next set of data into the buffer..
                        DebugUtilities.WriteSpecial("Read continued chunk from the stream");
                        request += Encoding.UTF8.GetString(buffer, 0, i); //append it to the overall request
                    }
                    while (stream.DataAvailable); //and repeat :)

                    DebugUtilities.WriteInfo("Got continued request, totalling " + request.Length + " characters");

                    DebugUtilities.WriteDebug("Heres what I got: " + request);
                    body = request;
                }
                catch
                {
                    DebugUtilities.WriteError("An error occured while trying to talk to the client (100 expectation response)");
                }
            }
            else if (split.Length > 1) body = split[1];

            string to_return = Program.DoProcessing(x, body);
            to_return = "<restbot>" + to_return + "</restbot>";
            DebugUtilities.WriteDebug("What I should return to the client: " + to_return);

            ResponseHeaders response_headers = new ResponseHeaders(200, "OK");
            string response = response_headers.ToString() + to_return;

            try
            {
                byte[] the_buffer = System.Text.Encoding.UTF8.GetBytes(response);
                response = ""; //unset for the hell of it
                stream.Write(the_buffer, 0, the_buffer.Length);
            }
            catch
            {
                DebugUtilities.WriteError("Could not write to the network stream!");
                //see below
            }

            try
            {
                stream.Close();
                client.Close();
            }
            catch
            {
                DebugUtilities.WriteError("An error occured while closing the stream");
                //ignore, sometimes the connection was closed by the client
            }
        }
Пример #3
0
        public static string DoProcessing(RequestHeaders headers, string body)
        {
            //Setup variables

            DebugUtilities.WriteDebug("New request - " + headers.RequestLine.Path);
            //Split the URL
            string[] parts = headers.RequestLine.Path.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length < 1)
            {
                return ("<error>invalidmethod</error>");
            }
            string Method = parts[0];
            //Process the request params from POST, URL
            Dictionary<string, string> Parameters = RestBot.HandleDataFromRequest(headers, body);
            string debugparams = null;
            string debugparts = null;
            foreach (KeyValuePair<string, string> kvp in Parameters)
            {
                debugparams = debugparams + "[" + kvp.Key + "=" + kvp.Value + "] ";
            }
            foreach (string s in parts)
            {
                debugparts = debugparts + "[ " + s + " ]";
            }
            DebugUtilities.WriteDebug("Parameters - " + debugparams);
            if (Method == "establish_session")
            {
                DebugUtilities.WriteDebug("We have an establish_session method.");
                //Alright, we're going to try to establish a session
                if (parts.Length >= 2 && parts[1] == Program.config.security.serverPass
                    && Parameters.ContainsKey("first") && Parameters.ContainsKey("last") && Parameters.ContainsKey("pass"))
                {
                    DebugUtilities.WriteDebug("Found required parameters for establish_session");
                    foreach (KeyValuePair<UUID, Session> ss in Sessions)
                    {
                        DebugUtilities.WriteSpecial("Avatar check: [" + ss.Value.Bot.First.ToLower() + "/" + ss.Value.Bot.Last.ToLower() + "] = [" + Parameters["first"].ToLower() + "/" + Parameters["last"].ToLower() + "]");
                        if (Parameters["first"].ToLower() == ss.Value.Bot.First.ToLower() &&
                             Parameters["last"].ToLower() == ss.Value.Bot.Last.ToLower()
                             )
                        {
                            DebugUtilities.WriteWarning("Already running avatar " + Parameters["first"] + " " + Parameters["last"]);
                            return ("<existing_session>true</existing_session>\n<session_id>" + ss.Key.ToString() + "</session_id>");

                        }
                    }
                    UUID id = UUID.Random();
                    Session s = new Session();
                    s.ID = id;
                    s.Hostname = headers.Hostname;
                    s.LastAccessed = DateTime.Now;
                    //Needs the $1$ for the md5 on the login for libsl
                    if (!Parameters["pass"].StartsWith("$1$")) Parameters["pass"] = "******" + Parameters["pass"];
                    s.Bot = new RestBot(s.ID, Parameters["first"], Parameters["last"], Parameters["pass"]);

                    lock (Sessions)
                    {
                        Sessions.Add(id, s);
                    }
                    RestBot.LoginReply reply = s.Bot.Login();
                    if (reply.wasFatal)
                    {
                        lock (Sessions)
                        {
                            if (Sessions.ContainsKey(id))
                            {
                                Sessions.Remove(id);
                            }
                        }
                    }
                    return (reply.xmlReply);
                }
                else
                {
                    String result = null;
                    if (parts.Length < 2)
                    {
                        result = "Missing a part.";
                    }
                    if (!Parameters.ContainsKey("first"))
                    {
                        result = result + " Missing 'first' arg.";
                    }
                    if (!Parameters.ContainsKey("last"))
                    {
                        result = result + " Missing 'last' arg.";
                    }
                    if (!Parameters.ContainsKey("pass"))
                    {
                        result = result + " Missing 'last' arg.";
                    }
                    return ("<error>arguments: "+result+"</error>");
                }
            }
            else if (Method == "server_quit")
            {
                if (parts[1] == Program.config.security.serverPass )
                {
                    foreach (KeyValuePair<UUID, Session> s in Sessions)
                    {
                        lock (Sessions) DisposeSession(s.Key);
                    }
                    StillRunning = false;
                    return ("<status>success</status>\n");
                }
            }

            //Only a method? pssh.
            if (parts.Length == 1)
            {
                return ("<error>nosession</error>");

            }

            UUID sess = new UUID();
            try
            {
                sess = new UUID(parts[1]);
            }
            catch (FormatException)
            {
                return ("<error>parsesessionkey</error>");

            }
            catch (Exception e)
            {
                DebugUtilities.WriteError(e.Message);
            }

            //Session checking
            if (!ValidSession(sess, headers.Hostname))
            {
                return ("<error>invalidsession</error>");

            }

            //YEY PROCESSING
            RestBot r = Sessions[sess].Bot;
            //Last accessed for plugins
            Sessions[sess].LastAccessed = DateTime.Now;
            //Pre-error checking
            if (r.myStatus != RestBot.Status.Connected) //Still logging in?
            {
                return ("<error>" + r.myStatus.ToString() + "</error>");

            }
            else if (!r.Client.Network.Connected) //Disconnected?
            {
                return ("<error>clientdisconnected</error>");

            }
            else if (Method == "exit")
            {
                DisposeSession(sess);
                return ("<disposed>true</disposed>");
            }
            else if (Method == "stats")
            {
                string response = "<bots>" + Sessions.Count.ToString() + "<bots>\n";
                response += "<uptime>" + (DateTime.Now - uptime) + "</uptime>\n";
                return (response);

            }

            return r.DoProcessing(Parameters, parts);
        }