пятница, 25 ноября 2011 г.

C++ библиотека-плагин для Unix. Часть 4-я. Сетевые засады: POSIX vs BSD

Есть такая замечательная OS, называется HP-UX. Имеет она целых 2 стека TCP: - POSIX и BSD. И разработчики этой замечательной системы такие юмористы - сделали одинаковые имена функций, но разные типы аргументов (а еще усугубили тем, что аргументы указатели).
Допустим, я разработал библиотеку с учетом использования BSD реализации, а приложение (не мое), которое данную библиотеку использует, было разработано с учетом использования POSIX реализации сокетов. Это приведет к тому, что при любой сетевой активности моей библиотеки (допустим при вызове из нее функции приложением) - мы получаем GPF.
Конечно, мы можем договорится с разработчиком приложения использовать одну и ту же реализацию сокетов. Это если приложение одно такое - использует мою библиотеку. А если их несколько? Как быть с уже не поддерживаемыми приложениями?

Выход мне подсказал клиент oracle - libclntsh.so. Ведь правда, линкуй хоть с POSIX хоть с BSD - все работает и не падает. Стал рыть дальше. Посмотрел какие вызовы sockets использует libclntsh.so. Например: setsockopt

elfdump -t libclntsh.so.10.1 | grep setsockopt
3253   FUNC GLOB 0     UNDEF      0x0000000000000000 0      _setsockopt


Ага, использует вызовы из libc (с подчерком перед символом). Как он это делает, интересно?
Ищем дальше. Смотрим в архивах *.o файлы - ничего там не находим. И вот оно - то что надо (для краткости, я опустил часть вывода):
nm xnetstubs.o
[28]     |                     0|       0|FUNC |GLOB |0|   UNDEF|_accept
[29]     |                     0|       0|FUNC |GLOB |0|   UNDEF|_bind
[30]     |                     0|       0|FUNC |GLOB |0|   UNDEF|_connect
[31]     |                     0|       0|FUNC |GLOB |0|   UNDEF|_getpeername
...

[39]     |                     0|      80|FUNC |GLOB |0|   .text|accept
[40]     |                     0|      80|FUNC |GLOB |0|   .text|bind
[41]     |                     0|      80|FUNC |GLOB |0|   .text|connect
[42]     |                     0|      80|FUNC |GLOB |0|   .text|getpeername
...
Смотрим, как он это дело линкует. Находим в clntsh.map на первой же строчке:
-h accept -h bind -h connect -h getpeername -h getsockname -h getsockopt -h setsockopt -h recv -h recvfrom -h send -h sendto -h setsockopt /u01/app/oracle/product/10.2.0/db/lib/xnetstubs.o
В документации по линкеру - -h это значит скрыть символ. Теперь при линковке  нашей библиотеки добавляем:

-Wl,-h,accept -Wl,-h,bind -Wl,-h,connect -Wl,-h,getpeername 
-Wl,-h,getsockname -Wl,-h,getsockopt 
-Wl,-h,setsockopt -Wl,-h,recv -Wl,-h,recvfrom 
-Wl,-h,send -Wl,-h,sendto -Wl,-h,setsockopt 
${ORACLE_HOME}/lib/xnetstubs.o
Все. Теперь наша библиотека будет использовать BSD сокеты при любых способах линковки основного приложения.

Кстати, таким образом можно и другие вызовы перенаправлять в требуемые библиотеки. (но об этом в другой раз)

Комментариев нет:

Отправить комментарий