diff --git a/p2pproxy/launcher/.cproject b/p2pproxy/launcher/.cproject index 8863ad35f..a6611c769 100644 --- a/p2pproxy/launcher/.cproject +++ b/p2pproxy/launcher/.cproject @@ -121,6 +121,7 @@ + @@ -506,6 +507,7 @@ + diff --git a/p2pproxy/launcher/Debug/makefile b/p2pproxy/launcher/Debug/makefile index 9685c7609..9559e2f52 100644 --- a/p2pproxy/launcher/Debug/makefile +++ b/p2pproxy/launcher/Debug/makefile @@ -29,7 +29,7 @@ all: p2pproxy-launcher p2pproxy-launcher: $(OBJS) $(USER_OBJS) @echo 'Building target: $@' @echo 'Invoking: GCC C Linker' - gcc -L/usr/lib/jvm/java-6-openjdk/jre/lib/amd64 -L/usr/lib/jvm/java-6-openjdk/jre/lib/i386 -L/usr/lib/jvm/java-6-openjdk/jre/lib/amd64/server -L/usr/lib/jvm/java-6-openjdk/jre/lib/i386/server -o"p2pproxy-launcher" $(OBJS) $(USER_OBJS) $(LIBS) + gcc -L/usr/lib/jvm/java-6-openjdk/jre/lib/amd64 -L/usr/lib/jvm/java-6-openjdk/jre/lib/amd64/server -o"p2pproxy-launcher" $(OBJS) $(USER_OBJS) $(LIBS) @echo 'Finished building target: $@' @echo ' ' diff --git a/p2pproxy/launcher/src/launcher-tester.c b/p2pproxy/launcher/src/launcher-tester.c index 2f92ecddb..2d907c0eb 100644 --- a/p2pproxy/launcher/src/launcher-tester.c +++ b/p2pproxy/launcher/src/launcher-tester.c @@ -32,15 +32,27 @@ int main(int argc, char **argv) { } char string_buffer[256]; - if (p2pproxy_resourcelocation_get_sip_proxyregistrar_uri(string_buffer,256) != P2PPROXY_NO_ERROR) { + if (p2pproxy_resourcemgt_lookup_sip_proxy(string_buffer,256,"p2p.linphone.org") != P2PPROXY_NO_ERROR) { printf("cannot get proxy\n"); } else { printf("registrar is [%s]\n",string_buffer); } + + if (p2pproxy_resourcemgt_revoke_sip_proxy(string_buffer) != P2PPROXY_NO_ERROR) { + printf("cannot fulsh proxy [%s]\n",string_buffer); + } + + if (p2pproxy_resourcemgt_lookup_sip_proxy(string_buffer,256,"toto.linphone.org") != P2PPROXY_RESOURCEMGT_SERVER_NOT_FOUND) { + printf("unexpected proxy [%s]\n",string_buffer); + } else { + printf("unknown domaine\n"); + } + if (p2pproxy_accountmgt_deleteAccount("sip:titi@p2p.linphone.org") != P2PPROXY_NO_ERROR) { printf("cannot delete account \n"); } + p2pproxy_application_stop(); pthread_join(th,NULL); return 0; diff --git a/p2pproxy/launcher/src/p2pproxy.c b/p2pproxy/launcher/src/p2pproxy.c index da4dd5e75..cae324cb3 100644 --- a/p2pproxy/launcher/src/p2pproxy.c +++ b/p2pproxy/launcher/src/p2pproxy.c @@ -1,5 +1,6 @@ #include #include +#include #include "p2pproxy.h" #ifndef P2PPROXY_JMX_PORT @@ -138,25 +139,43 @@ int p2pproxy_accountmgt_deleteAccount(const char* user_name) { return lResult; } -int p2pproxy_resourcelocation_get_sip_proxyregistrar_uri(char* aStringArray, size_t aSize) { - jmethodID getSipProxyRegistrarUriMethod; +int p2pproxy_resourcemgt_lookup_sip_proxy(char* proxy_uri,size_t size, char* domaine) { + jmethodID lLookupSipProxyUriMethod; jstring lJStringResult; const jbyte* lString; jboolean lIsCopy; - GET_JNI_ENV + jstring applicationArg; - getSipProxyRegistrarUriMethod = (*lJniEnv)->GetStaticMethodID(lJniEnv, lMainClass, "getSipProxyRegistrarUri", "()Ljava/lang/String;"); - lJStringResult = (*lJniEnv)->CallStaticObjectMethod(lJniEnv, lMainClass, getSipProxyRegistrarUriMethod); + GET_JNI_ENV + + + applicationArg = (*lJniEnv)->NewStringUTF(lJniEnv, domaine); + lLookupSipProxyUriMethod = (*lJniEnv)->GetStaticMethodID(lJniEnv, lMainClass, "lookupSipProxyUri", "(Ljava/lang/String;)Ljava/lang/String;"); + lJStringResult = (*lJniEnv)->CallStaticObjectMethod(lJniEnv, lMainClass, lLookupSipProxyUriMethod, applicationArg); if (lJStringResult == 0) { - return P2PPROXY_ERROR_RESOURCELOCATOR_SERVER_NOT_FOUND; + return P2PPROXY_RESOURCEMGT_SERVER_NOT_FOUND; } lString = (*lJniEnv)->GetStringUTFChars(lJniEnv, lJStringResult, &lIsCopy); - memcpy(aStringArray,lString,aSize); + memcpy(proxy_uri,lString,size); (*lJniEnv)->ReleaseStringUTFChars(lJniEnv, lJStringResult, lString); (*p2pproxy_application_jvm)->DetachCurrentThread(p2pproxy_application_jvm); return P2PPROXY_NO_ERROR; } +int p2pproxy_resourcemgt_revoke_sip_proxy(char* proxy_uri) { + jmethodID revokeProxyMethod; + jstring lJStringResult; + const jbyte* lString; + jboolean lIsCopy; + GET_JNI_ENV + + revokeProxyMethod = (*lJniEnv)->GetStaticMethodID(lJniEnv, lMainClass, "revokeSipProxy", "(Ljava/lang/String;)V"); + (*lJniEnv)->CallStaticVoidMethod(lJniEnv, lMainClass, revokeProxyMethod); + if (lJStringResult == 0) { + return P2PPROXY_ERROR; + } + return P2PPROXY_NO_ERROR; +} int p2pproxy_application_get_state() { jmethodID stateMethod; GET_JNI_ENV diff --git a/p2pproxy/launcher/src/p2pproxy.h b/p2pproxy/launcher/src/p2pproxy.h index 08f6a4999..4ebb90596 100644 --- a/p2pproxy/launcher/src/p2pproxy.h +++ b/p2pproxy/launcher/src/p2pproxy.h @@ -29,7 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define P2PPROXY_ACCOUNTMGT_USER_EXIST 1 #define P2PPROXY_ACCOUNTMGT_USER_NOT_EXIST 0 - +#define P2PPROXY_RESOURCEMGT_SERVER_NOT_FOUND 3 /* state code*/ #define P2PPROXY_CONNECTED 2 #define P2PPROXY_NOT_CONNECTED 1 @@ -41,7 +41,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define P2PPROXY_ERROR_APPLICATION_ALREADY_STARTED -3 #define P2PPROXY_ERROR_ACCOUNTMGT_USER_ALREADY_EXIST -4 #define P2PPROXY_ERROR_ACCOUNTMGT_BAD_SIP_URI -5 -#define P2PPROXY_ERROR_RESOURCELOCATOR_SERVER_NOT_FOUND -6 +#define P2PPROXY_ERROR_RESOURCEMGT_SERVER_NOT_FOUND -6 #ifndef SWIG /** @@ -97,16 +97,24 @@ int p2pproxy_accountmgt_isValidAccount(const char* user_name); */ int p2pproxy_accountmgt_deleteAccount(const char* user_name); -/***************************/ -/***resource location******/ -/***************************/ +/****************************/ +/***resource management******/ +/****************************/ /** -* access a proxy registrar sip addreess -* @param buffer allocated by the user -* @param size buffer size +* access a proxy registrar sip addreess for a given domaine name +* @param [out] proxy_uri buffer allocated by the user +* @param [in] size buffer size +* @param [in] domaine name * @return status code P2PPROXY_NO_ERROR, P2PPROXY_ERROR_RESOURCELOCATOR_SERVER_NOT_FOUND */ -int p2pproxy_resourcelocation_get_sip_proxyregistrar_uri(char* string_buffer,size_t size) ; +int p2pproxy_resourcemgt_lookup_sip_proxy(char* proxy_uri,size_t size, char* domaine) ; +/* + * notify the library at a given proxy is no longuer reachable +* @param [in] proxy sip uri +* @return status code P2PPROXY_NO_ERROR +*/ +int p2pproxy_resourcemgt_revoke_sip_proxy(char* proxy_uri); + #endif /*SWIG*/ diff --git a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxySipProxyRegistrarManagement.java b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxySipProxyRegistrarManagement.java index 35e7d4d39..3de678773 100644 --- a/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxySipProxyRegistrarManagement.java +++ b/p2pproxy/src/org/linphone/p2pproxy/api/P2pProxySipProxyRegistrarManagement.java @@ -19,12 +19,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.linphone.p2pproxy.api; -import java.net.InetSocketAddress; + public interface P2pProxySipProxyRegistrarManagement { /** * - * @return the SIP uri of an available sip proxy registrar + * @return the SIP uri of an available sip proxy registrar for a given domaine */ - public String getSipProxyRegistrarUri() throws P2pProxyException ; + public String lookupSipProxyUri(String aDomaine) throws P2pProxyException ; + + public void revokeSipProxy(String aProxy) throws P2pProxyException; + } diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/JxtaNetworkManager.java b/p2pproxy/src/org/linphone/p2pproxy/core/JxtaNetworkManager.java index 5210ba68c..2ab78ad39 100644 --- a/p2pproxy/src/org/linphone/p2pproxy/core/JxtaNetworkManager.java +++ b/p2pproxy/src/org/linphone/p2pproxy/core/JxtaNetworkManager.java @@ -136,7 +136,8 @@ public class JxtaNetworkManager { } else { lNetworkConfigurator.load(); } - + //mode is alway taken from start line + lNetworkConfigurator.setMode(lMode); // set sedding host if (aProperties.getProperty(SEEDING_RDV) != null) { StringTokenizer lSeedingRdvList = new StringTokenizer(aProperties.getProperty(SEEDING_RDV),"|" ); diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMain.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMain.java index f1bca231c..906035a04 100644 --- a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMain.java +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxyMain.java @@ -386,11 +386,10 @@ private static void isReady() throws P2pProxyNotReadyException { try { if ((mJxtaNetworkManager!=null && mJxtaNetworkManager.isConnectedToRendezVous(0) == true) || - (mJxtaNetworkManager!=null && mJxtaNetworkManager.getPeerGroup().getRendezVousService().isRendezVous())) - { + (mJxtaNetworkManager!=null && mJxtaNetworkManager.getPeerGroup().getRendezVousService().isRendezVous())) { //nop connected } else { - throw new P2pProxyNotReadyException("not connected to any rdv"); + throw new P2pProxyNotReadyException("not connected to any rdv: status ["+mJxtaNetworkManager.getPeerGroup().getRendezVousService().getRendezVousStatus()+"]"); } } catch (InterruptedException e) { throw new P2pProxyNotReadyException(e); @@ -431,10 +430,10 @@ public static int isValidAccount(String aUserName){ return P2pProxylauncherConstants.P2PPROXY_ERROR; } } -public static String getSipProxyRegistrarUri() { +public static String lookupSipProxyUri(String aDomaine) { try { isReady(); - return mP2pProxySipProxyRegistrarManagement.getSipProxyRegistrarUri(); + return mP2pProxySipProxyRegistrarManagement.lookupSipProxyUri(aDomaine); } catch (Exception e) { return null; } @@ -444,9 +443,20 @@ public static int getState() { isReady(); return P2pProxylauncherConstants.P2PPROXY_CONNECTED; } catch (P2pProxyException e) { + mLog.error("cannot get state",e); return P2pProxylauncherConstants.P2PPROXY_NOT_CONNECTED; } } +public static int revokeSipProxy(String aProxy) { + try { + isReady(); + mLog.error("not implemented"); + return P2pProxylauncherConstants.P2PPROXY_ERROR; + } catch (P2pProxyException e) { + return P2pProxylauncherConstants.P2PPROXY_NOT_CONNECTED; + } +} + public static void stop() { mExit = true; diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxySipProxyRegistrarManagementImpl.java b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxySipProxyRegistrarManagementImpl.java index b1a15a3ad..5ef52d245 100644 --- a/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxySipProxyRegistrarManagementImpl.java +++ b/p2pproxy/src/org/linphone/p2pproxy/core/P2pProxySipProxyRegistrarManagementImpl.java @@ -1,22 +1,38 @@ package org.linphone.p2pproxy.core; +import org.apache.log4j.Logger; import org.linphone.p2pproxy.api.P2pProxyException; import org.linphone.p2pproxy.api.P2pProxySipProxyRegistrarManagement; import org.linphone.p2pproxy.core.sipproxy.SipProxyRegistrarAdvertisement; public class P2pProxySipProxyRegistrarManagementImpl implements P2pProxySipProxyRegistrarManagement { - protected final JxtaNetworkManager mJxtaNetworkManager; - P2pProxySipProxyRegistrarManagementImpl(JxtaNetworkManager aJxtaNetworkManager) { - mJxtaNetworkManager = aJxtaNetworkManager; - } - public String getSipProxyRegistrarUri() throws P2pProxyException { - try { - SipProxyRegistrarAdvertisement lSipProxyRegistrarAdvertisement = (SipProxyRegistrarAdvertisement) (mJxtaNetworkManager.getAdvertisement(null, SipProxyRegistrarAdvertisement.NAME, true)); - return lSipProxyRegistrarAdvertisement.getAddress(); - }catch (Exception e) { - throw new P2pProxyException(e); - } + protected final JxtaNetworkManager mJxtaNetworkManager; + private final String DOMAINE="p2p.linphone.org"; + private final static Logger mLog = Logger.getLogger(P2pProxySipProxyRegistrarManagementImpl.class); + P2pProxySipProxyRegistrarManagementImpl(JxtaNetworkManager aJxtaNetworkManager) { + mJxtaNetworkManager = aJxtaNetworkManager; + } + public String lookupSipProxyUri(String aDomaine) throws P2pProxyException { + try { + if (!DOMAINE.equals(aDomaine)) { + //unknown domaine + return null; + } + SipProxyRegistrarAdvertisement lSipProxyRegistrarAdvertisement = (SipProxyRegistrarAdvertisement) (mJxtaNetworkManager.getAdvertisement(null, SipProxyRegistrarAdvertisement.NAME, true)); + return lSipProxyRegistrarAdvertisement.getAddress(); + }catch (Exception e) { + throw new P2pProxyException(e); + } - } + } + public void revokeSipProxy(String aProxy) throws P2pProxyException { + try { + SipProxyRegistrarAdvertisement lSipProxyRegistrarAdvertisement = (SipProxyRegistrarAdvertisement) (mJxtaNetworkManager.getAdvertisement(null, SipProxyRegistrarAdvertisement.ADDRESS_TAG, true)); + mJxtaNetworkManager.getPeerGroup().getDiscoveryService().flushAdvertisement(lSipProxyRegistrarAdvertisement); + mLog.info(aProxy +"revoked"); + } catch (Exception e) { + throw new P2pProxyException(e); + } + } } diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/stun/StunServer.java b/p2pproxy/src/org/linphone/p2pproxy/core/stun/StunServer.java new file mode 100644 index 000000000..ccbfaabc6 --- /dev/null +++ b/p2pproxy/src/org/linphone/p2pproxy/core/stun/StunServer.java @@ -0,0 +1,184 @@ +/* + * This file is part of JSTUN. + * + * Copyright (c) 2005 Thomas King - 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 org.linphone.p2pproxy.core.stun; + +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("org.linphone.p2pproxy.core.stun.StunServer"); + Vector sockets; + + public StunServer(int primaryPort, InetAddress primary, int secondaryPort) throws SocketException { + sockets = new Vector(); + sockets.add(new DatagramSocket(primaryPort, primary)); + sockets.add(new DatagramSocket(secondaryPort, primary)); + } + + 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; + + StunServerReceiverThread(DatagramSocket datagramSocket) { + this.receiverSocket = datagramSocket; + for (DatagramSocket socket : sockets) { + if ((socket.getLocalPort() != receiverSocket.getLocalPort()) && + (socket.getLocalAddress().equals(receiverSocket.getLocalAddress()))) + changedPort = 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); + if (cr.isChangePort()) { + 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("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 { + logger.warning("cannot handle cr ["+cr+"]"); + } + } + } 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(" 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(); + } + } + } + } + + +} \ No newline at end of file diff --git a/p2pproxy/src/org/linphone/p2pproxy/core/turnserver/TurnServer.java b/p2pproxy/src/org/linphone/p2pproxy/core/turnserver/TurnServer.java deleted file mode 100644 index 1931afec9..000000000 --- a/p2pproxy/src/org/linphone/p2pproxy/core/turnserver/TurnServer.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * This file is part of JSTUN. - * - * Copyright (c) 2005 Thomas King - 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 org.linphone.p2pproxy.core.turnserver; - -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 org.apache.log4j.BasicConfigurator; -import org.apache.log4j.Logger; - - -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. - * This implementation uses a single ip/port. This lead to limited functionnality. - */ -public class TurnServer { - private static Logger logger = Logger.getLogger(TurnServer.class); - Vector sockets; - - public TurnServer(int primaryPort, InetAddress primary) throws SocketException { - sockets = new Vector(); - sockets.add(new DatagramSocket(primaryPort, primary)); - } - - public TurnServer(int primaryPort, InetAddress primary, int secondaryPort, InetAddress secondary) throws SocketException { - sockets = new Vector(); - 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.debug(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " datagram received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort()); - MessageHeader receiveMH = MessageHeader.parseHeader(receive.getData()); - try { - receiveMH.parseAttributes(receive.getData()); - logger.info(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " Request received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort()); - - if (receiveMH.getType() == MessageHeaderType.BindingRequest) { - logger.info("Binding Request received "); - 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.info("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.info(changedPort.getLocalAddress().getHostAddress() + ":" + changedPort.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); - } else if ((!cr.isChangePort()) && cr.isChangeIP()) { - logger.info("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.info(changedIP.getLocalAddress().getHostAddress() + ":" + changedIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); - } else if ((!cr.isChangePort()) && (!cr.isChangeIP())) { - logger.info("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.info(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); - } else if (cr.isChangePort() && cr.isChangeIP()) { - logger.info("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.info(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort()); - } - } else if (receiveMH.getType() == MessageHeaderType.AllocateRequest) { - logger.info("Allocate Request received "); - MessageHeader sendMH = new MessageHeader(MessageHeaderType.AllocateResponse); - sendMH.setTransactionID(receiveMH.getTransactionID()); - - - byte[] data = sendMH.getBytes(); - DatagramPacket send = new DatagramPacket(data, data.length); - send.setPort(receive.getPort()); - send.setAddress(receive.getAddress()); - receiverSocket.send(send); - logger.info( "Send Allocate 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.info(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); - } - BasicConfigurator.configure(); - TurnServer ss = new TurnServer(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(); - } - } -} \ No newline at end of file diff --git a/p2pproxy/test-src/org/linphone/p2pproxy/test/TurnServerTester.java b/p2pproxy/test-src/org/linphone/p2pproxy/test/StunServerTester.java similarity index 98% rename from p2pproxy/test-src/org/linphone/p2pproxy/test/TurnServerTester.java rename to p2pproxy/test-src/org/linphone/p2pproxy/test/StunServerTester.java index d69bc7ae0..cdad2983c 100644 --- a/p2pproxy/test-src/org/linphone/p2pproxy/test/TurnServerTester.java +++ b/p2pproxy/test-src/org/linphone/p2pproxy/test/StunServerTester.java @@ -25,7 +25,8 @@ import junit.framework.TestCase; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; -import org.linphone.p2pproxy.core.turnserver.TurnServer; +import org.linphone.p2pproxy.core.stun.StunServer; + import de.javawi.jstun.attribute.ChangeRequest; @@ -40,8 +41,8 @@ import de.javawi.jstun.header.MessageHeaderParsingException; import de.javawi.jstun.test.DiscoveryInfo; import de.javawi.jstun.util.UtilityException; -public class TurnServerTester extends TestCase { - private static Logger logger = Logger.getLogger(TurnServerTester.class); +public class StunServerTester extends TestCase { + private static Logger logger = Logger.getLogger(StunServerTester.class); InetAddress iaddress ; String stunServer = "localhost"; int port = 16000; @@ -51,14 +52,14 @@ public class TurnServerTester extends TestCase { boolean nodeNatted = true; DatagramSocket socketTest1 = null; DiscoveryInfo di = null; - static TurnServer mSturServer = null; + static StunServer mSturServer = null; public void setUp() throws Exception { if (mSturServer == null) { BasicConfigurator.configure(); - if (mSturServer == null) mSturServer = new TurnServer(port,InetAddress.getByName("localhost")); + if (mSturServer == null) mSturServer = new StunServer(port,InetAddress.getByName("localhost"),port+1); mSturServer.start(); iaddress = InetAddress.getLocalHost(); }