Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > C/C++: Сетевое программирование > sendto


Автор: Columbo 21.04.15, 17:14
Уважаемые форумчане, подскажите пожалуйста кто сталкивался с такой проблемой или хотя бы в каком месте копать.
Суть проблемы такова. Пытаюсь выдавать ICMP пакеты. Написал класс, использующий функции библиотеки winsock2.h.
Сам метод класса не стал пока выкладывать. Дело в том, ошибку возвращает функция sendto, в том случае, если
раскомментировать закоментированные строчки кода. Т.е. если я пытаюсь отдать ей данные, веденные с формы.
Как это связано я просто не могу понять. Среда C++Builder5. Думал может старый компилятор. Поставил Borland2007,
перекинул исходники класса, ничего не меняя. Создал такую же форму с Edit и кнопочками, в общем повторил интерфейс
полностью. И все заработало! Ну я подумал, проблема решена, но сегодня опять столкнулся с ошибкой функции sendto
и опять по непонятной причине, но теперь уже ошибку вызывает объект Label на форме. Если он обновляется, то функция
выдает ошибку, если его не трогать, то не выдает. Ошибку выдает 10013 - это в Borland2007 в пятом не помню, возможно такая же.
Компилировал на другом компе - сначала не выдавал ошибку, потом что то на форме добавил - стал выдавать.
Короче полная для меня неясность, если кто в курсе просветите!

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ButtonClick(TObject *Sender)
    {
     tICMP ICMP1;                        
     unsigned char DataOut[512];
     
    // unsigned char d = StrToInt(EditDataOut->Text);
     
     for (int i=0; i<100; i++)
        {
         DataOut[i] = 0x55;
    //     DataOut[i] = d;
        }
     
     AnsiString Res = ICMP1.SendData("192.168.1.1", DataOut, 100);
     if (Res != "OK")
        {
         ShowMessage(Res);
         return;
        }
    }
    //-----------------------------------------------------------------


Добавлено
Еще кое что вспомнил! Ошибка вылетает даже если раскоментировать только верхнюю строчку, т.е. где объявляется переменная char и ей присваивается
значение из объекта Edit. Таким образом связь этих двух событий вообще становится непонятной..

Автор: Pacific 21.04.15, 19:56
Columbo
Цитата
WSAEACCES
10013 (0x271D)
An attempt was made to access a socket in a way forbidden by its access permissions.

Файрволл, антивирус случайно не блокируют твою программу? Какой-нибудь новый софт недавно устанавливал?

Автор: ЫукпШ 21.04.15, 20:46
Цитата Columbo @
Еще кое что вспомнил! Ошибка вылетает даже если раскоментировать только верхнюю строчку, т.е. где объявляется переменная char и ей присваивается
значение из объекта Edit.

Практически сразу возникает вопрос - а что будет, если:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ButtonClick(TObject *Sender)
    {
     tICMP ICMP1;                        
     unsigned char DataOut[512];
     
    // unsigned char d = StrToInt(EditDataOut->Text);
     
       unsigned char d = 0x55;
       for (int i=0; i<100; i++) { DataOut[i] = d; }
     
        AnsiString Res = ICMP1.SendData("192.168.1.1", DataOut, 100);
        if (Res != "OK")
        {
         ShowMessage(Res);
         return;
        }
    }
    //---------------------------------------------------------------------------

Сомнительно выглядит возврат функции строкой.
Достаточно вернуть NO_ERROR (=0), но это дело вкуса.

Автор: nemez 22.04.15, 05:30
Как всегда, форум не программистов, в экстрасенсов. Автор, где тобой написанный класс для ицмп?
Примеров в сети два вагона, не пойму в чем проблема взять готовое
http://tangentsoft.net/wskfaq/examples/dllping.html
?

Автор: Columbo 22.04.15, 17:36
Спасибо за участие, коллеги!
Итак начну отвечать в режиме LIFO:
Цитата nemez @
Автор, где тобой написанный класс для ицмп?
Примеров в сети два вагона, не пойму в чем проблема взять готовое
http://tangentsoft.net/wskfaq/examples/dllping.html
?

Дело в том, что я хочу использовать ICMP пакеты для обмена данными, а в библиотеке ICMP.dll функция SendEchoRequest кажется ждет ответа без искажения данных, т.е. что послал - то и принял. А мне надо послал одно - принял что то другое.
Вот метод класса:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    AnsiString tICMP::SendData(char* ip_addres, unsigned char* OutBuf, size_t num)
    {
     sockAddrLocal.sin_addr.S_un.S_addr = inet_addr(ip_addres);
     sockAddrLocal.sin_family = AF_INET;
     
     pIcmpHeader = (struct icmp *) IcmpSendPacket;   // Point at the data area
     pIcmpHeader->icmp_type = ICMP_ECHO;             // then fill in the data.
     pIcmpHeader->icmp_code = 0;                     // Use the Sockman instance
     pIcmpHeader->icmp_id = hInstance;               // handle as a unique ID.
     pIcmpHeader->icmp_seq = 0;                      // It's important to reset
     pIcmpHeader->icmp_cksum = 0;                    // the checksum to zero.
     
     iPacketSize = ICMP_HEADERSIZE + num;
     
     for (size_t i=ICMP_HEADERSIZE, j=0; j<num; i++, j++)
        {
         IcmpSendPacket[i] = OutBuf[j];
        }
     
     pIcmpHeader->icmp_cksum = InternetChksum((LPWORD)pIcmpHeader, iPacketSize);
     
     if (pIcmpHeader->icmp_cksum !=0 )
        {
         iSentBytes = sendto(hSocket, (LPSTR) IcmpSendPacket, iPacketSize,
         NO_FLAGS, (LPSOCKADDR) &sockAddrLocal, sizeof(sockAddrLocal));
         if (iSentBytes == SOCKET_ERROR)
            {
             int err = WSAGetLastError();
             return "Error.\r\nThe sendto() function returned a socket error: " + IntToStr(err);
            }
     
         if (iSentBytes != iPacketSize)
            {
             return "Error.\r\nWrong number of bytes sent: " + IntToStr(iSentBytes);
            }
        }
     
     return "OK";
    }


Повторюсь еще раз, программа работает, если не используется объект Edit, при этом не важно что записывается в массив: константа или переменная.
Как строка из Edit влияет на функцию sendto - для меня тайна покрытая мраком.
На другом компиляторе программа заработала и с Edit, но потом начала глючить при использовании объекта Label, причем зависит от того какая
строка выводится на экран.

Добавлено
Цитата ЫукпШ @

Сомнительно выглядит возврат функции строкой


Ну просто так удобнее выводить на экран и придумывать коды не надо.
По поводу Вашего примера реализации - будет работать, Edit же не используется.

Добавлено
Цитата Pacific @
Файрволл, антивирус случайно не блокируют твою программу? Какой-нибудь новый софт недавно устанавливал?

Нет ничего такого не делал. Опять повторюсь - пакеты высылаются, но при определенных обстоятельствах возникает облом.

Автор: ЫукпШ 22.04.15, 17:42
Есть ли уверенность, что размер (массива ?)"IcmpSendPacket"
действительно не меньше "iPacketSize = ICMP_HEADERSIZE + num" ?

Автор: Oleg2004 22.04.15, 17:43
Кстати такой вопрос.
Вы испытываете свой проект в режиме дебага или делаете автономный экзешник (релиз)?

Автор: Columbo 22.04.15, 17:49
Он значительно больше - 1024 байта. Но будь он меньше, как бы это объясняло данную проблему? В массив кладутся байты, какая разница откуда они берутся?

Автор: Columbo 22.04.15, 17:50
Oleg2004 в режиме дебага

Автор: ЫукпШ 22.04.15, 17:57
Цитата Columbo @
Он значительно больше - 1024 байта. Но будь он меньше, как бы это объясняло данную проблему? В массив кладутся байты, какая разница откуда они берутся?

Если бы он был меньше, то в этом цикле
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
    for (size_t i=ICMP_HEADERSIZE, j=0; j<num; i++, j++)  { IcmpSendPacket[i] = OutBuf[j]; }

будет выход за границы массива. С любыми последствиями.

Автор: Oleg2004 22.04.15, 18:01
Цитата Columbo @
в режиме дебага

Сетевые приложения так не отлаживаются.
Режим дебага зачастую - практически во всех средах разработки - достаточно трудно работает со стеком TCP/IP.
Это вам не поиск в базе данных отлаживать.
Потому я всегда требую от студентов делать релиз. Практика показала глючность режима дебага для сетевых приложений.

Автор: Columbo 22.04.15, 18:01
ЫукпШ это понятно... но тогда бы выход за пределы был всегда и почти всегда приводил бы к краху программы с соответствующими сообщениями. А тут ошибку возвращает функция, ничего не рушится, а если не использовать компонент Edit, то вообще все ок...

Добавлено
Oleg2004 Ваше замечание мне кажется наиболее точно объясняет такое поведение. Обязательно проверю это!

Автор: Oleg2004 22.04.15, 18:04
Цитата Columbo @
ничего не рушится, а если не использовать компонент Edit, то вообще все ок...

Во во... плавающий глюк вполне может быть именно в дебаге.

Автор: ЫукпШ 22.04.15, 18:15
Цитата Columbo @
ЫукпШ это понятно... но тогда бы выход за пределы был всегда и почти всегда приводил бы к краху программы с соответствующими сообщениями.

Нет. Это как повезёт.
Поведение приложения типа "что-то глючит" как раз хорошо подходит
под гипотезу о выходе за пределы массива.

Автор: Columbo 22.04.15, 18:35
Итак...
На всякий случай увеличил размер массива до 2 кб, а потом до 4 - программа стала просто зависать при отправке.
Сделал релиз - вываливает ту же ошибку.
Переписал exe-шники в одельную папку (до этого запускал просто из билдера): релиз, релиз с библиотеками, дебаг - все программы зависают на передаче.

Раскоментировал закоментированное в следующем коде:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    AnsiString tICMP::Startup()
    {
     WSAStartup(0x0101, &wsaData);
     
     sockAddrHost.sin_family = AF_INET;
     sockAddrHost.sin_port = htons(0);
     sockAddrHost.sin_addr.s_addr = 0;
     
     if ((lpProtocolEntry = getprotobyname("icmp")) == NULL)
        {
         nProtocol = IPPROTO_ICMP;
        }
     else
        {
         nProtocol = lpProtocolEntry->p_proto;
        }
     
     if ((hSocket = socket(PF_INET, SOCK_RAW, nProtocol)) == INVALID_SOCKET)
        {
         return "Error.\r\nCould not create a RAW socket.";
        }
     
    /*
     int err = bind(hSocket, (sockaddr*)&sockAddrHost, sizeof(struct sockaddr_in));
     if(err == SOCKET_ERROR)
        {
         closesocket(hSocket);
         return "Error in bind(): " + IntToStr(err);
        }
     
     const char a = 1;
     if (setsockopt(hSocket, SOL_SOCKET, SO_BROADCAST, &a, 1) == SOCKET_ERROR)
        {
         closesocket(hSocket);
         return "Error in setsockopt";
        }
    */
     
     return "OK";
    }


Ошибка перестала вываливаться программа стала передавать, ну и принимать естественно данные веденные с формы.
Другая программа с похожими симптомами тоже перестала вываливать ошибку. Вот только меня терзают сомнения, что
я уже это делал раньше. И почему биндинг сокета при использовании компонента Edit нужен, а без использования не нужен остается для меня загадкой.
Какая разница откуда берутся данные? Причем тут броадкаст тоже не понятно, хотя я где то читал что для RAW сокетов эта опция нужна.
В любом случае как говорится "будем посмотреть!" Завтра проверю на работе.

Автор: Oleg2004 22.04.15, 19:40
Цитата Columbo @
Переписал exe-шники в одельную папку (до этого запускал просто из билдера): релиз, релиз с библиотеками, дебаг - все программы зависают на передаче.

Стабильность ошибки позволяет надеяться на ее локализацию. :)
Цитата Columbo @
Причем тут броадкаст тоже не понятно, хотя я где то читал что для RAW сокетов эта опция нужна.

Нет. Эта опция совершенно не нужна. Зачем?

Автор: ЫукпШ 22.04.15, 19:40
Columbo, попробуй так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ...
    int err = bind(hSocket, (sockaddr*)&sockAddrHost, sizeof(sockAddrHost));
    ...

Автор: Oleg2004 22.04.15, 20:00
Нашел где то в кодах такую идею:
sendto(s, buf, sizeof(ICMP_HDR)+32, 0, (SOCKADDR *)&dest, sizeof(dest));

Автор: nemez 23.04.15, 13:36
Цитата Columbo @
Вот метод класса:

ну, господа туманные ежи..
Мы работаем с raw sockets. Это автоматически обозначает, что мы должны формировать заголовок ip, потом все остальное

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ipheader = (struct ip_header*)packet;
    icmp = (struct icmp_echo*)(packet+sizeof(struct ip_header));

ну и далее,
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ipheader->ver       = 4;    /*IPv4*/
    ipheader->hl        = 5;    /* This is the smallest possible value, our IP header is only 20 bytes */
    ipheader->tos       = 0;
    ipheader->totl      = sizeof(struct ip_header)+sizeof(struct icmp_echo);

и понеслась по кочкам метла, в свою очередь,
Цитата
icmp->type = 8; /* icmp echo */
icmp->code = 0; /* only valid value for echo or echo reply */
icmp->identifier = 0x1337;
icmp->sequence = ...

ну и естественно, заполнить датой и посчитать чексумму, и будет полный порядок.
Ро Сокет не знает в твоей ситуации, куда и что там нужно отправлять. Ты ему даешь охинею из байтов, от которой у винды несварение даты.
Возьми нормальный базовый пример и исходя из него, строй приложение.

Добавлено
вот пример icmp под мелкософт если чо
http://www.vijaymukhi.com/security/network/rawsockets.htm
попробуй сначала собери консольную аппликацию под студией или своим древним как говно мамонта борландом, потом переходи к формам-кнопкам, иначе будешь неделю какать кирпичами и соберешь на форуме вокруг себя толпу телепатов (что уже сделано)

Автор: Columbo 23.04.15, 19:39
nemez а я думал ip заголовок формируется автоматически... Ну если это не так, почему все же удается посылать и принимать пакеты, ну за исключением описаных мною ситуаций, когда функция возвращает ошибку?

Добавлено
ЫукпШ, Oleg2004 не помогло..
На другом компе фокус с биндингом и броадкастом не удался.. еще хуже стало - просто зависает программа.

Автор: ЫукпШ 23.04.15, 19:45
Цитата Columbo @
ЫукпШ, Oleg2004 не помогло..
На другом компе фокус с биндингом и броадкастом не удался.. еще хуже стало - просто зависает программа.

Где-то выход за границы массива или портится стек. Или вместе.
Это может быть где угодно в программе, а проявиться именно в этом месте.
Легче начать другой проект сначала и по-проще - какой-нибудь консольный
вариант исключительно для отладки класса.
И двигаться мелкими шажками.

Автор: Columbo 23.04.15, 19:55
ЫукпШ Вот я убрал из прогаммы обновление Label->Caption, точнее даже не убрал а просто убрал пару строк оттуда и прекрасно обменивался пакетами без ошибок. И какова вероятность того что в консольном варианте, где нет ничего лишнего все будет работать? Я думаю 100%. Так куда двигаться в такой ситуации?
Попробую как рекомендует nemez сделать, только вот как можно на другой стороне принять мой пакет причем с анализом контрольной суммы и размер наверняка учитывается а айпи заголовке, если я его не формирую мне также не понятно... а он тем временем принимается без ошибок.

Автор: Oleg2004 23.04.15, 19:58
Цитата Columbo @
nemez а я думал ip заголовок формируется автоматически...

Так оно и есть, если не применяется опция IP_HDRINCL. :yes:
А идеологически я согласен с ЫукпШ

Автор: Columbo 23.04.15, 20:03
Oleg2004 я уже понял

Автор: Columbo 23.04.15, 20:06
nemez я не нашел где формируется заголовок айпи в коде по твоей ссылке..
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    main(int argc, char **argv)
     
    {
     
    d = WSAStartup (MAKEWORD(2,1),&ws);
     
    printf("WSAStartup Return Value=%d\n",d);
     
    s = WSASocket(AF_INET,SOCK_RAW, IPPROTO_ICMP ,NULL, 0,0);
     
    printf("Socket Return Value=%d\n",s);
     
    hp = gethostbyname(argv[1]);
     
    memcpy(&dest.sin_addr,hp->h_addr,hp->h_length);
     
    dest.sin_family = hp->h_addrtype;
     
    printf("hp=%x Ip Address=%s\n",hp,inet_ntoa(dest.sin_addr));
     
    pIcmpHeader = (IcmpHeader *) malloc(sizeof(IcmpHeader));
     
    pIcmpHeader->i_type = 8;
     
    pIcmpHeader->i_code = 0;
     
    pIcmpHeader->i_id = (USHORT)GetCurrentProcessId();
     
    pIcmpHeader->i_cksum = 0;
     
    pIcmpHeader->i_seq = 326;
     
    memset(pIcmpHeader->data ,'A', 32);
     
    pIcmpHeader->timestamp = GetTickCount();
     
    pIcmpHeader->i_cksum = checksum((USHORT *)pIcmpHeader,sizeof(IcmpHeader));
     
    d = sendto(s,(char *)pIcmpHeader,sizeof(IcmpHeader),0,(struct sockaddr*)&dest,sizeof(dest));
     
    printf("Sentto return value=%d\n",d);
     
    dummy = sizeof(dest);
     
    d = recvfrom(s ,databuf,1024,0,(struct sockaddr*)&dest,&dummy);
     
    printf("recvfrom return value=%d\n",d);
     
    pIpHeader = (struct IpHeader *)databuf;
     
    printf("len=%x TOS=%d Total length %d %d\n",pIpHeader->lenver,pIpHeader->tos,pIpHeader->totallen , htons(pIpHeader->totallen));
     
    printf("ident=%d Frag=%d TTL=%d Protocol=%d\n",pIpHeader->ident,
     
    pIpHeader->fragandflags,pIpHeader->ttl,pIpHeader->proto);
     
    printf("CheckSum=%d %d\n",pIpHeader->checksum , checksum((USHORT *)databuf,20+32+12));
     
    printf("Source IP=%s Dest Ip=%s\n",inet_ntoa(pIpHeader->sourceIP),inet_ntoa(pIpHeader->destIP));
     
    printf("dest=%s\n",inet_ntoa(dest.sin_addr));
     
    int size = pIpHeader->lenver & 0x0f;
     
    size = size * 4;
     
    size = size - 20;
     
    printf("Size of IP headers %d\n",size);
     
    if ( size > 0)
     
    {
     
    struct ipopt *pipopt;
     
    pipopt = (struct ipopt *)(databuf + 20);
     
    printf("code=%d len=%d ptr=%d\n",pipopt->code,pipopt->len,pipopt->ptr);
     
    int noofstr;
     
    noofstr = (pipopt->ptr/4) - 1;
     
    printf("No of addr's=%d\n",noofstr);
     
    for ( i = 0 ; i < noofstr ; i++)
     
    {
     
    struct in_addr a;
     
    a.S_un.S_addr = pipopt->addr[i];
     
    printf("%s\n",inet_ntoa(a));
     
    }
     
    }
     
    }


структура заголовка заполняется уже после принятия пакета, это другая история, а перед отправкой - нет.

Автор: ЫукпШ 23.04.15, 20:31
Цитата Columbo @
ЫукпШ Вот я убрал из прогаммы обновление Label->Caption, точнее даже не убрал а просто убрал пару строк оттуда и прекрасно обменивался пакетами без ошибок.

Размеры программы изменились, возможно изменилось расположение кодов относительно данных.
По прежнему что-то портится, только в другом месте и в этой точке приложения не проявляется.

Автор: nemez 23.04.15, 21:05
Цитата Columbo @
nemez я не нашел где формируется заголовок айпи в коде по твоей ссылке..

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ipopt.code = 7;
    ipopt.ptr  = 4;
    ipopt.len  = 39;
    setsockopt (s, IPPROTO_IP, IP_OPTIONS,(char *)&ipopt, sizeof(ipopt));
    .....


вот тебе пдфочка
http://www.beknowledge.com/wp-content/uplo...2010/09/892.pdf
см. поиском функцию (<Ctrl-f>)
void DecodeIPOptions(char *buf, int bytes)
Через структуру (struct ipopt в том исходнике что ты смотрел) через setsockopt передаются параметры заголовка ip.

зы. Собери консольный пинг с примера рабочий, это тебе облегчит задачу

Автор: Columbo 23.04.15, 21:14
пошел собирать...

Автор: Kozlov_Sergey 26.09.15, 02:03
Предлагаю вместо
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    unsigned char d = StrToInt(EditDataOut->Text);


<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    unsigned int d = StrToInt(EditDataOut->Text);

Автор: comerc 19.10.15, 11:37
Цитата Columbo @
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ButtonClick(TObject *Sender)
    {
     tICMP ICMP1;                        
     unsigned char DataOut[512];
     
    // unsigned char d = StrToInt(EditDataOut->Text);
     
     for (int i=0; i<100; i++)
        {
         DataOut[i] = 0x55;
    //     DataOut[i] = d;
        }
     
     AnsiString Res = ICMP1.SendData("192.168.1.1", DataOut, 100);
     if (Res != "OK")
        {
         ShowMessage(Res);
         return;
        }
    }
    //-----------------------------------------------------------------

Что за говнокод?
Сплошной хардкодинг.
Это неприемлемо в коммерческом коде, отсюда ошибки.

Автор: Columbo 31.10.15, 15:50
Это не дает ответа на мой вопрос

Автор: Kozlov_Sergey 07.12.15, 06:54
Думаю, что
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    (EditDataOut == NULL)

Автор: azyz1998 13.12.15, 19:42
Очень интересно)

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)