/** {@inheritDoc} */ @Override protected IceSocketWrapper getCandidateIceSocketWrapper(SocketAddress remoteAddress) { for (IceSocketWrapper socket : sockets) { if (socket.getTCPSocket().getRemoteSocketAddress().equals(remoteAddress)) return socket; } return null; }
@Override protected void free() { StunStack stunStack = getStunStack(); TransportAddress localAddr = getTransportAddress(); for (IceSocketWrapper socket : sockets) { // remove our sockets from the stack. Socket tcpSocket = socket.getTCPSocket(); stunStack.removeSocket( localAddr, new TransportAddress(tcpSocket.getInetAddress(), tcpSocket.getPort(), Transport.TCP)); socket.close(); } super.free(); }
private void runOnDtlsTransport(StreamConnector connector) throws IOException { DtlsControlImpl dtlsControl = (DtlsControlImpl) getTransportManager().getDtlsControl(this); DtlsTransformEngine engine = dtlsControl.getTransformEngine(); final DtlsPacketTransformer transformer = (DtlsPacketTransformer) engine.getRTPTransformer(); byte[] receiveBuffer = new byte[SCTP_BUFFER_SIZE]; if (LOG_SCTP_PACKETS) { System.setProperty( ConfigurationService.PNAME_SC_HOME_DIR_LOCATION, System.getProperty("java.io.tmpdir")); System.setProperty( ConfigurationService.PNAME_SC_HOME_DIR_NAME, SctpConnection.class.getName()); } synchronized (this) { // FIXME local SCTP port is hardcoded in bridge offer SDP (Jitsi // Meet) sctpSocket = Sctp.createSocket(5000); assocIsUp = false; acceptedIncomingConnection = false; } // Implement output network link for SCTP stack on DTLS transport sctpSocket.setLink( new NetworkLink() { @Override public void onConnOut(SctpSocket s, byte[] packet) throws IOException { if (LOG_SCTP_PACKETS) { LibJitsi.getPacketLoggingService() .logPacket( PacketLoggingService.ProtocolName.ICE4J, new byte[] {0, 0, 0, (byte) debugId}, 5000, new byte[] {0, 0, 0, (byte) (debugId + 1)}, remoteSctpPort, PacketLoggingService.TransportName.UDP, true, packet); } // Send through DTLS transport transformer.sendApplicationData(packet, 0, packet.length); } }); if (logger.isDebugEnabled()) { logger.debug("Connecting SCTP to port: " + remoteSctpPort + " to " + getEndpoint().getID()); } sctpSocket.setNotificationListener(this); sctpSocket.listen(); // FIXME manage threads threadPool.execute( new Runnable() { @Override public void run() { SctpSocket sctpSocket = null; try { // sctpSocket is set to null on close sctpSocket = SctpConnection.this.sctpSocket; while (sctpSocket != null) { if (sctpSocket.accept()) { acceptedIncomingConnection = true; break; } Thread.sleep(100); sctpSocket = SctpConnection.this.sctpSocket; } if (isReady()) { notifySctpConnectionReady(); } } catch (Exception e) { logger.error("Error accepting SCTP connection", e); } if (sctpSocket == null && logger.isInfoEnabled()) { logger.info( "SctpConnection " + getID() + " closed" + " before SctpSocket accept()-ed."); } } }); // Notify that from now on SCTP connection is considered functional sctpSocket.setDataCallback(this); // Setup iceSocket DatagramSocket datagramSocket = connector.getDataSocket(); if (datagramSocket != null) { this.iceSocket = new IceUdpSocketWrapper(datagramSocket); } else { this.iceSocket = new IceTcpSocketWrapper(connector.getDataTCPSocket()); } DatagramPacket rcvPacket = new DatagramPacket(receiveBuffer, 0, receiveBuffer.length); // Receive loop, breaks when SCTP socket is closed try { do { iceSocket.receive(rcvPacket); RawPacket raw = new RawPacket(rcvPacket.getData(), rcvPacket.getOffset(), rcvPacket.getLength()); raw = transformer.reverseTransform(raw); // Check for app data if (raw == null) continue; if (LOG_SCTP_PACKETS) { LibJitsi.getPacketLoggingService() .logPacket( PacketLoggingService.ProtocolName.ICE4J, new byte[] {0, 0, 0, (byte) (debugId + 1)}, remoteSctpPort, new byte[] {0, 0, 0, (byte) debugId}, 5000, PacketLoggingService.TransportName.UDP, false, raw.getBuffer(), raw.getOffset(), raw.getLength()); } // Pass network packet to SCTP stack sctpSocket.onConnIn(raw.getBuffer(), raw.getOffset(), raw.getLength()); } while (true); } finally { // Eventually, close the socket although it should happen from // expire(). synchronized (this) { assocIsUp = false; acceptedIncomingConnection = false; if (sctpSocket != null) { sctpSocket.close(); sctpSocket = null; } } } }
/** * Gathers UPnP candidates for all host <tt>Candidate</tt>s that are already present in the * specified <tt>component</tt>. This method relies on the specified <tt>component</tt> to already * contain all its host candidates so that it would resolve them. * * @param component the {@link Component} that we'd like to gather candidate UPnP * <tt>Candidate</tt>s for * @return the <tt>LocalCandidate</tt>s gathered by this <tt>CandidateHarvester</tt> */ public synchronized Collection<LocalCandidate> harvest(Component component) { Collection<LocalCandidate> candidates = new HashSet<>(); int retries = 0; logger.fine("Begin UPnP harvesting"); try { if (device == null) { // do it only once if (finishThreads == 0) { try { UPNPThread wanIPThread = new UPNPThread(stIP); UPNPThread wanPPPThread = new UPNPThread(stPPP); wanIPThread.start(); wanPPPThread.start(); synchronized (rootSync) { while (finishThreads != 2) { rootSync.wait(); } } if (wanIPThread.getDevice() != null) { device = wanIPThread.getDevice(); } else if (wanPPPThread.getDevice() != null) { device = wanPPPThread.getDevice(); } } catch (Throwable e) { logger.info("UPnP discovery failed: " + e); } } if (device == null) return candidates; } InetAddress localAddress = device.getLocalAddress(); String externalIPAddress = device.getExternalIPAddress(); PortMappingEntry portMapping = new PortMappingEntry(); IceSocketWrapper socket = new IceUdpSocketWrapper(new MultiplexingDatagramSocket(0, localAddress)); int port = socket.getLocalPort(); int externalPort = socket.getLocalPort(); while (retries < MAX_RETRIES) { if (!device.getSpecificPortMappingEntry(port, "UDP", portMapping)) { if (device.addPortMapping( externalPort, port, localAddress.getHostAddress(), "UDP", "ice4j.org: " + port)) { List<LocalCandidate> cands = createUPNPCandidate(socket, externalIPAddress, externalPort, component, device); logger.info("Add UPnP port mapping: " + externalIPAddress + " " + externalPort); // we have to add the UPNPCandidate and also the base. // if we don't add the base, we won't be able to add // peer reflexive candidate if someone contact us on the // UPNPCandidate for (LocalCandidate cand : cands) { // try to add the candidate to the component and then // only add it to the harvest not redundant if (component.addLocalCandidate(cand)) { candidates.add(cand); } } break; } else { port++; } } else { port++; } retries++; } } catch (Throwable e) { logger.info("Exception while gathering UPnP candidates: " + e); } return candidates; }