• 2005-09-06

    cwRsync 를 이용한 클라이언트 배포

    Overview

    한동안 메신저 + zip 파일 기반의 배포 시스템을 고집하다가 더 이상 참을 수가 없어서 결국 cwRsync 라는 툴을 테스트 해보게 되었다. Cygwin + rsync + openssh 를 NullSoft 인스톨러로 깔끔하게 패키징한 이 유틸리티는 약간의 삽질 만으로 간편하면서도 공짜 파일 배포 시스템을 구축할 수 있게 해준다. 당연히 호스트 접근 제어도 가능하고, SSH 를 통해서만 배포할 수도 있다.

    이전 프로젝트에서도 InSync 를 이용해서 팀 내부에 클라이언트를 배포했었다. 클라이언트 프로그래머가 최신 파일들을 특정 공유 폴더에다가 업데이트하면, 각자가 로컬에 설치된 프로그램을 실행해서 변경된 파일들을 받아오는 방식인데, 가끔 동시에 많은 사람이 업데이트를 받을 경우 문제가 있었고, 무엇보다도 shareware 여서 어둠과자를 사용해야만 했다.

    Install

    이번에 테스트한 것은 '안전하지 않은' no-ssh 배포 방식. 간단히 삽질한 내용을 정리해보면...

    • 우선 cwRsync 서버를 설치하고 rsyncd.conf 를 열어 모듈을 설정하라. 모듈은 rsync 로 파일을 받아갈 때의 대표 이름으로 CVS 의 그것과 같다. 일반적으로 서버측의 파일을 클라이언트에서 받아가므로 read only 는 true 로 설정할 것.

    [모듈명]
    path = /cygdrive/드라이브/배포폴더
    read only = true
    transfer logging = yes

    • prepare a directory for upload 명령을 실행해서 rsync 서버가 제대로 폴더를 읽고 쓸 수 있게 하라.
    • 서비스는 기본적으로 꺼져 있는 상태. 자동 실행으로 만든 다음 서비스를 시작하라. 또한 방화벽에서 TCP 873 포트를 열어주는 것을 잊지 말 것.
    • 클라이언트를 설치하고 배치 파일을 작성하라. 기본적으로 제공하는 cwrsync.cmd 파일을 복사한 다음 적절히 수정해주면 된다. 특정 rsync 서버의 모듈을 recursive 로 받아오려면 다음과 같이 하면 된다.

    rsync -avr 서버::모듈 /cygdrive/드라이브/다운받을폴더

    • 물론 로컬 파일을 업로드하려면 순서를 뒤집으면 된다. 이때 서버측에서 read only = false 여야만 가능하다.

    rsync -avr /cygdrive/드라이브/업로드할폴더 서버::모듈

    Filter

    rsync 는 강력한 파일 필터링 기능을 제공한다. 물론 커맨드라인으로 지정할 수도 있지만 수정을 쉽게 하려면 필터 파일을 만들어 두는 것을 권장. 자세한 도움말은 rsync 도움말을 참조할 것. 아래의 필터 파일 예제는 log/ upload/ 폴더 및 로그 파일, VSS 관련 파일들을 무시한다는 의미이다.

    • log/
    • upload/
    • *.log
    • *.scc

    필터 파일을 지정하려면 '--exclude-from=필터파일명' 을 지정해주면 된다.

    마치며

    사실 내부 테스트를 위해서도 패치 시스템을 구축하는 것이 가장 좋겠지만, 보유중인 패치 시스템의 인터페이스가 간편하지 않다면 오히려 낭패... 차라리 부담없이 GNU 툴들을 도입해 보는 것이 정신 건강상 더 나을 듯하다.

    그리고, 아무래도 안정적으로 파일을 배포하려면,
    개발 머신 --(rsync)--> 패치 서버 --(rsync)--> 팀 배포
    의 2단계를 거치는 것이 좋은데, 이를 위해서는 서버에 같은 폴더를 나타내는 upload 모듈과 download 모듈을 만들어 둬야 한다. 또한 실행 파일만을 배포할 경우를 위한 배치 파일도 따로 만드는 것을 권장한다. (아무래도 recursive 로 검색을 하면 시간이 좀 걸린다)

  • 2005-08-10

    CPB 맛보기

    지금까지는 애용해왔던 XML 기반의 tweaking 방식이 너무 귀찮아서, 이번에 CPB 를 써보기로 마음을 먹었다. 근무 시간에 삽질을 하기엔 힘든 상황이라 집에 와서 해야만 했다. :(

    소스와 함께 배포되는 솔루션을 열고 적당한 루아 라이브러리와 링킹해서 실행해보면 별 문제가 없지만, 이걸 실제로 쓰기 위해 라이브러리와 샘플 프로젝트로 분리해서 해보면 잘 되지 않는다. 바로 test.lua 안에서 pdb 파일명이 틀려서 생긴 문제이다. 물론 샘플 프로젝트 이름을 CPTest 로 만들었다면 당신은 천재...

    CPB 가 사용하는 것은 Debugging Access Interface (DIA) SDK 로, Visual Studio .NET 2003 을 설치하면 Visual Studio SDKs/ 아래에 함께 설치가 된다. 물론 CPB 와 함께 배포되는 놈과 완전히 같다. 괜히 본인처럼 Platform SDK를 설치할 필요는 없다.

    pdb 파일을 한번 읽어서 .cpb 파일로 만들어서 배포할 수 있기 때문에 클라이언트 어플리케이션에 사용해도 무방하다. (이걸로 크랙하면 낭패겠지만..과연..) 물론 서버쪽이라면 매번 배포할 때마다 .cpb 파일을 만들기보다는 그냥 pdb 파일을 함께 배포해주는 것이 더 편할 것 같다.

    ps. 테스트 도중 갑자기 실행 파일 크기가 6k 로 줄어들면서 16비트 MS-DOS 프로그램을 CPU 에서 실행할 수 없다는 오류 메시지가 떴다. '아직 안정화가 덜 된 건가..' 하면서 접으려고 했는데, 프로젝트를 새로 만들어보니 문제가 없었다. 사실은 Ctrl+F5 로 실행하기 위해서 dll 과 lua 파일을 사용자 지정 작업에서 복사하도록 했는데, 이때 복사 위치를 $(TargetDir) 대신 $(TargetPath) 로 해서 생긴 문제.. *그 6k 짜리 실행파일은 사실은 test.lua 였었다는 사실.. *

    ps2. 여전히 namespace 지원은 안된다. 즉 어떤 변수나 클래스가 namespace 안에 존재할 경우 바인딩이 불가능하다. 이 말은, std::string 을 바인딩할 수 없다는 뜻이며, char * 변수에 대한 direct assignment 가 지원되지 않기에 이 문제는 조금 귀차니즘을 불러 일으키게 될 듯. :(

    ps3. const char * 를 리턴하는 함수를 호출해서 print 해보려고 했으나, 단지 userdata 로만 인식함. 약간은 서운한;;; (먼가 모르는 듯)

  • 2005-07-12

    맨티스에 custom severity 추가!

    mantis

    오래전부터 맨티스에다가 중요도나 우선순위 상수를 추가해달라는 요청이 있었으나, 소스를 고쳐야 하기 때문에 방법이 없다고 모른 척 했었다가, 이번에 잠시 짬을 내어 추가를 해 보았다. 관련 자료를 아래에 정리했으니 심심할 때 한번 읽어보시길. :)

    see also : MantisCustomize

  • 2005-06-02

    boost::test

    레이옷은 종전까지 CppUnit를 애용해왔다. 그러나 이넘은 VC7 에서는 컴파일조차 되지 않았다. 그리하여, 새로운 UnitTest 툴을 찾다가 발견한 것이 바로 이 Boost Library 에 포함된 BoostTest 이다. 이하 설명은 모두 VC7 을 사용한다고 가정하고 설명하겠다.

    사용법

    BoostTest 에는 아래와 같은 모듈이 포함되어 있다.

    모듈 설명
    Execution Monitor 실행 모니터, 아래 프로그램 실행 모니터 및 테스트 실행 모니터의 베이스 모듈
    Program Execution Mointor 배포되는 실행 프로그램의 테스트를 위해
    Test Execution Mointor 개발중인 실행 프로그램의 테스트를 위해
    Unit Test Framework 유닛 테스트.. 우리가 사용할 것이 이거다
    Test Tools 위에 4개 모듈에서 사용하는 각종 테스트 루틴 및 매크로들

    이 중에서 레이옷이 사용하는 것은 Unit Test Framework ( + Test Tools ) 이다. 우선 상세한 내용은 같이 배포되는 문서를 참고하기 바란다. 여기서는 실제 프로젝트와 어떻게 연관지을 것인가만을 고민한다.

    • 테스트할 모듈의 프로젝트 이름이 XXX 라고 하자.
    • 그러면 이 프로젝트를 테스트할 프로젝트인 test_XXX 를 솔루션에 새로 추가한다.
    • 이 프로젝트를 LibXXX 프로젝트에 종속되도록 설정한다.
    • Build Event 의 '''Custom Build''' 에 다음과 같은 내용을 추가하라.
    • "$(TargetPath)" --report_level=detailed --log_level=all
    • 참고로 --log_level 은 BOOST_MESSAGE, BOOST_WARN_MESSAGE, BOOST_CHECKPOINT 등의 매크로들의 출력을 화면에 나타낸다.
    • 나중에 메시지들이 귀찮아지면 모두 끄도록 한다. 이에 대한 내용 역시 문서를 참고할 것

    BoostTest with wstring

    UniCode 기반의 어플리케이션을 테스트할 때, BOOST_XXX 매크로에서 wide string 이 포함될 경우, 변환할 수 없다는 에러가 발생한다. 그럴 경우 아래의 코드를 해당 테스트 상단에 넣어주면 임시방편으로 수정이 가능하다. 물론 wstring string 컨버팅 함수는 직접 작성해야 한다. :)

    
    namespace boost { namespace test_tools { namespace tt_detail {
        template
        struct print_log_value
        {
            void  operator()( std::ostream& ostr, std::wstring t )
            {
                std::string s = convert_wstring_to_string(t);
                ostr
    
    
    
    // testLibCore.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
    //
    
    #include "stdafx.h"
    
    #include
    using namespace boost::unit_test_framework;
    
    #include "MMSocket.h"
    
    void test_winsock()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_ctor()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMSocket client;
            BOOST_CHECK( !client.IsAlive() );
            BOOST_CHECK( client.GetErrorCode() == 0 );
            BOOST_CHECK( client.GetHost() == MMString(TEXT("Unknown")) );
            BOOST_CHECK( client.GetPort() == 0 );
    
        BOOST_CHECK( client.Create() );
            BOOST_CHECK( client.IsAlive() );
    
        client.Close();
            BOOST_CHECK( !client.IsAlive() );
    
        MMSocket::EndWinsock();
    }
    
    void test_serversocket_create_with_port()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        WORD wPort = 8888;
    
        MMServerSocket server;
            BOOST_CHECK( server.IsAlive() );
            BOOST_CHECK( server.GetErrorCode() == 0 );
            BOOST_CHECK( server.GetHost() == MMString(TEXT("Unknown")) );
            BOOST_CHECK( server.GetPort() == 0 );
    
        BOOST_CHECK( server.Bind(wPort) );
            BOOST_CHECK( server.GetHost() == MMString(TEXT("localhost")) );
            // default host = localhost
            BOOST_CHECK( server.GetPort() == wPort );
    
        server.Close();
            BOOST_CHECK( !server.IsAlive() );
    
        MMSocket::EndWinsock();
    }
    
    void test_serversocket_create_with_addr()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMString strHost = TEXT("localhost");
        WORD wPort = 8888;
    
        MMServerSocket server;
            BOOST_CHECK( server.IsAlive() );
    
        BOOST_CHECK( server.Bind(wPort) );
            BOOST_CHECK( server.GetHost() == MMString(TEXT("localhost")) );
            BOOST_CHECK( server.GetPort() == wPort );
    
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_serversocket_create_with_public_ip()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMString strHost = TEXT("61.74.134.38");
        WORD wPort = 8888;
    
        MMServerSocket server;
            BOOST_CHECK( server.IsAlive() );
    
        BOOST_CHECK( server.Bind(strHost,wPort) );
            BOOST_CHECK( server.GetHost() == MMString(TEXT("61.74.134.38")) );
            BOOST_CHECK( server.GetPort() == wPort );
    
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_serversocket_create_with_private_ip()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMString strHost = TEXT("192.168.0.1");
        WORD wPort = 8888;
    
        MMServerSocket server;
            BOOST_CHECK( server.IsAlive() );
    
        BOOST_CHECK( server.Bind(strHost,wPort) );
            BOOST_CHECK( server.GetHost() == MMString(TEXT("192.168.0.1")) );
            BOOST_CHECK( server.GetPort() == wPort );
    
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_serversocket_listen()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("192.168.0.1");
        WORD wPort = 8888;
    
        MMServerSocket server;
    
        BOOST_CHECK( server.Bind(szHost,wPort) );
        BOOST_CHECK( server.Listen() );
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_connect()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("61.74.134.38");
        WORD wPort = 8888;
    
        MMServerSocket server;
    
        BOOST_CHECK( server.Bind(szHost,wPort) );
        BOOST_CHECK( server.Listen() );
            BOOST_CHECK( server.IsAlive() );
    
        MMSocket client;
        client.Create();
            BOOST_CHECK( client.IsAlive() );
        BOOST_CHECK( client.Connect(szHost,wPort) );
    
        client.Close();
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_connect_fail()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("61.74.134.38");
        WORD wPort = 8888;
    
        MMServerSocket server;
    
        BOOST_CHECK( server.Bind(szHost,wPort) );
        BOOST_CHECK( server.Listen() );
            BOOST_CHECK( server.IsAlive() );
    
        MMSocket client;
        client.Create();
            BOOST_CHECK( client.IsAlive() );
        BOOST_CHECK( !client.Connect(szHost,wPort-1) ); // must be failed
    
        client.Close();
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_serversocket_accept()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("61.74.134.38");
        WORD wPort = 8888;
    
        MMServerSocket server;
    
        BOOST_CHECK( server.Bind(szHost,wPort) );
        BOOST_CHECK( server.Listen() );
            BOOST_CHECK( server.IsAlive() );
    
        MMSocket client;
        client.Create();
            BOOST_CHECK( client.IsAlive() );
        BOOST_CHECK( client.Connect(szHost,wPort) );
    
        MMSocket * pClient = server.Accept();
            BOOST_CHECK( pClient != NULL );
            BOOST_CHECK( pClient->IsAlive() );
            //BOOST_CHECK( pClient->GetHost() == client.GetHost() );
            //BOOST_CHECK( pClient->GetPort() == client.GetPort() );
    
        client.Close();
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    /*
     *  accept 전에 닫아도 accept 된다.. 음냐..
     */
    void test_serversocket_accept_failed()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("61.74.134.38");
        WORD wPort = 8888;
    
        MMServerSocket server;
    
        BOOST_CHECK( server.Bind(szHost,wPort) );
        BOOST_CHECK( server.Listen() );
            BOOST_CHECK( server.IsAlive() );
    
        MMSocket client;
        client.Create();
            BOOST_CHECK( client.IsAlive() );
        BOOST_CHECK( client.Connect(szHost,wPort) );
        client.Close();     // close before accept
    
        Sleep(100);
    
        MMSocket * pClient = server.Accept();
            BOOST_WARN_MESSAGE( pClient == NULL, "헹.. 널이어야 할텐데.." );
    
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    /*
     *  정말 nonblocking 인지 확인해봐야 하지 않나?? 그걸 알아내는 방법은?
     */
    void test_socket_blocking()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMSocket client;
        client.Create();
        BOOST_CHECK( client.EnableNonblock() );
        BOOST_CHECK( client.DisableNonblock() );
        client.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_linger()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMSocket client;
        client.Create();
    
        BOOST_CHECK( !client.IsEnabledLinger() );           // no linger at default
            BOOST_CHECK( client.GetLingerTime() == 0 );
    
        BOOST_CHECK( client.EnableLinger(100) );
            BOOST_CHECK( client.IsEnabledLinger() );
            BOOST_CHECK( client.GetLingerTime() == 100 );
    
        BOOST_CHECK( client.DisableLinger() );
            BOOST_CHECK( !client.IsEnabledLinger() );
            BOOST_CHECK( client.GetLingerTime() == 100 );   // do not cleared
    
        client.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_recv_buffer()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMSocket client;
        client.Create();
    
        BOOST_CHECK( client.GetRecvBufferSize() == 8192 );  // default buffer size
    
        BOOST_CHECK( client.SetRecvBufferSize(10000) );
        BOOST_CHECK( client.GetRecvBufferSize() == 10000 );
    
        BOOST_CHECK( client.SetRecvBufferSize(65535) );
        BOOST_CHECK( client.GetRecvBufferSize() == 65535 );
    
        BOOST_CHECK( client.SetRecvBufferSize(65535*2) );
        BOOST_CHECK( client.GetRecvBufferSize() == 65535*2 );
    
        client.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_send_buffer()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMSocket client;
        client.Create();
    
        BOOST_CHECK( client.GetSendBufferSize() == 8192 );  // default buffer size
    
        BOOST_CHECK( client.SetSendBufferSize(10000) );
        BOOST_CHECK( client.GetSendBufferSize() == 10000 );
    
        BOOST_CHECK( client.SetSendBufferSize(65535) );
        BOOST_CHECK( client.GetSendBufferSize() == 65535 );
    
        BOOST_CHECK( client.SetSendBufferSize(65535*2) );
        BOOST_CHECK( client.GetSendBufferSize() == 65535*2 );
    
        BOOST_CHECK( client.SetSendBufferSize(-1) );
        BOOST_CHECK( client.GetSendBufferSize() == -1 );
    
        client.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_nagle()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMSocket client;
        client.Create();
    
        BOOST_CHECK( client.IsEnabledNagle() );     // enabled at default
    
        BOOST_CHECK( client.DisableNagle() );
            BOOST_CHECK( !client.IsEnabledNagle() );
        BOOST_CHECK( client.EnableNagle() );
            BOOST_CHECK( client.IsEnabledNagle() );
    
        client.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_serversocket_reuseaddr()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        MMServerSocket server;
        BOOST_CHECK( server.Bind( TEXT("61.74.134.38") ,9999) );
    
        MMServerSocket server2;
        BOOST_CHECK( !server2.Bind( TEXT("61.74.134.38") ,9999) );
        server2.Close();
    
        MMServerSocket server3;
        BOOST_CHECK( server3.EnableReuseAddr() );
        BOOST_CHECK( server3.Bind( TEXT("61.74.134.38") ,9999) );
        server3.Close();
    
        MMServerSocket server4;
        BOOST_CHECK( server4.EnableReuseAddr() );
        BOOST_CHECK( server4.DisableReuseAddr() );
        BOOST_CHECK( !server4.Bind( TEXT("61.74.134.38") ,9999) );
        server4.Close();
    
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_gethostbyname()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("comeng.ce.knu.ac.kr");
        BOOST_CHECK( MMSocket::GetHostByName(szHost) == MMString(TEXT("155.230.29.10")) );
    
        szHost = TEXT("mudmania.org");
        BOOST_CHECK( MMSocket::GetHostByName(szHost) == MMString(TEXT("61.74.134.38")) );
    
        //szHost = TEXT("reiot.cafe24.com");
        //BOOST_CHECK( MMSocket::GetHostByName(szHost) == MMString(TEXT("61.74.134.38")) );
    
        szHost = TEXT("mudmania2.org");
        BOOST_CHECK( MMSocket::GetHostByName(szHost) == MMString("") );
    
        MMSocket::EndWinsock();
    }
    
    void test_socket_send()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("61.74.134.38");
        WORD wPort = 9999;
    
            MMServerSocket server;
            BOOST_CHECK( server.Bind(szHost,wPort) );
            BOOST_CHECK( server.Listen() );
    
        MMSocket client;
        client.Create();
        BOOST_CHECK( client.Connect(szHost,wPort) );
    
            MMSocket * pClient = server.Accept();
            BOOST_CHECK( pClient != NULL );
    
        PTCHAR szSendMsg = TEXT("Hello World!");
        int iSendMsgLen = lstrlen(szSendMsg);
    
        BOOST_CHECK( iSendMsgLen == client.Send(szSendMsg,iSendMsgLen) );
    
            TCHAR szRecvMsg[1024];
            int iRecvMsgLen = pClient->Receive(szRecvMsg,1024);
            if ( iRecvMsgLen > 0 )
            {
                szRecvMsg[iRecvMsgLen] = 0;
            }
            BOOST_CHECK_MESSAGE( iRecvMsgLen == iSendMsgLen, "Received Msg : " Receive(szRecvMsg,1024);
            BOOST_CHECK_MESSAGE( iRecvMsgLen == 0 ,
            "second recv = " GetErrorCode() );
    
            pClient->Close();
            SAFE_DELETE(pClient);
    
        server.Close();
    
        MMSocket::EndWinsock();
    }
    
    /* just receive (guess socket is nonblocking) */
    void test_socket_nonblocked_recv()
    {
        BOOST_CHECK( MMSocket::BeginWinsock() );
    
        PTCHAR szHost = TEXT("61.74.134.38");
        WORD wPort = 80;
    
        MMSocket client;
        client.Create(true);
    
        BOOST_CHECK( client.Connect(szHost,wPort) );
    
        client.EnableNonblock();
    
        TCHAR szRecvMsg[1024];
        int iRecvMsgLen = client.Receive(szRecvMsg,1024);
        BOOST_CHECK( iRecvMsgLen == -1 );
        BOOST_CHECK( client.GetErrorCode() == WSAEWOULDBLOCK );
        client.Close();
    
        MMSocket::EndWinsock();
    }
    
    /*
    
    *TODO*
    
    - connect
    - socket constructor
    - error code checking
    - invalid address
    - socket buffer
    - socket blocking
    - 연결 실패
    
    */
    
    test_suite * test_MMSocket()
    {
        test_suite * test = BOOST_TEST_SUITE( "MMSocket Test" );
    
        test->add( BOOST_TEST_CASE( &test_winsock ) , 0 );
      test->add( BOOST_TEST_CASE( &test_socket_ctor ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_create_with_port ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_create_with_addr ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_create_with_public_ip ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_create_with_private_ip ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_listen ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_gethostbyname ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_connect ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_connect_fail ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_accept ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_accept_failed ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_blocking ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_linger ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_recv_buffer ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_send_buffer ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_nagle ) , 0 );
        test->add( BOOST_TEST_CASE( &test_serversocket_reuseaddr ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_send ) , 0 );
        test->add( BOOST_TEST_CASE( &test_socket_nonblocked_recv ) , 0 );
    
      return test;
    }