제3장 프로토콜 아키텍처

3.1 프로토콜 계층

DTP 구현은 다음 계층 구조에 따라 조직되어야 한다:

+-----------------------------------------------+
|           응용 계층 (Application Layer)         |
|   iFay / coFay / Personal Data Heap            |
|   단말 애플리케이션                              |
+-----------------------------------------------+
|           DTP 프로토콜 계층 (DTP Protocol Layer)|
|   DTP_Engine (DTP_Master / DTP_Slave)         |
|   - Agreement Manager                          |
|   - Frame Codec                                |
|   - DAG Manager                                |
|   - Encryption Module                          |
|   - Session Manager                            |
|   - Resume Manager                             |
+-----------------------------------------------+
|           어댑터 계층 (Adapter Layer)            |
|   Transport_Adapter                            |
+-----------------------------------------------+
|           전송 계층 (Transport Layer)            |
|   BLE / WebSocket / TCP / RTSP / ...           |
+-----------------------------------------------+

구현은 계층을 건너뛴 호출을 해서는 안 된다(예: 응용 계층은 어댑터 계층 인터페이스에 직접 접근해서는 안 된다).

3.2 핵심 컴포넌트

DTP_Engine은 다음 6개의 핵심 컴포넌트를 포함해야 한다:

3.2.1 Agreement Manager(협상 관리자)

Agreement Manager는 다음 능력을 제공해야 한다:

  1. 협상 흐름 관리: Request_Frame과 Response_Frame의 송수신을 처리한다.
  2. 약정 생명주기 관리: 약정의 negotiating에서 terminated까지의 상태 전이를 유지한다.
  3. 고유 식별자 생성: 달성된 각 약정에 대해 RFC 4122를 따르는 UUID v4를 Agreement_ID로 생성한다.
  4. 다중 약정 동시성 지원: 단일 세션에서 여러 활성 약정을 동시에 유지할 수 있어야 한다.

3.2.2 Frame Codec(프레임 인코딩/디코딩기)

Frame Codec은 다음 능력을 제공해야 한다:

  1. 직렬화: LogicalFrame 객체를 바이너리 바이트 시퀀스로 인코딩한다.
  2. 역직렬화: 바이너리 바이트 시퀀스를 LogicalFrame 객체로 디코딩한다.
  3. 왕복 일관성: 임의의 유효한 LogicalFrame 객체에 대해 직렬화 후 다시 역직렬화하면 원본 객체와 동등한 LogicalFrame이 생성되어야 한다.
  4. 포맷 출력(Pretty Printer): LogicalFrame을 사람이 읽을 수 있는 텍스트로 변환하는 능력을 제공해야 하며, 프레임 헤더의 모든 핵심 필드를 포함해야 한다.

3.2.3 DAG Manager(DAG 관리자)

DAG Manager는 다음 능력을 제공해야 한다:

  1. 순환 검출: Fragment가 DAG에 추가되기 전에 순환이 형성되지 않음을 검증해야 한다. 순환이 검출되면 해당 Fragment를 거부하고 DAG_CYCLE_DETECTED 오류(4001)를 반환해야 한다.
  2. 의존 해석: Fragment가 선언한 의존 대상이 아직 도착하지 않았을 때 해당 Fragment를 "의존 해석 대기" 상태로 표시하고 캐시해야 한다.
  3. 지연 해석: 의존 대상이 되는 Fragment가 도착하면 이전에 캐시된 Fragment를 자동으로 해석해야 한다.
  4. 관계 유형 지원: derived_from, annotates, supersedes 세 가지 관계 유형을 지원해야 한다.

3.2.4 Encryption Module(암호화 모듈)

Encryption Module은 다음 능력을 제공해야 한다:

  1. 페이로드 암호화: CAP에서 사전 협상한 키를 사용하여 Payload를 암호화한다.
  2. 페이로드 복호화: CAP에서 사전 협상한 키를 사용하여 수신한 Payload를 복호화한다.
  3. 키 준비 상태 검사: 암호화 작업 전에 CAP가 키 교환을 완료했는지 검증해야 한다.
  4. 암호화 메타데이터 생성: 프레임 헤더에 평문 형태로 암호화 메타데이터(알고리즘 식별자와 키 버전 번호)를 포함해야 한다.

3.2.5 Session Manager(세션 관리자)

Session Manager는 다음 능력을 제공해야 한다:

  1. 세션 생명주기 관리: 세션의 수립, 유지, 종료를 담당한다.
  2. 상태 영속화: 하위 연결이 중단될 때 세션 상태를 영속화해야 한다.
  3. 상태 복구: 연결이 회복되고 CAP 재검증이 통과한 후 이전 세션 상태를 복구할 수 있어야 한다.
  4. 타임아웃 검출: 세션 유휴 타임아웃 검출을 구현해야 한다.

3.2.6 Resume Manager(재개 관리자)

Resume Manager는 다음 능력을 제공해야 한다:

  1. 시퀀스 번호 할당: 전송되는 각 Fragment에 단조 증가하는 시퀀스 번호를 할당한다.
  2. 미확인 캐시: 수신측이 아직 확인하지 않은 Fragment를 로컬에 캐시한다.
  3. 단절 지점 보고: 연결이 회복될 때 상대측에 성공적으로 수신한 최고 시퀀스 번호를 보고한다.
  4. 캐시 관리: 캐시 용량 상한 검출을 구현해야 한다. 캐시가 상한에 도달하면 전송을 일시 중지하고 BUFFER_FULL 오류(6001)를 반환해야 한다.

3.3 상태 머신

DTP_Engine은 다음 상태 머신을 구현해야 한다:

                 [Idle]
                    |
                    | 연결 요청 수신
                    v
             [WaitingForCAP]
                    |
                    | CAP 검증 + 키 교환 완료
                    v
             [SessionEstablished]
                    |
                    | Request_Frame 발의 또는 수신
                    v
              [Negotiating]
                    |
                    | Agreement 달성
                    v
              [Transmitting]
                    |
                    | 연결 중단
                    v
                [Suspended]
                    |
                    | 연결 회복 + CAP 재검증
                    v
                [Resuming]
                    |
                    | 재개 핸드셰이크 완료
                    v
              [Transmitting]

완전한 상태 전이 규칙은 다음 표를 따라야 한다:

현재 상태트리거 이벤트목표 상태비고
Idle연결 요청 수신WaitingForCAP
WaitingForCAPCAP 검증 + 키 교환 완료SessionEstablished
WaitingForCAPCAP 실패 또는 타임아웃Idle관련 자원을 해제해야 한다
SessionEstablishedRequest_Frame 발의 또는 수신Negotiating
SessionEstablished세션 타임아웃Idle세션을 닫아야 한다
NegotiatingAgreement 달성Transmitting
Negotiating협상 실패 또는 거부됨SessionEstablished
TransmittingFragment 지속 전송Transmitting자체 루프
Transmittingadjustment 유형 Request_Frame 수신Negotiating
Transmitting하위 연결 단절Suspended세션 상태를 영속화해야 한다
TransmittingAgreement 종료 및 다른 활성 약정 없음SessionEstablished
Suspended연결 회복 및 CAP 재검증 통과Resuming
Suspended세션 타임아웃Idle자원을 해제해야 한다
Resuming재개 핸드셰이크 완료Transmitting
Resuming복구 실패Idle세션을 닫아야 한다

구현은 위 표에 나열되지 않은 상태 전이를 도입해서는 안 된다.

3.4 Transport_Adapter 인터페이스

Transport_Adapter는 다음 인터페이스를 제공해야 한다:

interface Transport_Adapter {
  // 연결 관리
  connect(endpoint: TransportEndpoint): Connection;
  disconnect(connectionId: ConnectionID): void;

  // 데이터 전송
  send(connectionId: ConnectionID, data: Uint8Array): void;
  onReceive(handler: (connectionId: ConnectionID, data: Uint8Array) => void): void;

  // 상태 이벤트
  onConnectionStateChange(handler: (connectionId: ConnectionID, state: ConnectionState) => void): void;
}

Transport_Adapter의 구체 구현은 다음 규범적 요구사항을 충족해야 한다:

  1. send() 작업은 비차단(non-blocking)이어야 한다.
  2. 하위 연결 상태가 변경되면 onConnectionStateChange 콜백을 통해 DTP_Engine에 알려야 한다.
  3. 지원하는 각 전송 프로토콜(BLE, WebSocket, TCP, RTSP)마다 통일된 인터페이스 구현을 제공해야 한다.
  4. DTP_Engine이 전달한 바이너리 데이터를 수정해서는 안 된다.

3.5 주종 상호작용 시퀀스

완전한 DTP 상호작용은 다음 5단계를 따라야 한다:

단계 1: CAP 사전 처리

DTP_Engine은 CAP가 신원 검증과 키 교환을 완료할 때까지 대기해야 한다. 이 단계에서 DTP는 어떠한 데이터 프레임도 전송해서는 안 된다.

단계 2: DTP 세션 수립

CAP 완료 후, DTP_Engine은 고유한 Session_ID(UUID v4)를 생성하고 SessionEstablished 상태로 진입해야 한다.

단계 3: 협상

단계 3a(데이터 수집 협상): Master는 requestType = collection인 Request_Frame을 전송할 수 있으며, Slave는 Response_Frame을 통해 accepted, rejected 또는 counter_proposal로 회신해야 한다.

단계 3b(데이터 주입 협상): Slave는 requestType = injection인 Request_Frame을 전송할 수 있으며, Master는 Response_Frame을 통해 회신해야 한다.

단계 4: 데이터 전송

Agreement가 달성된 후, 송신측은 데이터 프레임을 통해 Fragment를 전송해야 하며, 각 Fragment는 자신이 속한 Agreement_ID를 포함해야 한다(또는 컨텍스트를 상속하기 위해 생략, 제4.5절 참조).

단계 5: 연결 중단과 회복

하위 연결이 중단되면 DTP_Engine은 Suspended 상태로 진입하고 세션을 영속화해야 한다. 연결이 회복된 후 CAP 재검증을 거쳐 Resuming 상태로 진입하여 재개 핸드셰이크를 완료해야 한다.