На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Ошибка компиляции , invalid use of member (did you forget the ‘&’)
    Народ помогите. Пишу программу, которая должна определить все МАК и IP адрес, что-то на подобии tcpdump. Платформа Ubuntu 10.04.
    Есть программный код, который определяет МАК адреса. Решил его переделать его из С в С + +, соответственно с классом и H файлом
    ExpandedWrap disabled
      #include <pcap.h>
      #include <stdlib.h>
      #include <signal.h>
      #include <netinet/ip.h>
      #include <netinet/if_ether.h>
      #include <arpa/inet.h>
      #include <netinet/ether.h>
      #include <unistd.h>
      int child_pid = 0;
       
      void print_eth_addr(void *addr) {
        printf("%s\n", ether_ntoa((struct ether_addr *)addr));
        kill(child_pid, 9);
        exit(0);
      }
       
      void find_eth_addr(struct in_addr *search_ip, const struct pcap_pkthdr* pkthdr, const u_char *packet) {
        struct ether_header *eth_hdr = (struct ether_header *)packet;
       
        if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP) {
          struct ip *ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));
          if (ip_hdr->ip_dst.s_addr == search_ip->s_addr)
            print_eth_addr(eth_hdr->ether_dhost);
          if (ip_hdr->ip_src.s_addr == search_ip->s_addr)
            print_eth_addr(eth_hdr->ether_shost);
        }
      }
       
      int main(int argc, char **argv)
      {
        char *dev, errbuf[PCAP_ERRBUF_SIZE];
        pcap_t* descr;
        bpf_u_int32 maskp, netp;
       
        if (argc < 2) {
          printf("Usage: %s <ip> [interface]\n", argv[0]);
          return 1;
        }
       
        if (argc == 2 && !(dev = pcap_lookupdev(errbuf))) {
          fprintf(stderr, "%s\n", errbuf); return 1;
        } else if (argc == 3) {
          dev = argv[2];
        }
       
        pcap_lookupnet(dev,&netp,&maskp,errbuf);
       
        if (!(descr = pcap_open_live(dev, BUFSIZ, 1, -1, errbuf))) {
          printf("pcap_open_live(): %s\n", errbuf); return 1;
        }
       
        struct in_addr search_ip;
        if (!inet_aton(argv[1], &search_ip)) {
          fprintf(stderr, "bad ip\n"); exit(1);
        }
       
        int pid = fork();
        if (pid == 0) {
          while (1) {
            struct sockaddr_in sin;
            sin.sin_family = PF_INET;
            inet_aton(argv[1], &sin.sin_addr);
            sin.sin_port = htons(1);
            int s = socket(PF_INET, SOCK_STREAM, 0);
            connect(s, (struct sockaddr *)&sin, sizeof(sin));
            usleep(100000);
          }
        } else {
          child_pid = pid;
          //pcap_loop(descr, -1, (pcap_handler)find_eth_addr, (void *)&search_ip);
      pcap_loop(descr, -1, (pcap_handler)find_eth_addr, (u_char *)&search_ip);
        }
       
        return 0;
      }

    Код рабочий, дальше идет моя интерпретация. Соответственно h и cpp.
    local_mac.h
    ExpandedWrap disabled
      #pragma once
      #ifndef BASIC_H
      #define BASIC_H
      #include <pcap.h>
      #include <stdlib.h>
      #include <signal.h>
      #include <netinet/ip.h>
      #include <netinet/if_ether.h>
      #include <arpa/inet.h>
      #include <netinet/ether.h>
      #include <unistd.h>
       int child_pid = 0;
      class LocalMacAdd
      {
          public:
          LocalMacAdd(int ARGC, char **ARGV);
          int GetAddres();
          private:
         void print_eth_addr(void *addr);
         void find_eth_addr(struct in_addr *search_ip, const struct pcap_pkthdr* pkthdr, const u_char *packet);
       char *dev, *ErrorBuffer,**argv;
       struct in_addr search_ip;
        pcap_t* descr;
        bpf_u_int32 maskp, netp;
        int argc;
       
      };
      #endif

    local_mac.cpp
    ExpandedWrap disabled
      #include "local_mac.h"
      #include <iostream>
      using namespace std;
      LocalMacAdd::LocalMacAdd(int  ARGC, char **ARGV)
      {
      argc = ARGC;
      argv = ARGV;
      }
      void LocalMacAdd::print_eth_addr(void *addr)
      {
          cout << "  " << ether_ntoa((struct ether_addr *)addr) << " " << endl;
        kill(child_pid, 9);
        exit(0);
      }
      void LocalMacAdd::find_eth_addr(struct in_addr *search_ip, const struct pcap_pkthdr* pkthdr, const u_char *packet)
      {
      struct ether_header *eth_hdr = (struct ether_header *)packet;
        if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP) {
          struct ip *ip_hdr = (struct ip *)(packet + sizeof(struct ether_header));
          if (ip_hdr->ip_dst.s_addr == search_ip->s_addr)
            print_eth_addr(eth_hdr->ether_dhost);
          if (ip_hdr->ip_src.s_addr == search_ip->s_addr)
            print_eth_addr(eth_hdr->ether_shost);
        }
      }
      int LocalMacAdd::GetAddres()//int argc, char **argv)
      {
      ErrorBuffer = new char[PCAP_ERRBUF_SIZE];
      if (argc < 2) {
          cout << " Usage: <ip> [interface]\n" << argv[0] << endl;
          return 1;
        }
       
      if (argc == 2 && !(dev = pcap_lookupdev(ErrorBuffer))) {
          cerr << "  " << ErrorBuffer << "  " << endl;
          return 1;
        } else if (argc == 3) {
          dev = argv[2];
        }
       
      pcap_lookupnet(dev,&netp,&maskp,ErrorBuffer);
       
       if (!(descr = pcap_open_live(dev, BUFSIZ, 1, -1, ErrorBuffer))) {
           cout << "pcap_open_live(): \n " << ErrorBuffer << endl;
           return 1;
        }
       
        //struct in_addr search_ip;
        if (!inet_aton(argv[1], &search_ip)) {
            cerr << "bad ip\n" << endl;
            exit(1);
       
        }
       
      int pid = fork();
        if (pid == 0) {
          while (1) {
            struct sockaddr_in sin;
            sin.sin_family = PF_INET;
            inet_aton(argv[1], &sin.sin_addr);
            sin.sin_port = htons(1);
            int s = socket(PF_INET, SOCK_STREAM, 0);
            connect(s, (struct sockaddr *)&sin, sizeof(sin));
            usleep(100000);
          }
        } else {
          child_pid = pid;
         // u_char * temp =(u_char *) search_ip;
      pcap_loop(descr, -1, (pcap_handler)find_eth_addr,((u_char *) (&search_ip)) );
      //pcap_loop(descr, -1, (pcap_handler)find_eth_addr,(u_char *)&search_ip);
        }
      }

    Сама ошибка находится в строке
    ExpandedWrap disabled
      pcap_loop(descr, -1, (pcap_handler)find_eth_addr,((u_char *) (&search_ip)) );

    local_mac.cpp:69: error: invalid use of member (did you forget the ‘&’?)
    сигнатура функции
    ExpandedWrap disabled
      int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)

    Возможно кто-то чем-то поможет :rolleyes:
    Сообщение отредактировано: pesekot -
      LocalMacAdd::find_eth_addr() - это не свободная функция, это метод класса, и поэтому да, указатели на них должны браться явно. Но не это главное. Взяв указатель на него, ты получишь не тип pcap_handler. Сравни:
      ExpandedWrap disabled
        typedef void (             *func_ptr  )(struct in_addr *, const struct pcap_pkthdr*, const u_char *);
        typedef void (LocalMacAdd::*member_ptr)(struct in_addr *, const struct pcap_pkthdr*, const u_char *);
      Более того, эти типы неприводимы друг к другу. Даже явный каст типа даст ошибку. И это правильно, методу нужен this, а C-коду, использующему тип pcap_handler, неоткуда его взять, он вообще не курсе, что что-то ещё нужно. Если компилятор такое пропустит, код обязательно свалится, ибо this будет мусором.
        Цитата Qraizer @

        А если функцию GetAddres () объявить вне класса, и в ней инициализировать объект класса LocalMacAdd?
          Что-то я смутно представляю, как это тебе поможет. Давай я набросаю идею, а ты посмотри, что из этого будет полезным.
          Обычно в случаях, когда легаси-коду требуется передать метода класса, коллбэком делают всё-таки свободную функцию. Или статический метод, их сигнатуры от this не зависят и в общем-то совместимы со свободными функциями. При этом this как-то куда-то передают на сохранение, чтобы в этой свободной функции его достать и использовать по назначению - вызвать с ним требуемый его метод. Способов много. Например, в WinAPI у подавляющего большинства коллбэков в параметрах обязательно предусмотрен некий void*, каковой самим WinAPI не используется и просто передаётся из точки API-вызова в коллбэк. Например (для большей ясности определения чуть изменены):
          ExpandedWrap disabled
            BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
            typedef BOOL (*WNDENUMPROC)(HWND hwnd, LPARAM lParam);
          Этот самый lParam и является тем самым пользовательским данным. В него можно запихать, что душе угодно, им может быть указатель на структурку с передаваемыми в коллбэк параметрами и в частности this. Я предлагаю тебе использовать что-то вроде этого. Беда в том, что в pcap_handler нет пользовательских параметров, как я погляжу. Но ничего, его можно замешать в имеющиеся. Правда, все эти касты... будь они неладны. Вот наколеночное, я его не тестил, хоть и относительно, но-таки более-менее безопасное, решение. Используется RTTI для контроля в run-time:
          ExpandedWrap disabled
            struct in_addr_proxy
            {
              struct in_addr* search_ip;
              LocalMacAdd*    it_is_this;
             
                       in_addr_proxy(struct in_addr* ip, LocalMacAdd* obj): search_ip(ip), it_is_this(obj) {}
              operator in_addr*     () const                                                               { return search_ip; }
              virtual ~in_addr_proxy()                                                                     {}
            };
             
            void find_eth_addr_proxy(struct in_addr *search_ip, const struct pcap_pkthdr* pkthdr, const u_char *packet)
            {
              in_addr_proxy *restored = (in_addr_proxy *)((char*)search_ip - offsetof(in_addr_proxy, search_ip));
             
              if (typeid(*restored) != typeid(in_addr_proxy)) throw std::invalid_argument("find_eth_addr_proxy(): 1st param hasn't the in_addr_proxy type");
              restored->it_is_this->find_eth_addr(restored->search_ip, pkthdr, packet);
            }
             
            /* ... */
             
            pcap_loop(descr, -1, find_eth_addr_proxy, (u_char*)(in_addr*)&(in_addr_proxy(&search_ip, this)));


          P.S. Могут присутствовать даже опечатки.
          Сообщение отредактировано: Qraizer -
            Цитата Qraizer @
            Что-то я смутно представляю, как это тебе поможет. Давай я набросаю идею, а ты посмотри, что из этого будет полезным.
            Обычно в случаях, когда легаси-коду требуется передать метода класса, коллбэком делают всё-таки свободную функцию. Или статический метод, их сигнатуры от this не зависят и в общем-то совместимы со свободными функциями. При этом this как-то куда-то передают на сохранение, чтобы в этой свободной функции его достать и использовать по назначению - вызвать с ним требуемый его метод. Способов много. Например, в WinAPI у подавляющего большинства коллбэков в параметрах обязательно предусмотрен некий void*, каковой самим WinAPI не используется и просто передаётся из точки API-вызова в коллбэк. Например (для большей ясности определения чуть изменены):
            ExpandedWrap disabled
              BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
              typedef BOOL (*WNDENUMPROC)(HWND hwnd, LPARAM lParam);
            Этот самый lParam и является тем самым пользовательским данным. В него можно запихать, что душе угодно, им может быть указатель на структурку с передаваемыми в коллбэк параметрами и в частности this. Я предлагаю тебе использовать что-то вроде этого. Беда в том, что в pcap_handler нет пользовательских параметров, как я погляжу. Но ничего, его можно замешать в имеющиеся. Правда, все эти касты... будь они неладны. Вот наколеночное, я его не тестил, хоть и относительно, но-таки более-менее безопасное, решение. Используется RTTI для контроля в run-time:
            ExpandedWrap disabled
              struct in_addr_proxy
              {
                struct in_addr* search_ip;
                LocalMacAdd*    it_is_this;
               
                         in_addr_proxy(struct in_addr* ip, LocalMacAdd* obj): search_ip(ip), it_is_this(obj) {}
                operator in_addr*     () const                                                               { return search_ip; }
                virtual ~in_addr_proxy()                                                                     {}
              };
               
              void find_eth_addr_proxy(struct in_addr *search_ip, const struct pcap_pkthdr* pkthdr, const u_char *packet)
              {
                in_addr_proxy *restored = (in_addr_proxy *)((char*)search_ip - offsetof(in_addr_proxy, search_ip));
               
                if (typeid(*restored) != typeid(in_addr_proxy)) throw std::invalid_argument("find_eth_addr_proxy(): 1st param hasn't the in_addr_proxy type");
                restored->it_is_this->find_eth_addr(restored->search_ip, pkthdr, packet);
              }
               
              /* ... */
               
              pcap_loop(descr, -1, find_eth_addr_proxy, (u_char*)(in_addr*)&(in_addr_proxy(&search_ip, this)));


            P.S. Могут присутствовать даже опечатки.

            Спасибо за ответ, но я уже просто напросто для этого решения исключил класс, WinAPI не подойдет так как платформа Ubuntu 10.04. Запустил твое решение, просто без дебага выдало следующие ошибки, возможно наследникам пригодится :)
            ExpandedWrap disabled
              root@ubuntu:/home/administrator/Desktop/projectM# g++ -o main main.cpp basic_info.cpp local_mac.cpp -lpcap
              local_mac.cpp: In function ‘void find_eth_addr_proxy(in_addr*, const pcap_pkthdr*, const u_char*)’:
              local_mac.cpp:38: warning: invalid access to non-static data member ‘in_addr_proxy::search_ip’  of NULL object
              local_mac.cpp:38: warning: (perhaps the ‘offsetof’ macro was used incorrectly)
              local_mac.cpp:40: error: ‘invalid_argument’ was not declared in this scope
              local_mac.cpp:15: error: ‘void LocalMacAdd::find_eth_addr(in_addr*, const pcap_pkthdr*, const u_char*)’ is private
              local_mac.cpp:41: error: within this context
              local_mac.cpp: In member function ‘int LocalMacAdd::GetAddres()’:
              local_mac.cpp:87: error: invalid use of member (did  you forget the ‘&’ )

            Спасибо за быстрый ответ :good:
              Похоже, очередной раз идейный код был тупо использован в качестве готового решения. А подумать?
              Я ж говорил, что WinAPI тут для примера. Просто демонстрация дизайна кода, как обычно дружатся объекты с простым структурным API. Что касается остального... построчно:
              1. ...
              2. ...
              3. Это понятно. Многие реализации offsetof этим грешат. Хотя формально написать его так, чтобы не привлекать NULL-поинтеры, не проблема, авторы многих <cstddef> ленятся...
              4. ...Исправить это можно, написав собственный его аналог. Это несложно.
              5. Это понятно. #include <stdexcept>. Кроме того, это ж просто обработка ошибки, которой быть не должно, ибо это означает крупную лажу в коде. Исключения в таких случаях вполне уместны, однако у тебя может быть другое мнение, обрабатывай на своё усмотрение.
              6. Ну не зря же у меня struct. Во-первых, тесно связанная с LocalMacAdd свободная функция вполне может быть и другом, ...
              7. ...во-вторых, статические методы я тоже упоминал.
              8. ...
              9. Не вижу причины. Вероятно следовало уточнить &this->search_ip.
              Сообщение отредактировано: Qraizer -
                Цитата Qraizer @
                Похоже, очередной раз идейный код был тупо использован в качестве готового решения. А подумать?
                Я ж говорил, что WinAPI тут для примера. Просто демонстрация дизайна кода, как обычно дружатся объекты с простым структурным API. Что касается остального... построчно:
                1. ...
                2. ...
                3. Это понятно. Многие реализации offsetof этим грешат. Хотя формально написать его так, чтобы не привлекать NULL-поинтеры, не проблема, авторы многих <cstddef> ленятся...
                4. ...Исправить это можно, написав собственный его аналог. Это несложно.
                5. Это понятно. #include <stdexcept>. Кроме того, это ж просто обработка ошибки, которой быть не должно, ибо это означает крупную лажу в коде. Исключения в таких случаях вполне уместны, однако у тебя может быть другое мнение, обрабатывай на своё усмотрение.
                6. Ну не зря же у меня struct. Во-первых, тесно связанная с LocalMacAdd свободная функция вполне может быть и другом, ...
                7. ...во-вторых, статические методы я тоже упоминал.
                8. ...
                9. Не вижу причины. Вероятно следовало уточнить &this->search_ip.

                Друг, подумать всегда полезно но мне нужно завтра уже сдавать :)
                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                0 пользователей:


                Рейтинг@Mail.ru
                [ Script execution time: 0,0649 ]   [ 16 queries used ]   [ Generated: 20.11.25, 07:55 GMT ]