telnet.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2004, Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at http://curl.haxx.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * $Id$
  22. ***************************************************************************/
  23. #include "setup.h"
  24. #ifndef CURL_DISABLE_TELNET
  25. /* -- WIN32 approved -- */
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <stdarg.h>
  29. #include <stdlib.h>
  30. #include <ctype.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <errno.h>
  34. #if defined(WIN32)
  35. #include <time.h>
  36. #include <io.h>
  37. #else
  38. #ifdef HAVE_SYS_SOCKET_H
  39. #include <sys/socket.h>
  40. #endif
  41. #include <netinet/in.h>
  42. #include <sys/time.h>
  43. #ifdef HAVE_UNISTD_H
  44. #include <unistd.h>
  45. #endif
  46. #include <netdb.h>
  47. #ifdef HAVE_ARPA_INET_H
  48. #include <arpa/inet.h>
  49. #endif
  50. #ifdef HAVE_NET_IF_H
  51. #include <net/if.h>
  52. #endif
  53. #include <sys/ioctl.h>
  54. #include <signal.h>
  55. #ifdef HAVE_SYS_PARAM_H
  56. #include <sys/param.h>
  57. #endif
  58. #ifdef HAVE_SYS_SELECT_H
  59. #include <sys/select.h>
  60. #endif
  61. #endif
  62. #include "urldata.h"
  63. #include <curl/curl.h>
  64. #include "transfer.h"
  65. #include "sendf.h"
  66. #include "telnet.h"
  67. #define _MPRINTF_REPLACE /* use our functions only */
  68. #include <curl/mprintf.h>
  69. #define TELOPTS
  70. #define TELCMDS
  71. #include "arpa_telnet.h"
  72. #include "curl_memory.h"
  73. /* The last #include file should be: */
  74. #include "memdebug.h"
  75. #define SUBBUFSIZE 512
  76. #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer;
  77. #define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
  78. #define CURL_SB_ACCUM(x,c) \
  79. if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
  80. *x->subpointer++ = (c); \
  81. }
  82. #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
  83. #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
  84. #define CURL_SB_EOF(x) (x->subpointer >= x->subend)
  85. #define CURL_SB_LEN(x) (x->subend - x->subpointer)
  86. #ifdef WIN32
  87. typedef FARPROC WSOCK2_FUNC;
  88. static CURLcode check_wsock2 ( struct SessionHandle *data );
  89. #endif
  90. static
  91. void telrcv(struct connectdata *,
  92. unsigned char *inbuf, /* Data received from socket */
  93. ssize_t count); /* Number of bytes received */
  94. static void printoption(struct SessionHandle *data,
  95. const char *direction,
  96. int cmd, int option);
  97. static void negotiate(struct connectdata *);
  98. static void send_negotiation(struct connectdata *, int cmd, int option);
  99. static void set_local_option(struct connectdata *, int cmd, int option);
  100. static void set_remote_option(struct connectdata *, int cmd, int option);
  101. static void printsub(struct SessionHandle *data,
  102. int direction, unsigned char *pointer,
  103. size_t length);
  104. static void suboption(struct connectdata *);
  105. /* For negotiation compliant to RFC 1143 */
  106. #define CURL_NO 0
  107. #define CURL_YES 1
  108. #define CURL_WANTYES 2
  109. #define CURL_WANTNO 3
  110. #define CURL_EMPTY 0
  111. #define CURL_OPPOSITE 1
  112. /*
  113. * Telnet receiver states for fsm
  114. */
  115. typedef enum
  116. {
  117. CURL_TS_DATA = 0,
  118. CURL_TS_IAC,
  119. CURL_TS_WILL,
  120. CURL_TS_WONT,
  121. CURL_TS_DO,
  122. CURL_TS_DONT,
  123. CURL_TS_CR,
  124. CURL_TS_SB, /* sub-option collection */
  125. CURL_TS_SE /* looking for sub-option end */
  126. } TelnetReceive;
  127. struct TELNET {
  128. int please_negotiate;
  129. int already_negotiated;
  130. int us[256];
  131. int usq[256];
  132. int us_preferred[256];
  133. int him[256];
  134. int himq[256];
  135. int him_preferred[256];
  136. char subopt_ttype[32]; /* Set with suboption TTYPE */
  137. char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
  138. struct curl_slist *telnet_vars; /* Environment variables */
  139. /* suboptions */
  140. char subbuffer[SUBBUFSIZE];
  141. char *subpointer, *subend; /* buffer for sub-options */
  142. TelnetReceive telrcv_state;
  143. };
  144. #ifdef WIN32
  145. static CURLcode
  146. check_wsock2 ( struct SessionHandle *data )
  147. {
  148. int err;
  149. WORD wVersionRequested;
  150. WSADATA wsaData;
  151. curlassert(data);
  152. /* telnet requires at least WinSock 2.0 so ask for it. */
  153. wVersionRequested = MAKEWORD(2, 0);
  154. err = WSAStartup(wVersionRequested, &wsaData);
  155. /* We must've called this once already, so this call */
  156. /* should always succeed. But, just in case... */
  157. if (err != 0) {
  158. failf(data,"WSAStartup failed (%d)",err);
  159. return CURLE_FAILED_INIT;
  160. }
  161. /* We have to have a WSACleanup call for every successful */
  162. /* WSAStartup call. */
  163. WSACleanup();
  164. /* Check that our version is supported */
  165. if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
  166. HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
  167. /* Our version isn't supported */
  168. failf(data,"insufficient winsock version to support "
  169. "telnet");
  170. return CURLE_FAILED_INIT;
  171. }
  172. /* Our version is supported */
  173. return CURLE_OK;
  174. }
  175. #endif
  176. static
  177. CURLcode init_telnet(struct connectdata *conn)
  178. {
  179. struct TELNET *tn;
  180. tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
  181. if(!tn)
  182. return CURLE_OUT_OF_MEMORY;
  183. conn->proto.telnet = (void *)tn; /* make us known */
  184. tn->telrcv_state = CURL_TS_DATA;
  185. /* Init suboptions */
  186. CURL_SB_CLEAR(tn);
  187. /* Set the options we want by default */
  188. tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
  189. tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
  190. tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
  191. tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
  192. return CURLE_OK;
  193. }
  194. static void negotiate(struct connectdata *conn)
  195. {
  196. int i;
  197. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  198. for(i = 0;i < CURL_NTELOPTS;i++)
  199. {
  200. if(tn->us_preferred[i] == CURL_YES)
  201. set_local_option(conn, i, CURL_YES);
  202. if(tn->him_preferred[i] == CURL_YES)
  203. set_remote_option(conn, i, CURL_YES);
  204. }
  205. }
  206. static void printoption(struct SessionHandle *data,
  207. const char *direction, int cmd, int option)
  208. {
  209. const char *fmt;
  210. const char *opt;
  211. if (data->set.verbose)
  212. {
  213. if (cmd == CURL_IAC)
  214. {
  215. if (CURL_TELCMD_OK(option))
  216. Curl_infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
  217. else
  218. Curl_infof(data, "%s IAC %d\n", direction, option);
  219. }
  220. else
  221. {
  222. fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
  223. (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
  224. if (fmt)
  225. {
  226. if (CURL_TELOPT_OK(option))
  227. opt = CURL_TELOPT(option);
  228. else if (option == CURL_TELOPT_EXOPL)
  229. opt = "EXOPL";
  230. else
  231. opt = NULL;
  232. if(opt)
  233. Curl_infof(data, "%s %s %s\n", direction, fmt, opt);
  234. else
  235. Curl_infof(data, "%s %s %d\n", direction, fmt, option);
  236. }
  237. else
  238. Curl_infof(data, "%s %d %d\n", direction, cmd, option);
  239. }
  240. }
  241. }
  242. static void send_negotiation(struct connectdata *conn, int cmd, int option)
  243. {
  244. unsigned char buf[3];
  245. buf[0] = CURL_IAC;
  246. buf[1] = cmd;
  247. buf[2] = option;
  248. (void)swrite(conn->sock[FIRSTSOCKET], buf, 3);
  249. printoption(conn->data, "SENT", cmd, option);
  250. }
  251. static
  252. void set_remote_option(struct connectdata *conn, int option, int newstate)
  253. {
  254. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  255. if(newstate == CURL_YES)
  256. {
  257. switch(tn->him[option])
  258. {
  259. case CURL_NO:
  260. tn->him[option] = CURL_WANTYES;
  261. send_negotiation(conn, CURL_DO, option);
  262. break;
  263. case CURL_YES:
  264. /* Already enabled */
  265. break;
  266. case CURL_WANTNO:
  267. switch(tn->himq[option])
  268. {
  269. case CURL_EMPTY:
  270. /* Already negotiating for CURL_YES, queue the request */
  271. tn->himq[option] = CURL_OPPOSITE;
  272. break;
  273. case CURL_OPPOSITE:
  274. /* Error: already queued an enable request */
  275. break;
  276. }
  277. break;
  278. case CURL_WANTYES:
  279. switch(tn->himq[option])
  280. {
  281. case CURL_EMPTY:
  282. /* Error: already negotiating for enable */
  283. break;
  284. case CURL_OPPOSITE:
  285. tn->himq[option] = CURL_EMPTY;
  286. break;
  287. }
  288. break;
  289. }
  290. }
  291. else /* NO */
  292. {
  293. switch(tn->him[option])
  294. {
  295. case CURL_NO:
  296. /* Already disabled */
  297. break;
  298. case CURL_YES:
  299. tn->him[option] = CURL_WANTNO;
  300. send_negotiation(conn, CURL_DONT, option);
  301. break;
  302. case CURL_WANTNO:
  303. switch(tn->himq[option])
  304. {
  305. case CURL_EMPTY:
  306. /* Already negotiating for NO */
  307. break;
  308. case CURL_OPPOSITE:
  309. tn->himq[option] = CURL_EMPTY;
  310. break;
  311. }
  312. break;
  313. case CURL_WANTYES:
  314. switch(tn->himq[option])
  315. {
  316. case CURL_EMPTY:
  317. tn->himq[option] = CURL_OPPOSITE;
  318. break;
  319. case CURL_OPPOSITE:
  320. break;
  321. }
  322. break;
  323. }
  324. }
  325. }
  326. static
  327. void rec_will(struct connectdata *conn, int option)
  328. {
  329. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  330. switch(tn->him[option])
  331. {
  332. case CURL_NO:
  333. if(tn->him_preferred[option] == CURL_YES)
  334. {
  335. tn->him[option] = CURL_YES;
  336. send_negotiation(conn, CURL_DO, option);
  337. }
  338. else
  339. {
  340. send_negotiation(conn, CURL_DONT, option);
  341. }
  342. break;
  343. case CURL_YES:
  344. /* Already enabled */
  345. break;
  346. case CURL_WANTNO:
  347. switch(tn->himq[option])
  348. {
  349. case CURL_EMPTY:
  350. /* Error: DONT answered by WILL */
  351. tn->him[option] = CURL_NO;
  352. break;
  353. case CURL_OPPOSITE:
  354. /* Error: DONT answered by WILL */
  355. tn->him[option] = CURL_YES;
  356. tn->himq[option] = CURL_EMPTY;
  357. break;
  358. }
  359. break;
  360. case CURL_WANTYES:
  361. switch(tn->himq[option])
  362. {
  363. case CURL_EMPTY:
  364. tn->him[option] = CURL_YES;
  365. break;
  366. case CURL_OPPOSITE:
  367. tn->him[option] = CURL_WANTNO;
  368. tn->himq[option] = CURL_EMPTY;
  369. send_negotiation(conn, CURL_DONT, option);
  370. break;
  371. }
  372. break;
  373. }
  374. }
  375. static
  376. void rec_wont(struct connectdata *conn, int option)
  377. {
  378. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  379. switch(tn->him[option])
  380. {
  381. case CURL_NO:
  382. /* Already disabled */
  383. break;
  384. case CURL_YES:
  385. tn->him[option] = CURL_NO;
  386. send_negotiation(conn, CURL_DONT, option);
  387. break;
  388. case CURL_WANTNO:
  389. switch(tn->himq[option])
  390. {
  391. case CURL_EMPTY:
  392. tn->him[option] = CURL_NO;
  393. break;
  394. case CURL_OPPOSITE:
  395. tn->him[option] = CURL_WANTYES;
  396. tn->himq[option] = CURL_EMPTY;
  397. send_negotiation(conn, CURL_DO, option);
  398. break;
  399. }
  400. break;
  401. case CURL_WANTYES:
  402. switch(tn->himq[option])
  403. {
  404. case CURL_EMPTY:
  405. tn->him[option] = CURL_NO;
  406. break;
  407. case CURL_OPPOSITE:
  408. tn->him[option] = CURL_NO;
  409. tn->himq[option] = CURL_EMPTY;
  410. break;
  411. }
  412. break;
  413. }
  414. }
  415. static void
  416. set_local_option(struct connectdata *conn, int option, int newstate)
  417. {
  418. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  419. if(newstate == CURL_YES)
  420. {
  421. switch(tn->us[option])
  422. {
  423. case CURL_NO:
  424. tn->us[option] = CURL_WANTYES;
  425. send_negotiation(conn, CURL_WILL, option);
  426. break;
  427. case CURL_YES:
  428. /* Already enabled */
  429. break;
  430. case CURL_WANTNO:
  431. switch(tn->usq[option])
  432. {
  433. case CURL_EMPTY:
  434. /* Already negotiating for CURL_YES, queue the request */
  435. tn->usq[option] = CURL_OPPOSITE;
  436. break;
  437. case CURL_OPPOSITE:
  438. /* Error: already queued an enable request */
  439. break;
  440. }
  441. break;
  442. case CURL_WANTYES:
  443. switch(tn->usq[option])
  444. {
  445. case CURL_EMPTY:
  446. /* Error: already negotiating for enable */
  447. break;
  448. case CURL_OPPOSITE:
  449. tn->usq[option] = CURL_EMPTY;
  450. break;
  451. }
  452. break;
  453. }
  454. }
  455. else /* NO */
  456. {
  457. switch(tn->us[option])
  458. {
  459. case CURL_NO:
  460. /* Already disabled */
  461. break;
  462. case CURL_YES:
  463. tn->us[option] = CURL_WANTNO;
  464. send_negotiation(conn, CURL_WONT, option);
  465. break;
  466. case CURL_WANTNO:
  467. switch(tn->usq[option])
  468. {
  469. case CURL_EMPTY:
  470. /* Already negotiating for NO */
  471. break;
  472. case CURL_OPPOSITE:
  473. tn->usq[option] = CURL_EMPTY;
  474. break;
  475. }
  476. break;
  477. case CURL_WANTYES:
  478. switch(tn->usq[option])
  479. {
  480. case CURL_EMPTY:
  481. tn->usq[option] = CURL_OPPOSITE;
  482. break;
  483. case CURL_OPPOSITE:
  484. break;
  485. }
  486. break;
  487. }
  488. }
  489. }
  490. static
  491. void rec_do(struct connectdata *conn, int option)
  492. {
  493. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  494. switch(tn->us[option])
  495. {
  496. case CURL_NO:
  497. if(tn->us_preferred[option] == CURL_YES)
  498. {
  499. tn->us[option] = CURL_YES;
  500. send_negotiation(conn, CURL_WILL, option);
  501. }
  502. else
  503. {
  504. send_negotiation(conn, CURL_WONT, option);
  505. }
  506. break;
  507. case CURL_YES:
  508. /* Already enabled */
  509. break;
  510. case CURL_WANTNO:
  511. switch(tn->usq[option])
  512. {
  513. case CURL_EMPTY:
  514. /* Error: DONT answered by WILL */
  515. tn->us[option] = CURL_NO;
  516. break;
  517. case CURL_OPPOSITE:
  518. /* Error: DONT answered by WILL */
  519. tn->us[option] = CURL_YES;
  520. tn->usq[option] = CURL_EMPTY;
  521. break;
  522. }
  523. break;
  524. case CURL_WANTYES:
  525. switch(tn->usq[option])
  526. {
  527. case CURL_EMPTY:
  528. tn->us[option] = CURL_YES;
  529. break;
  530. case CURL_OPPOSITE:
  531. tn->us[option] = CURL_WANTNO;
  532. tn->himq[option] = CURL_EMPTY;
  533. send_negotiation(conn, CURL_WONT, option);
  534. break;
  535. }
  536. break;
  537. }
  538. }
  539. static
  540. void rec_dont(struct connectdata *conn, int option)
  541. {
  542. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  543. switch(tn->us[option])
  544. {
  545. case CURL_NO:
  546. /* Already disabled */
  547. break;
  548. case CURL_YES:
  549. tn->us[option] = CURL_NO;
  550. send_negotiation(conn, CURL_WONT, option);
  551. break;
  552. case CURL_WANTNO:
  553. switch(tn->usq[option])
  554. {
  555. case CURL_EMPTY:
  556. tn->us[option] = CURL_NO;
  557. break;
  558. case CURL_OPPOSITE:
  559. tn->us[option] = CURL_WANTYES;
  560. tn->usq[option] = CURL_EMPTY;
  561. send_negotiation(conn, CURL_WILL, option);
  562. break;
  563. }
  564. break;
  565. case CURL_WANTYES:
  566. switch(tn->usq[option])
  567. {
  568. case CURL_EMPTY:
  569. tn->us[option] = CURL_NO;
  570. break;
  571. case CURL_OPPOSITE:
  572. tn->us[option] = CURL_NO;
  573. tn->usq[option] = CURL_EMPTY;
  574. break;
  575. }
  576. break;
  577. }
  578. }
  579. static void printsub(struct SessionHandle *data,
  580. int direction, /* '<' or '>' */
  581. unsigned char *pointer, /* where suboption data is */
  582. size_t length) /* length of suboption data */
  583. {
  584. unsigned int i = 0;
  585. if (data->set.verbose)
  586. {
  587. if (direction)
  588. {
  589. Curl_infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
  590. if (length >= 3)
  591. {
  592. int j;
  593. i = pointer[length-2];
  594. j = pointer[length-1];
  595. if (i != CURL_IAC || j != CURL_SE)
  596. {
  597. Curl_infof(data, "(terminated by ");
  598. if (CURL_TELOPT_OK(i))
  599. Curl_infof(data, "%s ", CURL_TELOPT(i));
  600. else if (CURL_TELCMD_OK(i))
  601. Curl_infof(data, "%s ", CURL_TELCMD(i));
  602. else
  603. Curl_infof(data, "%d ", i);
  604. if (CURL_TELOPT_OK(j))
  605. Curl_infof(data, "%s", CURL_TELOPT(j));
  606. else if (CURL_TELCMD_OK(j))
  607. Curl_infof(data, "%s", CURL_TELCMD(j));
  608. else
  609. Curl_infof(data, "%d", j);
  610. Curl_infof(data, ", not IAC SE!) ");
  611. }
  612. }
  613. length -= 2;
  614. }
  615. if (length < 1)
  616. {
  617. Curl_infof(data, "(Empty suboption?)");
  618. return;
  619. }
  620. if (CURL_TELOPT_OK(pointer[0])) {
  621. switch(pointer[0]) {
  622. case CURL_TELOPT_TTYPE:
  623. case CURL_TELOPT_XDISPLOC:
  624. case CURL_TELOPT_NEW_ENVIRON:
  625. Curl_infof(data, "%s", CURL_TELOPT(pointer[0]));
  626. break;
  627. default:
  628. Curl_infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
  629. break;
  630. }
  631. }
  632. else
  633. Curl_infof(data, "%d (unknown)", pointer[i]);
  634. switch(pointer[1]) {
  635. case CURL_TELQUAL_IS:
  636. Curl_infof(data, " IS");
  637. break;
  638. case CURL_TELQUAL_SEND:
  639. Curl_infof(data, " SEND");
  640. break;
  641. case CURL_TELQUAL_INFO:
  642. Curl_infof(data, " INFO/REPLY");
  643. break;
  644. case CURL_TELQUAL_NAME:
  645. Curl_infof(data, " NAME");
  646. break;
  647. }
  648. switch(pointer[0]) {
  649. case CURL_TELOPT_TTYPE:
  650. case CURL_TELOPT_XDISPLOC:
  651. pointer[length] = 0;
  652. Curl_infof(data, " \"%s\"", &pointer[2]);
  653. break;
  654. case CURL_TELOPT_NEW_ENVIRON:
  655. if(pointer[1] == CURL_TELQUAL_IS) {
  656. Curl_infof(data, " ");
  657. for(i = 3;i < length;i++) {
  658. switch(pointer[i]) {
  659. case CURL_NEW_ENV_VAR:
  660. Curl_infof(data, ", ");
  661. break;
  662. case CURL_NEW_ENV_VALUE:
  663. Curl_infof(data, " = ");
  664. break;
  665. default:
  666. Curl_infof(data, "%c", pointer[i]);
  667. break;
  668. }
  669. }
  670. }
  671. break;
  672. default:
  673. for (i = 2; i < length; i++)
  674. Curl_infof(data, " %.2x", pointer[i]);
  675. break;
  676. }
  677. if (direction)
  678. {
  679. Curl_infof(data, "\n");
  680. }
  681. }
  682. }
  683. static CURLcode check_telnet_options(struct connectdata *conn)
  684. {
  685. struct curl_slist *head;
  686. char option_keyword[128];
  687. char option_arg[256];
  688. char *buf;
  689. struct SessionHandle *data = conn->data;
  690. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  691. /* Add the user name as an environment variable if it
  692. was given on the command line */
  693. if(conn->bits.user_passwd)
  694. {
  695. snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
  696. tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
  697. tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
  698. }
  699. for(head = data->set.telnet_options; head; head=head->next) {
  700. if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
  701. option_keyword, option_arg) == 2) {
  702. /* Terminal type */
  703. if(curl_strequal(option_keyword, "TTYPE")) {
  704. strncpy(tn->subopt_ttype, option_arg, 31);
  705. tn->subopt_ttype[31] = 0; /* String termination */
  706. tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
  707. continue;
  708. }
  709. /* Display variable */
  710. if(curl_strequal(option_keyword, "XDISPLOC")) {
  711. strncpy(tn->subopt_xdisploc, option_arg, 127);
  712. tn->subopt_xdisploc[127] = 0; /* String termination */
  713. tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
  714. continue;
  715. }
  716. /* Environment variable */
  717. if(curl_strequal(option_keyword, "NEW_ENV")) {
  718. buf = strdup(option_arg);
  719. if(!buf)
  720. return CURLE_OUT_OF_MEMORY;
  721. tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
  722. tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
  723. continue;
  724. }
  725. failf(data, "Unknown telnet option %s", head->data);
  726. return CURLE_UNKNOWN_TELNET_OPTION;
  727. } else {
  728. failf(data, "Syntax error in telnet option: %s", head->data);
  729. return CURLE_TELNET_OPTION_SYNTAX;
  730. }
  731. }
  732. return CURLE_OK;
  733. }
  734. /*
  735. * suboption()
  736. *
  737. * Look at the sub-option buffer, and try to be helpful to the other
  738. * side.
  739. */
  740. static void suboption(struct connectdata *conn)
  741. {
  742. struct curl_slist *v;
  743. unsigned char temp[2048];
  744. size_t len;
  745. size_t tmplen;
  746. char varname[128];
  747. char varval[128];
  748. struct SessionHandle *data = conn->data;
  749. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  750. printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
  751. switch (CURL_SB_GET(tn)) {
  752. case CURL_TELOPT_TTYPE:
  753. len = strlen(tn->subopt_ttype) + 4 + 2;
  754. snprintf((char *)temp, sizeof(temp),
  755. "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
  756. CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
  757. (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
  758. printsub(data, '>', &temp[2], len-2);
  759. break;
  760. case CURL_TELOPT_XDISPLOC:
  761. len = strlen(tn->subopt_xdisploc) + 4 + 2;
  762. snprintf((char *)temp, sizeof(temp),
  763. "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
  764. CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
  765. (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
  766. printsub(data, '>', &temp[2], len-2);
  767. break;
  768. case CURL_TELOPT_NEW_ENVIRON:
  769. snprintf((char *)temp, sizeof(temp),
  770. "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
  771. CURL_TELQUAL_IS);
  772. len = 4;
  773. for(v = tn->telnet_vars;v;v = v->next) {
  774. tmplen = (strlen(v->data) + 1);
  775. /* Add the variable only if it fits */
  776. if(len + tmplen < (int)sizeof(temp)-6) {
  777. sscanf(v->data, "%127[^,],%127s", varname, varval);
  778. snprintf((char *)&temp[len], sizeof(temp) - len,
  779. "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
  780. CURL_NEW_ENV_VALUE, varval);
  781. len += tmplen;
  782. }
  783. }
  784. snprintf((char *)&temp[len], sizeof(temp) - len,
  785. "%c%c", CURL_IAC, CURL_SE);
  786. len += 2;
  787. (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
  788. printsub(data, '>', &temp[2], len-2);
  789. break;
  790. }
  791. return;
  792. }
  793. static
  794. void telrcv(struct connectdata *conn,
  795. unsigned char *inbuf, /* Data received from socket */
  796. ssize_t count) /* Number of bytes received */
  797. {
  798. unsigned char c;
  799. int in = 0;
  800. struct SessionHandle *data = conn->data;
  801. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  802. while(count--)
  803. {
  804. c = inbuf[in++];
  805. switch (tn->telrcv_state)
  806. {
  807. case CURL_TS_CR:
  808. tn->telrcv_state = CURL_TS_DATA;
  809. if (c == '\0')
  810. {
  811. break; /* Ignore \0 after CR */
  812. }
  813. Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
  814. continue;
  815. case CURL_TS_DATA:
  816. if (c == CURL_IAC)
  817. {
  818. tn->telrcv_state = CURL_TS_IAC;
  819. break;
  820. }
  821. else if(c == '\r')
  822. {
  823. tn->telrcv_state = CURL_TS_CR;
  824. }
  825. Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
  826. continue;
  827. case CURL_TS_IAC:
  828. process_iac:
  829. switch (c)
  830. {
  831. case CURL_WILL:
  832. tn->telrcv_state = CURL_TS_WILL;
  833. continue;
  834. case CURL_WONT:
  835. tn->telrcv_state = CURL_TS_WONT;
  836. continue;
  837. case CURL_DO:
  838. tn->telrcv_state = CURL_TS_DO;
  839. continue;
  840. case CURL_DONT:
  841. tn->telrcv_state = CURL_TS_DONT;
  842. continue;
  843. case CURL_SB:
  844. CURL_SB_CLEAR(tn);
  845. tn->telrcv_state = CURL_TS_SB;
  846. continue;
  847. case CURL_IAC:
  848. Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
  849. break;
  850. case CURL_DM:
  851. case CURL_NOP:
  852. case CURL_GA:
  853. default:
  854. printoption(data, "RCVD", CURL_IAC, c);
  855. break;
  856. }
  857. tn->telrcv_state = CURL_TS_DATA;
  858. continue;
  859. case CURL_TS_WILL:
  860. printoption(data, "RCVD", CURL_WILL, c);
  861. tn->please_negotiate = 1;
  862. rec_will(conn, c);
  863. tn->telrcv_state = CURL_TS_DATA;
  864. continue;
  865. case CURL_TS_WONT:
  866. printoption(data, "RCVD", CURL_WONT, c);
  867. tn->please_negotiate = 1;
  868. rec_wont(conn, c);
  869. tn->telrcv_state = CURL_TS_DATA;
  870. continue;
  871. case CURL_TS_DO:
  872. printoption(data, "RCVD", CURL_DO, c);
  873. tn->please_negotiate = 1;
  874. rec_do(conn, c);
  875. tn->telrcv_state = CURL_TS_DATA;
  876. continue;
  877. case CURL_TS_DONT:
  878. printoption(data, "RCVD", CURL_DONT, c);
  879. tn->please_negotiate = 1;
  880. rec_dont(conn, c);
  881. tn->telrcv_state = CURL_TS_DATA;
  882. continue;
  883. case CURL_TS_SB:
  884. if (c == CURL_IAC)
  885. {
  886. tn->telrcv_state = CURL_TS_SE;
  887. }
  888. else
  889. {
  890. CURL_SB_ACCUM(tn,c);
  891. }
  892. continue;
  893. case CURL_TS_SE:
  894. if (c != CURL_SE)
  895. {
  896. if (c != CURL_IAC)
  897. {
  898. /*
  899. * This is an error. We only expect to get
  900. * "IAC IAC" or "IAC SE". Several things may
  901. * have happend. An IAC was not doubled, the
  902. * IAC SE was left off, or another option got
  903. * inserted into the suboption are all possibilities.
  904. * If we assume that the IAC was not doubled,
  905. * and really the IAC SE was left off, we could
  906. * get into an infinate loop here. So, instead,
  907. * we terminate the suboption, and process the
  908. * partial suboption if we can.
  909. */
  910. CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
  911. CURL_SB_ACCUM(tn, c);
  912. tn->subpointer -= 2;
  913. CURL_SB_TERM(tn);
  914. printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
  915. suboption(conn); /* handle sub-option */
  916. tn->telrcv_state = CURL_TS_IAC;
  917. goto process_iac;
  918. }
  919. CURL_SB_ACCUM(tn,c);
  920. tn->telrcv_state = CURL_TS_SB;
  921. }
  922. else
  923. {
  924. CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
  925. CURL_SB_ACCUM(tn, (unsigned char)CURL_SE);
  926. tn->subpointer -= 2;
  927. CURL_SB_TERM(tn);
  928. suboption(conn); /* handle sub-option */
  929. tn->telrcv_state = CURL_TS_DATA;
  930. }
  931. break;
  932. }
  933. }
  934. }
  935. CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
  936. {
  937. struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
  938. (void)status; /* unused */
  939. curl_slist_free_all(tn->telnet_vars);
  940. free(conn->proto.telnet);
  941. conn->proto.telnet = NULL;
  942. return CURLE_OK;
  943. }
  944. CURLcode Curl_telnet(struct connectdata *conn)
  945. {
  946. CURLcode code;
  947. struct SessionHandle *data = conn->data;
  948. curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
  949. #ifdef WIN32
  950. HMODULE wsock2;
  951. WSOCK2_FUNC close_event_func;
  952. WSOCK2_FUNC create_event_func;
  953. WSOCK2_FUNC event_select_func;
  954. WSOCK2_FUNC enum_netevents_func;
  955. WSAEVENT event_handle;
  956. WSANETWORKEVENTS events;
  957. HANDLE stdin_handle;
  958. HANDLE objs[2];
  959. DWORD obj_count;
  960. DWORD wait_timeout;
  961. DWORD waitret;
  962. DWORD readfile_read;
  963. #else
  964. fd_set readfd;
  965. fd_set keepfd;
  966. #endif
  967. ssize_t nread;
  968. bool keepon = TRUE;
  969. char *buf = data->state.buffer;
  970. struct TELNET *tn;
  971. code = init_telnet(conn);
  972. if(code)
  973. return code;
  974. tn = (struct TELNET *)conn->proto.telnet;
  975. code = check_telnet_options(conn);
  976. if(code)
  977. return code;
  978. #ifdef WIN32
  979. /*
  980. ** This functionality only works with WinSock >= 2.0. So,
  981. ** make sure have it.
  982. */
  983. code = check_wsock2(data);
  984. if (code)
  985. return code;
  986. /* OK, so we have WinSock 2.0. We need to dynamically */
  987. /* load ws2_32.dll and get the function pointers we need. */
  988. wsock2 = LoadLibrary("WS2_32.DLL");
  989. if (wsock2 == NULL) {
  990. failf(data,"failed to load WS2_32.DLL (%d)",GetLastError());
  991. return CURLE_FAILED_INIT;
  992. }
  993. /* Grab a pointer to WSACreateEvent */
  994. create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
  995. if (create_event_func == NULL) {
  996. failf(data,"failed to find WSACreateEvent function (%d)",
  997. GetLastError());
  998. FreeLibrary(wsock2);
  999. return CURLE_FAILED_INIT;
  1000. }
  1001. /* And WSACloseEvent */
  1002. close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
  1003. if (create_event_func == NULL) {
  1004. failf(data,"failed to find WSACloseEvent function (%d)",
  1005. GetLastError());
  1006. FreeLibrary(wsock2);
  1007. return CURLE_FAILED_INIT;
  1008. }
  1009. /* And WSAEventSelect */
  1010. event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
  1011. if (event_select_func == NULL) {
  1012. failf(data,"failed to find WSAEventSelect function (%d)",
  1013. GetLastError());
  1014. FreeLibrary(wsock2);
  1015. return CURLE_FAILED_INIT;
  1016. }
  1017. /* And WSAEnumNetworkEvents */
  1018. enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
  1019. if (enum_netevents_func == NULL) {
  1020. failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
  1021. GetLastError());
  1022. FreeLibrary(wsock2);
  1023. return CURLE_FAILED_INIT;
  1024. }
  1025. /* We want to wait for both stdin and the socket. Since
  1026. ** the select() function in winsock only works on sockets
  1027. ** we have to use the WaitForMultipleObjects() call.
  1028. */
  1029. /* First, create a sockets event object */
  1030. event_handle = (WSAEVENT)create_event_func();
  1031. if (event_handle == WSA_INVALID_EVENT) {
  1032. failf(data,"WSACreateEvent failed (%d)",WSAGetLastError());
  1033. FreeLibrary(wsock2);
  1034. return CURLE_FAILED_INIT;
  1035. }
  1036. /* The get the Windows file handle for stdin */
  1037. stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
  1038. /* Create the list of objects to wait for */
  1039. objs[0] = event_handle;
  1040. objs[1] = stdin_handle;
  1041. /* Tell winsock what events we want to listen to */
  1042. if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
  1043. close_event_func(event_handle);
  1044. FreeLibrary(wsock2);
  1045. return 0;
  1046. }
  1047. /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
  1048. else use the old WaitForMultipleObjects() way */
  1049. if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
  1050. /* Don't wait for stdin_handle, just wait for event_handle */
  1051. obj_count = 1;
  1052. /* Check stdin_handle per 100 milliseconds */
  1053. wait_timeout = 100;
  1054. } else {
  1055. obj_count = 2;
  1056. wait_timeout = INFINITE;
  1057. }
  1058. /* Keep on listening and act on events */
  1059. while(keepon) {
  1060. waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
  1061. switch(waitret) {
  1062. case WAIT_TIMEOUT:
  1063. {
  1064. unsigned char outbuf[2];
  1065. int out_count;
  1066. ssize_t bytes_written;
  1067. char *buffer = buf;
  1068. for(;;) {
  1069. if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
  1070. keepon = FALSE;
  1071. break;
  1072. }
  1073. nread = readfile_read;
  1074. if(!nread)
  1075. break;
  1076. if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
  1077. &readfile_read, NULL)) {
  1078. keepon = FALSE;
  1079. break;
  1080. }
  1081. nread = readfile_read;
  1082. while(nread--) {
  1083. outbuf[0] = *buffer++;
  1084. out_count = 1;
  1085. if(outbuf[0] == CURL_IAC)
  1086. outbuf[out_count++] = CURL_IAC;
  1087. Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
  1088. out_count, &bytes_written);
  1089. }
  1090. }
  1091. }
  1092. break;
  1093. case WAIT_OBJECT_0 + 1:
  1094. {
  1095. unsigned char outbuf[2];
  1096. int out_count;
  1097. ssize_t bytes_written;
  1098. char *buffer = buf;
  1099. if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
  1100. &readfile_read, NULL)) {
  1101. keepon = FALSE;
  1102. break;
  1103. }
  1104. nread = readfile_read;
  1105. while(nread--) {
  1106. outbuf[0] = *buffer++;
  1107. out_count = 1;
  1108. if(outbuf[0] == CURL_IAC)
  1109. outbuf[out_count++] = CURL_IAC;
  1110. Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
  1111. out_count, &bytes_written);
  1112. }
  1113. }
  1114. break;
  1115. case WAIT_OBJECT_0:
  1116. if(enum_netevents_func(sockfd, event_handle, &events)
  1117. != SOCKET_ERROR) {
  1118. if(events.lNetworkEvents & FD_READ) {
  1119. /* This reallu OUGHT to check its return code. */
  1120. (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
  1121. telrcv(conn, (unsigned char *)buf, nread);
  1122. fflush(stdout);
  1123. /* Negotiate if the peer has started negotiating,
  1124. otherwise don't. We don't want to speak telnet with
  1125. non-telnet servers, like POP or SMTP. */
  1126. if(tn->please_negotiate && !tn->already_negotiated) {
  1127. negotiate(conn);
  1128. tn->already_negotiated = 1;
  1129. }
  1130. }
  1131. if(events.lNetworkEvents & FD_CLOSE) {
  1132. keepon = FALSE;
  1133. }
  1134. }
  1135. break;
  1136. }
  1137. }
  1138. /* We called WSACreateEvent, so call WSACloseEvent */
  1139. if (close_event_func(event_handle) == FALSE) {
  1140. infof(data,"WSACloseEvent failed (%d)",WSAGetLastError());
  1141. }
  1142. /* "Forget" pointers into the library we're about to free */
  1143. create_event_func = NULL;
  1144. close_event_func = NULL;
  1145. event_select_func = NULL;
  1146. enum_netevents_func = NULL;
  1147. (void)create_event_func;
  1148. (void)close_event_func;
  1149. (void)event_select_func;
  1150. (void)enum_netevents_func;
  1151. /* We called LoadLibrary, so call FreeLibrary */
  1152. if (!FreeLibrary(wsock2))
  1153. infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
  1154. #else
  1155. FD_ZERO (&readfd); /* clear it */
  1156. FD_SET (sockfd, &readfd);
  1157. FD_SET (0, &readfd);
  1158. keepfd = readfd;
  1159. while (keepon) {
  1160. struct timeval interval;
  1161. readfd = keepfd; /* set this every lap in the loop */
  1162. interval.tv_sec = 1;
  1163. interval.tv_usec = 0;
  1164. switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) {
  1165. case -1: /* error, stop reading */
  1166. keepon = FALSE;
  1167. continue;
  1168. case 0: /* timeout */
  1169. break;
  1170. default: /* read! */
  1171. if(FD_ISSET(0, &readfd)) { /* read from stdin */
  1172. unsigned char outbuf[2];
  1173. int out_count = 0;
  1174. ssize_t bytes_written;
  1175. char *buffer = buf;
  1176. nread = read(0, buf, 255);
  1177. while(nread--) {
  1178. outbuf[0] = *buffer++;
  1179. out_count = 1;
  1180. if(outbuf[0] == CURL_IAC)
  1181. outbuf[out_count++] = CURL_IAC;
  1182. Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
  1183. out_count, &bytes_written);
  1184. }
  1185. }
  1186. if(FD_ISSET(sockfd, &readfd)) {
  1187. /* This OUGHT to check the return code... */
  1188. (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
  1189. /* if we receive 0 or less here, the server closed the connection and
  1190. we bail out from this! */
  1191. if (nread <= 0) {
  1192. keepon = FALSE;
  1193. break;
  1194. }
  1195. telrcv(conn, (unsigned char *)buf, nread);
  1196. /* Negotiate if the peer has started negotiating,
  1197. otherwise don't. We don't want to speak telnet with
  1198. non-telnet servers, like POP or SMTP. */
  1199. if(tn->please_negotiate && !tn->already_negotiated) {
  1200. negotiate(conn);
  1201. tn->already_negotiated = 1;
  1202. }
  1203. }
  1204. }
  1205. if(data->set.timeout) {
  1206. struct timeval now; /* current time */
  1207. now = Curl_tvnow();
  1208. if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
  1209. failf(data, "Time-out");
  1210. code = CURLE_OPERATION_TIMEOUTED;
  1211. keepon = FALSE;
  1212. }
  1213. }
  1214. }
  1215. #endif
  1216. /* mark this as "no further transfer wanted" */
  1217. Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
  1218. return code;
  1219. }
  1220. #endif