метод обратного вызова в цикле pcap


Я пытаюсь использовать функцию pcap_loop в библиотеке libpcab в Linux с этим прототипом:

int pcap_loop(pcap_t *, int, pcap_handler, u_char *);

Pcap_pkthdr-указатель на функцию:

typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *);

В своей программе я определил следующий метод в классе SniffEthernet:

void SniffEthernet::got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);

Теперь вызываем pcap_loop, как показано ниже

pcap_loop(handle, num_packets, this->got_packet, NULL);

Выдает мне следующую ошибку компиляции:

SniffEthernet.cc:139:58: error: cannot convert ‘VENTOS::SniffEthernet::got_packet’ from type ‘void (VENTOS::SniffEthernet::)(u_char*, const pcap_pkthdr*, const u_char*) {aka void (VENTOS::SniffEthernet::)(unsigned char*, const pcap_pkthdr*, const unsigned char*)}’ to type ‘pcap_handler {aka void (*)(unsigned char*, const pcap_pkthdr*, const unsigned char*)}’

Что я здесь делаю не так?

Edit: я нашел похожий пост здесь.

1 2

1 ответ:

Ваша функция обратного вызова не может быть функцией-членом (методом). Не забывайте, что функции-члены всегда имеют скрытый параметр this.

Функция обратного вызова должна быть либо функцией уровня пространства имен, либо статическим членом класса.

Если вы хотите, чтобы ваш объект был доступен для вашей функции CB, вы можете использовать член user (последний аргумент pcap_loop(), первый член функции обратного вызова), с соответствующими приведениями типов, для передачи произвольных данных, которые в вашем случае, это будет объект, который вы используете для захвата.

Приведенный ниже код является неполным и непроверенным, но может дать вам представление.
class SniffEther {
    private:
        pcap_t *cap_handler;
        char errbuf[PCAP_ERRBUF_SIZE];
        /* capture-related data members (properties) */

    public:
        static friend void pkt_callback(u_char *user, const pcap_pkthdr *hdr, const u_char *bytes){
            SniffEther *sniffer=reinterpret_cast<SniffEther *>(user);
            /*
                Process header and bytes.

                You can call things like sniffer->somemethod(), and also
                access sniffer->someproperty.
            */
        }

        // constructor
        SniffEther(const char *if_name){
            cap_handler=pcap_create(if_name, errbuf);
            if(!cap_handler)
                throw runtime_error(errbuf);
            /* Set the many pcap_options (see pcap(3)). */
            if(pcap_activate(cap_handler)!=0){
                string error(pcap_geterr(cap_handler));
                pcap_close(cap_handler);
                throw runtime_error(error);
            }
        }

        ~SniffEther(){
            if(cap_handler)
                pcap_close(cap_handler);
        }

        void capture_loop(int pkt_count=-1){
            if(
                pcap_loop(
                    cap_handler, pkt_count, pkt_callback,
                    reinterpret_cast<*u_char>(this)
                )==-1
            )
                throw runtime_error(pcap_geterr(cap_handler));
        }
};