@Override
	public void run() {
		long ctsReceivedTime = 0;
		while (running) {
			try {
				// check if sending is okay: last seen CTS not meant for this
				// sender is > ctsDelayTime ago
				// Don't be greedy: even if maca is disabled, respect CTS for
				// other sender!
				if ((lastCTSSeen + ctsDelayTime) <= System.currentTimeMillis()) {

					// pick topmost packet (but keep it in the list, if we like
					// to resend it in case of a RTSPacket)
					Packet p = packetQueue.peek();

					// if queue is empty: wait for queue to be filled again
					// @see sendPacket
					if (p == null) {
						Logger.getInstance().println("WLANSender.run: Packet queue empty, going to sleep", Logger.SPAM);
						synchronized (packetQueue) {
							packetQueue.wait();
						}
						continue;
					}

					// transform packet to DatagramPacket
					byte[] b = p.serialize();
					DatagramPacket wlanPacket = new DatagramPacket(b, b.length);
					wlanPacket.setAddress(Starter.getDestinationAddress());
					wlanPacket.setPort(socket.getLocalPort());

					Logger.getInstance().println("WLANSender.run: Send packet " + p.toString(), Logger.NOTICE);
					// send packet
					socket.send(wlanPacket);

					// if this packet was a "request to send" packet, sender
					// will wait for a "clear to send" one. If a CTS is received
					// (and meant for this sender), the receiver will remove the
					// RTS packet from this senders queue and will notify this
					// thread to go on
					// If no CTS is receive within the timeout time, the RTS
					// packet will remain in the queue and this thread will
					// wakeup to send the queue's topmost packet - which will be
					// a resend of the RTS packet and so on
					if (p instanceof RTSPacket) {
						long startWaitingTime = System.currentTimeMillis();
						Logger.getInstance().println("WLANSender.run: RTC packet send, waiting for CTS", Logger.SPAM);
						// wait for retryRTSTimeout on the packet to be removed
						// from the receiver
						synchronized (p) {
							p.wait(retryRTSTimeout);
						}
						ctsReceivedTime= System.currentTimeMillis();

						// if topmost packet is not a RTS packet, which means
						// the receiver polled the package due to a CTS packet,
						// we can calculate the time it required to receive a
						// RTS packet which we will use as a retryRTSTimeout
						if ( !(packetQueue.peek() instanceof RTSPacket) ) {
							// add a buffer of 10% on the new retryRTSTimeout
							retryRTSTimeout = Math.max(20, (long)((System.currentTimeMillis() - startWaitingTime)*1.20));
						}
					} else {
						packetQueue.poll();
						
						// if MACA is enabled, we wait the CTS delay time (starting when the CTS was received) to not
						// flood the channel with RTS pakets so that no other client may send any packets
						if ( useMaca && ctsReceivedTime != 0) {
							Thread.sleep(Math.max(1, ctsReceivedTime + ctsDelayTime - System.currentTimeMillis()));
						} 
						// make room for other threads
						else {
							Thread.yield();
						}
					}

				}
				// last CTS seen by the receiver still blocks this sender to
				// send any new packets. Wait, until delay is over
				else {
					Logger.getInstance().println("WLANSender.run: Last CTS blocks channel, waiting...", Logger.INFORMATION);
					Thread.sleep((lastCTSSeen + ctsDelayTime - System.currentTimeMillis()));
				}
			} catch (IOException e) {
				// The socket has thrown some IO exception: stop work
				e.printStackTrace();
				break;
			} catch (InterruptedException e) {
				// Something forced this thread to wake up:
				// Just print stack and resume to work
				e.printStackTrace();
			}
		}
	}