2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2003-2008 lfroen ( lfroen@gmail.com / http://www.amule.org )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 using System
.Security
;
28 using System
.Security
.Permissions
;
29 using System
.Threading
;
30 using System
.Collections
.Generic
;
33 using System
.Net
.Sockets
;
38 // Define the state object for the callback.
39 // Use hostName to correlate calls with the proper result.
40 public class ResolveState
{
41 IPHostEntry resolvedIPs
;
43 public string errorMsg
;
45 public IPHostEntry IPs
47 get { return resolvedIPs; }
48 set { resolvedIPs = value; }
52 public class ConnectState
{
54 public string errorMsg
;
56 public ConnectState(Socket s
)
62 public abstract class amuleECHandler
{
63 public amuleECHandler()
67 public abstract void HandlePacket(ecProto
.ecPacket packet
);
70 class amuleLogicHandler
: amuleECHandler
{
72 bool m_auth_result
= false;
74 public amuleLogicHandler(amuleRemote o
)
79 public override void HandlePacket(ecProto
.ecPacket packet
)
81 if ( packet
.Opcode() == ECOpCodes
.EC_OP_AUTH_OK
) {
82 Console
.WriteLine("amuleLogicHandler : Authenticated OK");
85 Console
.WriteLine("amuleLogicHandler : Authentication failed. Core reply was {0}", packet
.Opcode());
89 public bool AuthResult()
96 amuleECHandler m_handler
= null;
98 static ManualResetEvent m_socket_op_Done
= new ManualResetEvent(false);
100 // Record the IPs in the state object for later use.
101 static void GetHostEntryCallback(IAsyncResult ar
)
103 ResolveState ioContext
= (ResolveState
)ar
.AsyncState
;
105 ioContext
.IPs
= Dns
.EndGetHostEntry(ar
);
106 } catch (SocketException e
) {
107 ioContext
.errorMsg
= e
.Message
;
109 m_socket_op_Done
.Set();
114 static void ConnectCallback(IAsyncResult ar
)
116 // Retrieve the socket from the state object.
117 ConnectState state
= (ConnectState
)ar
.AsyncState
;
119 // Complete the connection.
120 state
.sock
.EndConnect(ar
);
122 Console
.WriteLine("Socket connected to {0}",
123 state
.sock
.RemoteEndPoint
.ToString());
125 // Signal that the connection has been made.
126 m_socket_op_Done
.Set();
127 } catch (Exception e
) {
128 state
.errorMsg
= e
.Message
;
132 byte[] m_rx_buffer
= new byte[32 * 1024];
133 MemoryStream m_rx_mem_stream
= null;
134 int m_rx_byte_count
= 0;
135 int m_rx_remaining_count
= 0;
137 byte[] m_tx_buffer
= new byte[32 * 1024];
138 MemoryStream m_tx_mem_stream
= null;
140 //LinkedList<byte[]> m_tx_queue;
141 BinaryReader m_sock_reader
= null;
142 BinaryWriter m_sock_writer
= null;
144 static void RxCallback(IAsyncResult ar
)
146 amuleRemote o
= (amuleRemote
)ar
.AsyncState
;
147 Console
.WriteLine("RxCallback signalled, calling EndReceive");
148 int bytesRead
= o
.m_s
.EndReceive(ar
);
149 if ( bytesRead
== 0 ) {
150 // remote side closed connection.
151 // indicate error to caller
152 o
.m_rx_byte_count
= -1;
153 m_socket_op_Done
.Set();
156 o
.m_rx_remaining_count
-= bytesRead
;
157 Console
.WriteLine("RxCallback: got {0} bytes, waiting for {1}",
158 bytesRead
, o
.m_rx_remaining_count
);
159 // are we still waiting for flags and size?
160 if (o
.m_rx_byte_count
< 8) {
161 if ((o
.m_rx_byte_count
+ bytesRead
) >= 8) {
162 // got flags and packet size - may proceed.
163 Int32 flags
= o
.m_sock_reader
.ReadInt32();
164 Int32 val32
= o
.m_sock_reader
.ReadInt32();
166 o
.m_rx_remaining_count
= (int)IPAddress
.NetworkToHostOrder(val32
) - (bytesRead
- 8);
167 Console
.WriteLine("RxCallback: expecting packet size={0}", o
.m_rx_remaining_count
);
168 if ( o
.m_rx_buffer
.Length
<= (o
.m_rx_remaining_count
+o
.m_rx_byte_count
) ) {
169 byte [] new_buffer
= new byte[o
.m_rx_remaining_count
+ o
.m_rx_buffer
.Length
+ 1];
170 o
.m_rx_buffer
.CopyTo(new_buffer
, 0);
171 o
.m_rx_buffer
= new_buffer
;
173 // update stream reader with new buffer
175 o
.m_rx_mem_stream
= new MemoryStream(o
.m_rx_buffer
);
176 o
.m_sock_reader
= new BinaryReader(o
.m_rx_mem_stream
);
180 if ( o
.m_rx_remaining_count
== 0 ) {
182 // Packet received - call handler
184 if ( o
.m_handler
!= null ) {
185 o
.m_rx_mem_stream
.Seek(0, SeekOrigin
.Begin
);
186 Console
.WriteLine("Packet received - call handler\n");
187 ecProto
.ecPacket p
= new ecProto
.ecPacket(o
.m_sock_reader
);
188 o
.m_handler
.HandlePacket(p
);
190 m_socket_op_Done
.Set();
192 // Keep waiting for more packets
198 o
.m_rx_byte_count
+= bytesRead
;
200 // not just yet - keep waiting
201 o
.m_s
.BeginReceive(o
.m_rx_buffer
, o
.m_rx_byte_count
, o
.m_rx_remaining_count
,
202 SocketFlags
.None
, new AsyncCallback(RxCallback
), o
);
205 static void TxCallback(IAsyncResult ar
)
207 amuleRemote o
= (amuleRemote
)ar
.AsyncState
;
208 Console
.WriteLine("TxCallback signalled, calling EndWrite");
210 m_socket_op_Done
.Set();
213 public bool SendPacket(ecProto
.ecPacket packet
)
215 m_tx_mem_stream
.Seek(0, SeekOrigin
.Begin
);
216 packet
.Write(m_sock_writer
);
218 m_socket_op_Done
.Reset();
219 m_s
.BeginSend(m_tx_buffer
, 0, packet
.PacketSize(),
220 SocketFlags
.None
, new AsyncCallback(TxCallback
), this);
224 public void StartReceive()
226 m_socket_op_Done
.Reset();
227 // reply packet is supposed to have at least 8 bytes
228 m_rx_remaining_count
= 8;
230 m_rx_mem_stream
.Seek(0, SeekOrigin
.Begin
);
231 m_s
.BeginReceive(m_rx_buffer
, 0, 8, SocketFlags
.None
, new AsyncCallback(RxCallback
), this);
234 [DnsPermission(SecurityAction
.Demand
, Unrestricted
= true)]
235 public bool ConnectToCore(string host
, int port
, string pass
, ref string error
)
238 m_socket_op_Done
.Reset();
239 ResolveState resolveContext
= new ResolveState();
240 Dns
.BeginGetHostEntry(host
,
241 new AsyncCallback(GetHostEntryCallback
), resolveContext
);
243 // Wait here until the resolve completes (the callback calls .Set())
244 m_socket_op_Done
.WaitOne();
245 if ( resolveContext
.IPs
== null ) {
246 error
= resolveContext
.errorMsg
;
249 Console
.WriteLine("Resolved: '{0}' -> '{1}", host
,resolveContext
.IPs
.AddressList
[0]);
250 Console
.WriteLine("Connecting to {0}:{1}", resolveContext
.IPs
.AddressList
[0], port
);
251 IPEndPoint remoteEP
= new IPEndPoint(resolveContext
.IPs
.AddressList
[0], port
);
252 m_s
= new Socket(AddressFamily
.InterNetwork
, SocketType
.Stream
, ProtocolType
.Tcp
);
254 m_socket_op_Done
.Reset();
255 ConnectState connectContext
= new ConnectState(m_s
);
256 m_s
.BeginConnect(remoteEP
, new AsyncCallback(ConnectCallback
), connectContext
);
257 if ( !m_socket_op_Done
.WaitOne(1000,true) ) {
258 error
= "Timeout during connection. Possible firewall";
262 if ( connectContext
.errorMsg
!= null) {
263 error
= connectContext
.errorMsg
;
267 m_tx_mem_stream
= new MemoryStream(m_tx_buffer
);
268 m_sock_writer
= new BinaryWriter(m_tx_mem_stream
);
269 m_rx_mem_stream
= new MemoryStream(m_rx_buffer
);
270 m_sock_reader
= new BinaryReader(m_rx_mem_stream
);
272 ecProto
.ecLoginPacket p
= new ecProto
.ecLoginPacket("amule.net", "0.0.1", pass
);
275 if (!m_socket_op_Done
.WaitOne(1000, true)) {
276 // Was unable to send login request for 1sec. Line must be really slow
280 m_handler
= new amuleLogicHandler(this);
283 // FIXME: must be able to cancel this read.
284 m_socket_op_Done
.WaitOne();
285 if ( m_rx_byte_count
== -1 ) {
286 // remote side terminated connection
287 Console
.WriteLine("Connection terminated on remote side");
289 Console
.WriteLine("Connect done");
290 bool result
= ((amuleLogicHandler
)m_handler
).AuthResult();
293 } catch (Exception e
) {
299 public void SetECHandler(amuleECHandler h
)