예제 #1
0
  /**
   * Remove the clientID from topic subscription, if not previously subscribed, doesn't reply any
   * error
   */
  public void processUnsubscribe(ServerChannel session, UnsubscribeMessage msg) {
    List<String> topics = msg.topicFilters();
    int messageID = msg.getMessageID();
    String clientID = (String) session.getAttribute(NettyChannel.ATTR_KEY_CLIENTID);
    LOG.debug("UNSUBSCRIBE subscription on topics {} for clientID <{}>", topics, clientID);

    ClientSession clientSession = m_sessionsStore.sessionForClient(clientID);
    verifyToActivate(clientID, clientSession);
    for (String topic : topics) {
      boolean validTopic = SubscriptionsStore.validate(topic);
      if (!validTopic) {
        // close the connection, not valid topicFilter is a protocol violation
        session.close(true);
        LOG.warn(
            "UNSUBSCRIBE found an invalid topic filter <{}> for clientID <{}>", topic, clientID);
        return;
      }

      subscriptions.removeSubscription(topic, clientID);
      clientSession.unsubscribeFrom(topic);
      m_interceptor.notifyTopicUnsubscribed(topic, clientID);
    }

    // ack the client
    UnsubAckMessage ackMessage = new UnsubAckMessage();
    ackMessage.setMessageID(messageID);

    LOG.info("replying with UnsubAck to MSG ID {}", messageID);
    session.write(ackMessage);
  }
예제 #2
0
  public void processDisconnect(ServerChannel session) throws InterruptedException {
    String clientID = (String) session.getAttribute(NettyChannel.ATTR_KEY_CLIENTID);
    boolean cleanSession = (Boolean) session.getAttribute(NettyChannel.ATTR_KEY_CLEANSESSION);
    LOG.info("DISCONNECT client <{}> with clean session {}", clientID, cleanSession);
    ClientSession clientSession = m_sessionsStore.sessionForClient(clientID);
    clientSession.disconnect();

    m_clientIDs.remove(clientID);
    session.close(true);

    // cleanup the will store
    m_willStore.remove(clientID);

    m_interceptor.notifyClientDisconnected(clientID);
    LOG.info("DISCONNECT client <{}> finished", clientID, cleanSession);
  }
예제 #3
0
 private void failedCredentials(ServerChannel session) {
   ConnAckMessage okResp = new ConnAckMessage();
   okResp.setReturnCode(ConnAckMessage.BAD_USERNAME_OR_PASSWORD);
   session.write(okResp);
   session.close(false);
 }
예제 #4
0
  public void processConnect(ServerChannel session, ConnectMessage msg) {
    LOG.debug("CONNECT for client <{}>", msg.getClientID());
    if (msg.getProtocolVersion() != VERSION_3_1 && msg.getProtocolVersion() != VERSION_3_1_1) {
      ConnAckMessage badProto = new ConnAckMessage();
      badProto.setReturnCode(ConnAckMessage.UNNACEPTABLE_PROTOCOL_VERSION);
      LOG.warn("processConnect sent bad proto ConnAck");
      session.write(badProto);
      session.close(false);
      return;
    }

    if (msg.getClientID() == null || msg.getClientID().length() == 0) {
      ConnAckMessage okResp = new ConnAckMessage();
      okResp.setReturnCode(ConnAckMessage.IDENTIFIER_REJECTED);
      session.write(okResp);
      m_interceptor.notifyClientConnected(msg);
      return;
    }

    // handle user authentication
    if (msg.isUserFlag()) {
      byte[] pwd = null;
      if (msg.isPasswordFlag()) {
        pwd = msg.getPassword();
      } else if (!this.allowAnonymous) {
        failedCredentials(session);
        return;
      }
      if (!m_authenticator.checkValid(msg.getUsername(), pwd)) {
        failedCredentials(session);
        return;
      }
      session.setAttribute(NettyChannel.ATTR_KEY_USERNAME, msg.getUsername());
    } else if (!this.allowAnonymous) {
      failedCredentials(session);
      return;
    }

    // if an old client with the same ID already exists close its session.
    if (m_clientIDs.containsKey(msg.getClientID())) {
      LOG.info(
          "Found an existing connection with same client ID <{}>, forcing to close",
          msg.getClientID());
      // clean the subscriptions if the old used a cleanSession = true
      ServerChannel oldSession = m_clientIDs.get(msg.getClientID()).session;
      ClientSession oldClientSession = m_sessionsStore.sessionForClient(msg.getClientID());
      oldClientSession.disconnect();
      oldSession.setAttribute(NettyChannel.ATTR_KEY_SESSION_STOLEN, true);
      oldSession.close(false);
      LOG.debug("Existing connection with same client ID <{}>, forced to close", msg.getClientID());
    }

    ConnectionDescriptor connDescr =
        new ConnectionDescriptor(msg.getClientID(), session, msg.isCleanSession());
    m_clientIDs.put(msg.getClientID(), connDescr);

    int keepAlive = msg.getKeepAlive();
    LOG.debug("Connect with keepAlive {} s", keepAlive);
    session.setAttribute(NettyChannel.ATTR_KEY_KEEPALIVE, keepAlive);
    session.setAttribute(NettyChannel.ATTR_KEY_CLEANSESSION, msg.isCleanSession());
    // used to track the client in the subscription and publishing phases.
    session.setAttribute(NettyChannel.ATTR_KEY_CLIENTID, msg.getClientID());
    LOG.debug("Connect create session <{}>", session);

    session.setIdleTime(Math.round(keepAlive * 1.5f));

    // Handle will flag
    if (msg.isWillFlag()) {
      AbstractMessage.QOSType willQos = AbstractMessage.QOSType.valueOf(msg.getWillQos());
      byte[] willPayload = msg.getWillMessage();
      ByteBuffer bb = (ByteBuffer) ByteBuffer.allocate(willPayload.length).put(willPayload).flip();
      // save the will testament in the clientID store
      WillMessage will = new WillMessage(msg.getWillTopic(), bb, msg.isWillRetain(), willQos);
      m_willStore.put(msg.getClientID(), will);
    }

    ConnAckMessage okResp = new ConnAckMessage();
    okResp.setReturnCode(ConnAckMessage.CONNECTION_ACCEPTED);

    ClientSession clientSession = m_sessionsStore.sessionForClient(msg.getClientID());
    boolean isSessionAlreadyStored = clientSession != null;
    if (!msg.isCleanSession() && isSessionAlreadyStored) {
      okResp.setSessionPresent(true);
    }
    session.write(okResp);
    m_interceptor.notifyClientConnected(msg);

    if (!isSessionAlreadyStored) {
      LOG.info("Create persistent session for clientID <{}>", msg.getClientID());
      clientSession = m_sessionsStore.createNewSession(msg.getClientID(), msg.isCleanSession());
    }
    clientSession.activate();
    if (msg.isCleanSession()) {
      clientSession.cleanSession();
    }
    LOG.info(
        "Connected client ID <{}> with clean session {}", msg.getClientID(), msg.isCleanSession());
    if (!msg.isCleanSession()) {
      // force the republish of stored QoS1 and QoS2
      republishStoredInSession(clientSession);
    }
    LOG.info("CONNECT processed");
  }