/** * This handles the packet forwarding protocol */ public void HandleData(MemBlock b, ISender ret_path, object state) { /* * Check it */ AHSender ahs = ret_path as AHSender; if( ahs != null ) { //This was an AHSender: /* * This goes A -> B -> C */ if( b[0] == 0 ) { int offset = 1; //This is the first leg, going from A->B Address add_c = AddressParser.Parse(b.Slice(offset, Address.MemSize)); offset += Address.MemSize; //Since ahs a sender to return, we would be the source: Address add_a = ahs.Destination; short ttl = NumberSerializer.ReadShort(b, offset);//2 bytes offset += 2; ushort options = (ushort) NumberSerializer.ReadShort(b, offset);//2 bytes offset += 2; MemBlock payload = b.Slice(offset); MemBlock f_header = MemBlock.Reference( new byte[]{1} ); /* * switch the packet from [A B f0 C] to [B C f 1 A] */ ICopyable new_payload = new CopyList(PType.Protocol.Forwarding, f_header, add_a, payload); /* * ttl and options are present in the forwarding header. */ AHSender next = new AHSender(_n, ahs.ReceivedFrom, add_c, ttl, options); next.Send(new_payload); } else if ( b[0] == 1 ) { /* * This is the second leg: B->C * Make a Forwarding Sender, and unwrap the inside packet */ Address add_a = AddressParser.Parse(b.Slice(1, Address.MemSize)); Address add_b = ahs.Destination; MemBlock rest_of_payload = b.Slice(1 + Address.MemSize); //Here's the return path: ISender new_ret_path = new ForwardingSender(_n, add_b, add_a); _n.HandleData(rest_of_payload, new_ret_path, this); } } else { //This is not (currently) supported. Console.Error.WriteLine("Got a forwarding request from: {0}", ret_path); } }
/** <summary>Sends the data over the multicast socket.</summary> <param name="data">The data to send.</summary> */ public override void Send(ICopyable data) { IPAddress[] ips = LocalIPAddresses; if(ips == null) { ips = IPHandler.GetLocalIPAddresses(); } // Silly users can trigger a handful of exceptions here... try { data = new CopyList(IPHandler.MagicCookie, data); byte[] buffer = new byte[data.Length]; int length = data.CopyTo(buffer, 0); // I REALLY HATE THIS but we can't be setting this option in more than one thread! lock(_s) { foreach(IPAddress ip in ips) { /* * This can throw an exception on an invalid address, we need to skip it and move on! * Never showed to be an issue in Linux, but Windows does some weird things. */ try { _s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, IPHandler.IPAddressToInt(ip)); } catch { continue; } _s.SendTo(buffer, 0, length, 0, EndPoint); } } } catch(System.Net.Sockets.SocketException sx) { throw new SendException(true, "SocketException", sx); } // Can't pass the fact that the IPHandler is not running :-/ catch (ObjectDisposedException odx) { throw new SendException(false, "Socket appears to be disposed", odx); } catch (Exception e) { ProtocolLog.WriteIf(ProtocolLog.Exceptions, "ERROR: " + e); throw new SendException(true, "Socket appears to be disposed", e); } }
/** <summary>Sends the data over the unicast socket.</summary> <param name="data">The data to send.</summary> */ public virtual void Send(ICopyable data) { // Silly users can trigger a handful of exceptions here... try { data = new CopyList(IPHandler.MagicCookie, data); byte[] buffer = new byte[data.Length]; int length = data.CopyTo(buffer, 0); _s.SendTo(buffer, 0, length, 0, EndPoint); } catch(System.Net.Sockets.SocketException sx) { throw new SendException(true, "SocketException", sx); } catch (ObjectDisposedException odx) { throw new SendException(false, "Socket appears to be disposed", odx); } catch (Exception e) { ProtocolLog.WriteIf(ProtocolLog.Exceptions, "ERROR: " + e); throw new SendException(true, "Socket appears to be disposed", e); } }
/** * Here we handle routing AHPackets */ public void HandleData(MemBlock data, ISender ret_path, object st) { AHState state = _state; //Read the state, it can't change after the read var header = new AHHeader(data); var payload = data.Slice(header.Length); Connection next_con; //Check to see if we can use a Leaf connection: int dest_idx = state.Leafs.IndexOf(header.Destination); if( dest_idx >= 0 ) { next_con = state.Leafs[dest_idx]; } else { var alg = state.GetRoutingAlgo(header); Pair<Connection, bool> result = alg.NextConnection(ret_path as Edge, header); if( result.Second ) { //Send a response exactly back to the node that sent to us var resp_send = new AHSender(_n, ret_path, header.Source, AHSender.DefaultTTLFor(_n.NetworkSize), AHHeader.Options.Exact); _n.HandleData( payload, resp_send, this); } next_con = result.First; } //Send it on: if( next_con != null ) { //Now we do the sending: var new_packet = new CopyList(PType.Protocol.AH, header.IncrementHops(), payload); try { next_con.Edge.Send(new_packet); } catch(EdgeException) { //Just drop the packet... } } }
override protected bool HandleOutgoing(ICopyable app_data, out ICopyable data) { MemBlock buffer = null; data = null; int written = 1; lock(_buffer_sync) { if(app_data != null) { int count = app_data.CopyTo(_buffer, 0); written = _ssl.Write(_buffer, count); } if(written > 0) { int count = _write.Read(_buffer, _buffer.Length); if(count <= 0) { // This really shouldn't ever happen ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, this + " error"); data = null; return false; } buffer = MemBlock.Copy(_buffer, 0, count); } } if(written > 0) { // Timer becomes -1 when there are no more control messages long to = _ssl.GetTimeout(); if(to >= 0) { HandleWouldBlock(); } if(buffer != null) { data = new CopyList(PType, Header, buffer); return true; } } // If the write failed, then Dtls is either waiting for a control message // or has a control message to send var error = _ssl.GetError(written); if(error == SslError.SSL_ERROR_WANT_READ) { HandleWouldBlock(); } else if(error == SslError.SSL_ERROR_SSL) { var ose = new OpenSslException(); Close("Received unrecoverable error: " + ose.ToString()); throw ose; } else { ProtocolLog.WriteIf(ProtocolLog.SecurityExceptions, "Send other"); } data = null; return false; }
/** * Abandon any attempts to get requests for the given ID. * @throw Exception if handler is not the original handler for this Request */ public void StopRequest(int request_id, IReplyHandler handler) { RequestState rs = null; lock( _sync ) { if( !_req_state_table.TryTake(request_id, out rs)) { rs = null; } } if( rs != null ) { /* * Send an ack for this reply: */ byte[] ack_payload = new byte[5]; ack_payload[0] = (byte)ReqrepType.ReplyAck; NumberSerializer.WriteInt(request_id, ack_payload, 1); ICopyable data = new CopyList(_prefix, MemBlock.Reference(ack_payload)); foreach(ISender ret_path in rs.Repliers) { try { //Try to send an ack, but if we can't, oh well... ret_path.Send(data); } catch { } } } }
/// <summary>Constructor for a RelayEdge, RemoteID == -1 for out bound.</summary> public RelayEdge(IEdgeSendHandler send_handler, RelayTransportAddress local_ta, RelayTransportAddress remote_ta, IForwarderSelector ias, List<Connection> overlap, int remote_id) : base(send_handler, remote_id != -1) { _remote_id = remote_id; lock(_rand) { LocalID = _rand.Next(); } byte[] bid = new byte[8]; NumberSerializer.WriteInt(LocalID, bid, 0); NumberSerializer.WriteInt(_remote_id, bid, 4); _mid = MemBlock.Reference(bid); _local_ta = local_ta; _remote_ta = remote_ta; _tunnels = new List<Connection>(overlap); _ias = ias; _ias.Update(_tunnels); AHHeader ahh = new AHHeader(1, 20, local_ta.Target, remote_ta.Target, AHHeader.Options.Exact); ICopyable header = new CopyList(PType.Protocol.AH, ahh, PType.Protocol.Relaying); Header = MemBlock.Copy(header); }
/** * This is how you invoke a method on a remote host. * Results are put into the Channel. * * If you want to have an Event based approach, listen to the EnqueueEvent * on the Channel you pass for the results. That will be fired * immediately from the thread that gets the result. * * When a result comes back, we put and RpcResult into the Channel. * When you have enough responses, Close the queue (please). The code * will stop sending requests after the queue is closed. If you never close * the queue, this will be wasteful of resources. * * @param target the sender to use when making the RPC call * @param q the Channel into which the RpcResult objects will be placed. * q may be null if you don't care about the response. * @param method the Rpc method to call * * @throw Exception if we cannot send the request for some reason. */ virtual public void Invoke(ISender target, Channel q, string method, params object[] args) { //build state for the RPC call RpcRequestState rs = new RpcRequestState(); rs.Results = q; rs.RpcTarget = target; object[] rpc_call = new object[2]; rpc_call[0] = method; if( args != null ) { rpc_call[1] = args; } else { //There are no args, which we represent as a zero length list rpc_call[1] = new object[0]; } AdrCopyable req_copy = new AdrCopyable(rpc_call); #if RPC_DEBUG Console.Error.WriteLine("[RpcClient: {0}] Invoking method: {1} on target: {2}", _rrman.Info, method, target); #endif ICopyable rrpayload = new CopyList( PType.Protocol.Rpc, req_copy ); int reqid = _rrman.SendRequest(target, ReqrepManager.ReqrepType.Request, rrpayload, this, rs); //Make sure we stop this request when the queue is closed. if( q != null ) { try { q.CloseEvent += delegate(object qu, EventArgs eargs) { _rrman.StopRequest(reqid, this); }; } catch { if(q.Closed) { _rrman.StopRequest(reqid, this); } else { throw; } } } }
public void HandleData(AHHeader header, ICopyable payload, ISender ret_path, object st) { AHState state = _state; //Read the state, it can't change after the read Connection next_con; //Check to see if we can use a Leaf connection: int dest_idx = state.Leafs.IndexOf(header.Destination); if( dest_idx >= 0 ) { next_con = state.Leafs[dest_idx]; } else { var alg = state.GetRoutingAlgo(header); Pair<Connection, bool> result = alg.NextConnection(ret_path as Edge, header); if( result.Second ) { //Send a response exactly back to the node that sent to us var resp_send = new AHSender(_n, ret_path, header.Source, AHSender.DefaultTTLFor(_n.NetworkSize), AHHeader.Options.Exact, header.Hops); MemBlock data = payload as MemBlock; if(data == null) { // Try to get the shared BufferAllocator, useful when we don't know // how big the data is, which in general is just as expensive as // doing a CopyTo... BufferAllocator ba = Interlocked.Exchange<BufferAllocator>(ref _ba, null); if( ba != null ) { try { int length = payload.CopyTo(ba.Buffer, ba.Offset); data = MemBlock.Reference(ba.Buffer, ba.Offset, length); ba.AdvanceBuffer(length); } catch(System.Exception x) { throw new SendException(false, "could not write the packet, is it too big?", x); } finally { Interlocked.Exchange<BufferAllocator>(ref _ba, ba); } } else { data = MemBlock.Copy(payload); } } _n.HandleData( data, resp_send, this); } next_con = result.First; } //Send it on: if( next_con != null ) { //Now we do the sending: var new_packet = new CopyList(PType.Protocol.AH, header.IncrementHops(), payload); try { next_con.State.Edge.Send(new_packet); } catch(SendException) { //Just drop the packet... } } }