123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- /*
- * This file is part of JSTUN.
- *
- * Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
- * reserved.
- *
- * This software is licensed under either the GNU Public License (GPL),
- * or the Apache 2.0 license. Copies of both license agreements are
- * included in this distribution.
- */
-
- package de.javawi.jstun.test.demo;
-
- import java.io.IOException;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- import java.net.SocketException;
- import java.net.UnknownHostException;
- import java.util.Vector;
- import java.util.logging.FileHandler;
- import java.util.logging.Handler;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import java.util.logging.SimpleFormatter;
-
- import de.javawi.jstun.attribute.ChangeRequest;
- import de.javawi.jstun.attribute.ChangedAddress;
- import de.javawi.jstun.attribute.MappedAddress;
- import de.javawi.jstun.attribute.MessageAttributeException;
- import de.javawi.jstun.attribute.MessageAttributeParsingException;
- import de.javawi.jstun.attribute.ResponseAddress;
- import de.javawi.jstun.attribute.SourceAddress;
- import de.javawi.jstun.attribute.UnknownAttribute;
- import de.javawi.jstun.attribute.UnknownMessageAttributeException;
- import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType;
- import de.javawi.jstun.header.MessageHeader;
- import de.javawi.jstun.header.MessageHeaderParsingException;
- import de.javawi.jstun.header.MessageHeaderInterface.MessageHeaderType;
- import de.javawi.jstun.util.Address;
- import de.javawi.jstun.util.UtilityException;
-
- /*
- * This class implements a STUN server as described in RFC 3489.
- * The server requires a machine that is dual-homed to be functional.
- */
- public class StunServer {
- private static Logger logger = Logger.getLogger("de.javawi.stun.test.StunServer");
- Vector<DatagramSocket> sockets;
-
- public StunServer(int primaryPort, InetAddress primary, int secondaryPort, InetAddress secondary) throws SocketException {
- sockets = new Vector<DatagramSocket>();
- sockets.add(new DatagramSocket(primaryPort, primary));
- sockets.add(new DatagramSocket(secondaryPort, primary));
- sockets.add(new DatagramSocket(primaryPort, secondary));
- sockets.add(new DatagramSocket(secondaryPort, secondary));
- }
-
- public void start() throws SocketException {
- for (DatagramSocket socket : sockets) {
- socket.setReceiveBufferSize(2000);
- StunServerReceiverThread ssrt = new StunServerReceiverThread(socket);
- ssrt.start();
- }
- }
-
- /*
- * Inner class to handle incoming packets and react accordingly.
- * I decided not to start a thread for every received Binding Request, because the time
- * required to receive a Binding Request, parse it, generate a Binding Response and send
- * it varies only between 2 and 4 milliseconds. This amount of time is small enough so
- * that no extra thread is needed for incoming Binding Request.
- */
- class StunServerReceiverThread extends Thread {
- private DatagramSocket receiverSocket;
- private DatagramSocket changedPort;
- private DatagramSocket changedIP;
- private DatagramSocket changedPortIP;
-
- StunServerReceiverThread(DatagramSocket datagramSocket) {
- this.receiverSocket = datagramSocket;
- for (DatagramSocket socket : sockets) {
- if ((socket.getLocalPort() != receiverSocket.getLocalPort()) &&
- (socket.getLocalAddress().equals(receiverSocket.getLocalAddress())))
- changedPort = socket;
- if ((socket.getLocalPort() == receiverSocket.getLocalPort()) &&
- (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress())))
- changedIP = socket;
- if ((socket.getLocalPort() != receiverSocket.getLocalPort()) &&
- (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress())))
- changedPortIP = socket;
- }
- }
-
- public void run() {
- while (true) {
- try {
- DatagramPacket receive = new DatagramPacket(new byte[200], 200);
- receiverSocket.receive(receive);
- logger.finest(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " datagram received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort());
- MessageHeader receiveMH = MessageHeader.parseHeader(receive.getData());
- try {
- receiveMH.parseAttributes(receive.getData());
- if (receiveMH.getType() == MessageHeaderType.BindingRequest) {
- logger.config(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " Binding Request received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort());
- ChangeRequest cr = (ChangeRequest) receiveMH.getMessageAttribute(MessageAttributeType.ChangeRequest);
- if (cr == null) throw new MessageAttributeException("Message attribute change request is not set.");
- ResponseAddress ra = (ResponseAddress) receiveMH.getMessageAttribute(MessageAttributeType.ResponseAddress);
-
- MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingResponse);
- sendMH.setTransactionID(receiveMH.getTransactionID());
-
- // Mapped address attribute
- MappedAddress ma = new MappedAddress();
- ma.setAddress(new Address(receive.getAddress().getAddress()));
- ma.setPort(receive.getPort());
- sendMH.addMessageAttribute(ma);
- // Changed address attribute
- ChangedAddress ca = new ChangedAddress();
- ca.setAddress(new Address(changedPortIP.getLocalAddress().getAddress()));
- ca.setPort(changedPortIP.getLocalPort());
- sendMH.addMessageAttribute(ca);
- if (cr.isChangePort() && (!cr.isChangeIP())) {
- logger.finer("Change port received in Change Request attribute");
- // Source address attribute
- SourceAddress sa = new SourceAddress();
- sa.setAddress(new Address(changedPort.getLocalAddress().getAddress()));
- sa.setPort(changedPort.getLocalPort());
- sendMH.addMessageAttribute(sa);
- byte[] data = sendMH.getBytes();
- DatagramPacket send = new DatagramPacket(data, data.length);
- if (ra != null) {
- send.setPort(ra.getPort());
- send.setAddress(ra.getAddress().getInetAddress());
- } else {
- send.setPort(receive.getPort());
- send.setAddress(receive.getAddress());
- }
- changedPort.send(send);
- logger.config(changedPort.getLocalAddress().getHostAddress() + ":" + changedPort.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
- } else if ((!cr.isChangePort()) && cr.isChangeIP()) {
- logger.finer("Change ip received in Change Request attribute");
- // Source address attribute
- SourceAddress sa = new SourceAddress();
- sa.setAddress(new Address(changedIP.getLocalAddress().getAddress()));
- sa.setPort(changedIP.getLocalPort());
- sendMH.addMessageAttribute(sa);
- byte[] data = sendMH.getBytes();
- DatagramPacket send = new DatagramPacket(data, data.length);
- if (ra != null) {
- send.setPort(ra.getPort());
- send.setAddress(ra.getAddress().getInetAddress());
- } else {
- send.setPort(receive.getPort());
- send.setAddress(receive.getAddress());
- }
- changedIP.send(send);
- logger.config(changedIP.getLocalAddress().getHostAddress() + ":" + changedIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
- } else if ((!cr.isChangePort()) && (!cr.isChangeIP())) {
- logger.finer("Nothing received in Change Request attribute");
- // Source address attribute
- SourceAddress sa = new SourceAddress();
- sa.setAddress(new Address(receiverSocket.getLocalAddress().getAddress()));
- sa.setPort(receiverSocket.getLocalPort());
- sendMH.addMessageAttribute(sa);
- byte[] data = sendMH.getBytes();
- DatagramPacket send = new DatagramPacket(data, data.length);
- if (ra != null) {
- send.setPort(ra.getPort());
- send.setAddress(ra.getAddress().getInetAddress());
- } else {
- send.setPort(receive.getPort());
- send.setAddress(receive.getAddress());
- }
- receiverSocket.send(send);
- logger.config(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
- } else if (cr.isChangePort() && cr.isChangeIP()) {
- logger.finer("Change port and ip received in Change Request attribute");
- // Source address attribute
- SourceAddress sa = new SourceAddress();
- sa.setAddress(new Address(changedPortIP.getLocalAddress().getAddress()));
- sa.setPort(changedPortIP.getLocalPort());
- sendMH.addMessageAttribute(sa);
- byte[] data = sendMH.getBytes();
- DatagramPacket send = new DatagramPacket(data, data.length);
- if (ra != null) {
- send.setPort(ra.getPort());
- send.setAddress(ra.getAddress().getInetAddress());
- } else {
- send.setPort(receive.getPort());
- send.setAddress(receive.getAddress());
- }
- changedPortIP.send(send);
- logger.config(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
- }
- }
- } catch (UnknownMessageAttributeException umae) {
- umae.printStackTrace();
- // Generate Binding error response
- MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingErrorResponse);
- sendMH.setTransactionID(receiveMH.getTransactionID());
-
- // Unknown attributes
- UnknownAttribute ua = new UnknownAttribute();
- ua.addAttribute(umae.getType());
- sendMH.addMessageAttribute(ua);
-
- byte[] data = sendMH.getBytes();
- DatagramPacket send = new DatagramPacket(data, data.length);
- send.setPort(receive.getPort());
- send.setAddress(receive.getAddress());
- receiverSocket.send(send);
- logger.config(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Error Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- } catch (MessageAttributeParsingException mape) {
- mape.printStackTrace();
- } catch (MessageAttributeException mae) {
- mae.printStackTrace();
- } catch (MessageHeaderParsingException mhpe) {
- mhpe.printStackTrace();
- } catch (UtilityException ue) {
- ue.printStackTrace();
- } catch (ArrayIndexOutOfBoundsException aioobe) {
- aioobe.printStackTrace();
- }
- }
- }
- }
-
- /*
- * To invoke the STUN server two IP addresses and two ports are required.
- */
- public static void main(String args[]) {
- try {
- if (args.length != 4) {
- System.out.println("usage: java de.javawi.jstun.test.demo.StunServer PORT1 IP1 PORT2 IP2");
- System.out.println();
- System.out.println(" PORT1 - the first port that should be used by the server");
- System.out.println(" IP1 - the first ip address that should be used by the server");
- System.out.println(" PORT2 - the second port that should be used by the server");
- System.out.println(" IP2 - the second ip address that should be used by the server");
- System.exit(0);
- }
- Handler fh = new FileHandler("logging_server.txt");
- fh.setFormatter(new SimpleFormatter());
- Logger.getLogger("de.javawi.stun").addHandler(fh);
- Logger.getLogger("de.javawi.stun").setLevel(Level.ALL);
- StunServer ss = new StunServer(Integer.parseInt(args[0]),
- InetAddress.getByName(args[1]),
- Integer.parseInt(args[2]),
- InetAddress.getByName(args[3]));
- ss.start();
- } catch (SocketException se) {
- se.printStackTrace();
- } catch (UnknownHostException uhe) {
- uhe.printStackTrace();
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- }
|