private function processMessage($msg, $qos)
    {
        // Package starts with topic
        $tlen = (ord($msg{0})<<8) + ord($msg{1});
        $msg_topic = substr($msg,2,$tlen);

        // QoS 1 and 2 packets also contain identifier
        $msg_id = null;
        if($qos == 0) {
            $msg = substr($msg,$tlen+2);
        } else {
            $msg_id = substr($msg,$tlen+2,2);
            $msg = substr($msg,$tlen+4);
        }

        // Then comes the message itself
        $found = false;
        foreach($this->topics as $topic=>$data) {

            $t_topic = str_replace("+","[^/]*", $topic);
            $t_topic = str_replace("/","\/",$t_topic);
            $t_topic = str_replace("$","\$",$t_topic);
            $t_topic = str_replace("#",".*",$t_topic);

            if(!preg_match("/^".$t_topic."$/", $msg_topic)) {
                continue;
            }

            $found = true;

            $this->debugMessage("Packet received (QoS: ".$qos." ; topic: ".$msg_topic." ; msg: ".$msg.")",2);

            // Is callback for this topic set?
            if(isset($data["function"]) && is_callable($data["function"])) {
                call_user_func($data["function"], $msg_topic, $msg, $qos);
            }
        }

        //
        if(!$found) {
            $this->debugMessage("Package received, but it doesn't match subscriptions");
        }

        // QoS 1 package requires PUBACK packet
        if($qos==1) {
            $this->debugMessage("Packet with QoS 1 received, sending PUBACK");
            $payload = chr(0x40).chr(0x02).$msg_id;
            fwrite($this->socket, $payload, 4);
        }

        // QoS 2 package requires PUBRECT packet, but we won't give it :)
        if($qos==2) {
            // FIXME
            $this->debugMessage("Packet with QoS 2 received, but feature is not implemented");
        }
    }