Esempio n. 1
0
  /////////////
  /// Public Methods
  ////////////
 
  /**
   * Implementing the interface from ITransferManager
   * When a request is allowed, we set up the state and
   * start acting
   */
  public Status Allow(Request req, System.IO.Stream data) {
 
    Status stat = new Status(req, data);
    lock( _sync ) { 
      _tid_to_status[req.LocalTID] = stat; 
    }

    if( req.Reqtype == Opcode.ReadReq ) {
      /**
       * We are starting a read request here.  We send the
       * first data packet as an ack of this request
       */
      StreamState rs = new StreamState();
      int new_block = 1;
      stat.StartBlock(new_block, rs);
      rs.Stat = stat;
      rs.Block = new_block;
      rs.Data = new byte[ stat.Request.Blksize ];
      rs.Offset = 0;
      stat.Data.BeginRead(rs.Data, rs.Offset, stat.Request.Blksize,
			  new AsyncCallback(this.ReadHandler),
			  rs);
    }
    else if( req.Reqtype == Opcode.WriteReq ) {
      SendAck(req, 0);
    }
    else {
      /**
       * This can't happen because we would only process Read or Write
       * requests
       * @todo add error handling if ReqType is non-sensical
       */
    }
    return stat;
  }
Esempio n. 2
0
 /**
  * Send this (Local) Request
  */
 protected void SendRequest(Request req) {
 
 }
Esempio n. 3
0
 /**
  * Send an error message for the transfer associated with Req
  */
 protected void SendError(Request req, Error err) {
   AHPacket resp = CreateErrorPacket(req.Peer, req.LocalTID, req.PeerTID, err);
   _node.Send(resp);
 }
Esempio n. 4
0
  /**
   * Send an acknowledgement for the given block in the given transfer
   */
  protected void SendAck(Request req, int block) {
    byte[] body = new byte[8];
    //Write the our TID
    NumberSerializer.WriteShort(req.LocalTID, body, 0);
    //Write the other TID
    NumberSerializer.WriteShort(req.PeerTID, body, 2);
    //Write the OP:
    NumberSerializer.WriteShort((short)Opcode.Ack, body, 4);
    //Write the Block number:
    NumberSerializer.WriteShort((short)block, body, 6);
    AHPacket resp = new AHPacket(0, 32, _node.Address, req.Peer, 
		                 AHPacket.Protocol.Tftp, body);
    _node.Send(resp);
  }
Esempio n. 5
0
  /**
   * Write all the data from the current position in data until the
   * end of the stream
   */
  public Status Put(Stream data, Address target, string filename) {
    //First we make a TID for this transfer:
    short tid = GetNextTID();
    Request req;
    //Send the Length if we can:
    if( data.CanSeek ) {
      req = new Request(tid, DefaultTID, Opcode.WriteReq,
		                target, filename, data.Length);
    }
    else {
      req = new Request(tid, DefaultTID, Opcode.WriteReq,
		                target, filename);
    }
    SendRequest(req);
    Status stat = new Status(req, data);
    lock( _sync ) { 
      _tid_to_status[tid] = stat; 
    }
    return stat;
  }
Esempio n. 6
0
  /**
   * Implementing from IAHPacketHandler
   * This is where we do the meat of the operating
   */
  public void HandleAHPacket(object node, AHPacket p, Edge from) {
    Node n = (Node)node;
    Stream packet_data = p.PayloadStream;
    short peer_tid = NumberSerializer.ReadShort(packet_data);
    short local_tid = NumberSerializer.ReadShort(packet_data);
    Opcode op = (Opcode)NumberSerializer.ReadShort(packet_data);
    /**
     * If there is any Error, an exception is thrown and the
     * Error is sent to the node which sent us this packet
     */
    Error err = null;
    //This is the Request to which this packet is associated
    Request req = null;
    try { 
      if( local_tid == DefaultTID ) {
	/**
	 * This is a new request being made to us from a remote node
	 */
        lock( _sync ) {
          //Check to see if this request is a duplicate:
          foreach(Request openr in _open_requests) {
            if( openr.Peer.Equals(p.Source) &&
	        (openr.PeerTID == peer_tid) ) {
	      req = openr;
            /**
	     * We need to send an Error response when we
	     * get the same TID from the same Address. 
	     * This must be a duplicate packet.
	     */
              err = new Error(Error.Code.NotDefined, "Duplicate Source TID");
	      throw new Exception();
	    }
          }
        }
        //This is a new operation
        local_tid = GetNextTID();
        //We need to parse the request and assign a new TID to this transfer
        req = new Request(peer_tid, local_tid, op, p.Source, packet_data);
        //If we get here, this is a new request
        IAcceptor acc = null;
        if( op == Opcode.ReadReq ) {
          acc = _read_acc;
        }
        else if( op == Opcode.WriteReq ) {
	  acc = _write_acc;
        }
      
        if( acc != null ) {
	  _open_requests.Add(req);
          acc.Accept(req, this);
        }
        else {
          //Something bad happened
	  err = new Error(Error.Code.IllegalOp, "Unknown Opcode");
	  throw new Exception();
        }
      }
      else if (_tid_to_status.ContainsKey(local_tid) ) {
       //This is continuing an existing transfer
       Status stat = (Status)_tid_to_status[local_tid];
       if( stat == null) {
	/**
	 * Status is null until a Request is accepted or denied.
	 * This request is either a (lucky) bug or an attack.
	 * You see, there is no way for the Peer to know which
	 * TID we are using when status is null.  This only happens
	 * when a TID has been assigned locally, but not yet sent
	 * over the network.  Hence, the Peer made a lucky guess.
	 */
	Error error = new Error(Error.Code.UnknownTID, "say what?");
        AHPacket resp = CreateErrorPacket(p.Source, DefaultTID, peer_tid, error);
        _node.Send(resp);
       }
       else {
       req = stat.Request;
       short block;
        switch(op) {
        case Opcode.Data:
	      ///@todo consider carefully that this works in both directions
	      ///@todo make all blocks ushort (so we can use an int == -1 to initialize)
              block = NumberSerializer.ReadShort(packet_data);
              /**
	       * When data comes, we send an Ack
	       */
	      lock( stat ) {
	        if( stat.LastBlockNumber == block ) {
	          /*
		   * This is a block we have already seen
		   */
	          SendAck(req, block);
		}
		else if( stat.PendingBlock == block ) {
                  //We are already dealing with this data
		  //So, we do nothing here
		}
		else {
	          /*
		   * This is a new Data block to us!
		   * Write it to disk and then send the Ack
		   */
		  StreamState ws = new StreamState();
	          stat.StartBlock(block, ws);
		  //This is new data we have not yet seen
		  ws.Stat = stat;
		  ws.Block = block;
		  ws.Data = new byte[ stat.Request.Blksize ];
		  ws.Offset = 0;
	          //The packet data is a MemoryStream which never blocks:
	          ws.Size = packet_data.Read(ws.Data, 0, stat.Request.Blksize);
	          stat.Data.BeginWrite(ws.Data, ws.Offset, ws.Size,
				       new AsyncCallback(this.WriteHandler),
				       ws);
		}
	      }
	      break;
        case Opcode.Ack:
              block = NumberSerializer.ReadShort(packet_data);
	      /**
	       * When an Ack comes, we know our last Data
	       * has made it across and we send the next Data
	       * We complete the block associated with that,
	       * and if we are not done, we start the next read
	       */
	      lock( stat ) {
	        StreamState sent = (StreamState)stat.PendingState;
	        bool finished = stat.CompleteBlock(block, sent.Size);
	        if( !finished ) {
                  //Do the next read:
		  StreamState rs = new StreamState();
		  int new_block = block + 1;
		  stat.StartBlock(new_block, rs);
		  rs.Stat = stat;
		  rs.Block = new_block;
		  rs.Data = new byte[ stat.Request.Blksize ];
		  rs.Offset = 0;
	          stat.Data.BeginRead(rs.Data, rs.Offset, stat.Request.Blksize,
				       new AsyncCallback(this.ReadHandler),
				       rs);
		}
	      }
	      break;
        case Opcode.Error:
              Error.Code code = (Error.Code)NumberSerializer.ReadShort(packet_data);
	      string message = ReadAsciiStringFrom(packet_data);
	      //Things did not work out for us
	      stat.SetError(new Error(code, message)); 
	      break;
        default:
	      err = new Error(Error.Code.IllegalOp, "Unknown Opcode");
	      throw new Exception();
        }//End of switch
       }//End of case where stat != null
      }//End of case where TID is known
      else {
        //Never heard of this TID!
	Error error = new Error(Error.Code.UnknownTID, "say what?");
        AHPacket resp = CreateErrorPacket(p.Source, DefaultTID, peer_tid, error);
        _node.Send(resp);
      }
    }
    catch(Exception x) {
      /**
       * If there has been any Exception or Error, we will wind up here
       * in which case we send an error response and release this TID.
       */
      if( err == null ) {
        //Set the error
	err = new Error(Error.Code.NotDefined, x.ToString() );
      }
      SendError(req, err);
      ReleaseTID(local_tid);
    }
  }
Esempio n. 7
0
 /**
  * Implementing the interface from ITransferManager
  */
 public void Deny(Request req, Error err) { 
   SendError(req, err);
   //Pop this request out of our memory:
   ReleaseTID(req.LocalTID);
 }