Итак, есть С++ прога, которую хочется запустить как CGI.
Кусок кода:
-----------------
namespace MagickLib //Загоняем инклюд в нэймспейс
{
#include <wand/MagickWand.h>
}
#include <cstring>using namespace MagickLib; //Используем пространство имён инклюда
std::string filePath="sample.gif"; // Исходный файл.
MagickWandGenesis(); // Инициализация ImageMagick
MagickWand *sourceImages, *coalescedImages, *resImages;
sourceImages = NewMagickWand(); // Инициализация структуры
coalescedImages = NewMagickWand();
resImages = NewMagickWand();
MagickBooleanType status;
status=MagickReadImage(sourceImages, filePath.c_str()); // Чтение картинки в структуру
if(status==MagickFalse) Warning("Error. Can't read image", 1); //Страховка
coalescedImages = MagickCoalesceImages(sourceImages); // Всяческие преобразования картинки
int i=0;
MagickBooleanType whileFlag = MagickTrue;
PixelWand *textColor; // Структура-цвет
textColor=NewPixelWand();
PixelSetRed(textColor, 1); // Делаем цвет рисования красным
DrawingWand *drawString;
drawString=NewDrawingWand();
DrawSetStrokeColor(drawString, textColor);
DrawSetFillColor(drawString, textColor);
DrawAnnotation(drawString, 5, 50, (const unsigned char*)("Test - Тест"));
while(whileFlag){ // Рисуем на всех кадрах GIF-анимации
MagickDrawImage(coalescedImages, drawString);
whileFlag=MagickNextImage(coalescedImages);
i++;
}
std::cout << "Content-type: text/html\r\n\r\n";
unsigned char *out;
size_t *outLength;
std::cout<<"Before write function - all is okay!\n";
std::fflush(stdout); //Выбрасываем буфер на "экран"
std::freopen("stdout.txt", "w", stdout); // Перенаправляем в файл
std::freopen("stderr.txt", "w", stderr);
out = MagickGetImageBlob(coalescedImages,outLength); // На этой строке выход без сообщений и ошибок.
std::cout<<"After write function - all is okay!\n"; // Сюда в CGI уже не попадаем.
std::fflush(stdout);
std::fflush(stderr);
MagickWandTerminus();
-----------------Компилятор g++ не ругается, прога из под консоли запускается и успешно работает. НО в режиме CGI не работает. Заголовки выводит - всё как надо. Но как доходит до строчки MagickGetImageBlob(...) - процесс завершается. Причём нет следов ни в логах ни в стандартном выводе (который я уже от отчаянья перенаправил в файлы). Если строчку MagickGetImageBlob(...) закомментировать - прога запускается даже как CGI и работает до конца.
Процесс лист во время исполнения CGI выглядит примерно так:
PID TT STAT TIME COMMAND
4223 ?? SN 0:00,06 sshd: u51990@ttyp0 (sshd)
45775 ?? S 0:00,04 /usr/local/apache-php5/bin/suexec u51990 u51990 cgi line
45778 ?? R 0:00,01 line
4227 p0 SNs 0:00,05 -bash (bash)
45880 p0 RN+ 0:00,00 ps axКОРОТКО: чем так отличается запуск приложения как CGI, что одна конкретная строчка вылетает прогу без ошибок?
>Итак, есть С++ прога, которую хочется запустить как CGI.
>Кусок кода:
>
>КОРОТКО: чем так отличается запуск приложения как CGI, что одна конкретная строчка
>вылетает прогу без ошибок?ну если коротко, то в СГИ нет терминала, поскольку все выплняется из под демона.
собственно говоря, пожалуй это единственное отличие.
на сколько я понял эта функциф преобразует имидж в строку байтов, сама выделяя под ее память? ну вообще говоря в проге ее тогда нужно будет потом осовбодить.ну еще размер буфера устанавливается длиной в 1 символ.
фиг знает из за чего может вылетать. А что это за библиотека? урл есть?
>[оверквотинг удален]
>под демона.
>собственно говоря, пожалуй это единственное отличие.
>на сколько я понял эта функциф преобразует имидж в строку байтов, сама
>выделяя под ее память? ну вообще говоря в проге ее тогда
>нужно будет потом осовбодить.
>
>ну еще размер буфера устанавливается длиной в 1 символ.
>
>фиг знает из за чего может вылетать. А что это за библиотека?
>урл есть?ха, нашел я эту библиотеку:
смотри
unsigned char *MagickGetImageBlob(MagickWand *wand,size_t *length)
так вот ты неправильно работаешь с длиной!
куда по твоему она запишеться?size_t *outLength;???
определи
size_t outLength; и программу передай ссылку на него.
out = MagickGetImageBlob(coalescedImages,&outLength);хотя конечно можно вызвать
size_t *outLength = malloc(тартата);
и делать дальше как ты делал.и както надо вызвать метод MagickRelinquishMemory, его я не нашел.
>[оверквотинг удален]
>size_t *outLength;???
>определи
>size_t outLength; и программу передай ссылку на него.
>out = MagickGetImageBlob(coalescedImages,&outLength);
>
>хотя конечно можно вызвать
>size_t *outLength = malloc(тартата);
>и делать дальше как ты делал.
>
>и както надо вызвать метод MagickRelinquishMemory, его я не нашел.Спасибо большое за желание помочь, но ошибка не в этом.
Итак, была проблема:
после вызова функции ImageMagick выводящей изображение (в память или в файл - не важно) программа будучи запущена как CGI завершала работу не выводя никаких ошибок и не выполняя поставленной задачи.
Решено было так:
Скачал весь дистрибутив с imagemagick.org , залил на свой виртуальный хостинг. Собрал ImageMagick с ключами --without-x --disable-installed --without-modules. И собирая свой файл слинковывал со СТАТИЧЕСКИМИ библиотеками MagickWand.a и Magick.a . При линковке с ДиНамИЧесКиМи (.so) библиотеками - всё те же симптомы (из под консоли работает, как CGI - нет).
Лучше сразу собирать ImageMagick с ключом --disable-shared , тогда поддержка динамических библиотек уйдёт нах и всё будет пучком.Всем спасибо.
>[оверквотинг удален]
>>size_t outLength; и программу передай ссылку на него.
>>out = MagickGetImageBlob(coalescedImages,&outLength);
>>
>>хотя конечно можно вызвать
>>size_t *outLength = malloc(тартата);
>>и делать дальше как ты делал.
>>
>>и както надо вызвать метод MagickRelinquishMemory, его я не нашел.
>
>Спасибо большое за желание помочь, но ошибка не в этом.ну ошибка то там была :)
>Итак, была проблема:
.
>Лучше сразу собирать ImageMagick с ключом --disable-shared , тогда поддержка динамических библиотек
>уйдёт нах и всё будет пучком.
>дык какая там проблема то? LD_LIBRARY_PATH установить для процесса httpd
что то я сомневаюсь что программа вообще запускалась! хотя у меня была точно такая же проблема когда в с консоли прога работала а из под сервера нет, и именно из за библиотек она не запускалась.не очень здорово все делать статически, сделаешь десяток прог с этой библиотекой, так они тебе в каждую по 10 мегов добавяться. вот будет прикольно!
так что лучше разобраться с динамически загружаемыми библиотекми
>>Спасибо большое за желание помочь, но ошибка не в этом.
>
>ну ошибка то там была :)Ну была, но это так... Я пробовал и так и сяк.
>дык какая там проблема то? LD_LIBRARY_PATH установить для процесса httpd
Это как? Поподробнее плиз.
>что то я сомневаюсь что программа вообще запускалась!
Нормалды ты зарядил. Может у меня галлюцинации, или мне бинарник прислать? >:|
Конкретно тот код что я публиковал, может быть и не запустился бы - как ты понимаешь я его из боооольшой программы вырезал и подгонял под работу независимо от неё. Может какую мелочь и упустил.>хотя у меня была
>точно такая же проблема когда в с консоли прога работала а
>из под сервера нет, и именно из за библиотек она не
>запускалась."Что то я сомневаюсь что программа вообще запускалась! =)"
>не очень здорово все делать статически, сделаешь десяток прог с этой библиотекой,
>так они тебе в каждую по 10 мегов добавяться. вот будет
>прикольно!Ну не 10, а всего-то 4. И прога будет одна но CGI. А вот это ужо плохо - апач запустит столько процессов, сколько клиенты запросят CGIку. Вот тут-то память пожрёт...
>так что лучше разобраться с динамически загружаемыми библиотекми
Согласен. Но уже ВСЁ перепробывал и весь гугл вытряс =)
С одной стороны - http://httpd.apache.org/docs/2.0/mod/mod_env.html
Т.е. убедись что mod_env подключен, и влепи в конфиг:PassEnv LD_LIBRARY_PATH
Это передаст в твой CGI-процесс LD_LIBRARY_PATH c которым ты стартуешь апач (проверь!!! А то вдруг он у тебя chrooted/jailed/VMzied ...)
А вот с другой ..."Suexec has very strict permission checking, and any failure in that checking will result in your CGI programs failing with Premature end of script headers"
Ну и есссно "Unless you fully understand suexec, you should not be using it."Короче suexec - вещь опасная, поэтому при малейшем чихе дожна давать отлуп. Где то там в недрах доки к ней есть строчка что весь evironment перед исполнением кастрируется до safest minimum ... Вобщем - смотри 1) suexec'овые логи и 2) доку на него.
>С одной стороны - http://httpd.apache.org/docs/2.0/mod/mod_env.html
>Т.е. убедись что mod_env подключен, и влепи в конфиг:
>
> PassEnv LD_LIBRARY_PATH
>
>Это передаст в твой CGI-процесс LD_LIBRARY_PATH c которым ты стартуешь апач (проверь!!!
>А то вдруг он у тебя chrooted/jailed/VMzied ...)У меня виртуальный хостинг - сижу в песочнице. Так что могу только .htaccess баловаться.
>А вот с другой ..."Suexec has very strict permission checking, and any
>failure in that checking will result in your CGI programs failing
>with Premature end of script headers"
>Ну и есссно "Unless you fully understand suexec, you should not be
>using it."
>Короче suexec - вещь опасная, поэтому при малейшем чихе дожна давать отлуп.
>Где то там в недрах доки к ней есть строчка что
>весь evironment перед исполнением кастрируется до safest minimum ... Вобщем -
>смотри 1) suexec'овые логи и 2) доку на него.suexec логи не доступны =(
>>>Спасибо большое за желание помочь, но ошибка не в этом.
>>
>>ну ошибка то там была :)
>
>Ну была, но это так... Я пробовал и так и сяк.
>
>>дык какая там проблема то? LD_LIBRARY_PATH установить для процесса httpd
>
>Это как? Поподробнее плиз.man dlopen
>>хотя у меня была
>>точно такая же проблема когда в с консоли прога работала а
>>из под сервера нет, и именно из за библиотек она не
>>запускалась.
>
>"Что то я сомневаюсь что программа вообще запускалась! =)":)))
да заглючила конкретно, главное непонятно было почему, оказалось у нас сервак(не я админ) всегда стартовали в ручную, а тут перезагрузили в автоматическом режиме, и там оказалось что пути по умолчанию пробиты к другим библиотекам(к ораклу их там целых 3 стоит) ну когда рут запускал в его окружении эти пути правились и все работало, а вот с автоматом косяк вышел.
но сама прога запускалась и в лог фигню писала. скорее всего именно из за динамической загрузки библиотек, если бы была статическая то как раз бы не ничего не загрузилось. у тебя наверное то же динамическая загрузка(см опять же dlopen).
В принципе эту переменную я мог бы и из своей проги выставлять :), не додумался сразу.>
>Ну не 10, а всего-то 4. И прога будет одна но CGI.
>А вот это ужо плохо - апач запустит столько процессов, сколько
>клиенты запросят CGIку. Вот тут-то память пожрёт...да мне тоже эта мысль пришла. а динамическая библиотека нескольких процессов отображается во все и если они постоянно присутствуют в памяти то и соответсвенно скорость загрузки(выполнения) будет выше.
>>>дык какая там проблема то? LD_LIBRARY_PATH установить для процесса httpd
>> <......> апач запустит столько процессов, сколько
>>клиенты запросят CGIку. Вот тут-то память пожрёт...
>
>да мне тоже эта мысль пришла. а динамическая библиотека нескольких процессов отображается
>во все и если они постоянно присутствуют в памяти то и
>соответсвенно скорость загрузки(выполнения) будет выше.Докладываю с поля боя =)
Скомпилировал с динамическими библиотеками. Не запускается.
Написал SH скрипт следущего содержания (line - название моей проги):File env.sh :
--------
export MAGICK_HOME=/home/u51990/
export PATH; PATH="$MAGICK_HOME/bin:$PATH"
export LD_LIBRARY_PATH="/home/u51990/lib"
export MAGICK_DEBUG="Cache,Blob,Coder,Render,Transform"
export MAGICK_TMPDIR="$MAGICK_HOME"
export MAGICK_CONFIGURE_PATH="$MAGICK_HOME/share/ImageMagick-6.3.5/config"
export TMP="$MAGICK_HOME"
export TMP_DIR="$MAGICK_HOME"
export MAGICK_MAP_LIMIT="16"
export MAGICK_MEMORY_LIMIT="16"
./line
--------Запустил как CGI (из консоли всё запускается без геморроя)
http://мой_сайт.ру/cgi-bin/env.sh
Магическая переменная LD_LIBRARY_PATH сделала своё дело и прога не вылетает с ошибкой.НО! Теперь другая проблема (она же была и со статическими библиотеками): функция ImageMagick пишущая текст на одном кадре GIF-анимации (в цикле - по всем кадрам) начинает себя странно вести. Тоесть под консолью генерится нормальная картинка в любом случае, а если запустить как CGI тогда если надпись больше 32 (!почему-то пробелы не учитываются!) символов то она отрисовывается только на первом кадре анимации, в остальных кругах цикла она как бы не срабатывает, а если меньше 32 символов - то всё окей и из под CGI. Из под консоли пробовал 50 символов - всё пучком. Причём если рисовать на анимации с меньшим количеством кадров, то порог глюка отступает. Тоесть можно забацать больше символов.
Я так понимаю проблема в памяти. Точнее в том, что suexec её режет. Я уже надеялся, что компиляция с динамическими библиотеками эту проблему решит (ведь статическая занимала 4 Мб памяти в пространстве проги), но ничего не изменилось.
>[оверквотинг удален]
>только на первом кадре анимации, в остальных кругах цикла она как
>бы не срабатывает, а если меньше 32 символов - то всё
>окей и из под CGI. Из под консоли пробовал 50 символов
>- всё пучком. Причём если рисовать на анимации с меньшим количеством
>кадров, то порог глюка отступает. Тоесть можно забацать больше символов.
>
>Я так понимаю проблема в памяти. Точнее в том, что suexec её
>режет. Я уже надеялся, что компиляция с динамическими библиотеками эту проблему
>решит (ведь статическая занимала 4 Мб памяти в пространстве проги), но
>ничего не изменилось.не знаю вряд ли памяти не хватает. тут надо с этой библиотекой разбираться. если памяти не хватает. то где то видно аллокация ошибку должна возвращать. все таки проверь еще раз везде ли ты правильно работаешь с библиотекой. помнишь как тот раз с длиной.
зачем ты из под суехек запускаешь? ну сомневаешься в ней запусти без нее.
>зачем ты из под суехек запускаешь? ну сомневаешься в ней запусти без
>нее.Дык без неё - из под консоли всё работает как надо. А мне нужно что бы приложение работало как CGI, а все CGI запускаются через suexec =( Или я чего-то недопонимаю?
>>зачем ты из под суехек запускаешь? ну сомневаешься в ней запусти без
>>нее.
>
>Дык без неё - из под консоли всё работает как надо. А
>мне нужно что бы приложение работало как CGI, а все CGI
>запускаются через suexec =( Или я чего-то недопонимаю?вообще говоря не обязательно. только если ты его специально пропишешь.
http://httpd.apache.org/docs/2.2/suexec.htmlразница в пользователе! и соответсвенно в его настройках: переменных среды. правах.
если нужен другой пользователь не апач.