if(observer != null) observer.up(evt);
    public void down(Event evt) {        Message      msg;        TunnelHeader hdr;        Address dest;        if(evt.getType() != Event.MSG) {            handleDownEvent(evt);            return;        }        hdr=new TunnelHeader(channel_name);        msg=(Message)evt.getArg();        dest=msg.getDest();        msg.putHeader(getName(), hdr);        if(msg.getSrc() == null)            msg.setSrc(local_addr);        if(trace)            log.trace(msg + ", hdrs: " + msg.getHeaders());        // Don't send if destination is local address. Instead, switch dst and src and put in up_queue.        // If multicast message, loopback a copy directly to us (but still multicast). Once we receive this,        // we will discard our own multicast message        if(loopback && (dest == null || dest.equals(local_addr) || dest.isMulticastAddress())) {            Message copy=msg.copy();            // copy.removeHeader(name); // we don't remove the header            copy.setSrc(local_addr);            // copy.setDest(dest);            evt=new Event(Event.MSG, copy);            /* Because Protocol.up() is never called by this bottommost layer, we call up() directly in the observer.               This allows e.g. PerfObserver to get the time of reception of a message */            if(observer != null)                observer.up(evt);            if(trace) log.trace("looped back local message " + copy);            passUp(evt);            if(dest != null && !dest.isMulticastAddress())                return;        }        if(!stub.isConnected()) {            startReconnector();        }        else {            if(stub.send(msg, channel_name) == false) {                startReconnector();            }        }    }