private void releaseAllocation() { if (refreshTask != null && !refreshTask.isCancelled()) { logger.debug("Releasing previous allocation"); sendBlockingStunRequest(MessageFactory.createRefreshRequest(0)); refreshTask.cancel(true); } }
/** * Creates a new <tt>Request</tt> instance which is to be sent by this * <tt>StunCandidateHarvest</tt> in order to retry a specific <tt>Request</tt>. For example, the * long-term credential mechanism dictates that a <tt>Request</tt> is first sent by the client * without any credential-related attributes, then it gets challenged by the server and the client * retries the original <tt>Request</tt> with the appropriate credential-related attributes in * response. * * @param request the <tt>Request</tt> which is to be retried by this * <tt>StunCandidateHarvest</tt> * @return the new <tt>Request</tt> instance which is to be sent by this * <tt>StunCandidateHarvest</tt> in order to retry the specified <tt>request</tt> */ protected Request createRequestToRetry(Request request) { switch (request.getMessageType()) { case Message.BINDING_REQUEST: return MessageFactory.createBindingRequest(); default: throw new IllegalArgumentException("request.messageType"); } }
private void permit(InetSocketAddress address) { logger.info("Permitting sends from {}", address); Request createPermissionRequest = MessageFactory.createCreatePermissionRequest( new TransportAddress(address, Transport.UDP), TransactionID.createNewTransactionID().getBytes()); sendBlockingStunRequest(createPermissionRequest); logger.debug("Permitted sends from {}", address); }
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); }
@NotNull private ScheduledFuture<?> scheduleRefresh(int interval) { return scheduledExecutorService.scheduleWithFixedDelay( (Runnable) () -> { logger.debug("Refreshing TURN allocation"); sendBlockingStunRequest(MessageFactory.createRefreshRequest(interval)); for (Map.Entry<TransportAddress, Character> entry : peerAddressToChannel.entrySet()) { bind(entry.getKey(), entry.getValue()); } }, interval, interval, TimeUnit.SECONDS); }
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 allocateAddress(TransportAddress turnServerAddress) throws StunException, IOException { logger.info("Requesting address allocation at {}", serverAddress); Response response = sendBlockingStunRequest(MessageFactory.createAllocateRequest(UDP, false)); byte[] transactionID = response.getTransactionID(); relayedAddress = ((XorRelayedAddressAttribute) response.getAttribute(XOR_RELAYED_ADDRESS)) .getAddress(transactionID); mappedAddress = ((XorMappedAddressAttribute) response.getAttribute(XOR_MAPPED_ADDRESS)) .getAddress(transactionID); logger.info("Relayed address: {}, mapped address: {}", relayedAddress, mappedAddress); refreshTask = scheduleRefresh(refreshInterval); }
private void bind(TransportAddress address, int channelNumber) { if (peerAddressToChannel.containsKey(address)) { return; } logger.info("Binding '{}' to channel '{}'", address, channelNumber); Response response = sendBlockingStunRequest( MessageFactory.createChannelBindRequest( (char) channelNumber, address, TransactionID.createNewTransactionID().getBytes())); if (response.isSuccessResponse()) { logger.debug("Bound '{}' to channel '{}'", address, channelNumber); peerAddressToChannel.put(address, (char) channelNumber); channelToPeerAddress.put((char) channelNumber, address); } else { logger.warn("Binding for '{}' to channel '{}' failed", address, channelNumber); } }
/** * Creates a new <tt>Request</tt> which is to be sent to {@link StunCandidateHarvester#stunServer} * in order to start resolving {@link #hostCandidate}. * * @return a new <tt>Request</tt> which is to be sent to {@link StunCandidateHarvester#stunServer} * in order to start resolving {@link #hostCandidate} */ protected Request createRequestToStartResolvingCandidate() { return MessageFactory.createBindingRequest(); }
@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; } }