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(); }
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); }
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); }
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); }
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); }
/* * 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; */ }
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(); } }
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"); } } } }
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); } } }