[Сygwin: среда для мультиплатформенного
программирования]
Автор: m-me de Chapeau Claque
Дата:
Немного лирики
Доброго времени суток, уважаемый
читатель! Я - новый автор статей для
сайта www.xakep.ru и, начиная с этой статьи, буду вести
здесь цикл публикаций,
посвящённый вопросам сетевой безопасности и
сетевого программирования платформ
Windows и UNIX.
К сожалению (надеюсь, не для многих), я
буду игнорировать всеобщую
любовь к Delphi и, нагло загиная привычную мне линию,
буду вворачивать примеры,
написанные на классическом ANSI C (так называемый gnu
style) и на ассемблере
UNIX'ового синтаксиса архитектуры x86. Однако, я
попытаюсь искупить этот
грешок, снабжая исходный текст своих программ
подробными комментариями. Ведь,
как говорил один мой знакомый, не самый последний
человек в хакерском мире,
"главное - не знание языка программирования, а
умение им воспользоваться!".
Очень рассчитываю на то, что этот аргумент
сохранит меня от очень модной на
этом сайте деликатности тех самых немногих
читателей :)
Я программирую в среде cygwin, но это
вовсе не означает, что всё, о чём
я буду рассказывать в своих статьях,
действительно лишь для cygwin. Вы можете
пользоваться любым компилятором и любой средой,
которой захотите. Вы можете
даже переписывать эти исходники на своём любимом
языке в своей любимой среде.
Я не буду агитировать Вас за cygwin.
Cygwin: что это такое?
Cygwin - это аббревиатура от 'Cygnus', группы
разработчиков свободного
ПО в рамках проекта 'RedHat' и 'Windows', всеми нами
любимой операционной
системы. Спешу развеять очень популярную точку
зрения, будто бы cygwin - это
эмулятор UNIX под Windows: это не так! Cygwin - это лишь
мощный, очень развитый
и, самое главное, бесплатный набор программных
средств переноса (портирования)
UNIX'ового ПО под Windows и кросс-компиляции (создания
бинарного кода на одной
платформе под другую) UNIX'овго софта. Лично для
меня, cygwin, прежде всего,
это мощнейший компилятор gcc с отшлифованными под
Windows хидерами и либами.
Cygwin нынче становится весьма
популярным: многие производители
свободного ПО под UNIX поддерживать '--target=cygwin' в
конфигах своих
программ, благо, это не столь трудоёмко. А cygwin, в
свою очередь, расширяет
совместимость с UNIX, поддерживая не только posix, но
и другие, более
узкоспецифичные стандарты UNIX-систем.
Cygwin: где смотреть?
http://www.cygwin.com - официальная страница cygwin'а,
на которой Вы
сможете найти достаточное количество информации
о текущем состоянии проекта, об
обновлениях cygwin'овских релизов, а также
официальный список ftp-серверов,
периодично зеркалящих cygwin.
Cygwin: что и как устанавливать?
Зайдите на любое из зеркал cygwin'а. Вы
увидите три основных
директории: contrib, latest и xfree. Первая - это программы,
портированные под
cygwin самим Cygnus'ом и требующие для работы лишь
доступности основной
библиотеки, cygwin1.dll. Третья - это портирование X-сервера
под среду cygwin.
Нам понадобится содержимое второй директории,
latest.
Если Вы собираетесь программировать в
cygwin'е, то для более-менее
комфортной работы Вам потребуются последние
версии пакетов ash, autoconf,
automake, bash, binutils, bzip2, cygwin, diff, fileutils, findutils, gcc,
gperf, groff, gzip, less, login, m4, make, man, mingw, mingw-runtime, ncurses,
patch, sed ,sh-utils, tar, w32api, zlib и, естественно, setup.exe. Если
Вы
маньяк, то можете выкачать исходники этих
пакетов.
По дефолту, cygwin встаёт в указанную Вами
директорию в рамках тех
прав, которые Вы ему укажете. Установка cygwin'а
создаст на рабочем столе свою
иконку и, щёлкнув по ней, Вы очутитесь в bash'е с
весьма, на мой взгляд, мило
сконфигурированной цветовой гаммой.
cygwin1.dll: что это такое?
В библиотеке cygwin1.dll сосредоточен весь
posix, который эмулирует
cygwin, а также некоторые особо важные функции cygwin'а.
Грубо говоря,
cygwin1.dll - это самая главная библиотека cygwin'а, его
kernel. Не забудьте
скопировать файл cygwin1.dll в любую директорию, к
которой у Вас прописан
'PATH=', например, в '%windir%' для того, чтобы cygwin'ные
программы работали
не только в внутри среды cygwin.
gcc: какой он?
Точно такой же, как и в UNIX. Сочный,
мощный, безглючный. Однако, не
такой быстрый. Дело в том, что запуск
препроцессора, компилятора, ассемблера и
линковщика требует определённого времени на
загрузку и пролинковку в памяти
библиотеки cygwin1.dll, требумую каждым из этих
компонентов gcc. Отмечу, что в
Windows 2000 это требует на порядок меньше времени, чем
в Windows 98. Скорость
компиляции в Windows 2000 очень близка к скорости
компиляции в UNIX. Но сок
остаётся соком: генерируемый бинарный код cygwin'ным
gcc остаётся вне
конкуренции по компактности и эффективности!
Если Вы когда-либо писали или
компилировали программы под UNIX, Вы не
будете испытывать никаких трудностей в работе с
cygwin. Только помните, что
cygwin'ный gcc может не поддерживать некоторые опции,
которыми Вы пользуетесь
в UNIX'е, хотя количество таких недоразумений
сведено к минимуму. На моём веку,
например, таких проблем не возникало. В любом
случае, если возникают какие-то
проблемы, все мы дружно знаем лучший способ их
решения: 'man gcc'! :)))
Если же Вам не доводилось прежде
заниматься программированием под UNIX
и Вы привыкли жать <F9> для того, чтобы
скомпилировать Вашу программу,
расстраиваться не стоит. Попробуйте 'man gcc' в bash'е
cygwin'а: вполне
достойное и увлекательное чтиво.
Таки начнём?
Оригинальничать я не буду, поэтому
начнём мы, как всегда и везде, с
вывода 'hello world!' на консоль. Итак, hello.c:
#include <stdio.h>
int main () {
printf("Hello World!\n");
return 0;
}
Компилируем:
gcc -s hello.c -o hello.exe
и смотрим на бинарник. 3072 байта
бинарного кода, формат PE, portable
executable, загружаемые dll:
cygwin1.dll, откуда hello.exe берёт нашу printf() и
другие функции,
которые накомпилировал нам gcc;
kernel32.dll, откуда hello.exe берёт GetModuleHandleA.
Хидер <stdio.h> gcc берёт из /usr/include,
который является дефолтной
инклудной директорией и в UNIX, и в cygwin'е.
В cygwin'ном gcc есть одна очень приятная
опция, которая, почему-то,
не задокументирована в man-файле, '-mno-cygwin'.
Скомпилируем нашу программу
с этой опцией:
gcc -mno-cygwin -s hello.c -o hello.exe
и смотрим на бинарник: опять, 3072 байта
бинарного кода, но наша
программа больше не нуждается в cygwin1.dll! вместо
этого она использует
msvcrt.dll, где и находит нужную нам функцию printf.
Если мы юзаем опцию '-mno-cygwin', cygwin кидает
gcc'шный препроцессор
в директорию /usr/include/mingw, и, соответственно, gcc
компилирует <stdio.h>
именно из этой директории.
Настоятельно рекомендую совершить
прогулку по содержимому директории
/usr/include для того, чтобы понять, что к чему. Думаю,
Вас особо порадует
содержимое директорий /usr/include/sys и /usr/include/w32api.
Таким образом, cygwin находит компромисс
между двумя противоречащими
друг с другом платформами, UNIX и Windows и даёт нам
уникальный шанс изучать
программирование под UNIX, не покидая Windows. Далее
следует пример простенькой
программки, компилирующейся и под posix'овые BSD Sockets,
и под WinSock2.
Программка открывает указанный в командной
строчке порт и ожидает
tcp-соединение с любого IP-адреса, принимает от
клиента литеру и возвращает
клиенту эту же литеру, увеличенную на единицу. Вы
можете скомпилировать эту
программку, запустить её ('easy.exe 500'),
приконнектиться к ней телнетом
('telnet 127.0.0.1 500') и ввести любой символ.
---[ Makefile (для неюниксоидов, Makefile с заглавной буквы
'M'):
# tiny makefile for a tiny program
all:
@echo Pick 'make posix' for UNIX/cygwin or 'make
windows' for Windows
posix:
@printf "Building easy.c for posix..."
@printf "#define ENV_POSIX" > plateform.h
@gcc -s easy.c -o easy.exe
@echo ok!
windows:
@printf "Building easy.c for windows..."
@printf "#define ENV_WINDOWS" > plateform.h
@gcc -mno-cygwin -s easy.c -lws2_32 -o easy.exe
@echo ok!
---[ easy.c:
#include "plateform.h"
#include <stdio.h>
#ifdef ENV_POSIX
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> // для
INADDR_ANY
#include <signal.h> // для signal()
#else
#include <winsock2.h>
#endif
int main (int argc, char **argv) {
struct sockaddr_in dst;
#ifdef ENV_POSIX
int sock, sid;
#else
SOCKET sock, sid;
WSADATA wsaData;
#endif
int
len = sizeof(struct
sockaddr);
char
buf;
unsigned short port;
// entry point
if(argc<2) {
printf("Usage: easy.exe
<tcp-port>\n");
return 1;
}
port = atoi(argv[1]);
if(!port) {
printf("Bad <tcp-port>
defined!\n");
return 2;
}
#ifdef ENV_POSIX // в позиксе мы игнорируем
сигналы, мало ли :)
signal(SIGPIPE, SIG_IGN);
#else ENV_WINDOWS // в Windows мы проверяем версию
винсока, мало ли :)
printf("Testing if the WinSock2 version is equal or higher than
2.1...");
if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0) {
printf("failed!\n");
return 1;
}
printf("ok!\n");
fflush(stdout);
#endif
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = htonl(INADDR_ANY);
dst.sin_port = htons(port);
sock = socket(AF_INET,SOCK_STREAM,0);
printf("Waiting for an incoming connection...");
fflush(stdout);
bind(sock,(struct sockaddr*)&dst,len);
listen(sock,1);
sid = accept(sock,(struct sockaddr*)&dst,&len);
printf("done!\nWaiting for incoming data...");
fflush(stdout);
recv(sid,&buf,1,0);
printf("received: [%2X]...",buf); fflush(stdout);
buf++;
send(sid,&buf,1,0);
printf("done!\n");
#ifdef ENV_POSIX
close(sock);
#else
WSACleanup();
closesocket(sock);
#endif
return 0;
}
Итак, мы набираем 'make posix' для того,
чтобы собрать программу под
UNIX'ом или под cygwin'ную среду или 'make windows' для того,
чтобы не зависеть
от cygwin'а и использовать лишь kernel32.dll, ws2_32.dll и
msvcrt.dll, которые
входят в стандартную поставку каждого
дистрибутива Windows. Обратите внимание
на размер бинарника: 4096 байт для cygwin, 4608 байт для
windows! :)
На этот раз всё! Ждите вскоре следующей
статьи в ближайшее время:
Технология сканирования сетей: Cокетный
движок
|