Пример #1
0
  private void transmitDatagram(MessagePacket p, boolean tryToAppendACKInfo) {
    // append SACK chunk if we can
    if (tryToAppendACKInfo && appendSACKData(p, false)) {
      _lastSACKTransmitTime = System.currentTimeMillis();
      _unacknowledgedPackets = 0;
    }

    // fill in outgoing datagram packet
    p.setWindowSize(_receiver.getCurrentWindowSize());
    p.setValidation(_validation);
    p.writeToDatagramPacket(_outgoingPacket);

    _outgoingPacket.setAddress(_remoteAddress);
    _outgoingPacket.setPort(_remotePort);

    // send packet over the socket
    try {
      _dgSocket.send(_outgoingPacket);
    } catch (IOException e) {
      e.printStackTrace();
    }

    // update last transmission time
    _lastTransmitTime = System.currentTimeMillis();

    Thread.yield();
  }
Пример #2
0
  private void transmitShutdownCompletePacket() {
    MessagePacket p = new MessagePacket();

    ShutdownCompleteChunk scChk = new ShutdownCompleteChunk();

    // append SHUTDOWN-COMPLETE chunk
    if (!p.addChunk(scChk)) {
      // this should never happen
      throw new RuntimeException("Impossible to add SHUTDOWN-COMPLETE chunk to an empty packet.");
    }

    transmitMessagePacket(p, true);
  }
Пример #3
0
  private void transmitHeartbeatPacket() {
    MessagePacket p = new MessagePacket();

    HeartbeatInfo hbInfo = new HeartbeatInfo(System.currentTimeMillis());
    HeartbeatChunk hbChk = new HeartbeatChunk(hbInfo);

    // append HEARTBEAT chunk
    if (!p.addChunk(hbChk)) {
      // this should never happen
      throw new RuntimeException("Impossible to add HEARTBEAT chunk to an empty packet.");
    }

    transmitMessagePacket(p, true);
  }
Пример #4
0
  private void transmitMessagePacket(MessagePacket p, boolean tryToAppendACKInfo) {
    // set packet sequence number
    long seqNum = 0;
    if (p.isFlagSet(MessagePacket.HEADER_FLAG_CONTROL)) {
      assert !p.isFlagSet(MessagePacket.HEADER_FLAG_RELIABLE)
          && !p.isFlagSet(MessagePacket.HEADER_FLAG_SEQUENCED);
      seqNum = _controlTSN;
      _controlTSN = SequentialArithmetic.add(_controlTSN, 1);
    } else if (p.isFlagSet(MessagePacket.HEADER_FLAG_SEQUENCED)) {
      if (p.isFlagSet(MessagePacket.HEADER_FLAG_RELIABLE)) {
        seqNum = _relSeqTSN;
        _relSeqTSN = SequentialArithmetic.add(_relSeqTSN, 1);
      } else {
        seqNum = _unrelSeqTSN;
        _unrelSeqTSN = SequentialArithmetic.add(_unrelSeqTSN, 1);
      }
    } else {
      if (p.isFlagSet(MessagePacket.HEADER_FLAG_RELIABLE)) {
        seqNum = _relUnseqID;
        _relUnseqID = SequentialArithmetic.add(_relUnseqID, 1);
      } else {
        seqNum = _unrelUnseqID;
        _unrelUnseqID = SequentialArithmetic.add(_unrelUnseqID, 1);
      }
    }
    p.setSequenceNumber(seqNum);

    transmitDatagram(p, tryToAppendACKInfo);
  }
Пример #5
0
  void cancel(boolean sequenced, int oldtag) {
    // cancel stuff from the pending packet queue
    _pendingPacketQueue.cancel(sequenced, oldtag);

    // cancel stuff from the outstanding packet queue
    TSNRangeHandler rh = new TSNRangeHandler(false, sequenced);
    _outstandingPacketQueue.cancel(sequenced, oldtag, rh);
    ACKInformation ai = new ACKInformation();
    rh.fillACKInformation(ai);

    // send control packet containing cancelled packets chunk
    MessagePacket p = new MessagePacket();
    p.setFlags(MessagePacket.HEADER_FLAG_CONTROL);
    CancelledPacketsChunk cpChk = new CancelledPacketsChunk(ai);
    p.addChunk(cpChk);
    MessagePacketInfo pi =
        new MessagePacketInfo(
            p, TxParams.MAX_PRIORITY, 0, 0, MessageMocket.DEFAULT_RETRANSMISSION_TIMEOUT);
    transmitPacket(pi);
  }
Пример #6
0
  /*
   * This method tries to append a SACK chunk to a MessagePacket.
   * Returns true if the operation succeeds, false elsewhere.
   */
  private boolean appendSACKData(MessagePacket p, boolean force) {
    /*
    if (force ||
        System.currentTimeMillis() > _lastSACKTransmitTime + SACK_XMIT_MIN_INTERVAL) {
    */
    SACKInformation sackInfo = _ackManager.getSACKInformation();
    assert sackInfo != null;

    // sackInfo._dump (System.out);

    // _logger.warning ("Created SACKInfo size: " + sackInfo.getLength());
    SACKChunk chk = new SACKChunk(sackInfo);
    // _logger.warning ("Created SACKChunk size: " + chk.getLength());
    assert chk != null;

    return p.setSACKChunk(chk);
    /*
    }

    return false;
    */
  }
Пример #7
0
  void send(
      boolean reliable,
      boolean sequenced,
      byte[] buf,
      int off,
      int len,
      int tag,
      int priority,
      long enqueue_timeout,
      long retry_timeout)
      throws IOException {
    /* we accept data only if the connection is not closed */
    if (_status.currentState() != MessageStateMachine.ESTABLISHED)
      throw new IOException("Connection closed!");

    /* this is the space we can use for data in each packet
     * (provided we have only a single DATA chunk in each packet) */
    int availSize =
        _mocket.getMTU() - (MessagePacket.HEADER_SIZE + DataChunk.DATA_CHUNK_HEADER_SIZE);

    if (_mocket.isCrossSequencingEnabled())
      availSize -= DeliveryPrerequisites.DELIVERY_PREREQUISITES_SIZE;

    _logger.fine(
        "MessageTransmitter::send "
            + (reliable ? "R " : "")
            + (sequenced ? "S " : "")
            + "len = "
            + len
            + " tag = "
            + tag);

    int toSend = len;
    int sent = 0;
    int fragmentNum = 0;
    boolean fragmentationNeeded = len > availSize;

    if (fragmentationNeeded) _logger.info("fragmentation needed!!!");

    // build and enqueue message packet(s)
    while (toSend > 0) {
      int cc = Math.min(toSend, availSize);

      MessagePacket p = new MessagePacket();
      if (reliable) p.setFlags(MessagePacket.HEADER_FLAG_RELIABLE);
      if (sequenced) p.setFlags(MessagePacket.HEADER_FLAG_SEQUENCED);

      if (fragmentationNeeded) p.allocateSpaceForDeliveryPrerequisites();

      DataChunk chk = new DataChunk(tag, buf, off + sent, cc);

      if (!p.addChunk(chk)) {
        // this should never happen
        throw new IOException("Buffer size too big");
      }

      toSend -= cc;

      if (fragmentationNeeded) {
        assert toSend >= 0;
        if (toSend == 0) {
          p.setFlags(MessagePacket.HEADER_FLAG_LAST_FRAGMENT);
        } else {
          if (fragmentNum == 0) {
            p.setFlags(MessagePacket.HEADER_FLAG_FIRST_FRAGMENT);
          }
          p.setFlags(MessagePacket.HEADER_FLAG_MORE_FRAGMENTS);
        }
      }

      // enqueue message packet
      if (!enqueueMessagePacket(p, priority, enqueue_timeout, retry_timeout)) {
        throw new IOException("Pending packet queue is full.");
      }

      ++fragmentNum;
      sent += cc;
    }

    transmitNextPacket();

    // wake up transmitter thread
    synchronized (this) {
      notifyAll();
    }
  }
Пример #8
0
  private void transmitNextPacket() {
    // TODO: implement a serious bandwidth constraint mechanism

    synchronized (_pendingPacketQueue) {
      if (!_pendingPacketQueue.isEmpty()) {
        // _logger.info ("CHECKING PENDING PACKET QUEUE");
        MessagePacketInfo mpi = _pendingPacketQueue.peek();
        int available = Math.max(_remoteWindowSize - _outstandingPacketQueue.getSize(), 0);
        /*
        _logger.info ("2send from PPQ: " + mpi.getPacket().getSize() +
                      " available: " + available +
                      " (win: " + _remoteWindowSize +
                      " opq.size: " + _outstandingPacketQueue.getSize() +
                      ")");
        */

        if (mpi != null && (mpi.getPacket().getSizeWithoutSACKChunk() < available)) {
          // _logger.info ("XMIT FROM PENDING PACKET QUEUE");

          // transmit packet
          transmitPacket(mpi);
          MessagePacket p = mpi.getPacket();

          // update remote window size
          _remoteWindowSize -= p.getSizeWithoutSACKChunk();

          // update statistics
          int sent = p.getSize();

          ++_mocket.getStatistics()._sentPackets;
          _mocket.getStatistics()._sentBytes += sent;

          _logger.info(
              "XMITTED PACKET "
                  + p.getSequenceNumber()
                  + " SIZE "
                  + p.getSize()
                  + " FROM PENDING PACKET QUEUE");
          _pendingPacketQueue._dump(System.err);

          // move packet from the pending packet queue...
          _pendingPacketQueue.remove(mpi);

          _logger.info(
              "REMOVED PACKET "
                  + p.getSequenceNumber()
                  + " SIZE "
                  + p.getSize()
                  + " FROM PENDING PACKET QUEUE");
          _pendingPacketQueue._dump(System.err);

          // ...to the outstanding queue
          if (mpi.getPacket().isFlagSet(MessagePacket.HEADER_FLAG_RELIABLE)
              || mpi.getPacket().isFlagSet(MessagePacket.HEADER_FLAG_CONTROL)) {
            // remove SACK chunk from packet which is going to be inserted
            // in the outstanding packet queue
            p.unsetSACKChunk();
            _outstandingPacketQueue.insert(mpi);
          }

          // _logger.info ("END XMIT FROM PENDING PACKET QUEUE");
        }
      }
    }

    synchronized (_outstandingPacketQueue) {
      if (!_outstandingPacketQueue.isEmpty()) {
        // _logger.info ("CHECKING OUTSTANDING PACKET QUEUE");
        MessagePacketInfo mpi = _outstandingPacketQueue.extractIfTimeout();
        if (mpi != null) {
          // _logger.info ("XMIT FROM OUTSTANDING PACKET QUEUE");

          // retransmit packet
          MessagePacket p = mpi.getPacket();
          transmitDatagram(p, true);

          _logger.info(
              "XMITTED PACKET "
                  + p.getSequenceNumber()
                  + " SIZE "
                  + p.getSize()
                  + " FROM OUTSTANDING PACKET QUEUE");
          _outstandingPacketQueue._dump(System.err);

          // update statistics
          int sent = p.getSize();
          ++_mocket.getStatistics()._retransmittedPackets;
          _mocket.getStatistics()._sentBytes += sent;

          // remove SACK chunk from packet which is going to be reinserted
          // in the outstanding packet queue
          p.unsetSACKChunk();
          assert p.getSize() == p.getSizeWithoutSACKChunk();

          // reinsert mpi at the end of the outstanding packet queue
          _outstandingPacketQueue.insert(mpi);

          // _logger.info ("END XMIT FROM OUTSTANDING PACKET QUEUE");
        }
      }
    }
  }
Пример #9
0
  public void render() {
    this.map.update();
    stage.act(Gdx.graphics.getDeltaTime());
    stage.draw();

    this.mapInputListener.update();

    while (Client.getCurrentState() == this) {
      TopPacket packet = Network.getInstance().pollPacket();
      if (packet == null) break;

      if (packet.getType() == TopPacket.CHARACTER) {
        if (((CharacterPacket) packet).getType2() == CharacterPacket.Add) {
          Character entity = new Character(this, (CharacterPacket) packet);
          this.map.addEntity(entity);
        } else if (((CharacterPacket) packet).getType2() == CharacterPacket.Del) {
          Entity entity = getEntityByEntityId(((CharacterPacket) packet).getEntityId());
          this.map.removeEntity(entity);
        }
      } else if (packet.getType() == TopPacket.MONSTER) {
        if (((MonsterPacket) packet).getType2() == MonsterPacket.Add) {
          Monster monster = new Monster(this, (MonsterPacket) packet);
          this.map.addEntity(monster);
        } else if (((MonsterPacket) packet).getType2() == MonsterPacket.Del) {
          Entity entity = getEntityByEntityId(((MonsterPacket) packet).getEntityId());
          this.map.removeEntity(entity);
        }
      } else if (packet.getType() == TopPacket.MOVE) {
        Entity target = getEntityByEntityId(((MovePacket) packet).getEntityId());
        if (target == null) break;

        int src_x = ((MovePacket) packet).getSx();
        int src_y = ((MovePacket) packet).getSy();
        int dest_x = ((MovePacket) packet).getDx();
        int dest_y = ((MovePacket) packet).getDy();

        target.move(src_x, src_y, dest_x, dest_y);
      } else if (packet.getType() == TopPacket.UPDATE) {
        Entity target = getEntityByEntityId(((UpdatePacket) packet).getEntityId());
        if (target == null) break;

        target.update((UpdatePacket) packet);
      } else if (packet.getType() == TopPacket.CHAT) {
        chattingDialog.append((ChatPacket) packet);
      } else if (packet.getType() == TopPacket.PARTY) {
        PartyPacket p = (PartyPacket) packet;
        if (p.getType2() == PartyPacket.info) {
          centerCharacterParty = new Party();
          int[] entityIds = p.getPartyMemberEntityIds();
          for (int i = 0; i < p.getPartyNumber(); i++) {
            Character c = (Character) getEntityByEntityId(entityIds[i]);
            centerCharacterParty.addMember(c);
          }
        } else if (p.getType2() == PartyPacket.withdraw) {
          centerCharacterParty = null;
        } else if (p.getType2() == PartyPacket.add) {
          centerCharacterParty.addMember((Character) getEntityByEntityId(p.getTargetEntityId()));
        } else if (p.getType2() == PartyPacket.del) {
          centerCharacterParty.removeMember(p.getTargetEntityId());
        } else if (p.getType2() == PartyPacket.invite) {
          stage.addActor(new ServerMsgDialog("", skin, p));
        }
      } else if (packet.getType() == TopPacket.MESSAGE) {
        MessagePacket p = (MessagePacket) packet;
        MessageDialog m = getMessageDialogByTarget(p.getName());
        if (m == null) {
          m = new MessageDialog("", skin, p.getName());
          messages.add(m);
          stage.addActor(m);
        }
        m.append(p);
      } else if (packet.getType() == TopPacket.SERVER) {
        SystemMessage.getInstance()
            .show(((ServerMsg) packet).getMsg(), 2000, 1.0f, 1.0f, 1.0f, 1.0f);
      }
    }
  }