blob: 1d50968deef2b62f6124c0fc4118a896ed42af0e [file] [log] [blame]
Kevin Clarkab4460d2009-03-20 02:28:41 +00001/**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
Todd Lipcon53ae9f32009-12-07 00:42:38 +000018 *
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
21 * details.
Kevin Clarkab4460d2009-03-20 02:28:41 +000022 */
David Reiss7f42bcf2008-01-11 20:59:12 +000023
24using System;
David Reiss7f42bcf2008-01-11 20:59:12 +000025using System.Net.Sockets;
26
27namespace Thrift.Transport
28{
29 public class TSocket : TStreamTransport
30 {
31 private TcpClient client = null;
32 private string host = null;
33 private int port = 0;
34 private int timeout = 0;
35
36 public TSocket(TcpClient client)
37 {
38 this.client = client;
39
40 if (IsOpen)
41 {
42 inputStream = client.GetStream();
43 outputStream = client.GetStream();
44 }
45 }
46
47 public TSocket(string host, int port) : this(host, port, 0)
48 {
49 }
50
51 public TSocket(string host, int port, int timeout)
52 {
53 this.host = host;
54 this.port = port;
55 this.timeout = timeout;
56
57 InitSocket();
58 }
59
60 private void InitSocket()
61 {
62 client = new TcpClient();
63 client.ReceiveTimeout = client.SendTimeout = timeout;
Bryan Duxbury2d9dfdb2011-02-08 16:38:15 +000064 client.Client.NoDelay = true;
David Reiss7f42bcf2008-01-11 20:59:12 +000065 }
66
67 public int Timeout
68 {
69 set
70 {
71 client.ReceiveTimeout = client.SendTimeout = timeout = value;
72 }
73 }
74
75 public TcpClient TcpClient
76 {
77 get
78 {
79 return client;
80 }
81 }
82
David Reiss63191332009-01-06 19:49:22 +000083 public string Host
84 {
85 get
86 {
87 return host;
88 }
89 }
90
91 public int Port
92 {
93 get
94 {
95 return port;
96 }
97 }
98
David Reiss7f42bcf2008-01-11 20:59:12 +000099 public override bool IsOpen
100 {
101 get
102 {
103 if (client == null)
104 {
105 return false;
106 }
107
108 return client.Connected;
109 }
110 }
111
112 public override void Open()
113 {
114 if (IsOpen)
115 {
116 throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
117 }
118
119 if (String.IsNullOrEmpty(host))
120 {
121 throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
122 }
123
124 if (port <= 0)
125 {
126 throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
127 }
128
129 if (client == null)
130 {
131 InitSocket();
132 }
133
Jens Geyer866c23b2013-07-05 19:20:27 +0200134 if( timeout == 0) // no timeout -> infinite
135 {
136 client.Connect(host, port);
137 }
138 else // we have a timeout -> use it
139 {
140 ConnectHelper hlp = new ConnectHelper(client);
141 IAsyncResult asyncres = client.BeginConnect(host, port, new AsyncCallback(ConnectCallback), hlp);
142 bool bConnected = asyncres.AsyncWaitHandle.WaitOne(timeout) && client.Connected;
143 if (!bConnected)
144 {
145 lock (hlp.Mutex)
146 {
147 if( hlp.CallbackDone)
148 {
149 asyncres.AsyncWaitHandle.Close();
150 client.Close();
151 }
152 else
153 {
154 hlp.DoCleanup = true;
155 client = null;
156 }
157 }
158 throw new TTransportException(TTransportException.ExceptionType.TimedOut, "Connect timed out");
159 }
160 }
161
David Reiss7f42bcf2008-01-11 20:59:12 +0000162 inputStream = client.GetStream();
163 outputStream = client.GetStream();
164 }
165
Jens Geyer866c23b2013-07-05 19:20:27 +0200166
167 static void ConnectCallback(IAsyncResult asyncres)
168 {
169 ConnectHelper hlp = asyncres.AsyncState as ConnectHelper;
170 lock (hlp.Mutex)
171 {
172 hlp.CallbackDone = true;
173
174 try
175 {
176 if( hlp.Client.Client != null)
177 hlp.Client.EndConnect(asyncres);
178 }
179 catch (SocketException)
180 {
181 // catch that away
182 }
183
184 if (hlp.DoCleanup)
185 {
186 asyncres.AsyncWaitHandle.Close();
187 if (hlp.Client is IDisposable)
188 ((IDisposable)hlp.Client).Dispose();
189 hlp.Client = null;
190 }
191 }
192 }
193
194 private class ConnectHelper
195 {
196 public object Mutex = new object();
197 public bool DoCleanup = false;
198 public bool CallbackDone = false;
199 public TcpClient Client;
200 public ConnectHelper(TcpClient client)
201 {
202 Client = client;
203 }
204 }
205
David Reiss7f42bcf2008-01-11 20:59:12 +0000206 public override void Close()
207 {
208 base.Close();
209 if (client != null)
210 {
211 client.Close();
212 client = null;
213 }
214 }
Roger Meierb1ec4cc2012-04-11 21:21:41 +0000215
216 #region " IDisposable Support "
217 private bool _IsDisposed;
218
219 // IDisposable
220 protected override void Dispose(bool disposing)
221 {
222 if (!_IsDisposed)
223 {
224 if (disposing)
225 {
226 if (client != null)
227 ((IDisposable)client).Dispose();
228 base.Dispose(disposing);
229 }
230 }
231 _IsDisposed = true;
232 }
233 #endregion
234 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000235}