---
# System prepended metadata

title: RFC 3903 Present

---

## Entity-Tag
- 接下來要詳細介紹一下 PUBLISH 會使用到的 Entity-Tag，但在這之前讓我們先來看一下 Entity-Tag 在 HTTP 中的應用。 

### HTTP ETag
- 以下的內容是參考自 RFC 2616，這篇 RFC 是 HTTP/1.1 版的標準文件，而 Entity-Tag 被寫在 section 3.11。這邊我就簡單介紹一下:
    - HTTP Entity-Tag 被用來辨別不同的 URI 發送的 request, request 的內容就是我們所謂的 entity.
    - Entity-Tag 是由不透明且帶有引號的字串組成，通常字串前面會再加上一個辨識用的標示符，被稱為 weakness indicator。
    - Entity-Tag 具有唯一性，只要該 entity 有任何的更動，都會再產生一個新的 Entity-Tag 並把把舊的淘汰，Server 在收到 Client 送來的 request 後會檢查裡面附帶的 Entity-Tag 是否跟自己這邊紀錄的相符，是的話才會處理那個 request。
        - 這有點像是用 GitHub 做版本控制時，新的 commit 會被 assign 新的 ID number 一樣。但不同的是 Entity-Tag 沒辦法用來回朔過去的狀態，只有最新產生的 Entity-Tag 才有用處。

### PUBLISH Entity-Tag
- PUBLISH Entity-Tag 就是參考 HTTP Entity-Tag 去延伸設計的。
- 你們會發現 SIP 有很多地方都跟 HTTP 很相似: request method, response code, entity-tag, authentication.
- 在 SIP PUBLISH 中 ESC(SIP Server) 用 Entity-Tag 來辨別不同的 URI 發送的 PUBLISH request，在這裡所謂的 entity 就是 PUBLISH request 中的 event state。
- SIP PUBLISH 在概念上跟 HTTP PUT 類似，但 Entity-Tag 的應用還是有幾點不同:
    - 剛剛前一頁有提到 HTTP Entity-Tag 是由不透明且帶有引號的字串組成，但在 SIP PUBLISH 中 Entity-Tag 是由 token 的形式存在，而不是一個帶引號的字串。
    - 再來 3903 裡面還提到 PUBLISH Request 一次只能附帶一個 Entity-Tag，我們沒辦法同時要求對多個 publication 進行操作。
    - 在 HTTP 中 Entity-Tag 是 optional 的，管理者可以選擇不使用。但在 SIP 只要 ESC 成功受理了一個 PUBLISH Request 就一定要回一個帶有 Entity-Tag 的 Response。

### Client/Server Usage
雖然宇騰前面有提過 PUBLISH 的流程，我在這邊在強調一下 Entity-Tag 分別在 EPA 跟 ESC 的作用。
- EPA 想 Initial 一個新的 publication 時會發送不帶有 Entity-Tag 的 PUBLISH Request 給 ESC，並從 ESC 那裡取得一個 Entity-Tag。
- EPA 要自己存好這個 Entity-Tag。當 EPA 在任何後續發送的 PUBLISH request 中要去修改、刷新或刪除該 event state 時都會使用 Entity-Tag 讓 ESC 進行辨識。
- 稍早我們有提到過，當 event state 有任何更動都會讓 ESC 再產生一個新的 Entity-Tag 給 EPA。所以基本上只要 EPA 再有新的 PUBLISH Request 送出，都應該要得到新的 Entity-Tag 並淘汰舊的。
- 關於 Entity-Tag 的 format 要如何制定以及所有產生的 Entity-Tag 要如何管理都是由 ESC 決定。
- ESC 只要成功受理一個 PUBLISH Request 就是要回一個帶有新 Entity-Tag 的 200 OK。

:::spoiler Event Packages
- 並非所有的 event packages 都有 multiple sources 的需求, 若有需要則要在最初設計時就定義清楚。
    - For presence, a PUA can publish presence state for just a subset of the tuples that may be composited into the presence document that watchers receive in a NOTIFY.
- 關於 ESC 是否支援 event state 的 segmentation 也應該在最初設計時就定義清楚 ESC 處理 segments 的方式。
    - In presence publication, the EPA MUST keep the "id" attributes of tuples consistent in the context of an entity-tag.
:::


### Protocol Elements
- 為了實作 publication 的功能，就直接定義了一個新的 Method "PUBLISH"。
- 也為了 PUBLISH 這個新的 Method 定義了一個新的 response code 412。當 ESC 收到 PUBLISH Request，卻發現裡面附帶的 Entity-Tag 是無效的時候就會回覆一個帶有 code 412 的 response。
- 新欄位


## Security Considerations
HTTP 如何進行身分驗證
### Basic
- Client 會使用 user ID 跟 password 讓 Server 驗證自己的身分。
- 只有經過身分驗證後的 request 才會被 server 處理。
- user ID 跟 password 是以明文的形式去傳送。
### Digest
- user ID 跟 password 不是以明文的形式去傳送，通常會使用 hash function 去進行加密。
- 另外，每一個 request 也會使用 checksum 來確保資料的正確性。

兩者的差別就在身分驗證用的資料是否有在傳送前先被加密過。

### ACL
- 如果每個 client 都能作為 EPA 自由的向 ESC 發布 publication 是不安全的。
- ESC 應該要能根據 EPA 的身份 選擇性地接受對方發過來的 PUBLISH Request。
- 所以 ESC 通常要有個 access control list 去管理被授權的 EPA。
- 應用 Digest Authentication 保護 EPA 的身分驗證資料。

### Replay


### Dos

謹慎選擇 default Expires Time，避免 Publication 過於頻繁的更新。



## QA
- 文中有提到entity-tag是在successful publish request時才會產生，那如果是失敗的，為什麼不用產生呢？



---


## Trace Code

### Structure
- **`pjsip_publishc`**
    ![](https://hackmd.io/_uploads/SytRxC29h.png)

### Functions in `pjsip_simple/publishc.c`
#### ETag
- **`create_request()`**
    ![](https://hackmd.io/_uploads/BJn0gA3qh.png)
    - Add **SIP-If-Match**
        - ![](https://hackmd.io/_uploads/BJ9-Z02c2.png)
- **`tsx_callback()`**
    - Save **ETag**
        - ![](https://hackmd.io/_uploads/SkBRU0353.png)
    - Add **SIP-If-Match**
        - ![](https://hackmd.io/_uploads/SJiQqR293.png)

#### Expires
- `set_expires()`
- `pjsip_publishc_update_expires()`

#### Publish
- `pjsip_publishc_create()`
- `pjsip_publishc_init()`
- `pjsip_publishc_publish()`
- `pjsip_publishc_send()`
- 

### Lab: ETag Changed
```c=
    /* Add SIP-If-Match if we have etag */
    if (pubc->etag.slen) {
        const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
        // Modify by Phoebe 7/25
        pj_str_t myetag;
        char* myetag_ptr = (char*)malloc(256);
        printf("Input your partner's UA ETag: ");
        scanf("%s", myetag_ptr);
        myetag.ptr = myetag_ptr;
        myetag.slen = strlen(myetag_ptr);
        if(myetag.slen)
            hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME, &myetag);
        //hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME, &pubc->etag);
        // End of Modification
        if (hdr)
            pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
    }
```


### Lab: Request URI Changed
```c=
        /* Add method. */
        len = msg->line.req.method.name.slen;
        pj_memcpy(p, msg->line.req.method.name.ptr, len);
        // Modify by Phoebe 7/25
        *(p + len) = '\0';
        char * comp_str = "PUBLISH";

        if (strcmp(p, comp_str) == 0) {
            p += len;
            *p++ = ' ';
            char* myuri_buf = "sip:111321511@sip.ncnu.net";
            strcpy(p, myuri_buf);
                //*(p + strlen(myuri_buf)) = '\0';
                //printf("Print out the Request URI: %s\n", p);
            p += strlen(myuri_buf);
        } // End of Modification
        else {
            p += len;
            *p++ = ' ';

            /* Add URI */
            uri = (pjsip_uri*)pjsip_uri_get_uri(msg->line.req.uri);

            len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, p, end - p);
            if (len < 1)
                return -1;
            p += len;
        }

```

### Command
```shell=
pjsua.exe --id=sip:111321512@sip.ncnu.net --registrar=sip:sip.ncnu.net --no-tcp --publish --reg-timeout=3600
```
