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 Froenchenko Leonid ( 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");
84 m_owner
.m_packet_op_Done
.Set();
86 Console
.WriteLine("amuleLogicHandler : Authentication failed. Core reply was {0}", packet
.Opcode());
90 public bool AuthResult()
97 amuleECHandler m_handler
= null;
99 public ManualResetEvent m_packet_op_Done
= new ManualResetEvent(false);
101 // Record the IPs in the state object for later use.
102 static void GetHostEntryCallback(IAsyncResult ar
)
104 ResolveState ioContext
= (ResolveState
)ar
.AsyncState
;
106 ioContext
.IPs
= Dns
.EndGetHostEntry(ar
);
107 } catch (SocketException e
) {
108 ioContext
.errorMsg
= e
.Message
;
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 } catch (Exception e
) {
126 state
.errorMsg
= e
.Message
;
130 byte[] m_rx_buffer
= new byte[32 * 1024];
131 MemoryStream m_rx_mem_stream
= null;
132 int m_rx_byte_count
= 0;
133 int m_rx_remaining_count
= 0;
135 byte[] m_tx_buffer
= new byte[32 * 1024];
136 MemoryStream m_tx_mem_stream
= null;
138 //LinkedList<byte[]> m_tx_queue;
139 BinaryReader m_sock_reader
= null;
140 BinaryWriter m_sock_writer
= null;
142 static void RxCallback(IAsyncResult ar
)
144 amuleRemote o
= (amuleRemote
)ar
.AsyncState
;
145 Console
.WriteLine("RxCallback signalled, calling EndReceive");
146 int bytesRead
= o
.m_s
.EndReceive(ar
);
147 if ( bytesRead
== 0 ) {
148 // remote side closed connection.
149 // indicate error to caller
150 o
.m_rx_byte_count
= -1;
153 o
.m_rx_remaining_count
-= bytesRead
;
154 Console
.WriteLine("RxCallback: got {0} bytes, waiting for {1}",
155 bytesRead
, o
.m_rx_remaining_count
);
156 // are we still waiting for flags and size?
157 if (o
.m_rx_byte_count
< 8) {
158 if ((o
.m_rx_byte_count
+ bytesRead
) >= 8) {
159 // got flags and packet size - may proceed.
160 Int32 flags
= o
.m_sock_reader
.ReadInt32();
161 Int32 val32
= o
.m_sock_reader
.ReadInt32();
163 o
.m_rx_remaining_count
= (int)IPAddress
.NetworkToHostOrder(val32
) - (bytesRead
- 8);
164 Console
.WriteLine("RxCallback: expecting packet size={0}", o
.m_rx_remaining_count
);
165 if ( o
.m_rx_buffer
.Length
<= (o
.m_rx_remaining_count
+o
.m_rx_byte_count
) ) {
166 byte [] new_buffer
= new byte[o
.m_rx_remaining_count
+ o
.m_rx_buffer
.Length
+ 1];
167 o
.m_rx_buffer
.CopyTo(new_buffer
, 0);
168 o
.m_rx_buffer
= new_buffer
;
170 // update stream reader with new buffer
172 o
.m_rx_mem_stream
= new MemoryStream(o
.m_rx_buffer
);
173 o
.m_sock_reader
= new BinaryReader(o
.m_rx_mem_stream
);
177 if ( o
.m_rx_remaining_count
== 0 ) {
179 // Packet received - call handler
181 if ( o
.m_handler
!= null ) {
182 o
.m_rx_mem_stream
.Seek(0, SeekOrigin
.Begin
);
183 Console
.WriteLine("Packet received - call handler");
184 ecProto
.ecPacket p
= new ecProto
.ecPacket(o
.m_sock_reader
);
185 //m_packet_op_Done.Set();
186 o
.m_handler
.HandlePacket(p
);
187 Console
.WriteLine("Handler done");
189 Console
.WriteLine("Signalling event");
190 //m_packet_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");
212 public IAsyncResult
SendPacket(ecProto
.ecPacket packet
)
214 m_tx_mem_stream
.Seek(0, SeekOrigin
.Begin
);
215 packet
.Write(m_sock_writer
);
217 return m_s
.BeginSend(m_tx_buffer
, 0, packet
.PacketSize(),
218 SocketFlags
.None
, new AsyncCallback(TxCallback
), this);
221 public void StartReceive()
223 // reply packet is supposed to have at least 8 bytes
224 m_rx_remaining_count
= 8;
226 m_rx_mem_stream
.Seek(0, SeekOrigin
.Begin
);
227 m_s
.BeginReceive(m_rx_buffer
, 0, 8, SocketFlags
.None
, new AsyncCallback(RxCallback
), this);
230 [DnsPermission(SecurityAction
.Demand
, Unrestricted
= true)]
231 public bool ConnectToCore(string host
, int port
, string pass
, ref string error
)
234 IAsyncResult async_result
;
236 ResolveState resolveContext
= new ResolveState();
237 async_result
= Dns
.BeginGetHostEntry(host
,
238 new AsyncCallback(GetHostEntryCallback
), resolveContext
);
240 async_result
.AsyncWaitHandle
.WaitOne();
241 if ( resolveContext
.IPs
== null ) {
242 error
= resolveContext
.errorMsg
;
245 Console
.WriteLine("Resolved: '{0}' -> '{1}", host
,resolveContext
.IPs
.AddressList
[0]);
246 Console
.WriteLine("Connecting to {0}:{1}", resolveContext
.IPs
.AddressList
[0], port
);
247 IPEndPoint remoteEP
= new IPEndPoint(resolveContext
.IPs
.AddressList
[0], port
);
248 m_s
= new Socket(AddressFamily
.InterNetwork
, SocketType
.Stream
, ProtocolType
.Tcp
);
250 ConnectState connectContext
= new ConnectState(m_s
);
251 async_result
= m_s
.BeginConnect(remoteEP
, new AsyncCallback(ConnectCallback
), connectContext
);
252 if ( !async_result
.AsyncWaitHandle
.WaitOne(10000, true) ) {
253 error
= "Timeout during connection. Possible firewall";
257 if ( connectContext
.errorMsg
!= null) {
258 error
= connectContext
.errorMsg
;
262 m_tx_mem_stream
= new MemoryStream(m_tx_buffer
);
263 m_sock_writer
= new BinaryWriter(m_tx_mem_stream
);
264 m_rx_mem_stream
= new MemoryStream(m_rx_buffer
);
265 m_sock_reader
= new BinaryReader(m_rx_mem_stream
);
267 ecProto
.ecLoginPacket p
= new ecProto
.ecLoginPacket("amule.net", "0.0.1", pass
);
268 async_result
= SendPacket(p
);
270 if (!async_result
.AsyncWaitHandle
.WaitOne()) {
271 // Was unable to send login request for 1sec. Line must be really slow
275 m_handler
= new amuleLogicHandler(this);
277 Console
.WriteLine("Waiting for auth done");
278 // FIXME: must be able to cancel this read.
279 m_packet_op_Done
.WaitOne();
280 if ( m_rx_byte_count
== -1 ) {
281 // remote side terminated connection
282 Console
.WriteLine("Connection terminated on remote side");
284 Console
.WriteLine("Connect done");
285 bool result
= ((amuleLogicHandler
)m_handler
).AuthResult();
288 } catch (Exception e
) {
294 public void SetECHandler(amuleECHandler h
)