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; } } } }
/** Starts this <tt>PacketTransformer</tt>. */ private synchronized void start() { if (this.datagramTransport != null) { if (this.connectThread == null && dtlsTransport == null) { logger.warn( getClass().getName() + " has been started but has failed to establish" + " the DTLS connection!"); } return; } if (rtcpmux && Component.RTCP == componentID) { // In the case of rtcp-mux, the RTCP transformer does not create // a DTLS session. The SRTP context (_srtpTransformer) will be // initialized on demand using initializeSRTCPTransformerFromRtp(). return; } AbstractRTPConnector connector = this.connector; if (connector == null) throw new NullPointerException("connector"); DtlsControl.Setup setup = this.setup; SecureRandom secureRandom = DtlsControlImpl.createSecureRandom(); final DTLSProtocol dtlsProtocolObj; final TlsPeer tlsPeer; if (DtlsControl.Setup.ACTIVE.equals(setup)) { dtlsProtocolObj = new DTLSClientProtocol(secureRandom); tlsPeer = new TlsClientImpl(this); } else { dtlsProtocolObj = new DTLSServerProtocol(secureRandom); tlsPeer = new TlsServerImpl(this); } tlsPeerHasRaisedCloseNotifyWarning = false; final DatagramTransportImpl datagramTransport = new DatagramTransportImpl(componentID); datagramTransport.setConnector(connector); Thread connectThread = new Thread() { @Override public void run() { try { runInConnectThread(dtlsProtocolObj, tlsPeer, datagramTransport); } finally { if (Thread.currentThread().equals(DtlsPacketTransformer.this.connectThread)) { DtlsPacketTransformer.this.connectThread = null; } } } }; connectThread.setDaemon(true); connectThread.setName(DtlsPacketTransformer.class.getName() + ".connectThread"); this.connectThread = connectThread; this.datagramTransport = datagramTransport; boolean started = false; try { connectThread.start(); started = true; } finally { if (!started) { if (connectThread.equals(this.connectThread)) this.connectThread = null; if (datagramTransport.equals(this.datagramTransport)) this.datagramTransport = null; } } notifyAll(); }