@Override
    public void sendResponse(Exchange exchange, Response response) {

      if (response.getDestination() == null)
        throw new NullPointerException("Response has no destination address");
      if (response.getDestinationPort() == 0)
        throw new NullPointerException("Response has no destination port");

      matcher.sendResponse(exchange, response);

      /*
       * Logging here causes significant performance loss.
       * If necessary, add an interceptor that logs the messages,
       * e.g., the MessageTracer.
       */

      for (MessageInterceptor interceptor : interceptors) interceptor.sendResponse(response);

      // MessageInterceptor might have canceled
      if (!response.isCanceled()) connector.send(serializer.serialize(response));
    }
    /*
     * The endpoint's executor executes this method to convert the raw bytes
     * into a message, look for an associated exchange and forward it to
     * the stack of layers.
     */
    private void receiveMessage(RawData raw) {
      DataParser parser = new DataParser(raw.getBytes());

      if (parser.isRequest()) {
        // This is a request
        Request request;
        try {
          request = parser.parseRequest();
        } catch (IllegalStateException e) {
          StringBuffer log =
              new StringBuffer("message format error caused by ")
                  .append(raw.getInetSocketAddress());
          if (!parser.isReply()) {
            // manually build RST from raw information
            EmptyMessage rst = new EmptyMessage(Type.RST);
            rst.setDestination(raw.getAddress());
            rst.setDestinationPort(raw.getPort());
            rst.setMID(parser.getMID());
            for (MessageInterceptor interceptor : interceptors) interceptor.sendEmptyMessage(rst);
            connector.send(serializer.serialize(rst));
            log.append(" and reset");
          }
          if (LOGGER.isLoggable(Level.INFO)) {
            LOGGER.info(log.toString());
          }
          return;
        }
        request.setSource(raw.getAddress());
        request.setSourcePort(raw.getPort());
        request.setSenderIdentity(raw.getSenderIdentity());

        /*
         * Logging here causes significant performance loss.
         * If necessary, add an interceptor that logs the messages,
         * e.g., the MessageTracer.
         */

        for (MessageInterceptor interceptor : interceptors) interceptor.receiveRequest(request);

        // MessageInterceptor might have canceled
        if (!request.isCanceled()) {
          Exchange exchange = matcher.receiveRequest(request);
          if (exchange != null) {
            exchange.setEndpoint(CoAPEndpoint.this);
            coapstack.receiveRequest(exchange, request);
          }
        }

      } else if (parser.isResponse()) {
        // This is a response
        Response response = parser.parseResponse();
        response.setSource(raw.getAddress());
        response.setSourcePort(raw.getPort());

        /*
         * Logging here causes significant performance loss.
         * If necessary, add an interceptor that logs the messages,
         * e.g., the MessageTracer.
         */

        for (MessageInterceptor interceptor : interceptors) interceptor.receiveResponse(response);

        // MessageInterceptor might have canceled
        if (!response.isCanceled()) {
          Exchange exchange = matcher.receiveResponse(response);
          if (exchange != null) {
            exchange.setEndpoint(CoAPEndpoint.this);
            response.setRTT(System.currentTimeMillis() - exchange.getTimestamp());
            coapstack.receiveResponse(exchange, response);
          } else if (response.getType() != Type.ACK) {
            LOGGER.fine("Rejecting unmatchable response from " + raw.getInetSocketAddress());
            reject(response);
          }
        }

      } else if (parser.isEmpty()) {
        // This is an empty message
        EmptyMessage message = parser.parseEmptyMessage();
        message.setSource(raw.getAddress());
        message.setSourcePort(raw.getPort());

        /*
         * Logging here causes significant performance loss.
         * If necessary, add an interceptor that logs the messages,
         * e.g., the MessageTracer.
         */

        for (MessageInterceptor interceptor : interceptors)
          interceptor.receiveEmptyMessage(message);

        // MessageInterceptor might have canceled
        if (!message.isCanceled()) {
          // CoAP Ping
          if (message.getType() == Type.CON || message.getType() == Type.NON) {
            LOGGER.info("Responding to ping by " + raw.getInetSocketAddress());
            reject(message);
          } else {
            Exchange exchange = matcher.receiveEmptyMessage(message);
            if (exchange != null) {
              exchange.setEndpoint(CoAPEndpoint.this);
              coapstack.receiveEmptyMessage(exchange, message);
            }
          }
        }
      } else {
        LOGGER.finest("Silently ignoring non-CoAP message from " + raw.getInetSocketAddress());
      }
    }