2 p2pproxy Copyright (C) 2007 Jehan Monnier ()
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package org.linphone.p2pproxy.core.stun;
23 import java.net.DatagramPacket;
24 import java.net.DatagramSocket;
25 import java.net.SocketException;
26 import org.apache.log4j.Logger;
27 import org.linphone.p2pproxy.api.P2pProxyException;
28 import org.linphone.p2pproxy.core.GenericUdpSession;
29 import org.linphone.p2pproxy.core.ServiceProvider;
31 import de.javawi.jstun.attribute.ChangeRequest;
32 import de.javawi.jstun.attribute.ErrorCode;
33 import de.javawi.jstun.attribute.MappedAddress;
34 import de.javawi.jstun.attribute.MessageAttributeException;
35 import de.javawi.jstun.attribute.ResponseAddress;
36 import de.javawi.jstun.attribute.SourceAddress;
37 import de.javawi.jstun.attribute.UnknownAttribute;
38 import de.javawi.jstun.attribute.UnknownMessageAttributeException;
39 import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType;
40 import de.javawi.jstun.header.MessageHeader;
41 import de.javawi.jstun.header.MessageHeaderParsingException;
42 import de.javawi.jstun.header.MessageHeaderInterface.MessageHeaderType;
43 import de.javawi.jstun.util.Address;
47 * This class implements a STUN server as described in RFC 3489.
48 * neither change port nor change address are implemented
50 public class StunServer implements GenericUdpSession.MessageHandler {
51 private static Logger mLog = Logger.getLogger(StunServer.class);
52 private final DatagramSocket mSocket;
54 public StunServer(DatagramSocket mListeningSocket) throws SocketException {
55 mSocket = mListeningSocket;
58 public void onMessage(DatagramPacket lMessage) {
59 // derivated from JSTUN (Thomas King)
60 MessageHeader receiveMH = null;
62 receiveMH = MessageHeader.parseHeader(lMessage.getData());
63 } catch (MessageHeaderParsingException e1) {
64 if (mLog.isInfoEnabled()) mLog.info("not a stun message");
69 receiveMH.parseAttributes(lMessage.getData());
70 if (receiveMH.getType() == MessageHeaderType.BindingRequest) {
71 ChangeRequest cr = (ChangeRequest) receiveMH.getMessageAttribute(MessageAttributeType.ChangeRequest);
72 if (cr == null) throw new MessageAttributeException("Message attribute change request is not set.");
73 ResponseAddress ra = (ResponseAddress) receiveMH.getMessageAttribute(MessageAttributeType.ResponseAddress);
75 MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingResponse);
76 sendMH.setTransactionID(receiveMH.getTransactionID());
78 // Mapped address attribute
79 MappedAddress ma = new MappedAddress();
80 ma.setAddress(new Address(lMessage.getAddress().getAddress()));
81 ma.setPort(lMessage.getPort());
82 sendMH.addMessageAttribute(ma);
83 if ((!cr.isChangePort()) && (!cr.isChangeIP())) {
84 if (mLog.isInfoEnabled()) mLog.info("Nothing received in Change Request attribute");
85 // Source address attribute
86 SourceAddress sa = new SourceAddress();
87 sa.setAddress(new Address(mSocket.getLocalAddress().getAddress()));
88 sa.setPort(mSocket.getLocalPort());
89 sendMH.addMessageAttribute(sa);
90 byte[] data = sendMH.getBytes();
91 DatagramPacket send = new DatagramPacket(data, data.length);
93 send.setPort(ra.getPort());
94 send.setAddress(ra.getAddress().getInetAddress());
96 send.setPort(lMessage.getPort());
97 send.setAddress(lMessage.getAddress());
100 if (mLog.isInfoEnabled()) mLog.info(mSocket.getLocalAddress().getHostAddress() + ":" + mSocket.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
102 // Generate Binding error response
103 sendMH = new MessageHeader(MessageHeaderType.BindingErrorResponse);
104 sendMH.setTransactionID(receiveMH.getTransactionID());
105 ErrorCode lErrorCode = new ErrorCode();
106 lErrorCode.setResponseCode(400); //bad request
107 sendMH.addMessageAttribute(lErrorCode);
108 byte[] data = sendMH.getBytes();
109 DatagramPacket send = new DatagramPacket(data, data.length);
110 send.setPort(lMessage.getPort());
111 send.setAddress(lMessage.getAddress());
113 if (mLog.isInfoEnabled()) mLog.info("cannot handle cr ["+cr+"] attibute");
116 } catch ( Exception e) {
119 // Generate Binding error response
121 MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingErrorResponse);
122 sendMH.setTransactionID(receiveMH.getTransactionID());
124 if (e instanceof UnknownMessageAttributeException) {
125 // Unknown attributes
126 UnknownAttribute ua = new UnknownAttribute();
127 ua.addAttribute(((UnknownMessageAttributeException) e).getType());
128 sendMH.addMessageAttribute(ua);
130 ErrorCode lErrorCode = new ErrorCode();
131 lErrorCode.setResponseCode(500);
132 sendMH.addMessageAttribute(lErrorCode);
134 byte[] data = sendMH.getBytes();
135 DatagramPacket send = new DatagramPacket(data, data.length);
136 send.setPort(lMessage.getPort());
137 send.setAddress(lMessage.getAddress());
139 mLog.error(" send Binding Error Response to " + send.getAddress().getHostAddress() + ":" + send.getPort(),e);
140 } catch(Exception e1) {
141 mLog.error("cannot handle error", e1);