public synchronized PacketBackup waitAndPopNext() {
		
		for(;;) {
			
			while(firstProperties == null) {
				// queue is empty, wait
				Log.debug(this, "queue is empty, waiting...");
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
					return null;
				}
			}
			
			ResendPacketQueueProperties properties = firstProperties;
			PacketBackup packetBackup = properties.getPacketBackup();
			long dataId = packetBackup.getPacketProperties().dataId;
			long nextResendTime = packetBackup.getResendPacketQueueProperties().getNextResendTime();
			long now = System.nanoTime()/1000000L;
			long diff = nextResendTime - now;
			
			Log.debug(this, "waiting %d millis (%s)", diff, packetBackup);
			if(diff > 0) {
				try {
					this.wait(diff);
				} catch (InterruptedException e) {
					e.printStackTrace();
					return null;
				}
			}
			
			if(properties == firstProperties) {
				// the backup we waited for is still the first; pop it off
				firstProperties = firstProperties.next;
				if(firstProperties == null) lastProperties = null; // queue is now empty, also set last item null
				else firstProperties.prior = null;
				if(packetBackup.getUsed() && packetBackup.getPacketProperties().dataId == dataId) {
					// this is still the exact same PacketBackup
					return packetBackup;
				} else {
					// this PacketBackup has been invalidated meanwhile
					Log.debug(this, "PacketBackup we waited for is invalid (packetBackup.getUsed()=%s, packetBackup's dataId=%d, expected dataId=%d)", packetBackup.getUsed(), packetBackup.getPacketProperties().dataId, dataId);
				}
			} else {
				Log.debug(this, "PacketBackup we waited for is no longer present");
			}
			
			lastInvalidPacketBackup = now;
			
		}
		
	}