/**
   * Send a message to a specified receiver address.
   *
   * @param msg string to send.
   * @param peerAddress Address of the place to send it to.
   * @param peerPort the port to send it to.
   * @throws IOException If there is trouble sending this message.
   */
  protected void sendMessage(byte[] msg, InetAddress peerAddress, int peerPort, boolean reConnect)
      throws IOException {
    // Via is not included in the request so silently drop the reply.
    if (sipStack.isLoggingEnabled() && this.sipStack.logStackTraceOnMessageSend) {
      this.sipStack.logWriter.logStackTrace(LogWriter.TRACE_MESSAGES);
    }
    if (peerPort == -1) {
      if (sipStack.isLoggingEnabled()) {
        this.sipStack.logWriter.logDebug(getClass().getName() + ":sendMessage: Dropping reply!");
      }
      throw new IOException("Receiver port not set ");
    } else {
      if (sipStack.isLoggingEnabled()) {
        this.sipStack.logWriter.logDebug(
            getClass().getName()
                + ":sendMessage "
                + peerAddress.getHostAddress()
                + "/"
                + peerPort
                + "\n"
                + new String(msg));
        this.sipStack.logWriter.logDebug("*******************\n");
      }
    }
    DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress, peerPort);
    try {
      DatagramSocket sock;
      boolean created = false;

      if (sipStack.udpFlag) {
        // Use the socket from the message processor (for firewall
        // support use the same socket as the message processor
        // socket -- feature request # 18 from java.net). This also
        // makes the whole thing run faster!
        sock = ((UDPMessageProcessor) messageProcessor).sock;

        // Bind the socket to the stack address in case there
        // are multiple interfaces on the machine (feature reqeust
        // by Will Scullin) 0 binds to an ephemeral port.
        // sock = new DatagramSocket(0,sipStack.stackInetAddress);
      } else {
        // bind to any interface and port.
        sock = new DatagramSocket();
        created = true;
      }
      sock.send(reply);
      if (created) sock.close();
    } catch (IOException ex) {
      throw ex;
    } catch (Exception ex) {
      InternalErrorHandler.handleException(ex);
    }
  }
  /**
   * Send a message to a specified receiver address.
   *
   * @param msg message string to send.
   * @param peerAddress Address of the place to send it to.
   * @param peerPort the port to send it to.
   * @param peerProtocol protocol to use to send.
   * @throws IOException If there is trouble sending this message.
   */
  protected void sendMessage(
      byte[] msg, InetAddress peerAddress, int peerPort, String peerProtocol, boolean retry)
      throws IOException {
    // Via is not included in the request so silently drop the reply.
    if (peerPort == -1) {
      if (sipStack.isLoggingEnabled()) {
        this.sipStack.logWriter.logDebug(getClass().getName() + ":sendMessage: Dropping reply!");
      }
      throw new IOException("Receiver port not set ");
    } else {
      if (sipStack.isLoggingEnabled()) {
        this.sipStack.logWriter.logDebug(
            getClass().getName()
                + ":sendMessage "
                + peerAddress.getHostAddress()
                + "/"
                + peerPort
                + "\n"
                + new String(msg));
        this.sipStack.logWriter.logDebug("*******************\n");
      }
    }
    if (peerProtocol.compareToIgnoreCase("UDP") == 0) {
      DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress, peerPort);

      try {
        DatagramSocket sock;
        if (sipStack.udpFlag) {
          sock = ((UDPMessageProcessor) messageProcessor).sock;

        } else {
          // bind to any interface and port.
          sock = sipStack.getNetworkLayer().createDatagramSocket();
        }
        if (sipStack.isLoggingEnabled()) {
          this.sipStack.logWriter.logDebug(
              "sendMessage "
                  + peerAddress.getHostAddress()
                  + "/"
                  + peerPort
                  + "\n"
                  + new String(msg));
        }
        sock.send(reply);
        if (!sipStack.udpFlag) sock.close();
      } catch (IOException ex) {
        throw ex;
      } catch (Exception ex) {
        InternalErrorHandler.handleException(ex);
      }

    } else {
      // Use TCP to talk back to the sender.
      Socket outputSocket =
          sipStack.ioHandler.sendBytes(
              this.messageProcessor.getIpAddress(), peerAddress, peerPort, "tcp", msg, retry);
      OutputStream myOutputStream = outputSocket.getOutputStream();
      myOutputStream.write(msg, 0, msg.length);
      myOutputStream.flush();
      // The socket is cached (dont close it!);
    }
  }