ubuntuusers.de

asd

Datum:
19. November 2009 01:12
Code:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package rn;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.zip.CRC32;

import javax.net.DataLinkLayer;
import javax.net.ReadFromLowerLayerTimeoutException;

public class SimpleDataLinkLayer extends DataLinkLayer {
	
	
	private static final int MAX_FRAME_PAYLOAD = 10; 	// maximale Größe der Nutzdaten
	private static final int HEADER_LENGTH = 4 + 4;		// Gesamtlänge des Headers
	private static final int CRC_LENGTH = 8;			// Länge der Checksumme
	private static final int ACK_TIMEOUT = 1000;		// Zeit bis ACK kommen muss
	private static final int MAX_TRIES = 10;			// maximale Sendungswiederholungen
	
	private int sequence = 0;		// Sequenznummer für aktuelles Paket
	private int resentcounter = 0;	// Sendungswiederholungszähler für aktuelles Paket
	private int current_tries = 0;


	
	
	
	public void mainloop() throws IOException, MaximumRetriesReachedException {
		
		// Daten von darüberliegender Schicht lesen (blockiert!)
		byte from_upper[] = new byte[MAX_FRAME_PAYLOAD];
		int len_to_send = readFromUpperLayer(from_upper, MAX_FRAME_PAYLOAD);
		
		/*
		 *  Einen ByteBuffer mit der Länge, die das entgültige Paket haben wird erzeugen. D.h. die
		 *  Länge von Header plus Footer plus dem Payload, den wir von der darüberliegenden 
		 *  Schicht erhalten haben  
		 */
		ByteBuffer send_buffer = ByteBuffer.allocate(HEADER_LENGTH + len_to_send + CRC_LENGTH);
		
		/*
		 * Die Daten aus dem Byte Array in den ByteBuffer übertragen
		 */
		send_buffer.position(HEADER_LENGTH);			// Buffer-Zeiger Payload-anfang
		send_buffer.put(from_upper, 0, len_to_send);	// Bytes für den Payload in Buffer schreiben
		
		
		/*
		 * Die Schleife sendet das Paket mit den Nutzdaten mindestens einmal. Nach dem senden wird
		 * für ACK_TIMEOUT Millisekunden auf ein ACK Paket gewartet. Trifft das nicht ein, wird
		 * das Senden wiederholt und dabei der Wiederholungszähler erhöht
		 */
		ByteBuffer ack_buffer = null;
		do {
			
			// Sequenznummer und Wiederholungszähler hinzufügen
			send_buffer.rewind();
			send_buffer.putInt(this.sequence);
			send_buffer.putInt(this.resentcounter++);

			// Daten senden
			writeToLowerLayer(send_buffer.array(), send_buffer.capacity());
			setReadFromLowerLayerTimeout(ACK_TIMEOUT);
			this.current_tries++;
			
			// auf ACK warten
			try {
				byte from_lower[] = new byte[MAX_FRAME_PAYLOAD];
				int len_ack = readFromLowerLayer(from_lower, MAX_FRAME_PAYLOAD);
				ack_buffer = ByteBuffer.allocate(HEADER_LENGTH + len_ack + CRC_LENGTH);

			} catch (ReadFromLowerLayerTimeoutException e) {
				/*
				 * Wird dieser Punkt erreicht hat readFromLowerLayer zu lange gewartet. Damit ist
				 * ack_buffer in jedem Fall leer und die Schleife wird wiederholt.
				 * Wir prüfen hier noch ob die maximale Anzahl der Sendungswiederholungen erreicht
				 * wurde und werfen nötigenfalls eine Exception.
				 */
				if(this.current_tries >= MAX_TRIES) {
					throw new MaximumRetriesReachedException();
				}
			}
		} while(ack_buffer == null);
		
		
	}
	
	/**
	 * Erzeugt eine CRC-32 Prüfsumme für den gegebenen Puffer. Die Berechnung erfolgt dabei von 
	 * Position 0 bis limit. 
	 * @param buffer Der ByteBuffer für den die CRC gebildet werden soll
	 * @param limit Die Anzahl der bytes (vom Anfang des Buffers) für die CRC gebildet werden soll
	 * @return Die gebildete CRC Prüfsumme
	 */
	private long createCRC(ByteBuffer buffer, int limit) {
		// Daten aus Buffer holen
		byte[] data = new byte[limit];
		buffer.position(0);
		buffer.get(data, 0, limit);
		
		// CRC berechnen und zurückgeben
		CRC32 crc = new CRC32();
		crc.update(data);
		return crc.getValue();
	}
	
	/**
	 * Überprüft für den gegebenen Buffer die enhaltene Prüfsumme druch erneute bildung und 
	 * anschließenden Vergleich. Die Prüfsumme steht dabei in den letzten 8 byte.
	 * @param buffer Der zu überprüfende Buffer
	 * @return true, wenn die Prüfsumme stimmt, andernsfalls false
	 */
	private boolean checkChecksum(ByteBuffer buffer) {
		
		// Prüfsumme aus dem Buffer holen
		int begin_crc = buffer.capacity() - CRC_LENGTH;
		long buffer_checksum = buffer.getLong(begin_crc);
		
		// Prüfsumme erneut bilden und vergleichen
		if(createCRC(buffer, begin_crc) == buffer_checksum) {
			return true;
		}
		return false;
		
	}
	
	/**
	 * Erzeugt für den gegebene Buffer eine Prüfsumme und schreibt sie in die letzten 8 byte.
	 * @param buffer Der Buffer für den die Prüfsumme erzeugt wird
	 */
	private void createChecksum(ByteBuffer buffer) {
		int begin_crc = buffer.capacity() - CRC_LENGTH;
		long checksum = createCRC(buffer, begin_crc);
		buffer.putLong(buffer.capacity() - CRC_LENGTH, checksum);
	}
	
	/**
	 * Testmethode zum überprüfen der korrekten CRC Bildung
	 */
	public void testChecksum() {
		
		byte[] data = {1,2,3,1,15,123,0,1};
		ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH + data.length + CRC_LENGTH);
		buffer.position(HEADER_LENGTH);			// Buffer-Zeiger Payload-anfang
		buffer.put(data, 0, data.length);	// Bytes für den Payload in Buffer schreiben
		
		createChecksum(buffer);
		boolean result = checkChecksum(buffer);
		System.out.println(result);
		
	}

	public void receive() {

	}

	public void send() {


	}

}