http + recv + return 0
От: ryglman  
Дата: 27.10.07 20:25
Оценка:
Есть web-сервер, конкретно apache2.2.6, есть клиентское приложение шлет HTTP 1.1
POST запрос, с флагом Connnection: Close, сервер отвечает, и закрывает соеденение.
Проблема в том что клинтское приложение получает ответ, вызовом блокирующей функции recv,
recv(sock, pool, POOL_SIZE, 0), буфер pool заполняется, но функкция возращает 0,
хотя может возращать -1 или же число записанных байт.
Вроде бы все выглядит логично, но если этот самый pool не заполнен нулями, а скажем заполнен cc(опкод инструкции int3, или же другой опкод напртимер неверная инструкция) в отладочных целях, то обработка полученного буфера как строки привеет к переполнению буфера.
Не использовать отладочные примочки не хорошо, и заполнять 0, тоже не красиво, что делать, как сделать это красиво?
Re: http + recv + return 0
От: The Lex Украина  
Дата: 27.10.07 20:32
Оценка:
Здравствуйте, ryglman, Вы писали:

R>Не использовать отладочные примочки не хорошо, и заполнять 0, тоже не красиво, что делать, как сделать это красиво?


А разве "заполнить буфер нулями" — это не "стандартный принцип работы с буфером"?
Голь на выдумку хитра, однако...
Re[2]: http + recv + return 0
От: ryglman  
Дата: 27.10.07 20:49
Оценка:
Здравствуйте, The Lex, Вы писали:

TL>А разве "заполнить буфер нулями" — это не "стандартный принцип работы с буфером"?


Приятнее было бы, выставить в ноль последний байт имеющий смысл что-то типа *pool[length] = '\0' и не трогать остальное простанство буфера, дело в том что далее будет очень много работа с тако строкой, а заполненность дальше последнего символа строки, т.е. 0, опкодами для отладки, тот же int3, может помоч отловить выход за границы буфера.
Re[3]: http + recv + return 0
От: Unmanaged Россия ICQ 476611995
Дата: 27.10.07 23:03
Оценка: +1
R>Приятнее было бы, выставить в ноль последний байт имеющий смысл что-то типа *pool[length] = '\0' и не трогать остальное простанство буфера, дело в том что далее будет очень много работа с тако строкой, а заполненность дальше последнего символа строки, т.е. 0, опкодами для отладки, тот же int3, может помоч отловить выход за границы буфера.

Чтобы получить кол-во прочитанных байт в вашем случае необходимо и достаточно читать данные побайтово — recv(..., ..., 1, ...) — и собирать их в собственный буфер.
Это самый простой вариант, однако при таком подходе не стоит расчитывать на высокую производительность.

Самый правильный вариант заключается в распарсивании HTTP-заголовка ответа сервера.
В частности, необходимо добраться до значения поля Content-Length, выделить необходимое кол-во байт и прочитать их в этот буфер.
Если клиентская система — Windows, тогда можно воспользоваться наиудобнейшей библиотекой WinINet.
STATUS_INVALID_DEVICE_REQUEST
Re: http + recv + return 0
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 28.10.07 06:10
Оценка: +3
Здравствуйте, ryglman, Вы писали:

R>Есть web-сервер, конкретно apache2.2.6, есть клиентское приложение шлет HTTP 1.1

R>POST запрос, с флагом Connnection: Close, сервер отвечает, и закрывает соеденение.
R>Проблема в том что клинтское приложение получает ответ, вызовом блокирующей функции recv,
R>recv(sock, pool, POOL_SIZE, 0), буфер pool заполняется, но функкция возращает 0,
R>хотя может возращать -1 или же число записанных байт.

Извините, но Вы пишете полный бред. Если в стеке нет явного бага (а я очень сомневаюсь, что Вы его нашли) — если recv() вернул ноль, это значит, что соединение закрыто, данных больше не будет и содержимое буфера не имеет никакого значения в принципе.
Если Вы пытаетесь что-то читать из буфера, который был передан в recv() вернувшую 0 — Ваш дизайн программы грубо неверен и это работать не будет.

Если же Вы про ноль написали для красного словца и основная обработка идёт всё же в случае положительного возврата, то:

R>Вроде бы все выглядит логично, но если этот самый pool не заполнен нулями, а скажем заполнен cc(опкод инструкции int3, или же другой опкод напртимер неверная инструкция) в отладочных целях, то обработка полученного буфера как строки привеет к переполнению буфера.


(А при чём тут опкод? Вы что, сразу же пытаетесь исполнять код???)

Вы не имеете в общем случае никакого права обрабатывать данные из сети как "строку" (NUL-terminated, судя по стилю рассказа). Нету у Вас на этом уровне ещё никакой строки, забудьте. (Я уж молчу, что вообще NUL-terminated string — диверсия, за использование которой где-либо кроме одноразовых поделок и интерфейсов к Unix-style ядру надо откручивать голову и прочие выступающие части.) Использовать интерфейс строки с нулём можно только тогда, когда Вы убедились, что в принятых данных нет нигде NUL; в общем для HTTP (для тела ответа) на это полагаться нельзя.

Используйте или строки со счётчиком, или (мне значительно больше нравится такой стиль — с ним удобнее работать) пару указателей на начало обрабатываемой части и на позицию за последним символом.

Если же Вы каким-то святым духом однозначно уверены, что в буфере не будет NUL, и всё же намерены использовать диверсионный API типа strlen(), strcat() и тому подобное — есть простейший приём: буфер заранее готовится на один символ больше чем передаётся в recv(), а если recv() вернула положительное значение как признак того, что что-то приняла — сделать
 buff[got] = '\0'
, где got — значение полученное из recv(). После этого — вытворяйте что хотите, лишь бы хватило места и не наезжали на соседние области (что с такими строками слишком просто сделать).
The God is real, unless declared integer.
Re[2]: http + recv + return 0
От: ryglman  
Дата: 29.10.07 13:58
Оценка:
Здравствуйте, netch80

Вобщем-то вопрос конечно был смешнйо согласен, он решился просто:
/**
* @param line
* @param stop
* @return
* char *
*/
char *getword(const char **line, char stop)
{
const char *pos = *line;
int len;
char *res;

while ((*pos != stop) && *pos) {
++pos;
}
#pragma warning(disable:4244)
len = pos — *line;
#pragma warning(default:4244)
res = (char *)malloc(len + 1);
memcpy(res, *line, len);
res[len] = 0;

if (stop) {
while (*pos == stop) {
++pos;
}
}
*line = pos;

return res;
}

while ((val = getword(&ppool2, '\n')) && strlen(val)) {
if (!strncmp(val, GOOD_TAG, sizeof(GOOD_TAG))) {
status = 1;
break;
}
}

Возник еще один — строка со счетчиком что это такое? Расскажите об этом приеме.
Я так понимаю это примерно такое:
struct string_t{
size_t size;
size_t count;
char data[1];
};
для удобства?
Re[3]: http + recv + return 0
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 02.11.07 19:30
Оценка:
Здравствуйте, ryglman, Вы писали:

R>Здравствуйте, netch80


R>Вобщем-то вопрос конечно был смешнйо согласен, он решился просто:


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

R>Возник еще один — строка со счетчиком что это такое? Расскажите об этом приеме.

R>Я так понимаю это примерно такое:
R>struct string_t{
R> size_t size;
R> size_t count;
R> char data[1];
R>};
R>для удобства?

Ну примерно да, хотя я бы не использовал стиль с переменной длиной всей области со структурой в начале. Использовать отдельный указатель часто удобнее, к тому же тогда содержание строки можно, если не меняется, разделять между разными объектами. И главное даже не в этом, а в API. В случае C++ это std::string со всеми её методами.
The God is real, unless declared integer.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.