Пример #1
0
  /** {@inheritDoc} */
  @Override
  protected IceSocketWrapper getCandidateIceSocketWrapper(SocketAddress remoteAddress) {
    for (IceSocketWrapper socket : sockets) {
      if (socket.getTCPSocket().getRemoteSocketAddress().equals(remoteAddress)) return socket;
    }

    return null;
  }
Пример #2
0
  @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();
  }
Пример #3
0
  /**
   * Creates a network access point.
   *
   * @param socket the socket that this access point is supposed to use for communication.
   * @param messageQueue the FIFO list where incoming messages should be queued
   * @param errorHandler the instance to notify when errors occur.
   */
  protected Connector(
      IceSocketWrapper socket, MessageQueue messageQueue, ErrorHandler errorHandler) {
    this.sock = socket;
    this.messageQueue = messageQueue;
    this.errorHandler = errorHandler;

    Transport transport = socket.getUDPSocket() != null ? Transport.UDP : Transport.TCP;

    listenAddress =
        new TransportAddress(socket.getLocalAddress(), socket.getLocalPort(), transport);
    if (transport == Transport.UDP) {
      remoteAddress = null;
    } else {
      Socket tcpSocket = socket.getTCPSocket();

      remoteAddress =
          new TransportAddress(tcpSocket.getInetAddress(), tcpSocket.getPort(), transport);
    }
  }
Пример #4
0
  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;
        }
      }
    }
  }
Пример #5
0
  /**
   * 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;
  }
Пример #6
0
  /** The listening thread's run method. */
  @Override
  public void run() {
    DatagramPacket packet = null;

    while (this.running) {
      try {
        IceSocketWrapper localSock;

        synchronized (sockLock) {
          if (!running) return;

          localSock = this.sock;
        }

        /*
         * Make sure localSock's receiveBufferSize is taken into
         * account including after it gets changed.
         */
        int receiveBufferSize = 1500;
        /*
        if(localSock.getTCPSocket() != null)
        {
            receiveBufferSize = localSock.getTCPSocket().
                getReceiveBufferSize();
        }
        else if(localSock.getUDPSocket() != null)
        {
            receiveBufferSize = localSock.getUDPSocket().
                getReceiveBufferSize();
        }
        */

        if (packet == null) {
          packet = new DatagramPacket(new byte[receiveBufferSize], receiveBufferSize);
        } else {
          byte[] packetData = packet.getData();

          if ((packetData == null) || (packetData.length < receiveBufferSize)) {
            packet.setData(new byte[receiveBufferSize], 0, receiveBufferSize);
          } else {
            /*
             * XXX Tell the packet it is large enough because the
             * socket will not look at the length of the data array
             * property and will just respect the length property.
             */
            packet.setLength(receiveBufferSize);
          }
        }

        localSock.receive(packet);

        // get lost if we are no longer running.
        if (!running) return;

        logger.finest("received datagram");

        RawMessage rawMessage =
            new RawMessage(
                packet.getData(),
                packet.getLength(),
                new TransportAddress(
                    packet.getAddress(), packet.getPort(), listenAddress.getTransport()),
                listenAddress);

        messageQueue.add(rawMessage);
      } catch (SocketException ex) {
        if (running) {
          logger.log(
              Level.WARNING, "Connector died: " + listenAddress + " -> " + remoteAddress, ex);

          stop();
          // Something wrong has happened
          errorHandler.handleFatalError(
              this, "A socket exception was thrown" + " while trying to receive a message.", ex);
        } else {
          // The exception was most probably caused by calling
          // this.stop().
        }
      } catch (ClosedChannelException cce) {
        logger.log(Level.WARNING, "A net access point has gone useless:", cce);

        stop();
        errorHandler.handleFatalError(
            this, "ClosedChannelException occurred while listening" + " for messages!", cce);
      } catch (IOException ex) {
        logger.log(Level.WARNING, "A net access point has gone useless:", ex);

        errorHandler.handleError(ex.getMessage(), ex);
        // do not stop the thread;
      } catch (Throwable ex) {
        logger.log(Level.WARNING, "A net access point has gone useless:", ex);

        stop();
        errorHandler.handleFatalError(
            this, "Unknown error occurred while listening for messages!", ex);
      }
    }
  }
Пример #7
0
  /**
   * Sends message through this access point's socket.
   *
   * @param message the bytes to send.
   * @param address message destination.
   * @throws IOException if an exception occurs while sending the message.
   */
  void sendMessage(byte[] message, TransportAddress address) throws IOException {
    DatagramPacket datagramPacket = new DatagramPacket(message, 0, message.length, address);

    sock.send(datagramPacket);
  }