class Channel implements Runnable {
    
    private static final Logger Log = LoggerFactory.getLogger(Channel.class);

    protected byte[] buf = new byte[5000];
    protected DatagramSocket dataSocket;
    protected DatagramPacket packet;
    protected boolean enabled = true;

    List<DatagramListener> listeners = new ArrayList<>();

    protected InetAddress host;
    protected int port;

    /**
     * Creates a Channel according to the parameters.
     *
     * @param dataSocket datasocket to used to send and receive packets
     * @param host       default destination host for received packets
     * @param port       default destination port for received packets
     */
    public Channel(DatagramSocket dataSocket, InetAddress host, int port) {
        this.dataSocket = dataSocket;
        this.host = host;
        this.port = port;
    }

    /**
     * Get the host that the packet will be sent to.
     *
     * @return remote host address
     */
    public InetAddress getHost() {
        return host;
    }

    /**
     * Set the host that the packet will be sent to.
     * @param host the host to send the packet to
     */
    protected void setHost(InetAddress host) {
        this.host = host;
    }

    /**
     * Get the port that the packet will be sent to.
     *
     * @return The remote port number
     */
    public int getPort() {
        return port;
    }

    /**
     * Set the port that the packet will be sent to.
     *
     * @param port the port to send the packet to
     */
    protected void setPort(int port) {
        this.port = port;
    }

    /**
     * Adds a DatagramListener to the Channel
     *
     * @param datagramListener the listener to add
     */
    public void addListener(DatagramListener datagramListener) {
        listeners.add(datagramListener);
    }

    /**
     * Remove a DatagramListener from the Channel
     *
     * @param datagramListener the listener to remove
     */
    public void removeListener(DatagramListener datagramListener) {
        listeners.remove(datagramListener);
    }

    /**
     * Remove every Listeners
     */
    public void removeListeners() {
        listeners.clear();
    }

    public void cancel() {<FILL_FUNCTION_BODY>}

    /**
     * Thread override method
     */
    @Override
    public void run() {
        try {
            while (enabled) {
                // Block until a datagram appears:
                packet = new DatagramPacket(buf, buf.length);
                dataSocket.receive(packet);

                if (handle(packet)) {
                    boolean resend = true;

                    for (DatagramListener dl : listeners) {
                        boolean send = dl.datagramReceived(packet);
                        if (resend && !send) {
                            resend = false;
                        }
                    }

                    if (resend) {
                        relayPacket(packet);
                    }
                }
            }
        }
        catch (UnknownHostException uhe) {
            if (enabled) {
                Log.error("Unknown Host", uhe);
            }
        }
        catch (SocketException se) {
            if (enabled) {
                Log.error("Socket closed", se);
            }
        }
        catch (IOException ioe) {
            if (enabled) {
                Log.error("Communication error", ioe);
            }
        }
    }

    public void relayPacket(DatagramPacket packet) {
        try {
            DatagramPacket echo = new DatagramPacket(packet.getData(), packet.getLength(), host, port);
            dataSocket.send(echo);
        }
        catch (IOException e) {
            Log.error(e.getMessage(), e);
        }
    }

    /**
     * Handles received packet and returns true if the packet should be processed by the channel.
     *
     * @param packet received datagram packet
     * @return true if listeners will be alerted that a new packet was received.
     */
    abstract boolean handle(DatagramPacket packet);
}

        this.enabled = false;
        if (dataSocket != null){
            dataSocket.close();
        }
    
<no_super_class>