@Override
 public void messageReceived(IoSession session, Object message) throws Exception {
   MRTMPPacket mrtmpPacket = (MRTMPPacket) message;
   int clientId = mrtmpPacket.getHeader().getClientId();
   RTMPConnection conn = rtmpConnManager.getConnection(clientId);
   if (conn == null) {
     log.debug("Client " + clientId + " is already closed.");
     return;
   }
   RTMP rtmpState = conn.getState();
   switch (mrtmpPacket.getHeader().getType()) {
     case MRTMPPacket.CLOSE:
       conn.setStateCode(RTMP.STATE_EDGE_DISCONNECTING);
       conn.close();
       break;
     case MRTMPPacket.RTMP:
       RTMPHeader rtmpHeader = (RTMPHeader) mrtmpPacket.getHeader();
       RTMPBody rtmpBody = (RTMPBody) mrtmpPacket.getBody();
       boolean toDisconnect = false;
       // conn.getWriteLock().lock();
       try {
         if (rtmpState.getState() == RTMP.STATE_ORIGIN_CONNECT_FORWARDED
             && rtmpHeader.getRtmpType() == TYPE_INVOKE) {
           // we got the connect invocation result from Origin
           // parse the result
           Invoke invoke = (Invoke) rtmpBody.getRtmpPacket().getMessage();
           if ("connect".equals(invoke.getCall().getServiceMethodName())) {
             if (invoke.getCall().getStatus() == Call.STATUS_SUCCESS_RESULT) {
               rtmpState.setState(RTMP.STATE_CONNECTED);
             } else {
               // TODO set EdgeRTMP state to closing ?
               toDisconnect = true;
             }
           }
         }
       } finally {
         //	conn.getWriteLock().unlock();
       }
       log.debug("Forward packet to client: {}", rtmpBody.getRtmpPacket().getMessage());
       // send the packet back to client
       conn.write(rtmpBody.getRtmpPacket());
       if (toDisconnect) {
         conn.close();
       }
       //	conn.getWriteLock().lock();
       try {
         if (rtmpState.getState() == RTMP.STATE_CONNECTED) {
           conn.startRoundTripMeasurement();
         }
       } finally {
         //	conn.getWriteLock().unlock();
       }
       break;
     default:
       break;
   }
 }
Example #2
0
 /** {@inheritDoc} */
 public void invoke(IServiceCall call, int channel) {
   // We need to use Invoke for all calls to the client
   Invoke invoke = new Invoke();
   invoke.setCall(call);
   invoke.setInvokeId(getInvokeId());
   if (call instanceof IPendingServiceCall) {
     registerPendingCall(invoke.getInvokeId(), (IPendingServiceCall) call);
   }
   getChannel(channel).write(invoke);
 }
 /** {@inheritDoc} */
 @Override
 public void connectionOpened(RTMPConnection conn) {
   log.trace("connectionOpened - conn: {}", conn);
   // Send "connect" call to the server
   Channel channel = conn.getChannel((byte) 3);
   PendingCall pendingCall = new PendingCall("connect");
   pendingCall.setArguments(connectArguments);
   Invoke invoke = new Invoke(pendingCall);
   invoke.setConnectionParams(connectionParams);
   invoke.setTransactionId(1);
   if (connectCallback != null) {
     pendingCall.registerCallback(connectCallback);
   }
   conn.registerPendingCall(invoke.getTransactionId(), pendingCall);
   log.debug("Writing 'connect' invoke: {}, invokeId: {}", invoke, invoke.getTransactionId());
   channel.write(invoke);
 }
 /**
  * Handler for pending call result. Dispatches results to all pending call handlers.
  *
  * @param conn Connection
  * @param invoke Pending call result event context
  */
 protected void handlePendingCallResult(RTMPConnection conn, Invoke invoke) {
   final IServiceCall call = invoke.getCall();
   final IPendingServiceCall pendingCall = conn.retrievePendingCall(invoke.getTransactionId());
   if (pendingCall != null) {
     // The client sent a response to a previously made call.
     Object[] args = call.getArguments();
     if (args != null && args.length > 0) {
       // TODO: can a client return multiple results?
       pendingCall.setResult(args[0]);
     }
     Set<IPendingServiceCallback> callbacks = pendingCall.getCallbacks();
     if (!callbacks.isEmpty()) {
       HashSet<IPendingServiceCallback> tmp = new HashSet<IPendingServiceCallback>();
       tmp.addAll(callbacks);
       for (IPendingServiceCallback callback : tmp) {
         try {
           callback.resultReceived(pendingCall);
         } catch (Exception e) {
           log.error("Error while executing callback {}", callback, e);
         }
       }
     }
   }
 }
  protected void handleConnect(
      RTMPConnection conn, Channel channel, Header header, Invoke invoke, RTMP rtmp) {
    final IPendingServiceCall call = invoke.getCall();
    // Get parameters passed from client to NetConnection#connection
    final Map<String, Object> params = invoke.getConnectionParams();

    // Get hostname
    String host = getHostname((String) params.get("tcUrl"));

    // App name as path, but without query string if there is one
    String path = (String) params.get("app");
    if (path.indexOf("?") != -1) {
      int idx = path.indexOf("?");
      params.put("queryString", path.substring(idx));
      path = path.substring(0, idx);
    }
    params.put("path", path);

    final String sessionId = null;

    conn.setup(host, path, sessionId, params);

    // check the security constraints
    // send back "ConnectionRejected" if fails.
    if (!checkPermission(conn)) {
      call.setStatus(Call.STATUS_ACCESS_DENIED);
      call.setResult(getStatus(NC_CONNECT_REJECTED));
      Invoke reply = new Invoke();
      reply.setCall(call);
      reply.setInvokeId(invoke.getInvokeId());
      channel.write(reply);
      conn.close();
    } else {
      synchronized (rtmp) {
        // connect the origin
        sendConnectMessage(conn);
        rtmp.setState(RTMP.STATE_EDGE_CONNECT_ORIGIN_SENT);
        Packet packet = new Packet(header);
        packet.setMessage(invoke);
        forwardPacket(conn, packet);
        rtmp.setState(RTMP.STATE_ORIGIN_CONNECT_FORWARDED);
        // Evaluate request for AMF3 encoding
        if (Integer.valueOf(3).equals(params.get("objectEncoding"))) {
          rtmp.setEncoding(Encoding.AMF3);
        }
      }
    }
  }
 /** {@inheritDoc} */
 @Override
 protected void onCommand(RTMPConnection conn, Channel channel, Header source, ICommand command) {
   log.trace("onCommand: {}, id: {}", command, command.getTransactionId());
   final IServiceCall call = command.getCall();
   final String methodName = call.getServiceMethodName();
   log.debug(
       "Service name: {} args[0]: {}",
       methodName,
       (call.getArguments().length != 0 ? call.getArguments()[0] : ""));
   if ("_result".equals(methodName) || "_error".equals(methodName)) {
     final IPendingServiceCall pendingCall = conn.getPendingCall(command.getTransactionId());
     log.debug("Received result for pending call - {}", pendingCall);
     if (pendingCall != null) {
       if ("connect".equals(methodName)) {
         Integer encoding = (Integer) connectionParams.get("objectEncoding");
         if (encoding != null && encoding.intValue() == 3) {
           log.debug("Setting encoding to AMF3");
           conn.getState().setEncoding(IConnection.Encoding.AMF3);
         }
       }
     }
     handlePendingCallResult(conn, (Invoke) command);
     return;
   }
   // potentially used twice so get the value once
   boolean onStatus = "onStatus".equals(methodName);
   log.debug("onStatus {}", onStatus);
   if (onStatus) {
     Integer streamId = source.getStreamId();
     if (log.isDebugEnabled()) {
       log.debug("Stream id from header: {}", streamId);
       // XXX create better to serialize ObjectMap to Status object
       ObjectMap<?, ?> objMap = (ObjectMap<?, ?>) call.getArguments()[0];
       // should keep this as an Object to stay compatible with FMS3 etc
       log.debug("Client id from status: {}", objMap.get("clientid"));
     }
     if (streamId != null) {
       // try lookup by stream id
       NetStreamPrivateData streamData = streamDataMap.get(streamId);
       // if null return the first one in the map
       if (streamData == null) {
         log.debug("Stream data was not found by id. Map contents: {}", streamDataMap);
         if (!streamDataMap.isEmpty()) {
           streamData = streamDataMap.values().iterator().next();
         }
       }
       if (streamData == null) {
         log.warn("Stream data was null for id: {}", streamId);
       }
       if (streamData != null && streamData.handler != null) {
         log.debug("Got stream data and handler");
         streamData.handler.onStreamEvent((Notify) command);
       }
     }
   }
   // if this client supports service methods, forward the call
   if (serviceProvider == null) {
     // client doesn't support calling methods on him
     call.setStatus(Call.STATUS_METHOD_NOT_FOUND);
     call.setException(new MethodNotFoundException(methodName));
     log.info(
         "No service provider / method not found; to handle calls like onBWCheck, add a service provider");
   } else {
     serviceInvoker.invoke(call, serviceProvider);
   }
   if (call instanceof IPendingServiceCall) {
     IPendingServiceCall psc = (IPendingServiceCall) call;
     Object result = psc.getResult();
     log.debug("Pending call result is: {}", result);
     if (result instanceof DeferredResult) {
       DeferredResult dr = (DeferredResult) result;
       dr.setTransactionId(command.getTransactionId());
       dr.setServiceCall(psc);
       dr.setChannel(channel);
       conn.registerDeferredResult(dr);
     } else if (!onStatus) {
       if ("onBWCheck".equals(methodName)) {
         onBWCheck(call.getArguments().length > 0 ? call.getArguments()[0] : null);
         Invoke reply = new Invoke();
         reply.setCall(call);
         reply.setTransactionId(command.getTransactionId());
         channel.write(reply);
       } else if ("onBWDone".equals(methodName)) {
         onBWDone(call.getArguments().length > 0 ? call.getArguments()[0] : null);
       } else {
         Invoke reply = new Invoke();
         reply.setCall(call);
         reply.setTransactionId(command.getTransactionId());
         log.debug("Sending empty call reply: {}", reply);
         channel.write(reply);
       }
     }
   }
 }