Ejemplo n.º 1
0
        protected override void DataReceived(string data, int clientNumber)
        {
            try
            {
                Stopwatch sw = new Stopwatch();

                sw.Start();

                NntpCommand nntpCommand = null;
                var         client      = GetClient(clientNumber);
                string      response;

                if (client == null)
                {
                    throw new Exception("Client object for [" + clientNumber + "] is not available");
                }

                //LogMessage(clientNumber, client.AuthenticatedClientUsername, data, NO_LOGGING, string.Empty);
                //LogMessage(clientNumber, string.Empty, data, NO_LOGGING, string.Empty);

                // log receive data size
                PerfCounters.IncrementCounterBy(PerfCounterName.BytesReceived, data.Length);

                bool   parseCommand   = false;
                string additionalData = string.Empty;

                if (client.PreviousCommand == Command.POST)
                {
                    Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "DataReceived: Client is posting data");

                    //System.Diagnostics.Debug.WriteLine("Buffer: {0}", client.Buffer);
                    //System.Diagnostics.Debug.WriteLine("Recv: {0}", data);
                    // client is posting data,
                    // keep buffering until dotted terminator reached
                    string postData = data;

                    /*
                     * string ascSeq = string.Empty;
                     * for (int i = 0; i < postData.Length; i++)
                     * {
                     *  ascSeq += (int)postData[i] + " ";
                     * }
                     * //System.Diagnostics.Trace.WriteLine("ascSeq - " + ascSeq);
                     */

                    // Append the data to the internal buffer
                    client.Buffer.Append(postData);

                    // Then extract (at least) the last 5 chars (or min the number of currently received bytes) to determine the termination...
                    string lastChars = string.Empty;
                    if (client.Buffer.Length >= 5)
                    {
                        int len = Math.Max(postData.Length, 5);
                        lastChars = client.Buffer.ToString(client.Buffer.Length - len, len);
                    }

                    // Check for "termination" signal...
                    if (lastChars.IndexOf("\r\n.\r\n") >= 0)
                    {
                        //System.Diagnostics.Trace.WriteLine("Termination sequence sent");
                        var buf = client.Buffer.ToString();

                        // extract post data up to the dot terminator
                        client.Buffer = new StringBuilder(buf.Substring(0, buf.IndexOf("\r\n.\r\n")));

                        // grab any data received after the terminator
                        additionalData = buf.Substring(buf.IndexOf("\r\n.\r\n") + 5);

                        // flag to say we wish to process the received data
                        parseCommand = true;
                    }
                    //else if (lastChars.StartsWith(".\r\n"))
                    //{
                    //    // WHAT does this mean???
                    //    // no post data in this request
                    //    postData = string.Empty;

                    //    // grab any data received after the terminator
                    //    additionalData = data.Substring(3);

                    //    // flag to say we wish to process the received data
                    //    parseCommand = true;
                    //}

                    //client.Buffer.Append(postData);

                    if (parseCommand)
                    {
                        //System.Diagnostics.Trace.WriteLine("Posting article");

                        // create a new command
                        nntpCommand =
                            new NntpCommandPostData
                        {
                            Provider = _dataProvider
                        };
                        // TODO: nntpCommand.ClientUsername = client.AuthenticatedClientUsername;

                        // log command
                        PerfCounters.IncrementCounter(PerfCounterName.TotalNntpCommandPostData);

                        // ensure command executed in context of authenticated user
                        // TODO: client.ImpersonateClient();

                        Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: {0}: {1}", nntpCommand.Command, client.Buffer.ToString());

                        // post the article
                        response = nntpCommand.Parse(client.Buffer.ToString(), null, client);

                        Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Response: {0}", response);

                        // revert to service security context
                        // TODO: client.RevertImpersonation();

                        // send back success/fail message
                        SendData(response, clientNumber);

                        PerfCounters.IncrementCounter(PerfCounterName.CommandsProcessedPerSecond);

                        // clear down buffer & reset command
                        client.Buffer          = new StringBuilder();
                        client.PreviousCommand = Command.NOTRECOGNISED;
                        nntpCommand            = null;
                    }
                }
                else
                {
                    //System.Diagnostics.Trace.WriteLine("Client not posting data");
                    // client is not posting data,
                    // wait until CR-LF pair is reached
                    string postData = data;
                    if (postData.IndexOf("\r\n") >= 0)
                    {
                        //System.Diagnostics.Trace.WriteLine("CR-LF pair received");

                        // extract up to end of line
                        postData = postData.Substring(0, postData.IndexOf("\r\n"));

                        // obtain further data (should not normally be present)
                        additionalData = data.Substring(data.IndexOf("\r\n") + 2);

                        parseCommand = true;
                    }
                    client.Buffer.Append(postData);

                    if (parseCommand)
                    {
                        // determine type of command and extract parameters
                        nntpCommand = ClassifyCommand(client);

                        // clear down buffer
                        client.Buffer = new StringBuilder();
                    }
                }

                if (nntpCommand != null)
                {
                    // ensure command executed in context of authenticated user
                    // TODO: client.ImpersonateClient();

                    // execute the command
                    var             dataSendInAction = false;
                    Action <string> streamWriter     = p =>
                    {
                        SendData(p, client.ClientNumber);
                        dataSendInAction = true;
                        Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: Response: {0}", p);
                    };

                    Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: Command: {0}, Parameters: {1}", nntpCommand.Command, client.CommandParameters);

                    response = nntpCommand.Parse(client.CommandParameters, streamWriter, client);


                    // revert to service security context
                    // TODO: client.RevertImpersonation();

                    // log command
                    PerfCounterName perfCounterNameForCommand = GetTotalCounterFromCommand(client.PreviousCommand);
                    PerfCounters.IncrementCounter(perfCounterNameForCommand);

                    // client attempting to authenticate more than once
                    // then re-authenticate
                    if (client.PreviousCommand == Command.AUTHINFO &&
                        nntpCommand.AuthToken == null)
                    {
                        if (client.Authenticated)
                        {
                            // TODO: client.AuthServerContext.Dispose();
                            // TODO: client.AuthServerContext = null;
                            client.Authenticated = false;
                        }
                    }

                    // steps 2 and 3 of the authentication process
                    if (client.PreviousCommand == Command.AUTHINFO &&
                        nntpCommand.AuthToken != null)
                    {
                        try
                        {
                            // TODO: ServerCredential serverCredential = new ServerCredential(Credential.Package.NTLM);
                            //if (client.AuthServerContext == null)
                            //{
                            //    client.AuthServerContext = new ServerContext(serverCredential, nntpCommand.AuthToken);
                            //    response = response.Replace("<token>", Convert.ToBase64String(client.AuthServerContext.Token));
                            //}
                            //else
                            //{
                            //client.AuthServerContext.Accept(nntpCommand.AuthToken);
                            client.Authenticated = true;
                            response             = GeneralResponses.AuthenticationAccepted;
                            //    PerfCounters.IncrementCounter(PerfCounterName.ResponseAuthenticationAccepted);
                            //}
                        }
                        catch (Exception ex)
                        {
                            // error during authentication (e.g. access denied)
                            // return response to client
                            Traces.NntpServerTraceEvent(TraceEventType.Critical, client, "Failed to authenticate: {0}", Traces.ExceptionToString((ex)));
                            // TODO: client.AuthServerContext.Dispose();
                            // TODO: client.AuthServerContext = null;
                            client.Authenticated = false;
                            response             = GeneralResponses.AccessDenied;
                            PerfCounters.IncrementCounter(PerfCounterName.ResponseAccessDenied);
                        }
                    }

                    //// if user not logged in, send back authenticated required
                    //// message
                    //if (client.PreviousCommand != Command.MODE &&
                    //    client.PreviousCommand != Command.AUTHINFO &&
                    //    (!client.Authenticated ||
                    //      (client.Authenticated &&
                    //       client.AuthenticatedClientUsername.Length == 0)))
                    //{
                    //    response = GeneralResponses.AuthenticationRequired;
                    //    PerfCounters.IncrementCounter(PerfCounterName.ResponseAuthenticationRequired);
                    //}

                    // send response to client
                    if (dataSendInAction == false)
                    {
                        if (string.IsNullOrEmpty(response) == false)
                        {
                            SendData(response, clientNumber);

                            Traces.NntpServerTraceEvent(TraceEventType.Verbose, client, "Received: Response: {0}", response);


                            PerfCounters.IncrementCounter(PerfCounterName.CommandsProcessedPerSecond);

                            // log sent data size
                            PerfCounters.IncrementCounterBy(PerfCounterName.BytesSent, response.Length);
                        }
                        else
                        {
                            throw new Exception("No data returned from parsed command [" + client.PreviousCommand + "]");
                        }
                    }


                    // adjust client state after command execution
                    switch (client.PreviousCommand)
                    {
                    case Command.POST:
                        if (nntpCommand.PostCancelled)
                        {
                            Trace.WriteLine("Posting is not allowed, reset status on client object");
                            client.PreviousCommand = Command.NOTRECOGNISED;
                        }
                        break;

                    case Command.QUIT:
                        DisconnectClient(clientNumber);
                        break;
                    }
                }

                // continue processing if needed
                // additional commands may follow the command
                // or post data just processed
                if (additionalData.Trim().Length > 0)
                {
                    DataReceived(additionalData, clientNumber);
                }

                sw.Stop();

                lock (_perfCounterLock)
                {
                    PerfCounters.IncrementCounterBy(PerfCounterName.AverageProcessingTime, sw.ElapsedTicks);
                    PerfCounters.IncrementCounter(PerfCounterName.AverageProcessingTimeBase);
                }
            }
            catch (Exception ex)
            {
                Traces.NntpServerTraceEvent(TraceEventType.Critical, "[Client {0}] DataReceived failed: {1}", clientNumber, Traces.ExceptionToString(ex));
                if (clientNumber > 0)
                {
                    PerfCounters.IncrementCounter(PerfCounterName.ResponseProgramFault);
                    // INFO: Reply with more specific error message:

                    //if (DetailedErrorResponse)
                    //{

                    var resp = string.Format(
                        "503 program fault - command not performed {0}\r\n",
                        GetErrorResponseFromExeption(ex));
                    SendData(resp, clientNumber);
                    //}
                    //else
                    //{
                    //    SendData(GeneralResponses.ProgramFault, clientNumber);
                    //}
                }
            }
        }