示例#1
0
        public HmuxConnection OpenConnection()
        {
            long now = Utils.CurrentTimeMillis();

            lock (this) {
                if (_failTime > 0 && (_failTime + _loadBalanceRecoverTime) > now)
                {
                    return(null);
                }

                if (_busyTime > 0 && (_busyTime + _loadBalanceRecoverTime) > now)
                {
                    return(null);
                }

                //only allow a single thread to open connection
                if ((_failTime > 0 || _busyTime > 0) && _startingCount > 0)
                {
                    return(null);
                }
            }

            HmuxConnection channel = OpenRecycle();

            if (channel != null)
            {
                return(channel);
            }

            return(Connect());
        }
示例#2
0
        public HmuxConnection OpenSessionServer(String sessionId)
        {
            if (sessionId == null || sessionId.Length < 1)
            {
                return(null);
            }

            char c = sessionId[0];

            int i = c - 'a';

            if (i < 0 || i >= _servers.Length)
            {
                return(null);
            }

            Server server = _servers[i];

            HmuxConnection connection = null;

            connection = server.OpenConnection();

            Trace.TraceInformation("open session server {0}->{1}", sessionId, connection);

            return(connection);
        }
示例#3
0
        public HmuxConnection OpenSessionServer(String sessionId)
        {
            char c = sessionId[0];

            Server server = _servers[(c - 'a')];

            HmuxConnection connection = null;

            connection = server.OpenConnection();

            return(connection);
        }
示例#4
0
        internal void Close(HmuxConnection connection)
        {
            if (_log.IsLoggable(EventLogEntryType.Information))
            {
                _log.Info("Close {0}", connection);
            }

            Trace.TraceInformation("Close '{0}'", connection);

            lock (this) {
                _activeCount--;
            }
        }
示例#5
0
        public HmuxConnection OpenAnyServer(Server xChannelFactory)
        {
            int serverCount = _servers.Length;

            Server         server     = null;
            HmuxConnection connection = null;

            int id = 0;

            lock (this) {
                _roundRobinIdx = _roundRobinIdx % serverCount;
                id             = _roundRobinIdx;
                _roundRobinIdx++;
            }

            server     = _servers[id];
            connection = server.OpenConnection();

            if (connection != null)
            {
                return(connection);
            }

            lock (this) {
                _roundRobinIdx = _random.Next(serverCount);

                for (int i = 0; i < serverCount; i++)
                {
                    id = (i + _roundRobinIdx) % serverCount;

                    server = _servers[id];
                    if (xChannelFactory != server || serverCount == 1)
                    {
                        connection = server.OpenConnection();
                    }

                    _roundRobinIdx = id;

                    if (connection != null)
                    {
                        break;
                    }
                }
            }

            Trace.TraceInformation("open any server {0}", connection);

            return(connection);
        }
示例#6
0
        public HmuxConnection OpenServer(String sessionId, Server xServer)
        {
            HmuxConnection connection = null;

            if (sessionId != null && sessionId.Length > 1)
            {
                connection = OpenSessionServer(sessionId);
            }

            if (connection == null)
            {
                connection = OpenAnyServer(xServer);
            }

            return(connection);
        }
示例#7
0
        public HmuxConnection OpenServer(String sessionId, Server xServer)
        {
            Trace.TraceInformation("OpenServer: {0}:{1}", _servers.Length, _servers[0]);

            HmuxConnection connection = null;

            if (sessionId != null)
            {
                connection = OpenSessionServer(sessionId);
            }

            if (connection == null)
            {
                connection = OpenAnyServer(xServer);
            }

            return(connection);
        }
示例#8
0
        private HmuxConnection OpenRecycle()
        {
            long           now     = Utils.CurrentTimeMillis();
            HmuxConnection channel = null;

            lock (this) {
                if (_idleHead != _idleTail)
                {
                    channel = _idle[_idleHead];
                    long freeTime = channel.GetIdleStartTime();

                    _idle[_idleHead] = null;
                    _idleHead        = (_idleHead + _idle.Length - 1) % _idle.Length;

                    if (now < freeTime + _loadBalanceIdleTime)
                    {
                        _activeCount++;

                        channel.ClearIdleStartTime();
                        channel.ToActive();

                        Trace.TraceInformation("OpenRecycle '{0}'", channel);

                        return(channel);
                    }
                }
            }

            if (channel != null)
            {
                if (_log.IsLoggable(EventLogEntryType.Information))
                {
                    _log.Info(this + " close idle " + channel
                              + " expire=" + new DateTime(channel.GetIdleStartTime() * 10 + _loadBalanceIdleTime * 10));
                }
                Trace.TraceInformation("closing expired channel '{0}'", channel);

                channel.CloseImpl();
            }

            Trace.TraceInformation("OpenRecyle return 'null'");

            return(null);
        }
示例#9
0
文件: Server.cs 项目: xuxx09/resin
        private HmuxConnection Connect()
        {
            lock (this) {
                if (_maxConnections <= _activeCount + _startingCount)
                {
                    return(null);
                }

                _startingCount++;
            }

            HmuxConnection connection = null;

            Object connectLock = new Object();

            Monitor.Enter(connectLock);
            try {
                Socket socket = new Socket(_address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                AsyncCallback connectListener = delegate(IAsyncResult result)
                {
                    Monitor.Enter(connectLock);
                    try {
                        Monitor.Pulse(connectLock);
                    } catch (Exception) {
                    } finally {
                        Monitor.Exit(connectLock);
                    }
                };

                socket.BeginConnect(_address, _port, connectListener, socket);
                Monitor.Wait(connectLock, _loadBalanceConnectTimeout);

                if (!socket.Connected)
                {
                    throw new SocketException(10053);
                }

                socket.SendTimeout    = _socketTimeout;
                socket.ReceiveTimeout = _socketTimeout;

                String traceId;
                if (_isDebug)
                {
                    int i = _traceId++;
                    traceId = i.ToString();
                }
                else
                {
                    traceId = socket.Handle.ToInt32().ToString();
                }

                connection = new HmuxConnection(socket, this, _serverInternalId, traceId);

                lock (this) {
                    _activeCount++;
                }

                if (_log.IsLoggable(EventLogEntryType.Information))
                {
                    _log.Info("Connect " + connection);
                }

                Trace.TraceInformation("Connect '{0}'", connection);

                return(connection);
            } catch (SocketException e) {
                String message = String.Format("Socket connection to {0}:{1} timed out on load-balance-connect-timeout {2}", _address, _port, _loadBalanceConnectTimeout);
                if (_log.IsLoggable(EventLogEntryType.Information))
                {
                    _log.Info(message);
                }

                Trace.TraceInformation(message);
            } catch (Exception e) {
                String message = String.Format("Can't create HmuxChannel to '{0}:{1}' due to: {2} \t {3}", _address, _port, e.Message, e.StackTrace);
                if (_log.IsLoggable(EventLogEntryType.Information))
                {
                    _log.Info(message);
                }

                Trace.TraceError(message);
            } finally {
                lock (this) {
                    _startingCount--;
                }

                if (connection == null)
                {
                    FailConnect();
                }

                Monitor.Exit(connectLock);
            }

            return(null);
        }
示例#10
0
        internal void Free(HmuxConnection channel)
        {
            Success();

            lock (this) {
                _activeCount--;

                bool failing = false;

                failing = _failTime > 0 || _busyTime > 0;

                int size = (_idleHead - _idleTail + _idle.Length) % _idle.Length;

                if (!failing && size < _idleSize)
                {
                    Trace.TraceInformation("Returning channel '{0}' to pool", channel);
                    _idleHead        = (_idleHead + 1) % _idle.Length;
                    _idle[_idleHead] = channel;

                    channel = null;
                }
            }

            long           now         = Utils.CurrentTimeMillis();
            long           maxIdleTime = _loadBalanceIdleTime;
            HmuxConnection oldChannel  = null;

            do
            {
                oldChannel = null;

                lock (this) {
                    if (_idleHead != _idleTail)
                    {
                        int nextTail = (_idleTail + 1) % _idle.Length;

                        oldChannel = _idle[nextTail];
                        if (oldChannel != null &&
                            (oldChannel.GetIdleStartTime() + maxIdleTime) < now)
                        {
                            _idle[nextTail] = null;
                            _idleTail       = nextTail;
                        }
                        else
                        {
                            oldChannel = null;
                        }
                    }
                }

                if (oldChannel != null)
                {
                    oldChannel.CloseImpl();
                    Trace.TraceInformation("closing expired channel '{0}'", oldChannel);
                }
            } while (oldChannel != null);

            if (channel != null)
            {
                channel.CloseImpl();
            }
        }
示例#11
0
        private HmuxConnection Connect()
        {
            lock (this) {
                if (_maxConnections <= _activeCount + _startingCount)
                {
                    return(null);
                }

                _startingCount++;
            }

            HmuxConnection connection = null;

            try {
                Socket       socket      = new Socket(_address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                IAsyncResult asyncResult = socket.BeginConnect(_address, _port, null, socket);
                asyncResult.AsyncWaitHandle.WaitOne(_loadBalanceConnectTimeout);

                if (!socket.Connected)
                {
                    try
                    {
                        socket.Close();
                    }
                    catch (Exception e)
                    {
                        if (_log.IsLoggable(EventLogEntryType.Error))
                        {
                            String message = String.Format("Closing of Socket {0}:{1} failed due to: {2}", _address, _port, e.Message);
                            _log.Error(message);
                        }
                    }
                    finally
                    {
                        throw new SocketException(10060);
                    }
                }

                socket.SendTimeout    = _socketTimeout;
                socket.ReceiveTimeout = _socketTimeout;

                String traceId;
                if (_isDebug)
                {
                    int i = _traceId++;
                    traceId = i.ToString();
                }
                else
                {
                    traceId = socket.Handle.ToInt32().ToString();
                }

                connection = new HmuxConnection(socket, this, _serverInternalId, traceId);

                lock (this) {
                    _activeCount++;
                }

                Trace.TraceInformation("Connect '{0}'", connection);

                return(connection);
            } catch (SocketException e) {
                String message = String.Format("Socket connection to {0}:{1} timed out on load-balance-connect-timeout {2} due to: {3}({4})", _address, _port, _loadBalanceConnectTimeout, e.Message, e.ErrorCode);
                if (_log.IsLoggable(EventLogEntryType.Error))
                {
                    _log.Error(message);
                }


                Trace.TraceInformation(message);
            } catch (Exception e) {
                String message = String.Format("Can't create HmuxChannel to '{0}:{1}' due to: {2} \t {3}", _address, _port, e.Message, e.StackTrace);
                if (_log.IsLoggable(EventLogEntryType.Error))
                {
                    _log.Error(message);
                }

                Trace.TraceError(message);
            } finally {
                lock (this) {
                    _startingCount--;
                }

                if (connection == null)
                {
                    FailConnect();
                }
            }

            return(null);
        }
        internal void Close(HmuxConnection connection)
        {
            if (_log.IsLoggable(EventLogEntryType.Information))
            _log.Info("Close {0}", connection);

              Trace.TraceInformation("Close '{0}'", connection);

              lock (this) {
            _activeCount--;
              }
        }
示例#13
0
        private HmuxConnection Connect()
        {
            lock (this) {
            if (_maxConnections <= _activeCount + _startingCount)
              return null;

            _startingCount++;
              }

              HmuxConnection connection = null;
              try {
            Socket socket = new Socket(_address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            IAsyncResult asyncResult = socket.BeginConnect(_address, _port, null, socket);
            asyncResult.AsyncWaitHandle.WaitOne(_loadBalanceConnectTimeout);

            if (!socket.Connected)
            {
              try
              {
            socket.Close();
              }
              catch (Exception e)
              {
            if (_log.IsLoggable(EventLogEntryType.Error))
            {
              String message = String.Format("Closing of Socket {0}:{1} failed due to: {2}", _address, _port, e.Message);
              _log.Error(message);
            }
              }
              finally
              {
            throw new SocketException(10060);
              }
            }

            socket.SendTimeout = _socketTimeout;
            socket.ReceiveTimeout = _socketTimeout;

            String traceId;
            if (_isDebug) {
              int i = _traceId++;
              traceId = i.ToString();
            } else {
              traceId = socket.Handle.ToInt32().ToString();
            }

            connection = new HmuxConnection(socket, this, _serverInternalId, traceId);

            lock (this) {
              _activeCount++;
            }

            Trace.TraceInformation("Connect '{0}'", connection);

            return connection;
              } catch (SocketException e) {
            String message = String.Format("Socket connection to {0}:{1} timed out on load-balance-connect-timeout {2} due to: {3}({4})", _address, _port, _loadBalanceConnectTimeout, e.Message, e.ErrorCode);
            if (_log.IsLoggable(EventLogEntryType.Error))
            {
              _log.Error(message);
            }

            Trace.TraceInformation(message);
              } catch (Exception e) {
            String message = String.Format("Can't create HmuxChannel to '{0}:{1}' due to: {2} \t {3}", _address, _port, e.Message, e.StackTrace);
            if (_log.IsLoggable(EventLogEntryType.Error))
              _log.Error(message);

            Trace.TraceError(message);
              } finally {
            lock (this) {
              _startingCount--;
            }

            if (connection == null)
              FailConnect();
              }

              return null;
        }
示例#14
0
        private int HandleRequest(HttpContext context,
                                  HttpRequest request,
                                  HttpResponse response,
                                  HmuxConnection hmuxChannel,
                                  BufferedStream rs,
                                  BufferedStream ws,
                                  byte[] buf, int length, bool isComplete,
                                  bool allowBusy)
        {
            Trace.TraceInformation("Handle request: length: {0}, complete: {1}, allowBusy {2}", length, isComplete, allowBusy);
            String traceId = hmuxChannel.GetTraceId();

            StringBuilder cb = new StringBuilder();

            bool isDebugFiner = true;

            String uri = request.Path;

            uri = Uri.EscapeUriString(uri);

            Trace.TraceInformation("Hmux[{0}] >>U:uri {1}->{2}", traceId, request.RawUrl, uri);
            WriteRequestString(ws, HmuxConnection.HMUX_URI, uri, traceId);

            String rawUri   = request.RawUrl;
            int    queryIdx = rawUri.IndexOf('?');

            if (queryIdx > -1 && queryIdx + 1 < rawUri.Length)
            {
                String query = rawUri.Substring(queryIdx + 1);
                Trace.TraceInformation("Hmux[{0}] >>U:query {1}", traceId, query);
                WriteRequestString(ws, HmuxConnection.CSE_QUERY_STRING, query, traceId);
            }

            Trace.TraceInformation("Hmux[{0}] >>m:method {1}", traceId, request.HttpMethod);
            WriteRequestString(ws, HmuxConnection.HMUX_METHOD, request.HttpMethod, traceId);

            Trace.TraceInformation("Hmux[{0}] >>u:server type {1}", traceId, "IIS");
            WriteRequestString(ws, HmuxConnection.CSE_SERVER_TYPE, "IIS", traceId);

            NameValueCollection serverVariables = request.ServerVariables;

            String serverPort = serverVariables.Get("SERVER_PORT");
            String serverName = serverVariables.Get("SERVER_NAME") + ':' + serverPort;

            Trace.TraceInformation("Hmux[{0}] >>v:server name {1}", traceId, serverName);
            WriteRequestString(ws, HmuxConnection.HMUX_SERVER_NAME, serverName, traceId);

            Trace.TraceInformation("Hmux[{0}] >>g:server port {1}", traceId, serverPort);
            WriteRequestString(ws, HmuxConnection.CSE_SERVER_PORT, serverPort, traceId);

            String remoteAddr = serverVariables.Get("REMOTE_ADDR");

            Trace.TraceInformation("Hmux[{0}] >>i:remote address {1}", traceId, remoteAddr);
            WriteRequestString(ws, HmuxConnection.CSE_REMOTE_ADDR, remoteAddr, traceId);

            String remoteHost = serverVariables.Get("REMOTE_HOST");

            if (remoteHost == null)
            {
                remoteHost = remoteAddr;
            }

            Trace.TraceInformation("Hmux[{0}] >>h:remote host {1}", traceId, remoteHost);
            WriteRequestString(ws, HmuxConnection.CSE_REMOTE_HOST, remoteHost, traceId);

            String protocol = serverVariables.Get("HTTP_VERSION");

            Trace.TraceInformation("Hmux[{0}] >>c:protocol {1}", traceId, protocol);
            WriteRequestString(ws, HmuxConnection.CSE_PROTOCOL, protocol, traceId);

            HttpClientCertificate clientCertificate = request.ClientCertificate;

            if (request.IsSecureConnection)
            {
                Trace.TraceInformation("Hmux[{0}] >>r:secure", traceId);
                WriteRequestString(ws, HmuxConnection.CSE_IS_SECURE, "", traceId);

                WriteRequestHeader(ws, "HTTPS", "on", traceId);
                WriteRequestHeader(ws, "SSL_SECRETKEYSIZE", clientCertificate.KeySize.ToString(), traceId);
            }

            if (clientCertificate.IsPresent)
            {
                Trace.TraceInformation("Hmux[{0}] >>r:certificate ({1})", traceId, clientCertificate.Certificate.Length);
                ws.WriteByte(HmuxConnection.CSE_CLIENT_CERT);
                WriteHmuxLength(ws, clientCertificate.Certificate.Length);
                ws.Write(clientCertificate.Certificate, 0, clientCertificate.Certificate.Length);
            }

            if (request.IsAuthenticated)
            {
                /*
                 * String remoteUser = request.LogonUserIdentity.Name;
                 */
                String remoteUser = context.Current.User.Identity.Name;
                WriteRequestString(ws, HmuxConnection.CSE_REMOTE_USER, remoteUser, traceId);
            }

            NameValueCollection headers = request.Headers;

            foreach (String key in headers.AllKeys)
            {
                if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                String[] values = headers.GetValues(key);
                foreach (String value in values)
                {
                    WriteRequestHeader(ws, key, value, traceId);
                }
            }

            if (_isDebug)
            {
                WriteRequestHeader(ws, "X-Resin-Debug", traceId, traceId);
            }

            Stream requestStream  = request.InputStream;
            Stream responseStream = null;

            bool hasHeader = true;
            bool hasStatus = false;


            if (length > 0)
            {
                Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
                WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, length, traceId);
            }

            int len;

            int code;

            while (!isComplete && (len = requestStream.Read(buf, 0, buf.Length)) > 0)
            {
                Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
                WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, len, traceId);

                Trace.TraceInformation("Hmux[{0}] >>Y: (yield)", traceId);
                ws.WriteByte(HmuxConnection.HMUX_YIELD);
                ws.Flush();

                while (true)
                {
                    code = rs.ReadByte();

                    if (code < 0)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<w: end of file", traceId);

                        if (hasStatus)
                        {
                            return(OK | EXIT);
                        }
                        else
                        {
                            // Trace.TraceInformation("Hmux[{0}] <<w: unexpected end of file", traceId);

                            return(FAIL | EXIT);
                        }
                    }
                    else if (code == HmuxConnection.HMUX_QUIT)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);

                        if (hasStatus)
                        {
                            return(OK | QUIT);
                        }
                        else
                        {
                            Trace.TraceInformation("Hmux[{0}] <<Q: unexpected quit file", traceId);

                            return(FAIL | QUIT);
                        }
                    }
                    else if (code == HmuxConnection.HMUX_EXIT)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

                        if (hasStatus)
                        {
                            return(OK | EXIT);
                        }
                        else
                        {
                            Trace.TraceInformation("Hmux[{0}] <<X: unexpected exit", traceId);

                            return(FAIL | EXIT);
                        }
                    }
                    else if (code == HmuxConnection.HMUX_YIELD)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

                        continue;
                    }

                    int sublen = ReadHmuxLength(rs);

                    if (code == HmuxConnection.HMUX_ACK)
                    {
                        if (isDebugFiner)
                        {
                            Trace.TraceInformation("Hmux[{0}] <<A: (ack) ({1})", traceId, sublen);
                        }

                        break;
                    }
                    else if (code == HmuxConnection.HMUX_CHANNEL)
                    {
                        int channel = sublen;
                        Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
                    }
                    else if (code == HmuxConnection.HMUX_STATUS && hasHeader)
                    {
                        String status = ReadHmuxString(rs, sublen);
                        Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);
                        int statusCode = 0;
                        for (int i = 0; i < 3; i++)
                        {
                            statusCode = 10 * statusCode + status[i] - '0';
                        }

                        if (statusCode != 200)
                        {
                            response.StatusCode = statusCode;
                        }

                        hasStatus = true;
                    }
                    else if (code == HmuxConnection.HMUX_HEADER && hasHeader)
                    {
                        String name = ReadHmuxString(rs, sublen);
                        rs.ReadByte();
                        sublen = ReadHmuxLength(rs);
                        String value = ReadHmuxString(rs, sublen);

                        Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

                        RelayResponseHeader(response, name, value);
                    }
                    else if (code == HmuxConnection.HMUX_DATA)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

                        if (responseStream == null)
                        {
                            responseStream = response.OutputStream;
                        }

                        RelayResponseData(rs, responseStream, sublen);
                    }
                    else if (code == HmuxConnection.HMUX_META_HEADER)
                    {
                        String name = ReadHmuxString(rs, sublen);
                        rs.ReadByte();
                        sublen = ReadHmuxLength(rs);
                        String value = ReadHmuxString(rs, sublen);

                        Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

                        if ("cpu-load".Equals(name))
                        {
                            double loadAvg = 0.001 * long.Parse(value);

                            hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
                        }
                    }
                    else
                    {
                        Skip(rs, sublen);
                    }
                }
            }

            ws.WriteByte(HmuxConnection.HMUX_QUIT);
            ws.Flush();

            code = rs.ReadByte();

            // #2369 - A slow modem can cause the app-tier and web-tier times
            // to get out of sync, with the app-tier thinking it's completed
            // (and starts the keepalive timeout) 30s before the web-tier reads
            // its data.
            // As a temporary measure, we start the idle time at the first data
            // read (later we might mark the time it takes to read an app-tier
            // packet.  If it's short, e.g. 250ms, don't update the time.)
            hmuxChannel.SetIdleStartTime(Utils.CurrentTimeMillis());

            bool isBusy = false;

            for (; code >= 0; code = rs.ReadByte())
            {
                if (code == HmuxConnection.HMUX_QUIT)
                {
                    if (isDebugFiner)
                    {
                        Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);
                    }

                    return(isBusy ? BUSY | QUIT : OK | QUIT);
                }
                else if (code == HmuxConnection.HMUX_EXIT)
                {
                    Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

                    return((isBusy || !hasStatus) ? BUSY | EXIT : OK | EXIT);
                }
                else if (code == HmuxConnection.HMUX_YIELD)
                {
                    Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

                    continue;
                }

                int sublen = (rs.ReadByte() << 8) + rs.ReadByte();

                if (code == HmuxConnection.HMUX_DATA)
                {
                    if (responseStream == null)
                    {
                        responseStream = response.OutputStream;
                    }

                    Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

                    if (!isBusy)
                    {
                        RelayResponseData(rs, responseStream, sublen);
                    }
                    else
                    {
                        Skip(rs, sublen);
                    }
                }
                else if (code == HmuxConnection.HMUX_STATUS && hasHeader)
                {
                    hasStatus = true;
                    String status = ReadHmuxString(rs, sublen);
                    Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);

                    int statusCode = 0;
                    for (int i = 0; i < 3; i++)
                    {
                        statusCode = 10 * statusCode + status[i] - '0';
                    }

                    if (statusCode == 503 && allowBusy)
                    {
                        isBusy = true;
                    }
                    else if (statusCode != 200)
                    {
                        response.StatusCode = statusCode;
                    }
                }
                else if (code == HmuxConnection.HMUX_HEADER && hasHeader)
                {
                    String name = ReadHmuxString(rs, sublen);
                    rs.ReadByte();
                    sublen = ReadHmuxLength(rs);
                    String value = ReadHmuxString(rs, sublen);

                    Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

                    if (!isBusy)
                    {
                        RelayResponseHeader(response, name, value);
                    }
                }
                else if (code == HmuxConnection.HMUX_META_HEADER)
                {
                    String name = ReadHmuxString(rs, sublen);
                    rs.ReadByte();
                    sublen = ReadHmuxLength(rs);
                    String value = ReadHmuxString(rs, sublen);

                    Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

                    if ("cpu-load".Equals(name))
                    {
                        double loadAvg = 0.001 * long.Parse(value);

                        hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
                    }
                }
                else if (code == HmuxConnection.HMUX_CHANNEL)
                {
                    int channel = sublen;
                    Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
                }
                else if (code == HmuxConnection.CSE_SEND_HEADER)
                {
                    Trace.TraceInformation("Hmux[{0}] <<G: send headers", traceId);
                    Skip(rs, sublen);
                }
                else if (code == 0)
                {
                    Trace.TraceInformation("Hmux[{0}] <<0: unknown code (0)", traceId);

                    return(FAIL | EXIT);
                }
                else
                {
                    Trace.TraceInformation("Hmux[{0}] <<?: unknown code ({1})", traceId, code);
                    Skip(rs, sublen);
                }
            }
            Trace.TraceInformation("Hmux[{0}] end of file", traceId);

            // server/269q
            if (hasStatus)
            {
                return(isBusy ? BUSY | EXIT : OK | EXIT);
            }
            else
            {
                // Trace.TraceInformation("Hmux[{0}] unexpected end of file", traceId, code);
                return(FAIL | EXIT);
            }
        }
示例#15
0
        private void DoHmux(HttpContext context)
        {
            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;

            String sessionId;

            if (!_isStickySessions)
            {
                sessionId = null;
            }
            else
            {
                sessionId = GetRequestedSessionId(request);
            }

            TempBuffer tempBuf = TempBuffer.Allocate();

            byte[] buf = tempBuf.GetBuffer();

            try {
                Stream is_ = request.InputStream;
                int    len = is_.Read(buf, 0, buf.Length);
                bool   isComplete;

                if (len < 0)
                {
                    isComplete = true;
                }
                else if (len < buf.Length)
                {
                    int sublen = is_.Read(buf, len, 1);

                    if (sublen == 0) //.NET return 0 for Stream.EOF
                    {
                        isComplete = true;
                    }
                    else
                    {
                        len       += sublen;
                        isComplete = false;
                    }
                }
                else
                {
                    isComplete = false;
                }

                Server client = null;
                int    result = OK | EXIT;

                HmuxConnection channel = _loadBalancer.OpenServer(sessionId, null);

                // If everything fails, return an error
                if (channel == null)
                {
                    SendNotAvailable(response);

                    return;
                }

                client = channel.GetPool();

                BufferedStream rs = channel.GetSocketStream();
                BufferedStream ws = channel.GetSocketStream();
                result = FAIL | EXIT;
                long requestStartTime = Utils.CurrentTimeMillis();

                try {
                    result = HandleRequest(context, request, response, channel, rs, ws,
                                           buf, len, isComplete, isComplete);

                    if ((result & STATUS_MASK) == OK)
                    {
                        client.ClearBusy();

                        return;
                    }
                    else if ((result & STATUS_MASK) == BUSY)
                    {
                        client.Busy();
                    }
                    else
                    {
                        client.FailSocket();
                    }
                } catch (ClientDisconnectException) {
                    _log.Info("Client disconnect detected for '{0}'", channel.GetTraceId());

                    return;
                } catch (IOException e) {
                    client.FailSocket();
                    _log.Error("IOException '{0}': '{1}' {2}", channel.GetTraceId(), e.Message, e.StackTrace);
                } finally {
                    if ((result & EXIT_MASK) == QUIT)
                    {
                        channel.Free(requestStartTime);
                    }
                    else
                    {
                        channel.Close();
                    }
                }

                // server/2675
                if (isComplete && (result & STATUS_MASK) == BUSY ||
                    "GET".Equals(request.HttpMethod))
                {
                    channel = _loadBalancer.OpenServer(sessionId, client);

                    // If everything fails, return an error
                    if (channel == null)
                    {
                        _log.Info("load-balance failed" + (client != null ? (" for " + client.GetDebugId()) : ""));

                        SendNotAvailable(response);

                        return;
                    }

                    Server client2 = channel.GetPool();

                    if (_log.IsLoggable(EventLogEntryType.Information))
                    {
                        _log.Info("load-balance failing over"
                                  + (client != null ? (" from " + client.GetDebugId()) : "")
                                  + " to " + client2.GetDebugId());
                    }

                    rs = channel.GetSocketStream();
                    ws = channel.GetSocketStream();

                    result           = FAIL | EXIT;
                    requestStartTime = Utils.CurrentTimeMillis();

                    try {
                        result = HandleRequest(context, request, response, channel, rs, ws,
                                               buf, len, isComplete, false);

                        if ((result & STATUS_MASK) == OK)
                        {
                            client2.ClearBusy();

                            return;
                        }
                        else if ((result & STATUS_MASK) == BUSY)
                        {
                            client2.Busy();
                        }
                        else
                        {
                            client2.FailSocket();
                        }
                    } catch (IOException e) {
                        client2.FailSocket();

                        _log.Info("Failover to '{0}' did not succeed '{1}', {2} ", client2.GetDebugId(), e.Message, e.StackTrace);
                    } finally {
                        if ((result & EXIT_MASK) == QUIT)
                        {
                            channel.Free(requestStartTime);
                        }
                        else
                        {
                            channel.Close();
                        }
                    }
                }

                SendNotAvailable(response);
            } finally {
                TempBuffer.Free(tempBuf);
                tempBuf = null;
            }
        }
示例#16
0
        private int HandleRequest(HttpRequest request,
            HttpResponse response,
            HmuxConnection hmuxChannel,
            BufferedStream rs,
            BufferedStream ws,
            byte[] buf, int length, bool isComplete,
            bool allowBusy)
        {
            Trace.TraceInformation("Handle request: length: {0}, complete: {1}, allowBusy {2}", length, isComplete, allowBusy);
              String traceId = hmuxChannel.GetTraceId();

              StringBuilder cb = new StringBuilder();

              bool isDebugFiner = true;

              String uri = request.Path;
              uri = Uri.EscapeUriString(uri);

              Trace.TraceInformation("Hmux[{0}] >>U:uri {1}->{2}", traceId, request.RawUrl, uri);
              WriteRequestString(ws, HmuxConnection.HMUX_URI, uri, traceId);

              String rawUri = request.RawUrl;
              int queryIdx = rawUri.IndexOf('?');
              if (queryIdx > -1 && queryIdx + 1 < rawUri.Length) {
            String query = rawUri.Substring(queryIdx + 1);
            Trace.TraceInformation("Hmux[{0}] >>U:query {1}", traceId, query);
            WriteRequestString(ws, HmuxConnection.CSE_QUERY_STRING, query, traceId);
              }

              Trace.TraceInformation("Hmux[{0}] >>m:method {1}", traceId, request.HttpMethod);
              WriteRequestString(ws, HmuxConnection.HMUX_METHOD, request.HttpMethod, traceId);

              Trace.TraceInformation("Hmux[{0}] >>u:server type {1}", traceId, "IIS");
              WriteRequestString(ws, HmuxConnection.CSE_SERVER_TYPE, "IIS", traceId);

              NameValueCollection serverVariables = request.ServerVariables;

              String serverPort = serverVariables.Get("SERVER_PORT");
              String serverName = serverVariables.Get("SERVER_NAME") + ':' + serverPort;
              Trace.TraceInformation("Hmux[{0}] >>v:server name {1}", traceId, serverName);
              WriteRequestString(ws, HmuxConnection.HMUX_SERVER_NAME, serverName, traceId);

              Trace.TraceInformation("Hmux[{0}] >>g:server port {1}", traceId, serverPort);
              WriteRequestString(ws, HmuxConnection.CSE_SERVER_PORT, serverPort, traceId);

              String remoteAddr = serverVariables.Get("REMOTE_ADDR");
              Trace.TraceInformation("Hmux[{0}] >>i:remote address {1}", traceId, remoteAddr);
              WriteRequestString(ws, HmuxConnection.CSE_REMOTE_ADDR, remoteAddr, traceId);

              String remoteHost = serverVariables.Get("REMOTE_HOST");
              if (remoteHost == null)
            remoteHost = remoteAddr;

              Trace.TraceInformation("Hmux[{0}] >>h:remote host {1}", traceId, remoteHost);
              WriteRequestString(ws, HmuxConnection.CSE_REMOTE_HOST, remoteHost, traceId);

              String protocol = serverVariables.Get("HTTP_VERSION");
              Trace.TraceInformation("Hmux[{0}] >>c:protocol {1}", traceId, protocol);
              WriteRequestString(ws, HmuxConnection.CSE_PROTOCOL, protocol, traceId);

              HttpClientCertificate clientCertificate = request.ClientCertificate;
              if (request.IsSecureConnection) {
            Trace.TraceInformation("Hmux[{0}] >>r:secure", traceId);
            WriteRequestString(ws, HmuxConnection.CSE_IS_SECURE, "", traceId);

            WriteRequestHeader(ws, "HTTPS", "on", traceId);
            WriteRequestHeader(ws, "SSL_SECRETKEYSIZE", clientCertificate.KeySize.ToString(), traceId);
              }

              if (clientCertificate.IsPresent) {
            Trace.TraceInformation("Hmux[{0}] >>r:certificate ({1})", traceId, clientCertificate.Certificate.Length);
            ws.WriteByte(HmuxConnection.CSE_CLIENT_CERT);
            WriteHmuxLength(ws, clientCertificate.Certificate.Length);
            ws.Write(clientCertificate.Certificate, 0, clientCertificate.Certificate.Length);
              }

              NameValueCollection headers = request.Headers;
              foreach (String key in headers.AllKeys) {
            if ("Connection".Equals(key, StringComparison.OrdinalIgnoreCase))
              continue;

            String[] values = headers.GetValues(key);
            foreach (String value in values) {
              WriteRequestHeader(ws, key, value, traceId);
            }
              }

              if (_isDebug) {
            WriteRequestHeader(ws, "X-Resin-Debug", traceId, traceId);
              }

              Stream requestStream = request.InputStream;
              Stream responseStream = null;

              bool hasHeader = true;
              bool hasStatus = false;

              if (length > 0) {
            Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
            WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, length, traceId);
              }

              int len;

              int code;

              while (!isComplete && (len = requestStream.Read(buf, 0, buf.Length)) > 0) {
            Trace.TraceInformation("Hmux[{0}] >>D: data ({1})", traceId, length);
            WriteRequestData(ws, HmuxConnection.HMUX_DATA, buf, len, traceId);

            Trace.TraceInformation("Hmux[{0}] >>Y: (yield)", traceId);
            ws.WriteByte(HmuxConnection.HMUX_YIELD);
            ws.Flush();

            while (true) {
              code = rs.ReadByte();

              if (code < 0) {
            Trace.TraceInformation("Hmux[{0}] <<w: end of file", traceId);

            if (hasStatus)
              return OK | EXIT;
            else {
              Trace.TraceInformation("Hmux[{0}] <<w: unexpected end of file", traceId);

              return FAIL | EXIT;
            }
              } else if (code == HmuxConnection.HMUX_QUIT) {
            Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);

            if (hasStatus)
              return OK | QUIT;
            else {
              Trace.TraceInformation("Hmux[{0}] <<Q: unexpected quit file", traceId);

              return FAIL | QUIT;
            }
              } else if (code == HmuxConnection.HMUX_EXIT) {
            Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

            if (hasStatus) {
              return OK | EXIT;
            } else {
              Trace.TraceInformation("Hmux[{0}] <<X: unexpected exit", traceId);

              return FAIL | EXIT;
            }
              } else if (code == HmuxConnection.HMUX_YIELD) {
            Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

            continue;
              }

              int sublen = ReadHmuxLength(rs);

              if (code == HmuxConnection.HMUX_ACK) {
            if (isDebugFiner)
              Trace.TraceInformation("Hmux[{0}] <<A: (ack) ({1})", traceId, sublen);

            break;
              } else if (code == HmuxConnection.HMUX_CHANNEL) {
            int channel = sublen;
            Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
              } else if (code == HmuxConnection.HMUX_STATUS && hasHeader) {
            String status = ReadHmuxString(rs, sublen);
            Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);
            int statusCode = 0;
            for (int i = 0; i < 3; i++)
              statusCode = 10 * statusCode + status[i] - '0';

            if (statusCode != 200)
              response.StatusCode = statusCode;

            hasStatus = true;
              } else if (code == HmuxConnection.HMUX_HEADER && hasHeader) {
            String name = ReadHmuxString(rs, sublen);
            rs.ReadByte();
            sublen = ReadHmuxLength(rs);
            String value = ReadHmuxString(rs, sublen);

            Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

            RelayResponseHeader(response, name, value);
              } else if (code == HmuxConnection.HMUX_DATA) {
            Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

            if (responseStream == null)
              responseStream = response.OutputStream;

            RelayResponseData(rs, responseStream, sublen);
              } else if (code == HmuxConnection.HMUX_META_HEADER) {
            String name = ReadHmuxString(rs, sublen);
            rs.ReadByte();
            sublen = ReadHmuxLength(rs);
            String value = ReadHmuxString(rs, sublen);

            Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

            if ("cpu-load".Equals(name)) {
              double loadAvg = 0.001 * long.Parse(value);

              hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
            }
              } else {
            Skip(rs, sublen);
              }
            }
              }

              ws.WriteByte(HmuxConnection.HMUX_QUIT);
              ws.Flush();

              code = rs.ReadByte();

              // #2369 - A slow modem can cause the app-tier and web-tier times
              // to get out of sync, with the app-tier thinking it's completed
              // (and starts the keepalive timeout) 30s before the web-tier reads
              // its data.
              // As a temporary measure, we start the idle time at the first data
              // read (later we might mark the time it takes to read an app-tier
              // packet.  If it's short, e.g. 250ms, don't update the time.)
              hmuxChannel.SetIdleStartTime(Utils.CurrentTimeMillis());

              bool isBusy = false;
              for (; code >= 0; code = rs.ReadByte()) {
            if (code == HmuxConnection.HMUX_QUIT) {
              if (isDebugFiner)
            Trace.TraceInformation("Hmux[{0}] <<Q: (keepalive)", traceId);

              return isBusy ? BUSY | QUIT : OK | QUIT;
            } else if (code == HmuxConnection.HMUX_EXIT) {

              Trace.TraceInformation("Hmux[{0}] <<X: (exit)", traceId);

              return (isBusy || !hasStatus) ? BUSY | EXIT : OK | EXIT;
            } else if (code == HmuxConnection.HMUX_YIELD) {
              Trace.TraceInformation("Hmux[{0}] <<Y: (yield)", traceId);

              continue;
            }

            int sublen = (rs.ReadByte() << 8) + rs.ReadByte();

            if (code == HmuxConnection.HMUX_DATA) {
              if (responseStream == null)
            responseStream = response.OutputStream;

              Trace.TraceInformation("Hmux[{0}] <<D: (data)({1})", traceId, sublen);

              if (!isBusy)
            RelayResponseData(rs, responseStream, sublen);
              else
            Skip(rs, sublen);
            } else if (code == HmuxConnection.HMUX_STATUS && hasHeader) {
              hasStatus = true;
              String status = ReadHmuxString(rs, sublen);
              Trace.TraceInformation("Hmux[{0}] <<s: (status) ({1})", traceId, status);

              int statusCode = 0;
              for (int i = 0; i < 3; i++)
            statusCode = 10 * statusCode + status[i] - '0';

              if (statusCode == 503 && allowBusy) {
            isBusy = true;
              } else if (statusCode != 200) {
            response.StatusCode = statusCode;
              }
            } else if (code == HmuxConnection.HMUX_HEADER && hasHeader) {
              String name = ReadHmuxString(rs, sublen);
              rs.ReadByte();
              sublen = ReadHmuxLength(rs);
              String value = ReadHmuxString(rs, sublen);

              Trace.TraceInformation("Hmux[{0}] <<H,S: (header) ({1}={2})", traceId, name, value);

              if (!isBusy)
            RelayResponseHeader(response, name, value);
            } else if (code == HmuxConnection.HMUX_META_HEADER) {
              String name = ReadHmuxString(rs, sublen);
              rs.ReadByte();
              sublen = ReadHmuxLength(rs);
              String value = ReadHmuxString(rs, sublen);

              Trace.TraceInformation("Hmux[{0}] <<M,S: header ({1}={2})", traceId, name, value);

              if ("cpu-load".Equals(name)) {
            double loadAvg = 0.001 * long.Parse(value);

            hmuxChannel.GetPool().SetCpuLoadAvg(loadAvg);
              }
            } else if (code == HmuxConnection.HMUX_CHANNEL) {
              int channel = sublen;
              Trace.TraceInformation("Hmux[{0}] <<C: (channel) ({1})", traceId, channel);
            } else if (code == 0) {
              Trace.TraceInformation("Hmux[{0}] <<0: unknown code (0)", traceId);

              return FAIL | EXIT;
            } else {
              Trace.TraceInformation("Hmux[{0}] <<?: unknown code ({1})", traceId, code);
              Skip(rs, sublen);
            }
              }
              Trace.TraceInformation("Hmux[{0}] end of file", traceId);

              // server/269q
              if (hasStatus)
            return isBusy ? BUSY | EXIT : OK | EXIT;
              else {
            Trace.TraceInformation("Hmux[{0}] unexpected end of file", traceId, code);
            return FAIL | EXIT;
              }
        }
        private HmuxConnection Connect()
        {
            lock (this) {
            if (_maxConnections <= _activeCount + _startingCount)
              return null;

            _startingCount++;
              }

              HmuxConnection connection = null;

              Object connectLock = new Object();
              Monitor.Enter(connectLock);
              try {
            Socket socket = new Socket(_address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            AsyncCallback connectListener = delegate(IAsyncResult result)
            {
              Monitor.Enter(connectLock);
              try {
            Monitor.Pulse(connectLock);
              } catch (Exception) {
              } finally {
            Monitor.Exit(connectLock);
              }
            };

            socket.BeginConnect(_address, _port, connectListener, socket);
            Monitor.Wait(connectLock, _loadBalanceConnectTimeout);

            if (!socket.Connected) {
              throw new SocketException(10053);
            }

            socket.SendTimeout = _socketTimeout;
            socket.ReceiveTimeout = _socketTimeout;

            String traceId;
            if (_isDebug) {
              int i = _traceId++;
              traceId = i.ToString();
            } else {
              traceId = socket.Handle.ToInt32().ToString();
            }

            connection = new HmuxConnection(socket, this, _serverInternalId, traceId);

            lock (this) {
              _activeCount++;
            }

            if (_log.IsLoggable(EventLogEntryType.Information))
              _log.Info("Connect " + connection);

            Trace.TraceInformation("Connect '{0}'", connection);

            return connection;
              } catch (SocketException e) {
            String message = String.Format("Socket connection to {0}:{1} timed out on load-balance-connect-timeout {2}", _address, _port, _loadBalanceConnectTimeout);
            if (_log.IsLoggable(EventLogEntryType.Information))
              _log.Info(message);

            Trace.TraceInformation(message);
              } catch (Exception e) {
            String message = String.Format("Can't create HmuxChannel to '{0}:{1}' due to: {2} \t {3}", _address, _port, e.Message, e.StackTrace);
            if (_log.IsLoggable(EventLogEntryType.Information))
              _log.Info(message);

            Trace.TraceError(message);
              } finally {
            lock (this) {
              _startingCount--;
            }

            if (connection == null)
              FailConnect();

            Monitor.Exit(connectLock);
              }

              return null;
        }
        internal void Free(HmuxConnection channel)
        {
            Success();

              lock (this) {
            _activeCount--;

            bool failing = false;

            failing = _failTime > 0 || _busyTime > 0;

            int size = (_idleHead - _idleTail + _idle.Length) % _idle.Length;

            if (!failing && size < _idleSize) {
              Trace.TraceInformation("Returning channel '{0}' to pool", channel);
              _idleHead = (_idleHead + 1) % _idle.Length;
              _idle[_idleHead] = channel;

              channel = null;
            }
              }

              long now = Utils.CurrentTimeMillis();
              long maxIdleTime = _loadBalanceIdleTime;
              HmuxConnection oldChannel = null;

              do {
            oldChannel = null;

            lock (this) {
              if (_idleHead != _idleTail) {
            int nextTail = (_idleTail + 1) % _idle.Length;

            oldChannel = _idle[nextTail];
            if (oldChannel != null
                && (oldChannel.GetIdleStartTime() + maxIdleTime) < now) {
              _idle[nextTail] = null;
              _idleTail = nextTail;
            } else {
              oldChannel = null;
            }
              }
            }

            if (oldChannel != null) {
              oldChannel.CloseImpl();
              Trace.TraceInformation("closing expired channel '{0}'", oldChannel);
            }
              } while (oldChannel != null);

              if (channel != null) {
            channel.CloseImpl();
              }
        }