Upstream tarball 9433
[amule.git] / src / libs / ec / c# / amuleRemote.cs
blob8732627052bd839f81342968bf537c27356e9930
1 //
2 // This file is part of the aMule Project.
3 //
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 )
6 //
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
9 // respective authors.
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.
20 //
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
25 using System;
26 using System.IO;
27 using System.Security;
28 using System.Security.Permissions;
29 using System.Threading;
30 using System.Collections.Generic;
31 using System.Text;
32 using System.Net;
33 using System.Net.Sockets;
35 namespace amule.net
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 {
53 public Socket sock;
54 public string errorMsg;
56 public ConnectState(Socket s)
58 sock = s;
62 public abstract class amuleECHandler {
63 public amuleECHandler()
67 public abstract void HandlePacket(ecProto.ecPacket packet);
70 class amuleLogicHandler : amuleECHandler {
71 amuleRemote m_owner;
72 bool m_auth_result = false;
74 public amuleLogicHandler(amuleRemote o)
76 m_owner = o;
79 public override void HandlePacket(ecProto.ecPacket packet)
81 if ( packet.Opcode() == ECOpCodes.EC_OP_AUTH_OK ) {
82 Console.WriteLine("amuleLogicHandler : Authenticated OK");
83 m_auth_result = true;
84 m_owner.m_packet_op_Done.Set();
85 } else {
86 Console.WriteLine("amuleLogicHandler : Authentication failed. Core reply was {0}", packet.Opcode());
90 public bool AuthResult()
92 return m_auth_result;
96 class amuleRemote {
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;
105 try {
106 ioContext.IPs = Dns.EndGetHostEntry(ar);
107 } catch (SocketException e) {
108 ioContext.errorMsg = e.Message;
112 Socket m_s;
114 static void ConnectCallback(IAsyncResult ar)
116 // Retrieve the socket from the state object.
117 ConnectState state = (ConnectState)ar.AsyncState;
118 try {
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;
151 return;
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);
176 } else {
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
194 o.StartReceive();
195 return;
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");
209 o.m_s.EndSend(ar);
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;
225 m_rx_byte_count = 0;
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)
233 try {
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;
243 return false;
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";
254 return false;
257 if ( connectContext.errorMsg != null) {
258 error = connectContext.errorMsg;
259 return false;
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
272 return false;
275 m_handler = new amuleLogicHandler(this);
276 StartReceive();
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();
286 m_handler = null;
287 return result;
288 } catch (Exception e) {
289 error = e.Message;
290 return false;
294 public void SetECHandler(amuleECHandler h)
296 m_handler = h;