KOEI's Diary 위치로그  |  태그  |  방명록
삽질 에 해당하는 글2 개
2007/03/26   Ruby 그리고 AIX (4)
2007/03/25   libpcap linux에서 timeout 되게 패치하기 (2)


Ruby 그리고 AIX
개발이야기 | 2007/03/26 02:17
2007/03/26 02:17 2007/03/26 02:17

AIX에서 Ruby 돌리기?

별로 생각하고 싶지 않은 스토리인데.. 상황이 그리 되는 어쩔 수 없으니...

1차시도 1.8.5을 visual age c compiler로 컴팔하기
 => __ceil, __floor를 못 찾겠다 꾀꼬리
2차시도 1.8.5를 gcc로 컴팔하기
 => 컴팔이 잘 된다 오예~, 그러나 ext/socket 은 왜 컴파일을 안 하는데. 소켓써야하는데 ㅠ.ㅠ
3차시도 1.8.6을 gcc로 컴팔하기
 => 오옹 그냥 해봤는데 socket도 들어있네 아싸

흐웅 그나저나 이 머신 왜이리 접속하는데 오래걸려. 그래도 행복하게 ruby를 쓸 수 있네 ㅋㅋ
들어가는게 느리니 느리겠거니...

require 'socket'

t = TCPSocket.new('www.daum.net',80) # 가는 세월 그누구가~ 막을수가 있나요 ㅠ.ㅠ

요게 느린 것도 아마 AIX 요 머신이 특이한 걸 것이야..
얼래 그런데 ftp로 데이터 받아오기나, 그 외의 것들은 빠른데.... -ㅅ-
알고보니 Ruby에서 ext/socket 모듈로 Socket 생성시 접속이 오라지게 느리게 된다.
꾸에엑 이를 어쩌나.. 소켓이 필요한 부분이 TCPSocket으로 접속도 해야하고, open-uri를 이용해서 ftp에서 파일도 받아와야하는데..

고객은 앞에 있고.. 데모 보여줘야하는데... ㄷㄷㄷ
부랴 부랴 netcat, wget으로 두부분을 스슥 바꿨다.
UNIX는 저에게 system, popen과 ``를 주셨나이다. ㄳㄳ

일단 일단락.. 그러나 상황이 조금 바뀌어서 AIX에서 Ruby/Pcap도 써야할 상황.
컴파일을 하는데 잘 안 되네.. -ㅅ-
컴파일하고 나니 모듈 로딩이 안 된다.

 구글링하던 도중 AIX에서 Ruby Building할때 1차시도의 해결책을 찾았다.
 알고 보니 망할 Visual Age Compiler 6.0의 버그문제. python을 비롯한 다른 오픈프로젝트에서도 관련 얘기가 나오네. -ㅅ- 그래서 vac로 다시 한번 컴팔해봤다.

 4차시도 잘 된다. 그러나 확장모듈 로딩이 죄다~ 안 된다. 쩝쩝쩝..
  gcc로 다시 회귀 그러면서 아차차 생각난 것...
 5차시도 CC="gcc -maix64" 요리 하니 ext/socket에서 지연되던 문제가 사라졌다. 성능도 조금 좋아진 느낌이다. GOOD!

 그러나 역시 Ruby/pcap은 로딩이 되지 않는다. (해결되면 포스팅 이어짐 안되면 한동안 좀비모드일듯.. C++ Porting 고고싱 T-T)
 libpcap 컴파일시에 CC="gcc -maix64" CFLAGS="-g -O2" ./configure --with-pcap=dlpi --disable-ipv6  로 옵션을 줘서 해결. README.aix문서를 읽어보고 bpf를 사용하지 않고 dlpi를 사용하게 하니 문제없이 작동 - 머 특정 용도 활용이라서 원하는 기능만 돌아가는지 확인. (Fixnum을 Symbol로 사용하짐 랄라는 에러가 3개 뜬다 덜덜덜.. -ㅅ-)

추가적인 수정 사항 (흑 2006.03.29 새벽3시 퇴근 ㅠ.ㅠ)
1. Endian 문제가 있어서 (실제 데이터는 리틀엔디안 AIX는 빅엔디안) 2바이트짜리 길이를 나타내는 부분이었는데 len.unpack('s')를 len.reverse.unpack('s')로 수정
2. 이상하게 tcpdump에서 쓴 패킷 캡쳐시간이 리눅스에서와 AIX에서 14시간 정도 차이가 난다. 그냥 그런가 부다 하고 처리하는 중.

오랜만에 AIX만지면서 알게된 잼있는거 linux기반의 opensource들과 AIX가 좀 더 친해졌다.
미리 컴파일된 바이너리를 http://aixpdslib.seas.ucla.edu/ 에서 잘 받아썼는데 IBM에서 rpm으로 공식지원하는 녀석이 생겼다. 이름도 그럴듯하다~
 AIX Toolbox for Linux Applications 엄훠 이젠 rpm으로 설치하세요~
 
 또하나는 netcat, libpcap, tcpdump 그리고 몇몇 소프트웨어를 컴팔하면서 간단하게 에러나는 것을 잡은 부분 정리

 1) extern int h_errno; 를 만나면 가뿐히 지워주세요. (AIX버젼 바이너리가 올리간 사이트의 소스와 원본소스를 비교)
 2) VAC C 컴파일러는 enum { AA,BB, CC,} 와 같은 코드를 용납하지 않아요~ 마지막에 여유로 쉼표를 찍지 말아주세요~

태그 : , , ,
트랙백0 | 댓글4
이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/489
aqua 2007/03/29 09:30 L R X
UNIX는 저에게 system, popen과 ``를 주셨나이다. ㄳㄳ <-- 이 부분 욜라 인정 큭큭
KOEI 2007/03/29 18:46 L X
그래도 얼마나 덜덜덜이었는지 모를꺼야 ㅠ.ㅠ
생각도 못 했었지.. TCPSocket 생성이 느릴꺼라고는..
aqua 2007/03/29 09:31 L R X
아 그런데 AIX 쓰는 곳도 의외로 많이 보게 되는 구나 -_-;
KOEI 2007/03/29 19:21 L X
전에 거기야 또 ㅋㅋ

[로그인][오픈아이디란?]
아이디 :
비밀번호 :
홈페이지 :
  비밀글로 등록
내용 :
 



libpcap linux에서 timeout 되게 패치하기
개발이야기 | 2007/03/25 20:39
2007/03/25 20:39 2007/03/25 20:39
근래에 계속 하고 있는 프로젝트에서 결국 tcpdump를 사용하게 되었는데,
Failover 처리를 하다보니 캡쳐하다 특정 시간만큼 패킷이 없을 경우 timeout을 처리해야할 필요성이 생겼다. tcpdump 소스에서 관련 부분을 보면
- tcpdump.c -
 885         *ebuf = '\0';
 886         pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf);
 887         if (pd == NULL)
4번째 인자가 to_ms, timeout과 관련된 인자로 설정이 되어있어서, 잘 되는구나 하고 진행을 했으나, 리눅스에서는 timeout이 동작하지 않아서 소스를 들여다 봤다.
 pcap.c에서 보니 죄다 function pointer로 위임해놨군. 으움 실제 빌드를 돌려보고 실제로 컴파일되는 녀석을 찾아보니 이놈이다. pcap-linux.c 그중에 일부를 보면
- pcap-linux.c -
 236 pcap_t *
 237 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
 238     char *ebuf)
 239 {
...
 267         /* Initialize some components of the pcap structure. */
 268
 269         memset(handle, 0, sizeof(*handle));
 270         handle->snapshot        = snaplen;
 271         handle->md.timeout      = to_ms;
...
 492     /* Receive a single packet from the kernel */
 493
 494     bp = handle->buffer + handle->offset;
 495     do {
 496         /*
 497          * Has "pcap_breakloop()" been called?
 498          */
 499         if (handle->break_loop) {
 500             /*
 501              * Yes - clear the flag that indicates that it
 502              * has, and return -2 as an indication that we
 503              * were told to break out of the loop.
 504              */
 505             handle->break_loop = 0;
 506             return -2;
 507         }
 508         fromlen = sizeof(from);
 509         packet_len = recvfrom(
 510             handle->fd, bp + offset,
 511             handle->bufsize - offset, MSG_TRUNC,
 512             (struct sockaddr *) &from, &fromlen);
 513     } while (packet_len == -1 && errno == EINTR);

 디버거를 돌릴 생각을 못하고 recvfrom 전후로 출력만을 넣어본 결과 blocking이 된다는 사실을 확인. 일단 늘 그렇듯이 당황. nonblocking으로 바꾸면.. 상상하기도 싫고..... 잠시 마음의 여유를 가지고 시간이 별로 없어서 다른 방법을 찾아보지 않고 소스를 고쳐보기로 했다.
 (얼마전에 했었던 C++로 작업된 프로젝트 삽질 이후에 또 삽질을.... 이번에는 C다. -ㅅ-)

 이런 패턴을 어디서 많이 보던건데..... 아하!
 IRC서버소스에서 sleep이 없을 때 select를 쓴다.. 이건 상관없잖아!!
 ACE에서 recv에서 timeout을 지원하지 않을 때 어떻게 하더라. multiplexer의 timeout을 이용하면. That's right~
 그래서 붙이려다가 이왕이면 select말고 다른거 한번 써보자. 해서 epoll로 살포시 붙여봤다. 작업하면서 소스보기 번거로우니 쓰지 않는 파일이나 화면에 출력결과를 보여주는 루틴등은 싸악 날려주고 -ㅅ- 오옹 보다보니 리눅스에서 어떻게 캡쳐를 하면 되는지도 나온다. 여러 인터페이스(각각 fd로 나오니까)에서 캡쳐하는걸 하나의 epoll로 처리해도 괜찮겠다는 생각이 들기 시작.. 그러나 그런게 중요한건 아니니..

#include <sys/epoll.h>

.... 중략 ....

#define  EPOLL_EVENTS_COUNT 16
static int epollfd = -1;
static struct epoll_event ev, * epoll_events = NULL;

.... 중략 ....

pcap_t *
pcap_open_live(const char *device, int snaplen, int promisc, int to_ms
    char *ebuf)
{

.... 중략 ....

    handle->selectable_fd = handle->fd;
    do {
        if ( -1 == epollfd)
            epollfd = epoll_create(EPOLL_EVENTS);
        if ( -1 == epollfd )
           break;
        if ( NULL == epoll_events )
             epoll_events = (struct epoll_event *)malloc(sizeof(*epoll_events) * EPOLL_EVENTS);
        ev.events = EPOLLIN;
        ev.data.fd = handle->selectable_fd;
        if ( -1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, handle->selectable_fd, &ev) )
           break;

       handle->read_op = pcap_read_linux;
       handle->inject_op = pcap_inject_linux;
       handle->setfilter_op = pcap_setfilter_linux;
       handle->setdirection_op = pcap_setdirection_linux;
       handle->set_datalink_op = NULL; /* can't change data link type */
       handle->getnonblock_op = pcap_getnonblock_fd;
       handle->setnonblock_op = pcap_setnonblock_fd;
       handle->stats_op = pcap_stats_linux;
       handle->close_op = pcap_close_linux;

       return handle;
    } while(0);
  
    fprintf(stderr, "epoll setting error\n");
    pcap_close_linux(handle);
    free(handle);
    return NULL;
}
....
static int
pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
{
 u_char   *bp;
 int   offset;
#ifdef HAVE_PF_PACKET_SOCKETS
 struct sockaddr_ll from;
 struct sll_header *hdrp;
#else
 struct sockaddr  from;
#endif
 socklen_t  fromlen;
 int   packet_len, caplen;
 struct pcap_pkthdr pcap_header;

 int n ; /* epoll returned count */
  
.... 중략 ....

 /* Receive a single packet from the kernel */

 bp = handle->buffer + handle->offset;
 do {
  /*
   * Has "pcap_breakloop()" been called?
   */
  if (handle->break_loop) {
   /*
    * Yes - clear the flag that indicates that it
    * has, and return -2 as an indication that we
    * were told to break out of the loop.
    */
   handle->break_loop = 0;
   return -2;
  }
  fromlen = sizeof(from);

  n = epoll_wait(epollfd, epoll_events, EPOLL_EVENTS, handle->md.timeout);
  if (0 >= n)
  {
   break ;
  }
  for ( int i = 0 ; i < n ; ++i )
  {
    if ( epoll_events[i] == handle->selectable_fd )
    {

       packet_len = recvfrom(
       handle->fd, bp + offset,
       handle->bufsize - offset, MSG_TRUNC,
      (struct sockaddr *) &from, &fromlen);
    }
 } while (packet_len == -1 && errno == EINTR);

 if ( n == 0 || (  n < 0 && errno == EINTR ) )
 {
  /* callback function must check packet_header, buffer_pointer is NULL. if they are NULL, it is timeout */
  callback(userdata, NULL, NULL);
  return 0;
 }

.... 중략 ....

static void pcap_close_linux( pcap_t *handle )
{
 struct pcap *p, *prevp;
 struct ifreq ifr;

.... 중략 ....

 if (handle->md.device != NULL)
  free(handle->md.device);
 handle->md.device = NULL;
 if (handle->selectable_fd > 0 ) /* 여긴 대충 대충 -ㅅ- */
 {
   close(epollfd);
 }
 pcap_close_common(handle);

 요렇게 간단하게 몇 부분을 고치니 timeout을 callback에서 packet_header와 capture buffer가 NULL임을 확인하는 것으로 timeout 체킹이 가능해졌다. 다만 50라인 정도 작업하는데 3시간 정도를 쓰다니 -_+
 요튼 소기의 목적을 달성하고 timeout을 이용한 다른 코드를 tcpdump에 붙이기 성공.
작업하면서 뻘짓한 것은 tcpdump 소스를 보면서 print-*.c 얘네들을 지우면서 소스를 파악할 때까지는 분위기가 좋았다. libpcap 소스를 보면서 먼저 문서화된 것을 보지 않아서 인터페이스를 파악하는데 삽질한 것(Ruby/Pcap만으로 이미 난 대부분을 알고 있어라는 자만심에)에서 시간을 많이 뺏겼다. 언제나 그렇듯이 소스보다는 문서를, 문서보다는 예제를 먼저 보자라는 생각을 빼먹는다.
 
 작업하면서 printf에서 사용하는 formatted string에서 잼있는 것을 발견. (나만 몰랐는지도)
  sprintf(buffer, "%s%0*d", orig_name, max_chars, cnt);
%*d라고 적으면 두개의 인자를 받고 앞의 인자가 *로 자리수를 받고 뒤의 인자가 값이 된다.

여튼 즐거운 working sunday..... ㅠ.ㅠ

태그 : , , ,
트랙백0 | 댓글2
이 글의 관련글(트랙백) 주소 :: http://koei.fiaa.net/trackback/488
rath 2007/04/02 03:56 L R X
오랜만에 놀러왔는데, 열정 가득한 포스팅이 ㄷㄷㄷ하게 올라왔네요~ >.<
KOEI 2007/04/03 11:14 L X
흐흐 부끄럽사와요. 래쓰횽이야 말로 요사이 무지 달리시더라는. 건강 조심하세용~
일하다가 삽질한거 정리해놓으면 나중에 볼때 좋아서연..
래쓰횽 보고 시퍼요 ㅠ.ㅠ

[로그인][오픈아이디란?]
아이디 :
비밀번호 :
홈페이지 :
  비밀글로 등록
내용 :
 



[PREV] [1] [NEXT]
관리자  |   글쓰기
BLOG main image
소소한 일상.. 그안의 나..
전체 (11)
개발이야기 (7)
전산쟁이 맹달이 (2)
사랑하는사람들 (2)
Reading (0)
데스크탑 개발 삽질 Feisty COBL call_graph AIX 짝프로그래밍 리눅스 tcpdump agile 조카 Ruby TCP 나연이 Ubuntu VB.NET libpcap
COBOL call flow 그려보기 (8)
Ruby 그리고 AIX (4)
libpcap linux에서 timeout... (2)
사랑하는 조카 =)
[리뷰] Ubuntu Feisty - 충분... (6)
헙 마님 3개월만에 들어와봤...
2009 - KOEI
별걸 다 해 -_-
2009 - seha
냥냥 올만이야 3달만의 리플...
2008 - KOEI
광용싸마~ 간만이에용~ㅋㅋ...
2008 - nurinamu
로오오오옹 타이이임 노오오...
2008 - KOEI
Active Directory 에 사용자...
해적의 쉼터
Total : 23773
Today : 6
Yesterday : 6
태터툴즈 배너
rss
 
 
 
위치로그 : 태그 : 방명록 : 관리자
KOEI’s Blog is powered by Tattertools.com / Designed by plyfly.net