private void handleChannelBindRequest() throws InterruptedException, IOException, StunException {
    StunMessageEvent event = eventsReceivedByTurnServer.poll(5, TimeUnit.SECONDS);
    TransportAddress remoteAddress = event.getRemoteAddress();

    Request request = (Request) event.getMessage();
    assertThat(request.getMessageType(), is(Message.CHANNELBIND_REQUEST));
    Response channelBindResponse = MessageFactory.createChannelBindResponse();

    sendResponse(remoteAddress, request, channelBindResponse);
  }
  private void handleCreatePermissionRequest()
      throws StunException, IOException, InterruptedException {
    StunMessageEvent event = eventsReceivedByTurnServer.poll(5, TimeUnit.SECONDS);
    TransportAddress remoteAddress = event.getRemoteAddress();

    Request request = (Request) event.getMessage();
    assertThat(request.getMessageType(), is(Message.CREATEPERMISSION_REQUEST));
    Response createPermissionResponse = MessageFactory.createCreatePermissionResponse();

    sendResponse(remoteAddress, request, createPermissionResponse);
  }
  private void handleAllocationRequest() throws StunException, IOException, InterruptedException {
    StunMessageEvent event = eventsReceivedByTurnServer.poll(5, TimeUnit.SECONDS);
    TransportAddress localAddress = event.getLocalAddress();
    TransportAddress remoteAddress = event.getRemoteAddress();

    Request request = (Request) event.getMessage();
    assertThat(request.getMessageType(), is(Message.ALLOCATE_REQUEST));
    Response allocationResponse =
        MessageFactory.createAllocationResponse(
            request,
            remoteAddress,
            new TransportAddress(localAddress.getHostAddress(), 2222, UDP),
            100);

    sendResponse(remoteAddress, request, allocationResponse);
  }
  private void onIndication(StunMessageEvent event) {
    Message message = event.getMessage();
    byte[] data = ((DataAttribute) message.getAttribute(Attribute.DATA)).getData();
    TransportAddress sender =
        ((XorPeerAddressAttribute) message.getAttribute(XOR_PEER_ADDRESS))
            .getAddress(message.getTransactionID());

    if (logger.isTraceEnabled()) {
      logger.trace(
          "Received {} bytes indication from '{}': {}",
          data.length,
          sender,
          new String(data, 0, data.length, StandardCharsets.US_ASCII));
    }

    DatagramPacket datagramPacket = new DatagramPacket(data, data.length);
    datagramPacket.setSocketAddress(sender);
    onPacketReceived(datagramPacket);
  }
  @Override
  public void processRequest(StunMessageEvent evt) throws IllegalArgumentException {
    if (logger.isLoggable(Level.FINER)) {
      logger.setLevel(Level.FINEST);
    }
    Message message = evt.getMessage();
    if (message.getMessageType() == Message.CONNECT_REQUEST) {
      logger.finer("Received Connect request " + evt);

      Character errorCode = null;
      XorPeerAddressAttribute peerAddress = null;
      FiveTuple fiveTuple = null;
      Response response = null;
      ConnectionIdAttribute connectionId = null;
      if (!message.containsAttribute(Attribute.XOR_PEER_ADDRESS)) {
        errorCode = ErrorCodeAttribute.BAD_REQUEST;
      } else {
        peerAddress = (XorPeerAddressAttribute) message.getAttribute(Attribute.XOR_PEER_ADDRESS);
        peerAddress.setAddress(peerAddress.getAddress(), evt.getTransactionID().getBytes());
        logger.finest("Peer Address requested : " + peerAddress.getAddress());
        TransportAddress clientAddress = evt.getRemoteAddress();
        TransportAddress serverAddress = evt.getLocalAddress();
        Transport transport = evt.getLocalAddress().getTransport();
        fiveTuple = new FiveTuple(clientAddress, serverAddress, transport);
        Allocation allocation = this.turnStack.getServerAllocation(fiveTuple);
        if (allocation == null) {
          errorCode = ErrorCodeAttribute.ALLOCATION_MISMATCH;
        } else if (!allocation.isPermitted(peerAddress.getAddress())) {
          errorCode = ErrorCodeAttribute.FORBIDDEN;
        } else {
          // code for processing the connect request.
          connectionId = AttributeFactory.createConnectionIdAttribute();
          logger.finest("Created ConnectionID : " + connectionId.getConnectionIdValue());
          try {
            Socket socket =
                new Socket(
                    peerAddress.getAddress().getAddress(), peerAddress.getAddress().getPort());
            socket.setSoTimeout(30 * 1000);
            IceTcpSocketWrapper iceSocket = new IceTcpSocketWrapper(socket);
            this.turnStack.addSocket(iceSocket);
          } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
          /**
           * TODO Create a new TCP connection to the peer from relay address. wait for at-least 30
           * seconds. If it fails then send 447 error code.
           */
          this.turnStack.addUnAcknowlededConnectionId(
              connectionId.getConnectionIdValue(), peerAddress.getAddress(), allocation);
          logger.finest("Creating Connect Success Response.");
          response = MessageFactory.createConnectResponse(connectionId.getConnectionIdValue());
        }
      }
      if (errorCode != null) {
        response = MessageFactory.createConnectErrorResponse(errorCode);
        logger.finest("error Code : " + (int) errorCode + " on ConnectRequest");
      }
      try {
        logger.finest("Sending Connect Response");
        turnStack.sendResponse(
            evt.getTransactionID().getBytes(),
            response,
            evt.getLocalAddress(),
            evt.getRemoteAddress());
      } catch (Exception e) {
        System.err.println("Failed to send response");
        logger.log(
            Level.INFO, "Failed to send " + response + " through " + evt.getLocalAddress(), e);
        // try to trigger a 500 response although if this one failed,
        throw new RuntimeException("Failed to send a response", e);
      }
    } else {
      return;
    }
  }