뭘 이런걸..

Posted
Filed under Tech/프로그래밍
Neowiz 는 시스템 설치를 PXE 와 kickstart 의 post script 를 이용하여 자동 관리를 하고 있습니다. 회사에서는 이 시스템을 P.I.P.E (본 뜻은 까먹었음. 그냥 파이프라고 함) 라고 칭합니다.

이번에 pipe system 을 migration 을 하고 있는데, 다음주 즈음 대략 몇백대를 동시에 설치할 일이 있어서, web daemon 을 apache 에서 lighttpd 로 변경을 했습니다.

centos 를 테스트 할 때까지만 해도 좋았는데.. redhat 9 의 anaconda 에서 lighttpd 기반에서 kickstart 파일을 받아오지 않는 난감한 사태가 발생을 하더군요. apache 로 가도 상관이 없지만, 몇백대씩 설치를 하려면 apache 로는 1대로는 버틸수가 없다는 문제가 발생을 합니다. 또한, pipe 의 특성상 설치를 하면서 시스템 내부에서 작업을 많이 하게 되는데, apache 로 몇백대를 설치할 경우에는 시스템이 과부하가 걸리게 됩니다.

그래서 고민하다가, 그래 한번 해결해 보자는 오기가 생기더군요. 원래 제가 이 바닥에서 뽀로꾸로 시작해서 오직

안되면 될 때까지 !!!


라는 신념으로 버텨온지라.. 이번에도 누가 이기나 한번 해 보자는 "자포자기"식으로 도전을 하게 되었습니다.

먼저.. 그럼 뭐가 문제일까.. 하고선 lighttpd 를 debug symbol 을 줘서 빌드한 후에 debugging 도 해 보았지만 뚜력한 이유를 알수가 없었고, 그럼 패킷이 어떻게 지나가나 보자.. 하고선 dump 를 떠 보았지만.. 시간만 속절없이 흘러가더군요. 그러다가.. 제대로 되는 패킷과 안되는 패킷을 비교하는 도중 아래의 붉은 글자 부분의 차이를 발견하게 됩니다.

* 400 Bad Request 경우
0x0000: 4510 0069 52fc 4000 4006 e980 7f00 0001 E..iR.@.@....... 0x0010: 7f00 0001 886f 0050 9443 d892 9435 6606 .....o.P.C...5f. 0x0020: 8018 0040 fe5d 0000 0101 080a 92a6 8da3 ...@.].......... 0x0030: 92a6 8a69 4745 5420 2f70 726f 6669 6c65 ...iGET./profile 0x0040: 2f64 6566 6175 6c74 2e72 6564 6861 742e /default.redhat. 0x0050: 392e 6933 3836 2f70 6970 652e 6b73 2048 9.i386/pipe.ks.H 0x0060: 5454 502f 312e 3009 0a TTP/1.0..


* 200 정상적인 경우
0x0000: 4510 0069 52fc 4000 4006 e980 7f00 0001 E..iR.@.@....... 0x0010: 7f00 0001 886f 0050 9443 d892 9435 6606 .....o.P.C...5f. 0x0020: 8018 0040 fe5d 0000 0101 080a 92a6 8da3 ...@.].......... 0x0030: 92a6 8a69 4745 5420 2f70 726f 6669 6c65 ...iGET./profile 0x0040: 2f64 6566 6175 6c74 2e72 6564 6861 742e /default.redhat. 0x0050: 392e 6933 3836 2f70 6970 652e 6b73 2048 9.i386/pipe.ks.H 0x0060: 5454 502f 312e 300d 0a TTP/1.0..


해당 자리는 carrige return (\r) 이 들어가야 할 자리인데.. 대체 09 가 무야 하고 찍어보니.. tab (\t) 를 찍고 있는 것입니다. 이제껏.. query 를 던지면서 왜 똑같은데 안되지 하고 있었는데.. RH9 anaconda 는

GET http://domain.com/uri\t\n


을 찍고 있었던 겁니다. 그러니 될 턱이 없지요 --; 이것 땜시 anaconda 소스와 lighttpd 의 소스를 까보면서 헛되이 시간을 보내고 있었던 것이었습니다. 알고나자 허탈함이 밀려 오면서.. (속으로는 이런 "씹x"...) 여기서 포기해야 하는가 하다가, 들인 시간이 아까와서 다시

안되면 될 때까지 !!!


의 정신으로, lighttpd 가 저 쿼리를 받아들일 수 있도록 수정해 보자는 말도 안되는 결심을 하게 됩니다. 그렇게 한참을 뒤져서 다음의 패치가 나오게 됩니다.

diff -urNp lighttpd-1.4.11.org/src/connections.c lighttpd-1.4.11/src/connections.c --- lighttpd-1.4.11.org/src/connections.c 2006-07-21 00:27:44.000000000 +0900 +++ lighttpd-1.4.11/src/connections.c 2006-07-21 00:26:47.000000000 +0900 @@ -910,15 +910,21 @@ int connection_handle_read_state(server /* check if we need the full package */ if (con->request.request->used == 0) { buffer b; + char *_bptr; b.ptr = c->mem->ptr + c->offset; b.used = c->mem->used - c->offset; + /* fixed redhat 9 anaconda bug */ + _bptr = strstr (b.ptr, "\t\n"); + if ( _bptr != NULL ) *_bptr = '\r'; + + //log_error_write(srv, __FILE__, __LINE__, "ss", "request header1:", b.ptr); if (NULL != (h_term = buffer_search_rnrn(&b))) { /* \r\n\r\n found * - copy everything incl. the terminator to request.request */ buffer_copy_string_len(con->request.request, b.ptr, h_term - b.ptr + 4);


간단하게, \t\n 을 찾아서 \t 를 \r 로 바꾸는 거죠. ^^; 이렇게 하다가 갑자기 포인터로 구현을 해 보고 싶더군요. 전 앞에서 밝혔다 시피 뽀로꾸와 수많은 닥질의 경험으로 오늘날의 바탕을 마련했는데, C 역시 그냥 마구잡이로 소스를 써내려간 막가파로서, 포인터에 대한 이해가 전혀 없이 사용해 왔는데 갑자기 포인터가 이해가 되는 듯한 느낌이 들었습니다. 그래서 별 소용은 없지만 다음과 같은 코드도 만들게 됩니다.

diff -urNp lighttpd-1.4.11.org/src/connections.c lighttpd-1.4.11/src/connections.c --- lighttpd-1.4.11.org/src/connections.c 2006-07-21 00:27:44.000000000 +0900 +++ lighttpd-1.4.11/src/connections.c 2006-07-21 00:26:47.000000000 +0900 @@ -910,15 +910,31 @@ int connection_handle_read_state(server /* check if we need the full package */ if (con->request.request->used == 0) { buffer b; + char *_bptr; b.ptr = c->mem->ptr + c->offset; b.used = c->mem->used - c->offset; + /* fixed redhat 9 anaconda bug */ + if ( strchr (b.ptr, '\t') != NULL ) { + _bptr = b.ptr; + while ( *_bptr != 0 ) { + if ( *_bptr == '\t' ) { + if ( *(_bptr+1) == '\n' ) { + *_bptr = '\r'; + break; + } + } else *_bptr++; + } + } + /* fixed redhat 9 anaconda bug */ + + //log_error_write(srv, __FILE__, __LINE__, "ss", "request header1:", b.ptr); if (NULL != (h_term = buffer_search_rnrn(&b))) { /* \r\n\r\n found * - copy everything incl. the terminator to request.request */ buffer_copy_string_len(con->request.request, b.ptr, h_term - b.ptr + 4);


누워서 침뱉기 일지는 모르겠지만.. 포인터를 사용하면서 한번에 이렇게 써 내려간 적은 처음인 듯 싶습니다. 예전에 기타를 칠때도 한동안 안 늘다가 어느날 갑자기 못치던 것을 치게 되는 경우가 있었는데, 마치 오늘 위의 코드가 그런 경우인 듯 싶습니다. 스스로가 감탄스럽더군요. (저는 가끔 제멋에 뻑 갈때가 종종 있습니다. ^^)

RH9 의 말도 안되는 request query 덕분에, 고생도 엄청 했고, 저런 것까지 처리를 해 주고 있는 apache 에 대해서 새삼스럽게 존경을 하게 되었으며 (괜히 apache 라고 하는게 아니구나..), 이런 코드를 한번만에 만들어 낸 자신에게 감탄도 하고.. (워낙 설계라는 것 없이 하나 보니, 한번에 쓰는 경우는 정말 드물었죠..), 금방 위치를 찾아낸 것도 감탄 스럽고.. 몸은 힘들었지만, 마음은 그대로 나름대로 뿌듯합니다.

처음에는 google 신에게 구걸을 하려고 시도를 했으나, 결국에는 찾지를 못하여.. 이 글로 내가 했던 고생을 좀 덜 수 있으면 다행이라 생각하고 후기를 남깁니다.
2006/07/21 04:01 2006/07/21 04:01
비밀방문자

관리자만 볼 수 있는 댓글입니다.

김정균

ㅎㅎ 버그가 맞네요. \t\n 을 \r\n 으로 하는 것이 목적인데, 제 코드는 \t\r 을 만들고 있었네요. ㅋㅋ 오류 알려 주셔서 감사합니다.

뭐 어차피 이 코드는 실제 패치에 사용한 코드가 아니라 그냥 심심해서 만들어본 코드였으니 상관은 없습니다만..

그리고 요즘 버전은 이 패치가 맞지 않습니다. 그래서 패치 자체도 바뀌었죠. 요즘은..

+ /* if rh9 support flag on, convert \t\n to \r\n */
+ if ( srv->config_storage[0]->rh9support ) {
+ //log_error_write (srv, __FILE__, __LINE__, "s", "RH9 Support flag on";);
+ if ( ch == '\\t' && b.ptr[i+1] == '\n' )
+ b.ptr[i] = '\\r';
+ }

이정도로 처리가 되고 있네요 :-)

popori

역쉬 뽀로꾸 마왕.. 그거땜시 내 점심이 날아간겨?

박정욱

이야.. 그때 그놈이군요.. 당황케했던.. 결국 발견.. @.@