/**
         * Constructs a StunMessageEvent according to the specified message.
         * @param source the access point that received the message
         * @param message the message itself
         * @param remoteAddress the address that sent the message
         */
        public StunMessageEvent(NetAccessPointDescriptor source,
			Message                  message,
			StunAddress        remoteAddress)
        {
            this.message = message;
            this.remoteAddress  = remoteAddress;
        }
        //--------------- SENDING MESSAGES -----------------------------------------
        /**
         * Sends the specified stun message through the specified access point.
         * @param stunMessage the message to send
         * @param apDescriptor the access point to use to send the message
         * @param address the destination of the message.
         * @throws StunException if message encoding fails, ILLEGAL_ARGUMENT if the
         * apDescriptor references an access point that had not been installed,
         * NETWORK_ERROR if an error occurs while sending message bytes through the
         * network socket.
         */
        public virtual void SendMessage(Message                  stunMessage,
			NetAccessPointDescriptor apDescriptor,
			StunAddress                  address)
        {
            byte[] bytes = stunMessage.Encode();
            NetAccessPoint ap = (NetAccessPoint)netAccessPoints[apDescriptor];

            if(ap == null)
                throw new StunException(
                    StunException.ILLEGAL_ARGUMENT,
                    "The specified access point had not been installed.");

            try
            {
                ap.SendMessage(bytes, address);
            }
            catch (Exception ex)
            {
                throw new StunException(StunException.NETWORK_ERROR,
                    "An Exception occurred while sending message bytes "
                    +"through a network socket!",
                    ex);
            }
        }