삽질하는플머

우분투 서버 8.10에 VMWare server 1.0.8 설치.

탐구생활
사실 우분투는 게으른 사람에게는 좋지 않은 환경인데... 사내의 리눅스 박스도 오랫동안 별 문제 없길래 그냥 내버려두고 있다가 갑자기 테스트 서버를 한 대 설정해야 할 일이 생겼다.

귀차니즘에 8.04를 집어들고 설치 시작. VMWare server 는 1.0.8 을 다운받았는데...

apt-get으로 설치한 GCC는 4.2.4. 커널을 컴파일한 GCC와 버전이 다르다는 경고가 출력된다. 흠... 여기서부터 날고생... 겉으로는 멀쩡히 설치된 듯 하지만... 뭔가 요상하게 동작한다. 윈도에서 구동시킨 VMWare console 에서 예전에는 호스트의 디렉토리를 표시했는데, 생뚱맞게 로컬의 디렉토리가 나온다던가...

이거 고쳐보려고 하루종일 벼라별 삽질을 다 하다가... 그냥 8.10 으로 올라가기로 했다.

http://ubuntu-tutorials.com/2008/11/01/vmware-server-107-on-ubuntu-810-intrepid-2627-7-generic/
http://geekzine.org/2008/11/20/install-vmware-server-on-ubuntu-intrepid-810/


필요한 도구들 설치
apt-get install build-essential linux-headers-`uname -r` xinetd
apt-get install xorg 

VMWare setver 패치 다운로드
wget -c http://www.insecure.ws/warehouse/vmware-update-2.6.27-5.5.7-2.tar.gz

VMWare setver 와 패치의 압축 해제
tar -xzf vmware-update*.tar.gz
tar -xzf VMware-server*.tar.gz

압축이 풀린 경로에서 설치 시작.
cd vmware-server-distrib/
./vmware-install.pl

답변들에는 디폴트로 응답. 그러나 설치 중간에 다음 메시지가 나오면  no 라고 해야 한다.
Before running VMware Server for the first time, you need to configure it by
invoking the following command: "/usr/bin/vmware-config.pl". Do you want this
program to invoke the command for you now? [yes]

이제 패치가 풀린 디렉토리로 이동해서 패치를 진행.
cd ..
cd vmware-update-2.6.27-5.5.7-2
./runme.pl

이 스크립트는 구성에 대한 패치를 진행하고 아까 마지막에 받은 질문을 다시 물어본다. 이번에는 yes로 응답.
나머지 설치는 이전과 동일하다.

-->> 이렇게 해도 뭔가 이상하네... 한 번 이상해지니 완전히 다시 밀고 새로 깔아도 계속 이상하네...
-->> 결국... VMWare 2.0 을 깔았음. 너무 좋아~~~


코드 페이지 삽질기.

탐구생활/Delphi

게임을 일본에 내보냈던 몇년 전 경험에 대해 조금 이야기 해 볼까 합니다.
제가 만든 개허접 GUI엔진에서는 순전히 글립 캐싱할 때 인덱싱이 쉽다는 이유로 유니코드를 사용하고 있습니다.
뭘 모르고 선택했던 것인데... 두고 두고 생각할 때 가장 잘 한 일이었다고 생각해요.

그러나 델파이의 string과 widestring은 "현재 시스템의 코드페이지를 기준으로 자동변환된다" 는, 어쩌면 지극히 상식적인 문제 때문에 일본 서비스를 시작하면서 웃지 못할 일이 발생하고 맙니다.

이 델파이의 신묘함 때문에 초창기 게임 클라이언트는 의도하지 않은 기능을 하나 갖게 되는데, 바로 코드페이지가 같은 시스템 끼리는 같은 나라 언어로 대화할 수 있다는 것이었죠.

예를 들어 일본 서버에 접속한 한국 유저들 끼리는 한글로 채팅을 할 수 있었습니다.
물론 주위의 일본사람들이 볼 때는 의미없이 깨져버린 문자열로 보이겠지만요. (한글로 보인다는 의미가 아닙니다.)
한국 유저가 게임에서 채팅을 시작하면, 입력은 유니코드로 됩니다. 엔터를 누르는 순간 이 유니코드 문자열은 채팅내용을 서버로 전달하는 RequestChat() 함수의 인자로 전달되는데, 이 인자값은 string으로 정의되어 있었고 따라서 현재 시스템의 로케일을 기준으로 자동으로 KSC-5601로 바뀌어 서버로 날아갑니다. 서버야 뭐 이 내용을 그대로 다시 전달하겠죠?? 받아들이는 입장에서 만약 한글 윈도라면... 날아온 코드는 KSC-5601 이니 그대로 다시 GUI엔진으로 들어가면서 자동변환되어 제대로 된 한글이 표시됩니다. 그러나 일본어 윈도에서는 이 문자열을 SHIFT-JIS라고 판단해 전혀 엉뚱한 말로 바꾸어 표시하게 되죠.

'十分' 이라는 한자어를 예로 들어 봅시다. 두 글자 모두 한국과 일본에서 동일하게 표현되는 글자지만 KSC-5601에서는 #223, #168, #221, #194 라는 아스키값으로, SHIFT-JIS에서는 #143, #92, #149, #170 이라는 값으로 처리됩니다. 한마디로 한글윈도에서 일본어로 채팅을 해도 일본사람이 알 수 없는 문자열로 바뀌어버린다는 이야기죠.
한글로 채팅하는 어이없는 기능 대신, 일본어를 보기 위해서는 로케일 설정을 일본어로 하거나 일본어 윈도를 깔아야 하는 상황이 된 겁니다.

사실, 일본의 X게임을 돌리기 위해 VDos 설치까지 감수했던 우리로서는 뭐 어차피 일본서비스, 이정도는 애교로 봐 주자 했었죠. 굳이 일어윈도를 안 깔아도 AppLocale, 또는 Oh!TextHooker 같은 걸출한 물건들이 있었으니까요. 

그러나 문제는 생각지도 않았던 곳에서 발생합니다.

일본사람들이 바글거리는 곳에서 한국 유저가 특정한 단어를 채팅창에 입력하면 일본 유저들의 클라이언트는 모두 종료되어 버리더군요. 어찌나 황당하던지... 반대로 일본사람이 어떤 단어를 입력하면 이번에는 한글윈도에서 띄운 클라이언트들이 휘리릭~ 증발되어 버렸죠. 의도하지 않게 변환된 문자열이 Format문을 만났고, 랜더링 틱 마다 중첩된 에러로 스택오버플로가 발생하면서 클라이언트가 죽은 것이었습니다.

그래서... 일본 서버에서 날아온 문자열은 그냥 SHIFT-JIS라고 판단하는 쪽으로 생각을 바꾸게 됩니다.
문자열이 widestring -> string, 또는 string -> widestring 으로 변환되는 모든 곳에 WideCharToMultiByte(), MultiByteToWideChar() API로 둑을 쌓아야 했습죠.
델파이가 이걸 자동으로 바꿔줘 버리니 에러가 표시되는 것도 아니고... 정말 미칠 것 같더군요. ㅠㅠ;;;

아무튼 몇 달에 걸친 삽질 끝에 십수만라인 곳곳에 뚝을 쌓았고, 데이터에도 코드페이지를 명시 했습니다.
덕분에 일본 클라이언트를 한글윈도에서 띄워도 일본어가 제대로 표시될 수 있게 되었고...
이 때의 경험은 두고두고 좋은 약이 되었네요.


  // 안시 문자열을 유니코드로...
  function AnsiToWide(const aAnsiBuf: PChar; aAnsiLen: Integer; aCodePage: UINT): WideString;
  var
    Str: String;
    WideStrLen: Integer;
  begin
    WideStrLen :=
      MultiByteToWideChar(
        aCodePage,
        MB_PRECOMPOSED,
        aAnsiBuf,
        aAnsiLen,
        nil,
        0
      );

    SetLength(Result, WideStrLen);

    MultiByteToWideChar(
      aCodePage,
      MB_PRECOMPOSED,
      aAnsiBuf,
      aAnsiLen,
      PWideChar(Result),
      WideStrLen
    );
  end;


  // 유니코드를 안시문자열로...
  function WideToAnsi(const aWideBuf: PWideChar; aWideLen: Integer; aCodePage: UINT): String;
  var
    AnsiStrLen: Integer;
  begin
    AnsiStrLen :=
      WideCharToMultiByte(
        aCodePage,
        0,
        aWideBuf,
        aWideLen,
        nil,
        0,
        nil,
        nil
      );

    SetLength(Result, AnsiStrLen);

    WideCharToMultiByte(
      aCodePage,
      0,
      aWideBuf,
      aWideLen,
      PChar(Result),
      AnsiStrLen,
      nil,
      nil
    );
  end;


이후 루아를 만나게 됩니다. 그런데 루아라는 물건은 유니코드와는 아무 관계없는 놈 입니다.
사실 컴파일러나 인터프리터라는 입장에는 유니코드 따위 고민할 필요가 전혀 없죠. 그저 로직의 처리만 신경쓰고 인자로 넘겨받은 문자열의 내용은 단지 그 문자열을 넘겨받는 함수가 고민해야 할 부분이니까요.

먼저 경험을 토대로 문자열이 들어간 모든 데이터는 자신의 '코드페이지'를 가지도록 만들었으므로,  게임 내 아이템 이름을 넘겨받거나 할 때도 위의 함수에 이 코드페이지를 넘겨 변환하는 방식으로 처리할 수 있었습니다.  

그렇게 몇 년을 이게 정답이다~ 하면서 사용하다가... 오늘 옆자리의 하모씨가 한마디 던집니다.

    "그래 우리는 그렇고... 그렇다면 와우의 루아는 어떻게 UTF-8 을 처리하지?"
    "응~ 그러게~~ 음... 응?? UTF-8은 안시문자열이잖아~~!!"

그쵸. UCS2, UCS4가 아니더라도 안시문자열에 다국어가 훌륭하게 담기는 규약이 이미 오래전 부터 존재하고 있었고 이곳 저곳에 아무 생각없이 써 오고 있었던 겁니다. 처음부터 내부처리는 UCS2, 외부저장은 UTF-8이라는 규칙만 떠 올렸다면 국가별 코드 페이지 관리는 개나 던져주고 많은 이들이 행복하게 살 수 있었는데 말이죠.

위의 함수를 약간 손봐서 aCodePage가 CP_UTF8 (65001) 인 경우는 Multi우쩌구 말고 UTF8Decode, UTF8Encode를 사용하도록 변경 했습니다. 그리고 다국어가 섞인 루아파일을 UTF-8로 저장해 클라이언트에서 불러 봤습니다.


 Lua.SetCodePage(65001)
 Gui.MessageBox(
   "일어 : パリス・ヒルトン 突然の破局\n" ..
   "한글 : 민성기 만세만세만세\n" ..
   "쭝국 : 时髦单品购买清单",
   "테스트 대화상자"
 )  
  


오오오~~ 감동의 눈물이~~ 주주륵~~~
'十分' 만에 해결될 일을 도대체 얼마나 돌아온건지~~~


언어별 데이터 관리로 고생하는 기획팀에 심심한 애도의 묵념을~~~ㅠㅠ;;




2009.6.24

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/System_SetMultiByteConversionCodePage.html

System.SetMultiByteConversionCodePage Function

여기에 적절한 코드페이지를 설정하면, Wide <> Ansi 변환시 기준 코드페이지가 설정된다.

ssh 연결시 암호 입력 건너뛰자.

탐구생활/CYGWIN
ssh의 멋진 점은, 내가 원하는 명령을 서버에 전달하고 그 결과값을 받아볼 수 있다는 것이다.
예를 들어 다음과 같은 명령어를 통해

ssh root@192.168.0.151 ps -eaf

현재 서버에서 192.168.0.151 서버에서 구동중인 프로세스 리스트를 살펴볼 수도 있다.
screen과 병행한다면 원격지에서 한 번의 명령으로 많은 서버를 구동 / 정지시킬 수도 있다는 의미!

다만 이 경우 대상 서버의 암호를 입력 해야 한다. 이 부분은 자동화의 적! 따라서 암호없이
ssh 연결을 하는 방법을 알아보자.

다음 사이트에 좋은 정보가 있다. 
http://www.csua.berkeley.edu/~ranga/notes/ssh_nopass.html

간단히 정리 해 보면...

1. 먼저 클라이언트에서 다음 작업을 진행한다.


$ mkdir -p $HOME/.ssh
$ chmod 0700 $HOME/.ssh
$ ssh-keygen -t dsa -f $HOME/.ssh/id_dsa -P ''


한 번이라도 ssh를 사용했더면 $HOME/.ssh 디렉토리가 이미 존재하므로 윗 두 줄은 생략해도 좋다.
이제 .ssh 디렉토리에는 개인키 id_dsa 와 공개키 id_dsa.pub 두 개의 파일이 생겼다.

2. 위에서 생성된 공개키 id_dsa.pub 파일을 서버로 옮겨준다.

3. 서버에서 다음 작업을 진행한다.


$ cat id_dsa.pub >> $HOME/.ssh/authorized_keys2
$ chmod 0600 $HOME/.ssh/authorized_keys2


OpenSSH의 버전에 따라 다음 작업이 추가로 필요할 수도 있다.


$ cat id_dsa.pub >> $HOME/.ssh/authorized_keys
$ chmod 0600 $HOME/.ssh/authorized_keys


또는 심볼릭 링크를 걸어도 좋다.


$ cd $HOME/.ssh && ln -s authorized_keys2 authorized_keys


4. 클라이언트에서 다음과 같이 연결을 테스트 해 본다.


$ ssh -i $HOME/.ssh/id_dsa server



다음 화면은 Cygwin 이 깔린 로컬 컴퓨터에서 ssh로 우분투가 깔린 컴퓨터에 접속해 ls -al 를 날리고 그 결과를
받아오는 화면이다.






발급된 개인키를 사용해 PuTTY로 로컬호스트에 패스워드 없이 접속해보자. 
PuTTY Key generator 를 실행시킨다. 




Load 버튼을 눌러 위에서 만들어둔 개인키 id_dsa 를 불러들인다. 성공적으로 불리웠다는 메시지가 나오면 이번에는 'Save private key' 버튼을 눌러 *.ppk 형식으로 저장한다. 이 때 패스워드를 입력하지 않으면 경고가 뜨는데 지금 목적은 패스워드 없이 접속하는 것이므로 무시하자. 

PuTTY Config 에서 새로운 세션을 만들고 SSH - Auth 항목의 'Private key file for authentication' 에 방금 생성한 PPK 파일을 지정해준다. 

로컬호스트가 PuTTY에서 지정된 개인키를 인식할 수 있도록 해주어야 한다. 

$ cd ~/.ssh
$ cat id_dsa.pub >> authorized_keys2
$ ln -s authorized_keys2 authorized_keys


이제 접속해보면 암호를 묻지 않고 바로 들어갈 수 있게 된다. 




이 다음에 살펴볼 PuTTY_Cyg 를 사용하면 간단하지만, 그래도 로컬이 아닌 다른 접속에 유용한 내용이므로 정리 해 둔다. 





윈도 2003 서버에서 CygWin의 SSHD 동작시키기

탐구생활/CYGWIN
대부분 XP에서의 설치와 비슷하다.
그러나 설치 후 ssh -v localhost 로 접속을 테스트 해 보면 키교환이 안되고 멈추는 현상이 나타난다.

이 문제 때문에 공개용 OpenSSH부터 상용 WinSSHD까지 별별 삽질을 다 해 봤는데...
결국은 미국에서 돌아온 멋쟁이 정팀장님이 문제를 해결 해 버렸다.

설치 후 /etc/hosts.allow 파일을 열고

ALL : PARANOID : deny

이 부분을 주석처리 한 후 sshd를 재구동시킨다.

만세! 만세! 만만세!!!

OpenSSH설치. sshd 구동.

탐구생활/CYGWIN

Cygwin 자체는 내 컴퓨터에서 돌아가는 로컬환경이지만,
아무래도 콘솔창이라는 한계 때문에 복사/붙이기에 에로사항이 피어나고
컬럼 수 또한 제한을 받게 된다.

또한 서버 관리를 콘솔 앞에 앉아서 하는 경우는 거의 없다.
리눅스 깔 때도 OpenSSH 서버도 함께 설치하고 네트웍 설정만 마무리 한 다음
자리로 돌아와 PuTTY를 띄우게 된다.

따라서 비록 로컬환경이지만 sshd 를 구동시켜 PuTTY로 접속할 수 있다면
여러가지로 편리 할 것이다.

구글에서 cygwin, sshd 로 검색하자 다음 떡밥이 걸려든다.
http://pigtail.net/LRP/printsrv/cygwin-sshd.html 

1. setup.exe 를 실행시켜 openssh, tcp_wrappers, diffutils, zlib 를 설치한다.
 자동으로 따라붙는 패키지들도 함께 설치되도록 한다.

사용자 삽입 이미지


2. 제어판 -> 시스템 -> 고급 -> 환경변수 를 선택, CYGWIN 변수에 ntsec tty 값을 추가한다.

사용자 삽입 이미지


3. 환경변수 "Path" 뒷부분에 ";c:\cygwin\bin" 를 붙여준다.


4. 최근에 릴리즈 된 Cygwin 의 경우 권한 관련 문제가 발생할 수 있으므로 다음 세 줄의 명령어를 입력 해 준다.

  chmod +r  /etc/passwd
  chmod +r  /etc/group
  chmod  777  /var


5. ssh-host-config  -y 명령을 실행, 모든 질문에 yes 로 답변하도록 한다.
  중간에 스크립트가 실행되면서 "environment variable CYGWIN=" 이라고 묻는다면
  "ntsec tty" 라고 답변한다. (시연을 위해 다시 따라해보니... 이번에는 안물어보는군... 흠...)


6. 여기까지 해서 시작 -> 실행 에서 "services.msc" 를 입력, CYGWIN sshd 가 보인다면 제대로 된 것이다.
  이 서비스를 시작하거나 다음 명령을 입력한다.

  cygrunsrv --start sshd
    또는
  net start sshd


7. 윈도의 각 유저에 암호를 걸어준다.


8. 이제 PuTTY로 접속 해 보자.

사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지

  이제 넓직한 화면에서 Cygwin을 사용할 수 있다... ^^;;