商選項(xiàng)配置指南:CURLOPT_TELNETOPTIONS 完整解析)
libcurl TELNET 協(xié)商選項(xiàng)配置指南CURLOPT_TELNETOPTIONS 完整解析【免費(fèi)下載鏈接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features項(xiàng)目地址: https://gitcode.com/GitHub_Trending/cu/curl本文圍繞 curl 開源倉(cāng)庫(kù)中 TELNET 協(xié)議實(shí)現(xiàn)的核心接口CURLOPT_TELNETOPTIONS講解如何在 libcurl 中通過(guò)curl_slist向 Telnet 服務(wù)器傳遞協(xié)商選項(xiàng)終端類型、顯示位置、環(huán)境變量等并結(jié)合 lib/telnet.c 與 lib/setopt.c 的源碼揭示選項(xiàng)解析、協(xié)商狀態(tài)機(jī)與底層發(fā)送邏輯。讀完本文你將掌握該接口的完整用法、全部支持選項(xiàng)及其取值范圍并能寫出可實(shí)際運(yùn)行的 TELNET 客戶端代碼。一、接口速覽CURLOPT_TELNETOPTIONS是 libcurl 提供的、專門用于 TELNET 協(xié)議選項(xiàng)協(xié)商的 easy 接口選項(xiàng)自 libcurl 7.7 版本加入僅在 URL 協(xié)議為telnet://時(shí)生效。屬性值選項(xiàng)名CURLOPT_TELNETOPTIONS適用協(xié)議TELNET引入版本7.7參數(shù)類型struct curl_slist *默認(rèn)值NULL頭文件include/curl/curl.h函數(shù)原型#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TELNETOPTIONS, struct curl_slist *cmds);核心語(yǔ)義官方接口文檔傳入一個(gè)curl_slist鏈表鏈表中的每個(gè)字符串代表一條傳給 Telnet 協(xié)商流程的變量格式必須為optionvalue重復(fù)調(diào)用本選項(xiàng)時(shí)最后一次設(shè)置會(huì)覆蓋之前的所有設(shè)置將參數(shù)設(shè)為NULL可再次禁用本選項(xiàng)libcurl不會(huì)復(fù)制該鏈表調(diào)用方必須保證鏈表在傳輸完成之前一直存活。二、支持的 Telnet 選項(xiàng)接口文檔明確聲明 libcurl 支持TTYPE、XDISPLOC與NEW_ENV三個(gè)選項(xiàng)。而深入 lib/telnet.c 的解析邏輯可以發(fā)現(xiàn)實(shí)際實(shí)現(xiàn)還額外支持WS窗口大小與BINARY二進(jìn)制傳輸開關(guān)兩個(gè)選項(xiàng)它們?cè)谕粋€(gè)循環(huán)中被解析。選項(xiàng)解析實(shí)現(xiàn)以下代碼位于 lib/telnet.c是CURLOPT_TELNETOPTIONS的核心解析入口函數(shù)telnet_easy_initfor(head >#define CURL_TELOPT_BINARY 0 /* binary 8-bit data */ #define CURL_TELOPT_ECHO 1 /* echo */ #define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */ #define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */ #define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */ #define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */ #define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */ #define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */各選項(xiàng)深入說(shuō)明TTYPE終端類型設(shè)置后將tn-subopt_ttype指向?qū)?yīng)值并把us_preferred[CURL_TELOPT_TTYPE]置為CURL_YES表示本端希望在協(xié)商通過(guò)后以IAC SB TTYPE IS 值 IAC SE格式發(fā)送終端類型子選項(xiàng)。若值中包含 IAC 命令字節(jié)255會(huì)返回CURLE_BAD_FUNCTION_ARGUMENT若值長(zhǎng)度超過(guò) 1000 字節(jié)則返回CURLE_SEND_ERRORlib/telnet.c。XDISPLOC顯示位置處理邏輯與 TTYPE 完全對(duì)稱設(shè)置tn-subopt_xdisploc并在協(xié)商成功后發(fā)送IAC SB XDISPLOC IS 值 IAC SElib/telnet.c。NEW_ENV環(huán)境變量每條選項(xiàng)以NAME,VALUE格式追加到tn-telnet_vars鏈表同時(shí)將us_preferred[CURL_TELOPT_NEW_ENVIRON]置為CURL_YES。協(xié)商成功后libcurl 會(huì)構(gòu)造IAC SB NEW_ENVIRON IS ... IAC SE子選項(xiàng)其中變量名以CURL_NEW_ENV_VAR0開頭、變量值以CURL_NEW_ENV_VALUE1作為分隔標(biāo)記lib/telnet.c。WS窗口大小值必須形如寬x高寬高均為 0655350xffff范圍內(nèi)的數(shù)字。解析使用curlx_str_number與curlx_str_single語(yǔ)法不合法時(shí)返回CURLE_SETOPT_OPTION_SYNTAXlib/telnet.c。窗口尺寸最終會(huì)以網(wǎng)絡(luò)字節(jié)序htons寫入IAC SB NAWS w h IAC SE子選項(xiàng)lib/telnet.c。BINARY二進(jìn)制模式默認(rèn)情況下 libcurl 會(huì)將 BINARY 選項(xiàng)置為CURL_YES與歷史版本行為保持一致見 lib/telnet.c傳入BINARY1保持默認(rèn)傳入其他值解析為 0則同時(shí)關(guān)閉本端與對(duì)端的二進(jìn)制協(xié)商偏好lib/telnet.c。注意兩個(gè)容易踩坑的細(xì)節(jié)選項(xiàng)值不允許包含 IAC 字節(jié)bad_option檢查見 lib/telnet.c源碼注釋明確說(shuō)明這是為了禁止通過(guò)選項(xiàng)值注入命令字節(jié)若選項(xiàng)值包含非 ASCII 字符該條會(huì)被靜默跳過(guò)str_is_nonascii檢查用戶名非 ASCII 時(shí)同理返回CURLE_BAD_FUNCTION_ARGUMENT。三、完整可運(yùn)行示例接口文檔給出了基礎(chǔ)示例CURLOPT_TELNETOPTIONS.md這里將其補(bǔ)全為可直接編譯的完整程序并同時(shí)演示 TTYPE、XDISPLOC 與 NEW_ENV 的組合用法#include stdio.h #include curl/curl.h int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; struct curl_slist *options NULL; /* 終端類型 */ options curl_slist_append(options, TTYPEvt100); /* 環(huán)境變量NAME,VALUE 形式逗號(hào)分隔 */ options curl_slist_append(options, NEW_ENVUSER,foobar); options curl_slist_append(options, NEW_ENVTERM,vt100); /* X 顯示位置 */ options curl_slist_append(options, XDISPLOC:0.0); /* 窗口大小寬x高 */ options curl_slist_append(options, WS800x600); curl_easy_setopt(curl, CURLOPT_URL, telnet://example.com/); curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, options); result curl_easy_perform(curl); if(result ! CURLE_OK) fprintf(stderr, curl_easy_perform() failed: %s\n, curl_easy_strerror(result)); curl_easy_cleanup(curl); curl_slist_free_all(options); } return 0; }要點(diǎn)鏈表在curl_easy_perform結(jié)束后才釋放滿足 libcurl“不復(fù)制鏈表”的生命周期要求選項(xiàng)字符串必須形如KEYvalue缺少會(huì)被判定為語(yǔ)法錯(cuò)誤返回CURLE_SETOPT_OPTION_SYNTAX官方文檔示例中的USERfoobar需要注意USER 變量不需要也不能通過(guò)選項(xiàng)列表傳遞。當(dāng) URL 中攜帶了user:password憑據(jù)如telnet://user:passhost/時(shí)libcurl 會(huì)在 lib/telnet.c 中自動(dòng)將用戶名以USER,name形式注入NEW_ENV協(xié)商此時(shí)手動(dòng)傳入U(xiǎn)SER...反而會(huì)因“USER”長(zhǎng)度4不匹配任何分支而返回CURLE_UNKNOWN_OPTION。四、底層原理選項(xiàng)如何進(jìn)入?yún)f(xié)商流程1. 設(shè)置階段僅保存指針在 lib/setopt.c 中CURLOPT_TELNETOPTIONS被歸類為 slist 類型選項(xiàng)處理方式非常輕量#ifndef CURL_DISABLE_TELNET case CURLOPT_TELNETOPTIONS: /* * Set a linked list of telnet options */ s-telnet_options slist; break; #endif它只是把指針存進(jìn) easy handle 的配置區(qū)不拷貝鏈表內(nèi)容——這正是文檔要求“鏈表必須存活到傳輸結(jié)束”的原因。在 lib/setopt.c 的Curl_vsetopt中它與CURLOPT_HTTPHEADER、CURLOPT_QUOTE、CURLOPT_MAIL_RCPT等一樣被統(tǒng)一分派到setopt_slist處理。2. 協(xié)商階段RFC 1143 狀態(tài)機(jī)libcurl 的 TELNET 實(shí)現(xiàn)遵循 RFC 1143 的協(xié)商規(guī)范lib/telnet.c為每個(gè)選項(xiàng)維護(hù)雙方狀態(tài)/* For negotiation compliant to RFC 1143 */ #define CURL_NO 0 #define CURL_YES 1 #define CURL_WANTYES 2 #define CURL_WANTNO 3 #define CURL_EMPTY 0 #define CURL_OPPOSITE 1struct TELNETlib/telnet.c為 256 個(gè)可能的選項(xiàng)各維護(hù)一組狀態(tài)us/usq/us_preferred描述本端we/us意愿him/himq/him_preferred描述對(duì)端he/him意愿subnegotiation標(biāo)記協(xié)商通過(guò)后需要發(fā)送的子選項(xiàng)。CURLOPT_TELNETOPTIONS解析結(jié)果寫入us_preferred與subopt_*字段隨后由send_negotiation()lib/telnet.c以IAC WILL/DO/WONT/DONT option三字節(jié)命令發(fā)起協(xié)商。3. 接收階段子選項(xiàng)收集接收側(cè)的狀態(tài)機(jī)lib/telnet.c逐字節(jié)掃描輸入流typedef enum { CURL_TS_DATA 0, CURL_TS_IAC, CURL_TS_WILL, CURL_TS_WONT, CURL_TS_DO, CURL_TS_DONT, CURL_TS_CR, CURL_TS_SB, /* sub-option collection */ CURL_TS_SE /* looking for sub-option end */ } TelnetReceive;收到IAC SB后進(jìn)入子選項(xiàng)收集模式用 512 字節(jié)的subbuffer累積數(shù)據(jù)CURL_SB_ACCUM宏lib/telnet.c收到IAC SE后交給suboption()處理當(dāng)服務(wù)器以DO TTYPE等方式請(qǐng)求時(shí)libcurl 將之前配置的 TTYPE/XDISPLOC/NEW_ENV/NAWS 子選項(xiàng)編碼發(fā)送回去lib/telnet.c。4. 默認(rèn)協(xié)商偏好即使未調(diào)用CURLOPT_TELNETOPTIONSlibcurl 也會(huì)默認(rèn)請(qǐng)求 SGASuppress Go Ahead、BINARY 以及對(duì)端 ECHOlib/telnet.c其中 BINARY 可用BINARY選項(xiàng)關(guān)閉ECHO 因可能迫使服務(wù)器關(guān)閉連接而被特殊處理。五、命令行工具映射--telnet-optioncurl 命令行工具通過(guò)-t/--telnet-option optionvalue暴露同一能力可多次指定curl -t TTYPEvt100 -t NEW_ENVUSER,foobar -t WS800x600 telnet://example.com/工具側(cè)實(shí)現(xiàn)位于 src/tool_getparam.c每次調(diào)用將參數(shù)追加到config-telnet_options鏈表case C_TELNET_OPTION: /* --telnet-option */ /* Telnet options */ err add2list(config-telnet_options, nextarg); break;隨后在 src/config2setopts.c 中一次性映射到 libcurl 接口my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config-telnet_options);六、返回值與錯(cuò)誤處理curl_easy_setopt(handle, CURLOPT_TELNETOPTIONS, list)返回CURLcode其中CURLE_OK (0)設(shè)置成功CURLE_UNKNOWN_OPTION選項(xiàng)名不匹配長(zhǎng)度或拼寫不對(duì)如誤寫為TTTYPE或完全不認(rèn)識(shí)該選項(xiàng)CURLE_SETOPT_OPTION_SYNTAX選項(xiàng)缺少或WS的寬/高不是合法數(shù)字CURLE_BAD_FUNCTION_ARGUMENT選項(xiàng)值包含 IAC 字節(jié)或憑據(jù)用戶名含非 ASCII 字符傳輸階段返回CURLE_SEND_ERRORTTYPE/XDISPLOC 值超過(guò) 1000 字節(jié)等發(fā)送階段錯(cuò)誤傳輸階段返回。注意解析錯(cuò)誤發(fā)生在curl_easy_perform()執(zhí)行時(shí)的 TELNET 協(xié)議初始化階段telnet_easy_init而非curl_easy_setopt()調(diào)用時(shí)因此判斷結(jié)果必須結(jié)合curl_easy_perform()的返回值與curl_easy_strerror()輸出。七、與其他選項(xiàng)的關(guān)系CURLOPT_TELNETOPTIONS與 CURLOPT_QUOTE、CURLOPT_HTTPHEADER 同為 slist 類型接口內(nèi)存管理約定一致列表不復(fù)制、需自行維護(hù)生命周期URL 中的user:password憑據(jù)會(huì)自動(dòng)注入 NEW_ENV 的USER變量無(wú)需也不應(yīng)通過(guò)選項(xiàng)列表重復(fù)指定若需在編譯期裁剪 TELNET 支持可在構(gòu)建時(shí)定義CURL_DISABLE_TELNET此時(shí)該選項(xiàng)在 lib/setopt.c 中會(huì)被整體禁用。八、小結(jié)CURLOPT_TELNETOPTIONS是 libcurl 暴露 TELNET 選項(xiàng)協(xié)商能力的唯一入口通過(guò)curl_slist以optionvalue格式配置 TTYPE、XDISPLOC、NEW_ENV以及實(shí)現(xiàn)額外支持的 WS、BINARYlibcurl 會(huì)在連接建立后按 RFC 1143 規(guī)范自動(dòng)完成 WILL/DO 協(xié)商與子選項(xiàng)收發(fā)。掌握本接口需要同時(shí)留意三件事鏈表必須存活到傳輸結(jié)束、選項(xiàng)名與值格式必須嚴(yán)格匹配源碼解析規(guī)則、錯(cuò)誤碼的返回時(shí)機(jī)在perform階段。配合 lib/telnet.c 與 lib/arpa_telnet.h 閱讀可完整還原從配置到協(xié)商的整個(gè) TELNET 數(shù)據(jù)通路?!久赓M(fèi)下載鏈接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features項(xiàng)目地址: https://gitcode.com/GitHub_Trending/cu/curl創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考