키워드 [Programming][VC++][Tip]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=6499&ref=6499

질문글에 답변을 달다가.. 언뜻 스쳐지나간 MSDN 내용을 찾아서.. 올려봅니다.

현재 내가 실행시킨 프로그램이 스스로 떠 있는 상태에서 자기 자신의 실행파일을 다른 곳으로 이동하는 질문이
있어서.. 기억을 살려 보았습니다.

일반적으로 구동중인 실행파일이나.. 그런것을 지울 수는 없습니다.
공유 에러를 발생시키기 때문이죠.

근디, 윈도의 치명적인 버그인지는 몰라도 이동은 가능합니다.
(버그일까.. 아님 일부러 그렇게 가능하도록 만든 것일까.. ???? )

물론 다른 파티션이나 드라이브로의 이동은 불가능합니다.
하지만 동일한 드라이브 내에서의 이동은 가능하죠.

정확하게 확인한것은 아니지만, 메모리와 메핑되어 있는 파일의 영역은 그대로 살리고
NTFS의 링크만 이동하는것으로 짐작합니다.

즉, 탐색기 상에서는 파일이 이동한 것으로 보이지만, 링크만 바뀌었을 뿐 메핑된 파일 영역은 디스크상에
그 위치 그대로 존재하게 되는 것이겠죠.

위와 같은 동작을 하기위해서는 Window 2000 이상에서만 가능합니다...
파티션이 NTFS이어야만 하는 지는 잘 모르겠고, FAT16 or FAT32 는 실험해보지 않았습니다.

#define WINVER 0x0500
#define _WIN32_WINNT 0x0500

MoveFileEx(original path, move path, MOVEFILE_FAIL_IF_NOT_TRACKABLE);

PS. 참고로 이동할 경로에 동일한 이름을 가진 파일이 존재하면 에러 납니다..

----------------------------------------------------------------------------------------

정일호 (madness_kr)   정일호님께 메시지 보내기정일호님을 내 주소록에 추가합니다.정일호님의 개인게시판 가기 
Window 2000. FAT32 에서도 잘 되네요...

키워드 [Programming][VC++][API]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=6761&ref=6761


디렉토리에 대한 변경이 발생하면, 발생한 이벤트와 경로를 큐에 저장
2. 큐 처리 전용스레드를 이용하여, 만약 부모 윈도 핸들을 주면, PostMessage로 정보 전송

조언을 듣고 코드 프로젝트에도 잘 꾸며진 소스를 살펴밨습니다만...
제가 사용하기에는 코드가 좀 크고 복잡해서 잘 분석이 않되네요.
그래서, 이전 버전을 좀더 업데이트 해봤습니다.
앞으로 필요에 의해 쭈욱 업데이트를 하겠지만, 제 본래 작업과는 거리가 먼 분야라..

짬짬이..  ^^;
참고로, 실행파일과 샘플 프로젝트를 올립니다.
샘플은 C:\와 D:\에 걸쳐 동작하도록 두개를 돌렸습니다.
대략.. 3개 드라이브에..  CD 한장 분량을 복사하고 해봐도.. 큰 문제는 없군요.
버그도 좀 있으면, 리플주세요

구조가 좀 지저분한데, 혹시나 정리하시는 분이 생기시면 업데이트 해주세요 ^^;

키워드 [Programming][VC++][Regsitry]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7471&ref=7471

// 레지스트리를 설정한 후 키이름을 변경할 만한 방법이 없어서 구현해봤습니다.
// 직접적으로 이름의 변경이 가능한건 아니고, 현재 열린 키를 포함 하위를 몽땅
// 파일로 백업한 다음에, 변경할 새 키로 몽땅 리스토어 한후, 기존 키를 지웁니다.

// 대상 키는 미리 만들어 주셔야 하며, 그게 귀찬을 경우
// 소스를 조금 수정하시면 없을 경우는 만들고 동작하도록 구성하시면 됩니다.

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege = TRUE)
{
    HANDLE hToken;
 
    if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
  return FALSE;
 
    TOKEN_PRIVILEGES tp;
    LUID luid;
 
    if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid )) {
        TRACE("LookupPrivilegeValue error: %u\n", GetLastError() );
        return FALSE;
    }
 
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 else
  tp.Privileges[0].Attributes = 0;
 
 if ( !AdjustTokenPrivileges(hToken, FALSE,  &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) ) {
  TRACE("AdjustTokenPrivileges error: %u\n", GetLastError() );
  return FALSE;
 }
 
 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
  TRACE("The token does not have the specified privilege. \n");
  return FALSE;
 }
 
 return TRUE;
}

#define TEMP_BACK_FILE  "_#temp"

BOOL RegRenameKey(HKEY srcROOT, const char* srcSUB, HKEY dstROOT, const char* dstSUB)
{
 HKEY hKeySrc=0, hKeyDst=0;
 DWORD Ret;
 
 // 저장할 때는 SeBackupPrivilege, 복구할 때는 SeRestorePrivilege 권한이 필요하다. msdn 발췌
 if( !SetPrivilege("SeBackupPrivilege") || !SetPrivilege("SeRestorePrivilege") )
  return FALSE;
 
 if( RegOpenKeyEx(srcROOT, srcSUB, 0, KEY_ALL_ACCESS, &hKeySrc) != ERROR_SUCCESS ||
  RegOpenKeyEx(dstROOT, dstSUB, 0, KEY_ALL_ACCESS, &hKeyDst) != ERROR_SUCCESS )
  return FALSE;
 
 Ret = RegSaveKey(hKeySrc, TEMP_BACK_FILE, NULL);
 if(ERROR_SUCCESS != Ret)
 {
  RegCloseKey(hKeySrc);
  DeleteFile(TEMP_BACK_FILE);
  return FALSE;
 }
 RegCloseKey(hKeySrc);
 hKeySrc = 0;
 
 Ret = RegRestoreKey(hKeyDst, TEMP_BACK_FILE, REG_FORCE_RESTORE | REG_NO_LAZY_FLUSH);
 if(ERROR_SUCCESS != Ret)
 {
  RegCloseKey(hKeyDst);
  DeleteFile(TEMP_BACK_FILE);
  return FALSE;
    }
 
    RegCloseKey(hKeyDst);
    SHDeleteKey(srcROOT, srcSUB);
    return TRUE;
}

----------------------------------------------------------------------------------------------

오승우 (Ċhobits)   오승우님께 메시지 보내기오승우님을 내 주소록에 추가합니다.오승우님의 개인게시판 가기  61.75.68.12
참고로 XP이상에선 NtDll.dll에 native API NtRenameKey가 있습니다.
http://www.codeproject.com/system/NtRegistry.asp

키워드 [Programming][VC++][Multimedia]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7518&ref=7518

전에도 한번 올라왔던 내용인데..
요즘 중복되는 질문 내용이 자주 보여 간단하게 정리해서 올립니다.

PlaySound()는 아주 간단하게 리소스나 파일의 wav폼 파일을 읽어서 재생할 수 있는 함수입니다.
단점이 싱크모드와 어싱크 모드로 재생이 가능한데.. 싱크모드로 돌리면 제어가 불가능하고..
어싱크모드로 돌리면 종료시 점을 알수 없다는데 있습니다.

아래의 기법을 이용하면 어싱크모드로 재생하면서 종료 시점을 알수 있고요..
Sleep에 의한 오차 100ms가 있긴 하지만.. 어쨋든...

원하는 소리를 원하는 시점에서 재생 및 중지를 시킬 수 있다는게 장점입니다.

// 소리를 재생하는 스레드입니다.
DWORD CALLBACK AAA(void* param)
{
   // 임시로 aaa.wav란 넘을 어싱크모드로 플레이 합니다.
    PlaySound("aaa.wav", NULL, SND_FILENAME | SND_ASYNC);

    while(1)
    {
        Sleep(100);

        // 재생이 끝날 때 까지 대기 합니다.
        // SND_NOSTOP 옵션이 있어서 현재 재생중일 때는 아래의 함수가 FALSE를 리턴함다.
        if(PlaySound(NULL, NULL, SND_PURGE | SND_NOSTOP | SND_NOWAIT | SND_SYNC))
            break;
    }

    return 0;
}

// 아무 곳에서나 현재 재생중인 음악을 중지 하시고 싶으시면.
// 음악을 중지시키면 당연히 위의 스레드도 바로 종료하게 됩니다.
PlaySound(NULL, NULL, SND_PURGE | SND_NOWAIT | SND_ASYNC);

키워드 [Programming][VC++][String]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7534&ref=7534

질문글을 보다가 문득 예전 자료가 생각나서.. 잠시 올려봅니다.
보통 문자열을 파싱할 때, 많이 쓰이는게 구분자를 문자열중에 찾는 겁니다.
만약 구분자가 여러개라면?


아이디어는 strtok 소스를 보면서 따온겁니다.
현재 고속으로 문자열을 처리할 때 지금도 사용중이며, 좀더 좋은 아이디어나 자료가 있으신분들은
공유해 주시면 감사~~ ^^;


아래의 예제는 간단하게, 주어진 문자열에서 숫자, 대문자, 소문자의 갯수를 출력하는 루틴입니다.
응용은 본인이 필요한 형식에 따라 하시면 되겠죠.
(한글이 포함되었을 경우는 별도 처리가 필요하지만 생략...)
 
문자열 고속 처리에 관심이 많은데, 좋은 자료를 구할 수 있는 곳이나..
숨겨놓은 보석이 있으시면 공개좀.. ^^;

#define CHECK_MAP(map, arg) ((map[arg >> 3] & (1 << (arg & 7))) && arg)
 
unsigned char map_num[32];
unsigned char map_so[32];
unsigned char map_dae[32];

void init()
{
    int i;
    char* ctrl_num = "1234567890";
    for (i = 0; i < 32; ++i)
        map_num[i] = 0;
    do
    {
        map_num[*ctrl_num >> 3] |= (1 << (*ctrl_num & 7));
    } while (*ctrl_num++);

    char* ctrl_so = "abcdefghijklmnopqrstuvwxyz";
    for (i = 0; i < 32; ++i)
        map_so[i] = 0;
    do
    {
        map_so[*ctrl_so >> 3] |= (1 << (*ctrl_so & 7));
    } while (*ctrl_so++);

    char* ctrl_dae = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    for (i = 0; i < 32; ++i)
        map_dae[i] = 0;
    do
    {
        map_dae[*ctrl_dae >> 3] |= (1 << (*ctrl_dae & 7));
    } while (*ctrl_dae++);
}

void getsome(const char* str, int& num, int& so, int& dae)
{
    if(str == NULL || str[0] == 0)
        return;

    num = so = dae = 0;
    while(*str)
    {
        if(CHECK_MAP(map_num, *str))
            num++;
        else if(CHECK_MAP(map_so, *str))
            so++;
        else if(CHECK_MAP(map_dae, *str))
            dae++;
        ++str;
    }
}

int main()
{
    const char* p = "12341441srsfafAAFSaf";
    int num, so, dae;
    init();
    getsome(p, num, so, dae);
    return 0;
}

------------------------------------------
num = 8, so = 8, dae = 4;

키워드 [Programming][VC++][File][Security]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7537&ref=7537

MSSQL2005는 참.. 쓰기가 까다롭군요. (드럽다는 표현이.. -_-);
DB를 다루다 보면 DB파일을 여러가지 이유 때문에 Attach or Detach 할경우가 많이 있습니다.
근디, 2005 이놈이 파일을 Detach하면 보안 속성을 어드민 전용, 혹은 심할 경우 시스템 전용으로
보안 속성을 싹 바까버립니다.
 

사람이 손까락으로 할 경우는 눈으로 확인하고, 이것 저것 건드려서 보안 속성을 풀면 되지만
어플리케이션에서 할 경우는 돌아버립니다. --^;
Detach한 파일에 대한 접근이 차단되어 버리기 때문에 다시 Attach할 수도 혹은 복사도 불가능해지죠.
 
그래서, 어플리케이션에서 파일의 보안 속성을 필요한 형태로 변경할 수 있도록 구성해 봤습니다.
삽질하시는데 도움이 되시기를...
 
#include <windows.h>
#include <aclapi.h>
 
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege = TRUE)
{
    HANDLE hToken;
    if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
        return FALSE;

    TOKEN_PRIVILEGES tp;
    LUID luid;   

    if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid ))
        return FALSE;

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;
   
    if ( !AdjustTokenPrivileges(hToken, FALSE,  &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) )
        return FALSE;

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
        return FALSE;

    return TRUE;
}

BOOL AddToACL(PACL pACL, const char* AccountName)
{
    BYTE SidBuffer[100] = {0};
    PSID ptr_sid;
    DWORD SidBufSz;
    char DomainNameBuf[256] = {0};
    DWORD DomainNameBufSz;
    SID_NAME_USE SNU;

    ptr_sid = SidBuffer;
    SidBufSz = 100;
    DomainNameBufSz = 256;
 
    if(!LookupAccountName(NULL, AccountName, ptr_sid, &SidBufSz, DomainNameBuf, &DomainNameBufSz, &SNU))
        return FALSE;   

    return AddAccessAllowedAce(pACL, ACL_REVISION,
        GENERIC_ALL+GENERIC_READ+GENERIC_WRITE+GENERIC_EXECUTE,
        ptr_sid);
}

BOOL ChangeFileSecurity(const char* path)
{
    // 권한이 없을 경우는 생성해야 한다.
    // 보통은 어드민이므로 생략 가능하다.
    // SetPrivilege("SeSecurityPrivilege");
 
    SECURITY_DESCRIPTOR SD;
    SECURITY_ATTRIBUTES SA;
    BYTE AclBuf[100] = {0};
    PACL pACL;   

    if(!InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION))
        return FALSE;
 
    pACL = (PACL)AclBuf;
    if(!InitializeAcl(pACL, 100, ACL_REVISION))
        return FALSE;

     AddToACL(pACL, "Everyone");
    AddToACL(pACL, "Administrator");
    AddToACL(pACL, "SYSTEM");   

    if(!SetSecurityDescriptorDacl(&SD, TRUE, pACL, FALSE))
        return FALSE;

    SA.nLength = sizeof(SECURITY_ATTRIBUTES);
    SA.bInheritHandle = FALSE;
    SA.lpSecurityDescriptor = &SD;

    LocalFree(pACL);
    return SetFileSecurity(path, DACL_SECURITY_INFORMATION, &SD);
}


 

키워드 [Programming][VC++][Certfication][PFX]
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7598&ref=7598

윈도에서 OpenSSL을 사용할경우 인증서를 익스포트 시켜서
PEM 파일로 변환한 후 로드하는 과정이 필요하죠.

보통 제어판에서 인증서를 열어가지고 마우스로 콕콕 찍어서..
프라이빗 키 설정한 후 익스포트 하여 사용하곤 하는데..

귀찬죠.. 가끔 까먹기도 하죠.. 설명할라믄 메뉴얼 작성해야죠.. -_-

윈도 크립토 API를 사용하여 간단하게 샘플을 만들어 보았습니다.

첨부된 클래스의 헤더는 아래와 같습니다.

//////////////////////////////////////////////////////////
#include <windows.h>
#include <wincrypt.h>
#include <cryptuiapi.h>

class CCertToPFX  
{
public:
    CCertToPFX();
    virtual ~CCertToPFX();

    void SetStoreName(CHAR* name);
    void SetCertName(CHAR* name);
    void SetSaveName(CHAR* name);
    void SetPrivatePassword(CHAR* name);

    BOOL Export();
    DWORD GetLastError();

protected:
    HCERTSTORE  m_hCertStore;        
    HCERTSTORE  m_hCertTemp;        
    CHAR        m_pszStoreName[256];
    CHAR        m_pszCertName[256];
    CHAR        m_pszSaveName[MAX_PATH];
    CHAR        m_pszPrivatePass[256];

    DWORD       m_dwLastError;
};

샘플 코드는 아래와 같습니다.
////////////////////////////////////////////////////
    CCertToPFX con;
    con.SetStoreName("MY");
    con.SetCertName("my_ssl");
    con.SetSaveName("C:\\test.pfx");
    con.SetPrivatePassword("my_password");

    if(!con.Export())
        con.GetLastError();


1.3.9 Feature Description
아래의 내용들은 RUDP를 이해하는데 도움이될 몇몇 특징을 적어놓았다. 아래의 세부 내용들은 서버와 클라이언트 간의 연결속에서 세그먼트를 서보 주고받을 때에 사용된 용어 및 동작에 관한 내용들이다.

Retransmission timer
전송측은 설정가능한 전송주기 타이머를 가진다. 이 타이머는 data, nul, or reset 등이 전송되었을 때 마다 항상 초기화되어 가동된다. 만약 송신에 대한 응답을 받지 못하였을 경우.. 타이머가 지정된 시간에 동작하여 재전송하는데 이용된다. 만약 여전히 하나 혹은 여러개의 응답을 받지 못하였을 경우 이 타이머는 재가동 될것이다. 추천값은 600 ms 이다.

Retransmission Counter
위에서 나온 재전송 타이머의 최대 반복 횟수에 필요한 카운터이다. 이 것또한 설정가능한 값이며 추천값은 2이다. 만약 카운터 값이 설정된 값을 초과하게 되면 이 연결은 깨진 연결로 간주하고 처리해야한다. 아래의 Broken connection handling 에서 이러한 상태를 어떻게 처리하는지 세부적으로 설명하고 있다.

Stand-alone acknowledgments
stand-alone acknowledgment 세그먼도 하나의 세그먼트로 acknowledgment 에 관한 정보만을 포함하고 있다.  시쿤스 번호 필드에는 data, null, or rest의 다음 시퀀스 번호를 포함한다.

Piggyback acknowledgments
수신자가 전송자에게 data, null, or reset 세그먼트를 전송할 때는 마지막 시퀀스 번호에 대응한 엑크를 포함하여 전송하여야 한다.

Out-of-sequence acknowledgments counter
수신자는 시퀀스 번호가 잘못된 세그먼트가 도착하였을 경우 그 수를 세고 있어야 한다. 그 수가 한도를 초과하면 EACK에다가 out-of-sequence의 한도값을 넣어서 송신자에게 보내주어야 한다. 그리고 0으로 리셋한다. 추천값은 3이다. 만약 송신자에게 EACK를 포함한 놈이 도착되면 자신이 보낸 데이터가 수신자에게 전달되어 못하였음을 인지해야 한다.

Cumulative acknowledge timer
응답이 아니거나 잘못된 시퀀스를 받았을 경우 수신자는 타이머를 설정하고 기다려야한다. 이 타이머가 익스파이어 되면 아웃오프시퀀스 경우는 EACK를 전송한다. 다른 경우 스탠드얼론 엑크를 전송한다. 추천값은 300 ms 이다.

Null segment timer
클라이언트는 타이머를 연결이 열기는 순간부터 유지해야한다. 그리고 데이터 세그먼트를 전송할 때 마다 초기화 시켜서 재가동 시켜준다. 만약 클라이언트의 null segment 타이머가 익스파이어되면, 클라이언트는 서버로 null 세그먼트를 전송해준다. 즉 keep alive 첵크를 유지해야 한다는 이야기다. 이 세그먼트의 시퀀스 번호가 유효하다면 서버는 이에 응답해야 한다. 서버는 널 세그먼트의 이전의 값과 현재 값 두개를 타임아웃 값으로 유지해야한다. 만약 클라리언트로 부터 널 세그먼트를 수신 받으면 이 타이머는 리셋된다. 만약 이 타이머가 익스파이어되면 연결이 끊어진 것으로 간주한다.  이 부분에 대해서는 아래의 Broken Connection Handling 을 참조한다. 추천 값은 2 sec 이다.

Auto Reset
양쪽의 연결은 오토 리셑으로 초기화 할 수 있다. 이 오토리셑은 과도한 재전송, 널 세그먼트 타이머 익스파이어, 전송 상태 타이머의 익스파이어등 다양한 상황에서 사용될 수 있다. 오토 리셑은 양측 연결을 초기화 하고 각종 타이머값을 초기할 수 있으며, 시퀀스의 초기화 등 연결에 필요한 설정값을 다시 협상하여 재설정 할 수 있다. 오토 리셑 카운터의 최대값을 넘기지 않으면 연결을 유지한 상태에서 설정이 가능하다. 최대값을 넘든다면 당연히 연결설정이 초기화 된다. 추천값은 3이다.

Receiver Input Queue Size
입력 큐 사이즈는 설정 가능한 파라미터이다. 추천값은 32 패킷이다. 입려 큐의 사이즈는 플로우 컨트롤 메카니즘을 따른다. 대충 하나의 데이터 크기는 저 패킷수를 넘지 않도록 조절하라는 이야기인건가?

Congestion control and slow start
RUDP는 이러걸 지원하지 않는단다.

UDP port numbers
RUDP에서는 특정한 포트 번호를 제안하지 않고있다. 쓰고 싶은데로 정해서 쓰면된다. 단 일반적으로 쓰고 있는 디파인된 포트는 피하는게 좋다.  RFC 1700 참조.

Support for redundant connections
만약 RUDP 연결이 실패하면 상위 레이어 프로토콜(ULP - Upper Layered Protocol)에서 스트널이 발생할 것이고 전송상태 타이머를 가동한다. 그리고 상위 레이어에서는 새로운 연결을 열어서 이전에 보내던 패킷을 다시 보내게 된다.  패킷이 중복되거나 잃어버리지 않는 것을 보장한다. 만약 ULP에서 새로운 연결로 상태정보를 보내지 않거나 상태 타이머가 익스파이어되면 이 연결은 해제되어 버린다. 이 타이머의 ㄱ밧은 설정 가능한 값이다. 추천값은 1 sec 이다.

Broken connection handling
만약 다음과 같은 현상이 발생하면 RUDP 연결이 끊어졌다고 가정한다.
 - 재전송 타이머가 익스파이어되고, 최대값을 초과하였을 때
 - 서버의 널 세그먼트 타이머가 익스파이어 됬을 때

만약 위의 두경우중 하나가 발생하고 상태 타이머가 0이 아니면, ULP는 연결이 끊어졌음을 인지하고 API를 통하여 시그널을 날린 후에 전송 상태 타이머를 가동한다. 만악 이 타이머가 익스파이어 되면 오토 리셑이 가동된다. 전송 상태 타이머의 값이 0이 되면, ULP는 연결이 실패한 것으로 간주하고 리셑시킨다.

Retransmission Algorithm
재선송은 EACK 세그먼트를 받던가, 혹은 재전송 타이머가 익스파이어되면 수행된다. EACK 세그먼틀 수신하였을 경우 unacknowledged sent queue를 비운다. EACK 세그먼트로 부터 마지막 잘못된 시퀀스 번호와 필요한 ACK 넘버를 추출한다. 그리고 응답하지 않은 큐에 있던 것들을 재전송한다.

Signals to Upper Layer Protocol (ULP)
아래의 시그날들이 API를 통해 ULP로 전송될 수 있다. 이것들은 비동기 적인 이벤트로 ULP에 전달된다.
 - 연결 열림 : 전송을 위한 연결이 생성되었음.
 - 연결 거부 : 종료 대기상태가 아닌 상태에서 연결이 종료되었을 때
 - 연결 종료 : 종료 대기상태에서 종료되었을 때
 - 연결 실패 : 재전송 알고리즘에 의해 연결이 끊어진 것으로 판명 되었을 때
 - 오토 리셋 : 데이터가 로스되어 새로운 연결을 열었을 때

Checksum Algorithm
16-bit one's complement of the one's complement

FEC
Forward Error Connect(FEC)에 대해 별도로 디파인된건 없다. 알라서 처리하라는 이야기다.

1.4 Feature Negotiation
클라이언트는 협상가능할 파라미터를 포함한 SYN 세그먼트를 전송하여 연결을 초기화 한다.
서버는 어셉트를 하고, 클라이언트가 보낸 파라미터를 그냥 수용하거나 다른 값이 있을 경우는 그 값을 넣어서 SYN에 ACK를 담아서 응답을 보낸다. 클라이언트는 서버가 보낸 파라미터를 선택하고 수락된 연결을 거부 한 후 RST를 날린다. 그리고 필요한 것을 취사선택 한 후 다시 연결을 한다. 오토 리셑의 경우에는 이 과정을 수행할 수 없다.

2.0 Future Potential Enhancements
RUDP는 앞으로 클라이언트/서버의 연결에 시메트릭 모드를 지원할 것이다. 이것은 양쪽 어느곳에서나 연결을 능동적으로 시작할 수 있다.

RUDP는 익스텐드 시퀀스와 엑크널리지 필드를 현재 1 옥텟에서 2 옥텟으로 확장 지원할 것이다. 이것은 전송 윈도우가 현재 255보다 더 커짐을 의미한다.

또한 네트워크를 좀더 효율 적으로 사용할 수 있도록 Nagle Algorithm을 사용할 수 있도록 연구중이다.


3.0  References

[1]  Postel, J. (ed.), "Internet Protocol - DARPA Internet Program
     Protocol Specification", RFC 791, USC/Information Sciences Institute,
     September 1981.

[2]  Postel, J., "User Datagram Protocol", RFC 768, USC/Information
     Sciences Institute, August 1980.

[3]  Postel, J. (ed.), "Transmission Control Protocol", RFC 793,
     USC/Information Sciences Institute, September 1981.

[4]  Velten, D., Hinden, R. and Sax, J., "Reliable Data Protocol", RFC
     908, BBN Communications Corporation, July 1984.

[5]  Partridge, C. and Hinden, R., "Version 2 of the Reliable Data
     Protocol", RFC 1151, BBN Corporation, April 1990.

[6]  Braden, R., "Computing the Internet Checksum", RFC 1071, ISI,
     September 1988

[7]  V. Jacobson, "Congestion Avoidance and Control," Computer
     Communication Review, Val. 18, no. 4, pp. 314-329, Aug. 1988.

[8]  W. Stevens, RFC 2001 ?TCP Slow Start, Congestion Avoidance, Fast
     Retransmit, and Fast Recovery Algorithms?, January 1997

[9]  V. Jacobson, "Modified TCP Congestion Avoidance Algorithm", April
     30, 1990.

[10] Z. Wang, J. Crowcroft, A Dual-Window Model for Flow and Congestion
     Control, The Distributed Computing Engineering Journal, Institute
     of Physics/British Computer Society/IEEE, Vol 1, No 3, page 162-172,
     May 1994.

[11] Romanow, Allyn, "TCP over ATM: Some Performance Results",
     ATM Forum/93-784


4.0  Author's Addresses

Tom Bova                               Tel:  +1-703-484-3331
Cisco Systems                          Email:  tbova@cisco.com
13615 Dulles Technology Drive
Herndon, VA  20171
USA

Ted Krivoruchka                        Tel:  +1-703-484-3325
Cisco Systems                          Email:  tedk@cisco.com
13615 Dulles Technology Drive
Herndon, VA  20171
USA


--------------------------------------------------------------------------------------------
흠.. 첨에 시작할 때는 상당히 심플한 프로토콜로 간주하고 시작했는데.. 직접 다 구현하려면
이것 저것 치댈개 많아 보이네요.. 흠.. IPSec는 아직 다뤄보지 않았는데..  -_-
영어를 헤이트 하다보니 번역이 엉망임다... 혼자 볼려구 만든거지만 서도.. 혹시나 구린데가 있으면
주석 남겨 주세요.. 뱌뱌~





 

1.3.3  ACK Segment
ACK 세그먼트는 연속적인 세그먼트 사이에 사용된다. 이는 RUDP 헤더에 다음 시퀀스 번호와 액크넘버를 포함하고 있다. ACK 세그먼트는 세그먼트를 구분할 때 보내어지나, 전송할 때 데이터를 포함하여 전송이 가능하다. DATA세그먼트와 NULL 세그먼트는 항상 ACK 필드를 포함해야 하며
Acknowledgment Number 를 채워야한다. 독립적인 ACK 세그먼트는 6바이트로 구성되어있다.

   0 1 2 3 4 5 6 7 8              15
   +-+-+-+-+-+-+-+-+---------------+
   |0|1|0|0|0|0|0|0|       6       |
   +-+-+-+-+-+-+-+-+---------------+
   | Sequence #    |   Ack Number  |
   +---------------+---------------+
   |           Checksum            |
   +---------------+---------------+

    Figure 3, Stand-alone ACK segment

1.3.4 EACK segment
EACK 세그먼트는 out of sequence(시퀀스 번호가 잘못됨)를 받았을 경우 보내는 acknowledge segments 이다. 이 세그먼트는 잘못된 시퀀스 번호를 포함한게 몇개였는지 정보가 포함되어있다.
항상 ACK 세그먼트아 함께 보내지며, 마지막에 제대로 전송된 시퀀스 번호를 넣어서 보낸다. 헤더의 길이는 확정되어 있지 않다(variable). 최소 길이는 7바이트이며 최대 길이는 maximum receive queue length 값에 의존한다.

    0 1 2 3 4 5 6 7 8            15
   +-+-+-+-+-+-+-+-+---------------+
   |0|1|1|0|0|0|0|0|     N + 6     |
   +-+-+-+-+-+-+-+-+---------------+
   | Sequence #    |   Ack Number  |
   +---------------+---------------+
   |1st out of seq |2nd out of seq |
   |  ack number   |   ack number  |
   +---------------+---------------+
   |  . . .        |Nth out of seq |
   |               |   ack number  |
   +---------------+---------------+
   |            Checksum           |
   +---------------+---------------+

       Figure 4, EACK segment


1.3.5 RST segment
RST 세그먼트는 연결을 닫거나 리셋활 때 사용된다. RST 세그먼트를 받았을 경우, 전송자는 반드시 새로운 패킷을 보내는 것을 중지해야한다. 그러나 이미 보내어지고 있던 패킷은 모두 보내어야한다. RST 세그먼트는 구분자로써 사용되너 어떠한 데이터도 포함해서는 않된다.

   0 1 2 3 4 5 6 7 8              15
   +-+-+-+-+-+-+-+-+---------------+
   | |A| | | | | | |               |
   |0|C|0|1|0|0|0|0|        6      |
   | |K| | | | | | |               |
   +-+-+-+-+-+-+-+-+---------------+
   | Sequence #    |   Ack Number  |
   +---------------+---------------+
   |         Header Checksum       |
   +---------------+---------------+

          Figure 5, RST segment


1.3.6 NUL segment
NUL 세그먼트는 상대측이 아직도 살아있나를 결정하는데 사용된다(일종의 Keep-Alive). 그래서 일걸 keep-alive 라고 부르기도 한다. NUL 세그먼트를 전송받으면, 그 즉시 ACK 세그먼트로 응답해야 하며, 다음 시퀀스 번호를 넣어서 연결이 유효함을 알려주어야한다. 그리고 받은 NUL 세그먼트는 그냥 버린다. NUL 은 반드시 ACK를 포함해야하며 유저데이터는 절대 포함되어서는 않된다.

    0 1 2 3 4 5 6 7 8             15
   +-+-+-+-+-+-+-+-+---------------+
   |0|1|0|0|1|0|0|0|       6       |
   +-+-+-+-+-+-+-+-+---------------+
   | Sequence #    |  Ack Number   |
   +---------------+---------------+
   |            Checksum           |
   +---------------+---------------+

        Figure 6, NUL segment


1.3.7 TCS Segment
TCS 세그먼트는 현재 연결의 상태정보를 전달한다.

    0 1 2 3 4 5 6 7 8             15
   +-+-+-+-+-+-+-+-+---------------+
   | |A| | | | | | |               |
   |0|C|0|0|0|0|1|0|       12      |
   | |K| | | | | | |               |
   +-+-+-+-+-+-+-+-+---------------+
   | Sequence #    |   Ack Number  |
   +---------------+---------------+
   | Seq Adj Factor|      Spare    |
   +---------------+---------------+
   |      Connection Identifier    |
   +                               +          
   |       (32 bits in length)     |
   +---------------+---------------+
   |            Checksum           |
   +---------------+---------------+

          Figure 7, TCS segment


Sequence Number
현재 연결에 선택되었던 초기의 시퀀스 번호...

Acknowledgment Number
마지막 시퀀스 넘버에 대응하는 ack number를 만들어 넣는다.

Seq Adj Factor
This field is used during transfer of state to adjust sequence numbers
between the old and current connections.

Connection Identifier
새로 열린 RUDP 연결에서 전 구간에 걸쳐 유일하게 연결을 구분할 수 있도록 해주는 ID값이다.
여러개의 연결이 있을 경우 각각의 연결을 구분해주는데 사용된다.

1.3.8 Detailed Design
A separate internet draft is being prepared which details in connections
state transitions in Specification and Description Language (SDL) format. 
It also contains more details on the internal design of RUDP.

to bo continue...




1.3.2 SYN 세그먼트
SYN은 두 호스트간에 연결할 때 시퀀스 넘버를 동기화 할 때 사용한다. 이 세그먼트를 포함한 패킷에는 연결에 필요한 협상정보(negotiable parameters)를 포함한다. 설정가능한 모든 파라미터는 상대방이 알아야 하므로 협상을 위하여 포함시킨다. SYN은 유저 디파인 데이터를 포함 할 수 없다. SYN 세그먼트는 연결을 자동으로 리셋시키는데 사용될 수 도 있다. ( 대충 연결되어 있는데
다시 싱크 날리면 연결정보를 재설정하는가 보다. )
아래 그림은 SYN 세그먼트이다.

   0             7 8              15
   +-+-+-+-+-+-+-+-+---------------+
   | |A| | | | | | |               |
   |1|C|0|0|0|0|0|0|       28      |
   | |K| | | | | | |               |
   +-+-+-+-+-+-+-+-+---------------+
   +  Sequence #   +   Ack Number  |
   +---------------+---------------+
   | Vers  | Spare | Max # of Out  |
   |       |       | standing Segs |
   +---------------+---------------+
   | Option Flags  |     Spare     |
   +---------------+---------------+
   |    Maximum Segment Size       |
   +---------------+---------------+
   | Retransmission Timeout Value  |
   +---------------+---------------+
   | Cumulative Ack Timeout Value  |
   +---------------+---------------+
   |   Null Segment Timeout Value  |
   +---------------+---------------+
   | Transfer State Timeout Value  |
   +---------------+---------------+
   |  Max Retrans  | Max Cum Ack   |
   +---------------+---------------+
   | Max Out of Seq| Max Auto Reset|
   +---------------+---------------+
   |    Connection Identifier      |
   +                               +
   |      (32 bits in length)      |
   +---------------+---------------+
   |           Checksum            |
   +---------------+---------------+

        Figure 2, SYN segment

Sequence Number
이 연결을 위한 초기 시퀀스 번호를 포함하고 있다. (랜덤하게 생성한다.)

Acknowledgment Number
이 필드는 ACK가 설정되어 있을 경우만 유효하다. 이 케이스에서 , 필드는 상대측에서 보낸 SYN 세그먼트의 시퀀스 넘버가 포함된다.

Version
RUDP버전. 초기 버전은 1이다.

Maximum Number of Outstanding Segments
위 정보는 ACK 없이 보내져야한다. 이 정보는 받는 측에서 플로우 컨트롤에 사용된다. 이 값은 초기에 설정되면 연결이 유지되는 동안에는 변경될 수 없다. 이 정보는 협상대상이 될 수 없다.

Options Flag Field
이 플래그는 2바이트짜리다. 아래 보이는것 처럼 디자인되어있다.

BIT#         Name           Description
 0          not used        ---
 1            CHK           데이타 첵섬 인에이블. 이게 1로 설정되어 있으면 헤더와
                            데이터를 포함한 첵섬을 포함한다. 협상가능한 파라미터
 2           REUSE          이 비트는 오토리셑ㄷ되는 동안에 이전에 협상된 파라미터의
                            사용 여부를 결정하기 위하여 꼴 설정되어야 한다. 1로 설정
                            되면 이전 껄 쓰고 따라붙는 항목을 무시하고, 0이면 새걸쓴다
3-7          Spare

Maximum Segment Size
이 값은 상대측에서 SYN을 보낼 때 내가 받는 정보이다. 이 값은 서로 다른 값을 가질 수도 있다.
서로가 연결 협상을 하고 있는 동안 서로가 받게되며, 각각은 상대에게 이 값보다 크게 패킷을 전송하면 않된다. 이 숫자는 RUDP으 헤더의 크기도 포함한다. 이 정보는 협상대상이 될 수 없다.

Retransmission Timeout Value
패킷이 응답하지 않을 경우 재전송까지 기다리는 시간값. 밀리세컨단위. 레인지는 0 - 65536. 협상가능한 값으로 양쪽이 모두 같은 값에 동의해야한다.

Cumulative Ack Timeout Value
연속된 세그먼트중에 하나를 보내지 않았을 경우 다음 세그먼트를 보내기까지 사이 값에 해당하는 타임아웃 값. 밀리세컨단위. 레인지는 100-65536. 양쪽이 동의한 값에 협상이 가능하다. 추가적으로 이 값은 무조껀 Retransmission Timeout Value 보다는 작아야한다.

Null Segment Timeout Value
데이터 세그먼트를 보내지 않았을 경우, 널 세그먼트를 보내기 위한 타임아웃. 널 세그먼트는 킾 얼라이브와 같은 메카니즘이다. 밀리세컨단위. 레인지는 0-65536. 협상가능한 파라미터.

Transfer State Timeout Value
자동 리셋이 발생하기전의 연걸을 위하여 저장되어 있어야 하는 상태 정보의 타임아웃. 밀리세컨단위. 레인지는 0-65536. 협상가능한 파라미터. 만약 이 값이 0이면 상태정보의 저장 없이 바로 재연결이 이루어진다.

Max Retrans
재 전송이 연속적으로 이루어질 때 몇번을 할것인지를 알려주는 최대값. 레인지는 0-255. 이 값이 0이면 계속 재전송을 한다. 협상가능한 파라미터.

Max Cum Ack
The maximum number of acknowledgments that will be accumulated before sending an acknowledgment if another segment is not sent. 레인지는 0-255. 이 값이 0이면 데이터, 널, 리셋 세그먼트를 받았을 경우 acknowledgment segment를 바로 보낸다. 협상 가능한 파라미터.

Max Out of Seq
EACK를 보내기 전까지 누적된 시퀀스 넘버가 잘못된 패킷의 최대 값. 레인지는 0-255. 이 값이 0이면 EACK를 바로 보낸다. 협상가능한 파라미터.

Max Auto Reset
연결을 리셋하기 전까지 수행된 연속적인 오토 리셋의 최대값. 레인지는 0-255. 이 값이 0이면
토리셋은 수행되지 않고, 바로 리셋되어 버린다. 협상가능한 파라미터. 이 카운터는 연결이 새로 열리면 클리어된다.

Connection Identifier
새로운 연결이 설정되면 현재 연결사이에서 구분될 수 있는 유일값을 주고 받는다. 양쪽에서는 이값을 저장하고 있어야한다. 오토리셑이 수행되면 상대측에서는 저장해 두었던 오리지날 ID를 전송하여 오토리셋이 수행되는 동안 사용한다.

to bo continue...




+ Recent posts