| | 1 | | // Copyright (c) ZeroC, Inc. |
| | 2 | |
|
| | 3 | | using System.Diagnostics; |
| | 4 | | using System.Globalization; |
| | 5 | | using System.Net; |
| | 6 | | using System.Net.Security; |
| | 7 | |
|
| | 8 | | namespace Ice.Internal; |
| | 9 | |
|
| | 10 | | internal sealed class TcpEndpointI : IPEndpointI |
| | 11 | | { |
| | 12 | | private const int defaultTimeout = 60_000; // 60,000 milliseconds (1 minute) |
| | 13 | |
|
| | 14 | | public TcpEndpointI( |
| | 15 | | ProtocolInstance instance, |
| | 16 | | string ho, |
| | 17 | | int po, |
| | 18 | | EndPoint sourceAddr, |
| | 19 | | int ti, |
| | 20 | | string conId, |
| | 21 | | bool co) |
| 1 | 22 | | : base(instance, ho, po, sourceAddr, conId) |
| | 23 | | { |
| 1 | 24 | | _timeout = ti; |
| 1 | 25 | | _compress = co; |
| 1 | 26 | | } |
| | 27 | |
|
| | 28 | | public TcpEndpointI(ProtocolInstance instance) |
| 1 | 29 | | : base(instance) |
| | 30 | | { |
| | 31 | | // This timeout is not used in Ice 3.8 or greater. |
| 1 | 32 | | _timeout = defaultTimeout; |
| 1 | 33 | | _compress = false; |
| 1 | 34 | | } |
| | 35 | |
|
| | 36 | | public TcpEndpointI(ProtocolInstance instance, Ice.InputStream s) |
| 1 | 37 | | : base(instance, s) |
| | 38 | | { |
| 1 | 39 | | _timeout = s.readInt(); |
| 1 | 40 | | _compress = s.readBool(); |
| 1 | 41 | | } |
| | 42 | |
|
| | 43 | | public override void streamWriteImpl(Ice.OutputStream s) |
| | 44 | | { |
| 1 | 45 | | base.streamWriteImpl(s); |
| 1 | 46 | | s.writeInt(_timeout); |
| 1 | 47 | | s.writeBool(_compress); |
| 1 | 48 | | } |
| | 49 | |
|
| | 50 | | public override EndpointInfo getInfo() => |
| 1 | 51 | | new TCPEndpointInfo( |
| 1 | 52 | | _compress, |
| 1 | 53 | | host_, |
| 1 | 54 | | port_, |
| 1 | 55 | | Network.endpointAddressToString(sourceAddr_), |
| 1 | 56 | | type(), |
| 1 | 57 | | secure()); |
| | 58 | |
|
| 1 | 59 | | public override int timeout() => _timeout; |
| | 60 | |
|
| | 61 | | public override EndpointI timeout(int timeout) |
| | 62 | | { |
| 1 | 63 | | if (timeout == _timeout) |
| | 64 | | { |
| 0 | 65 | | return this; |
| | 66 | | } |
| | 67 | | else |
| | 68 | | { |
| 1 | 69 | | return new TcpEndpointI(instance_, host_, port_, sourceAddr_, timeout, connectionId_, _compress); |
| | 70 | | } |
| | 71 | | } |
| | 72 | |
|
| 1 | 73 | | public override bool compress() => _compress; |
| | 74 | |
|
| | 75 | | public override EndpointI compress(bool compress) |
| | 76 | | { |
| 1 | 77 | | if (compress == _compress) |
| | 78 | | { |
| 1 | 79 | | return this; |
| | 80 | | } |
| | 81 | | else |
| | 82 | | { |
| 1 | 83 | | return new TcpEndpointI(instance_, host_, port_, sourceAddr_, _timeout, connectionId_, compress); |
| | 84 | | } |
| | 85 | | } |
| | 86 | |
|
| 1 | 87 | | public override bool datagram() => false; |
| | 88 | |
|
| 1 | 89 | | public override Transceiver transceiver() => null; |
| | 90 | |
|
| | 91 | | public override Acceptor acceptor(string adapterName, SslServerAuthenticationOptions serverAuthenticationOptions) |
| | 92 | | { |
| | 93 | | Debug.Assert(serverAuthenticationOptions is null); |
| 1 | 94 | | return new TcpAcceptor(this, instance_, host_, port_); |
| | 95 | | } |
| | 96 | |
|
| | 97 | | public TcpEndpointI endpoint(TcpAcceptor acceptor) |
| | 98 | | { |
| 1 | 99 | | int port = acceptor.effectivePort(); |
| 1 | 100 | | if (port == port_) |
| | 101 | | { |
| 1 | 102 | | return this; |
| | 103 | | } |
| | 104 | | else |
| | 105 | | { |
| 1 | 106 | | return new TcpEndpointI(instance_, host_, port, sourceAddr_, _timeout, connectionId_, _compress); |
| | 107 | | } |
| | 108 | | } |
| | 109 | |
|
| | 110 | | public override string options() |
| | 111 | | { |
| | 112 | | // |
| | 113 | | // WARNING: Certain features, such as proxy validation in Glacier2, |
| | 114 | | // depend on the format of proxy strings. Changes to toString() and |
| | 115 | | // methods called to generate parts of the reference string could break |
| | 116 | | // these features. Please review for all features that depend on the |
| | 117 | | // format of proxyToString() before changing this and related code. |
| | 118 | | // |
| 1 | 119 | | string s = base.options(); |
| | 120 | |
|
| 1 | 121 | | if (_timeout != defaultTimeout) |
| | 122 | | { |
| 1 | 123 | | if (_timeout == -1) |
| | 124 | | { |
| 1 | 125 | | s += " -t infinite"; |
| | 126 | | } |
| | 127 | | else |
| | 128 | | { |
| 1 | 129 | | s += " -t " + _timeout; |
| | 130 | | } |
| | 131 | | } |
| | 132 | |
|
| 1 | 133 | | if (_compress) |
| | 134 | | { |
| 1 | 135 | | s += " -z"; |
| | 136 | | } |
| | 137 | |
|
| 1 | 138 | | return s; |
| | 139 | | } |
| | 140 | |
|
| | 141 | | public override int CompareTo(EndpointI obj) |
| | 142 | | { |
| 1 | 143 | | if (!(obj is TcpEndpointI)) |
| | 144 | | { |
| 0 | 145 | | return type() < obj.type() ? -1 : 1; |
| | 146 | | } |
| | 147 | |
|
| 1 | 148 | | var p = (TcpEndpointI)obj; |
| 1 | 149 | | if (this == p) |
| | 150 | | { |
| 1 | 151 | | return 0; |
| | 152 | | } |
| | 153 | |
|
| 1 | 154 | | if (_timeout < p._timeout) |
| | 155 | | { |
| 0 | 156 | | return -1; |
| | 157 | | } |
| 1 | 158 | | else if (p._timeout < _timeout) |
| | 159 | | { |
| 0 | 160 | | return 1; |
| | 161 | | } |
| | 162 | |
|
| 1 | 163 | | if (!_compress && p._compress) |
| | 164 | | { |
| 0 | 165 | | return -1; |
| | 166 | | } |
| 1 | 167 | | else if (!p._compress && _compress) |
| | 168 | | { |
| 0 | 169 | | return 1; |
| | 170 | | } |
| | 171 | |
|
| 1 | 172 | | return base.CompareTo(p); |
| | 173 | | } |
| | 174 | |
|
| 1 | 175 | | public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), _timeout, _compress); |
| | 176 | |
|
| | 177 | | public override EndpointI toPublishedEndpoint(string publishedHost) |
| | 178 | | { |
| | 179 | | // A server endpoint can't have a source address or connection ID. |
| | 180 | | Debug.Assert(sourceAddr_ is null && connectionId_.Length == 0); |
| | 181 | |
|
| 1 | 182 | | if (publishedHost.Length == 0) |
| | 183 | | { |
| 1 | 184 | | return this; |
| | 185 | | } |
| | 186 | | else |
| | 187 | | { |
| 1 | 188 | | return new TcpEndpointI(instance_, publishedHost, port_, sourceAddr: null, _timeout, conId: "", _compress); |
| | 189 | | } |
| | 190 | | } |
| | 191 | |
|
| | 192 | | protected override bool checkOption(string option, string argument, string endpoint) |
| | 193 | | { |
| 1 | 194 | | if (base.checkOption(option, argument, endpoint)) |
| | 195 | | { |
| 1 | 196 | | return true; |
| | 197 | | } |
| | 198 | |
|
| 1 | 199 | | switch (option[1]) |
| | 200 | | { |
| | 201 | | case 't': |
| | 202 | | { |
| 1 | 203 | | if (argument == null) |
| | 204 | | { |
| 0 | 205 | | throw new ParseException($"no argument provided for -t option in endpoint '{endpoint}'"); |
| | 206 | | } |
| | 207 | |
|
| 1 | 208 | | if (argument == "infinite") |
| | 209 | | { |
| 0 | 210 | | _timeout = -1; |
| | 211 | | } |
| | 212 | | else |
| | 213 | | { |
| | 214 | | try |
| | 215 | | { |
| 1 | 216 | | _timeout = int.Parse(argument, CultureInfo.InvariantCulture); |
| 1 | 217 | | if (_timeout < 1) |
| | 218 | | { |
| 0 | 219 | | throw new ParseException($"invalid timeout value '{argument}' in endpoint '{endpoint}'"); |
| | 220 | | } |
| 1 | 221 | | } |
| 0 | 222 | | catch (System.FormatException ex) |
| | 223 | | { |
| 0 | 224 | | throw new ParseException($"invalid timeout value '{argument}' in endpoint '{endpoint}'", ex); |
| | 225 | | } |
| | 226 | | } |
| | 227 | |
|
| 1 | 228 | | return true; |
| | 229 | | } |
| | 230 | |
|
| | 231 | | case 'z': |
| | 232 | | { |
| 1 | 233 | | if (argument != null) |
| | 234 | | { |
| 0 | 235 | | throw new ParseException( |
| 0 | 236 | | $"unexpected argument '{argument}' provided for -z option in endpoint '{endpoint}'"); |
| | 237 | | } |
| | 238 | |
|
| 1 | 239 | | _compress = true; |
| | 240 | |
|
| 1 | 241 | | return true; |
| | 242 | | } |
| | 243 | |
|
| | 244 | | default: |
| | 245 | | { |
| 1 | 246 | | return false; |
| | 247 | | } |
| | 248 | | } |
| | 249 | | } |
| | 250 | |
|
| | 251 | | protected override Connector createConnector(EndPoint addr, NetworkProxy proxy) => |
| 1 | 252 | | new TcpConnector(instance_, addr, proxy, sourceAddr_, _timeout, connectionId_); |
| | 253 | |
|
| | 254 | | protected override IPEndpointI createEndpoint(string host, int port, string connectionId) => |
| 1 | 255 | | new TcpEndpointI(instance_, host, port, sourceAddr_, _timeout, connectionId, _compress); |
| | 256 | |
|
| | 257 | | private int _timeout; |
| | 258 | | private bool _compress; |
| | 259 | | } |
| | 260 | |
|
| | 261 | | internal sealed class TcpEndpointFactory : EndpointFactory |
| | 262 | | { |
| | 263 | | internal TcpEndpointFactory(ProtocolInstance instance) => _instance = instance; |
| | 264 | |
|
| | 265 | | public void initialize() |
| | 266 | | { |
| | 267 | | } |
| | 268 | |
|
| | 269 | | public short type() => _instance.type(); |
| | 270 | |
|
| | 271 | | public string protocol() => _instance.protocol(); |
| | 272 | |
|
| | 273 | | public EndpointI create(List<string> args, bool oaEndpoint) |
| | 274 | | { |
| | 275 | | IPEndpointI endpt = new TcpEndpointI(_instance); |
| | 276 | | endpt.initWithOptions(args, oaEndpoint); |
| | 277 | | return endpt; |
| | 278 | | } |
| | 279 | |
|
| | 280 | | public EndpointI read(Ice.InputStream s) => new TcpEndpointI(_instance, s); |
| | 281 | |
|
| | 282 | | public EndpointFactory clone(ProtocolInstance instance) => new TcpEndpointFactory(instance); |
| | 283 | |
|
| | 284 | | private readonly ProtocolInstance _instance; |
| | 285 | | } |