Annotation of embedaddon/curl/lib/telnet.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, 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 https://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: ***************************************************************************/
22:
23: #include "curl_setup.h"
24:
25: #ifndef CURL_DISABLE_TELNET
26:
27: #ifdef HAVE_NETINET_IN_H
28: #include <netinet/in.h>
29: #endif
30: #ifdef HAVE_NETDB_H
31: #include <netdb.h>
32: #endif
33: #ifdef HAVE_ARPA_INET_H
34: #include <arpa/inet.h>
35: #endif
36: #ifdef HAVE_NET_IF_H
37: #include <net/if.h>
38: #endif
39: #ifdef HAVE_SYS_IOCTL_H
40: #include <sys/ioctl.h>
41: #endif
42:
43: #ifdef HAVE_SYS_PARAM_H
44: #include <sys/param.h>
45: #endif
46:
47: #include "urldata.h"
48: #include <curl/curl.h>
49: #include "transfer.h"
50: #include "sendf.h"
51: #include "telnet.h"
52: #include "connect.h"
53: #include "progress.h"
54: #include "system_win32.h"
55: #include "arpa_telnet.h"
56: #include "select.h"
57: #include "strcase.h"
58: #include "warnless.h"
59:
60: /* The last 3 #include files should be in this order */
61: #include "curl_printf.h"
62: #include "curl_memory.h"
63: #include "memdebug.h"
64:
65: #define SUBBUFSIZE 512
66:
67: #define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
68: #define CURL_SB_TERM(x) \
69: do { \
70: x->subend = x->subpointer; \
71: CURL_SB_CLEAR(x); \
72: } while(0)
73: #define CURL_SB_ACCUM(x,c) \
74: do { \
75: if(x->subpointer < (x->subbuffer + sizeof(x->subbuffer))) \
76: *x->subpointer++ = (c); \
77: } while(0)
78:
79: #define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
80: #define CURL_SB_LEN(x) (x->subend - x->subpointer)
81:
82: /* For posterity:
83: #define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
84: #define CURL_SB_EOF(x) (x->subpointer >= x->subend) */
85:
86: #ifdef CURL_DISABLE_VERBOSE_STRINGS
87: #define printoption(a,b,c,d) Curl_nop_stmt
88: #endif
89:
90: #ifdef USE_WINSOCK
91: typedef WSAEVENT (WINAPI *WSOCK2_EVENT)(void);
92: typedef FARPROC WSOCK2_FUNC;
93: static CURLcode check_wsock2(struct Curl_easy *data);
94: #endif
95:
96: static
97: CURLcode telrcv(struct connectdata *,
98: const unsigned char *inbuf, /* Data received from socket */
99: ssize_t count); /* Number of bytes received */
100:
101: #ifndef CURL_DISABLE_VERBOSE_STRINGS
102: static void printoption(struct Curl_easy *data,
103: const char *direction,
104: int cmd, int option);
105: #endif
106:
107: static void negotiate(struct connectdata *);
108: static void send_negotiation(struct connectdata *, int cmd, int option);
109: static void set_local_option(struct connectdata *conn,
110: int option, int newstate);
111: static void set_remote_option(struct connectdata *conn,
112: int option, int newstate);
113:
114: static void printsub(struct Curl_easy *data,
115: int direction, unsigned char *pointer,
116: size_t length);
117: static void suboption(struct connectdata *);
118: static void sendsuboption(struct connectdata *conn, int option);
119:
120: static CURLcode telnet_do(struct connectdata *conn, bool *done);
121: static CURLcode telnet_done(struct connectdata *conn,
122: CURLcode, bool premature);
123: static CURLcode send_telnet_data(struct connectdata *conn,
124: char *buffer, ssize_t nread);
125:
126: /* For negotiation compliant to RFC 1143 */
127: #define CURL_NO 0
128: #define CURL_YES 1
129: #define CURL_WANTYES 2
130: #define CURL_WANTNO 3
131:
132: #define CURL_EMPTY 0
133: #define CURL_OPPOSITE 1
134:
135: /*
136: * Telnet receiver states for fsm
137: */
138: typedef enum
139: {
140: CURL_TS_DATA = 0,
141: CURL_TS_IAC,
142: CURL_TS_WILL,
143: CURL_TS_WONT,
144: CURL_TS_DO,
145: CURL_TS_DONT,
146: CURL_TS_CR,
147: CURL_TS_SB, /* sub-option collection */
148: CURL_TS_SE /* looking for sub-option end */
149: } TelnetReceive;
150:
151: struct TELNET {
152: int please_negotiate;
153: int already_negotiated;
154: int us[256];
155: int usq[256];
156: int us_preferred[256];
157: int him[256];
158: int himq[256];
159: int him_preferred[256];
160: int subnegotiation[256];
161: char subopt_ttype[32]; /* Set with suboption TTYPE */
162: char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
163: unsigned short subopt_wsx; /* Set with suboption NAWS */
164: unsigned short subopt_wsy; /* Set with suboption NAWS */
165: struct curl_slist *telnet_vars; /* Environment variables */
166:
167: /* suboptions */
168: unsigned char subbuffer[SUBBUFSIZE];
169: unsigned char *subpointer, *subend; /* buffer for sub-options */
170:
171: TelnetReceive telrcv_state;
172: };
173:
174:
175: /*
176: * TELNET protocol handler.
177: */
178:
179: const struct Curl_handler Curl_handler_telnet = {
180: "TELNET", /* scheme */
181: ZERO_NULL, /* setup_connection */
182: telnet_do, /* do_it */
183: telnet_done, /* done */
184: ZERO_NULL, /* do_more */
185: ZERO_NULL, /* connect_it */
186: ZERO_NULL, /* connecting */
187: ZERO_NULL, /* doing */
188: ZERO_NULL, /* proto_getsock */
189: ZERO_NULL, /* doing_getsock */
190: ZERO_NULL, /* domore_getsock */
191: ZERO_NULL, /* perform_getsock */
192: ZERO_NULL, /* disconnect */
193: ZERO_NULL, /* readwrite */
194: ZERO_NULL, /* connection_check */
195: PORT_TELNET, /* defport */
196: CURLPROTO_TELNET, /* protocol */
197: PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
198: };
199:
200:
201: #ifdef USE_WINSOCK
202: static CURLcode
203: check_wsock2(struct Curl_easy *data)
204: {
205: int err;
206: WORD wVersionRequested;
207: WSADATA wsaData;
208:
209: DEBUGASSERT(data);
210:
211: /* telnet requires at least WinSock 2.0 so ask for it. */
212: wVersionRequested = MAKEWORD(2, 0);
213:
214: err = WSAStartup(wVersionRequested, &wsaData);
215:
216: /* We must've called this once already, so this call */
217: /* should always succeed. But, just in case... */
218: if(err != 0) {
219: failf(data,"WSAStartup failed (%d)",err);
220: return CURLE_FAILED_INIT;
221: }
222:
223: /* We have to have a WSACleanup call for every successful */
224: /* WSAStartup call. */
225: WSACleanup();
226:
227: /* Check that our version is supported */
228: if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
229: HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
230: /* Our version isn't supported */
231: failf(data, "insufficient winsock version to support "
232: "telnet");
233: return CURLE_FAILED_INIT;
234: }
235:
236: /* Our version is supported */
237: return CURLE_OK;
238: }
239: #endif
240:
241: static
242: CURLcode init_telnet(struct connectdata *conn)
243: {
244: struct TELNET *tn;
245:
246: tn = calloc(1, sizeof(struct TELNET));
247: if(!tn)
248: return CURLE_OUT_OF_MEMORY;
249:
250: conn->data->req.protop = tn; /* make us known */
251:
252: tn->telrcv_state = CURL_TS_DATA;
253:
254: /* Init suboptions */
255: CURL_SB_CLEAR(tn);
256:
257: /* Set the options we want by default */
258: tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
259: tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
260:
261: /* To be compliant with previous releases of libcurl
262: we enable this option by default. This behaviour
263: can be changed thanks to the "BINARY" option in
264: CURLOPT_TELNETOPTIONS
265: */
266: tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
267: tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
268:
269: /* We must allow the server to echo what we sent
270: but it is not necessary to request the server
271: to do so (it might forces the server to close
272: the connection). Hence, we ignore ECHO in the
273: negotiate function
274: */
275: tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
276:
277: /* Set the subnegotiation fields to send information
278: just after negotiation passed (do/will)
279:
280: Default values are (0,0) initialized by calloc.
281: According to the RFC1013 it is valid:
282: A value equal to zero is acceptable for the width (or height),
283: and means that no character width (or height) is being sent.
284: In this case, the width (or height) that will be assumed by the
285: Telnet server is operating system specific (it will probably be
286: based upon the terminal type information that may have been sent
287: using the TERMINAL TYPE Telnet option). */
288: tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
289: return CURLE_OK;
290: }
291:
292: static void negotiate(struct connectdata *conn)
293: {
294: int i;
295: struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
296:
297: for(i = 0; i < CURL_NTELOPTS; i++) {
298: if(i == CURL_TELOPT_ECHO)
299: continue;
300:
301: if(tn->us_preferred[i] == CURL_YES)
302: set_local_option(conn, i, CURL_YES);
303:
304: if(tn->him_preferred[i] == CURL_YES)
305: set_remote_option(conn, i, CURL_YES);
306: }
307: }
308:
309: #ifndef CURL_DISABLE_VERBOSE_STRINGS
310: static void printoption(struct Curl_easy *data,
311: const char *direction, int cmd, int option)
312: {
313: if(data->set.verbose) {
314: if(cmd == CURL_IAC) {
315: if(CURL_TELCMD_OK(option))
316: infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
317: else
318: infof(data, "%s IAC %d\n", direction, option);
319: }
320: else {
321: const char *fmt = (cmd == CURL_WILL) ? "WILL" :
322: (cmd == CURL_WONT) ? "WONT" :
323: (cmd == CURL_DO) ? "DO" :
324: (cmd == CURL_DONT) ? "DONT" : 0;
325: if(fmt) {
326: const char *opt;
327: if(CURL_TELOPT_OK(option))
328: opt = CURL_TELOPT(option);
329: else if(option == CURL_TELOPT_EXOPL)
330: opt = "EXOPL";
331: else
332: opt = NULL;
333:
334: if(opt)
335: infof(data, "%s %s %s\n", direction, fmt, opt);
336: else
337: infof(data, "%s %s %d\n", direction, fmt, option);
338: }
339: else
340: infof(data, "%s %d %d\n", direction, cmd, option);
341: }
342: }
343: }
344: #endif
345:
346: static void send_negotiation(struct connectdata *conn, int cmd, int option)
347: {
348: unsigned char buf[3];
349: ssize_t bytes_written;
350: struct Curl_easy *data = conn->data;
351:
352: buf[0] = CURL_IAC;
353: buf[1] = (unsigned char)cmd;
354: buf[2] = (unsigned char)option;
355:
356: bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
357: if(bytes_written < 0) {
358: int err = SOCKERRNO;
359: failf(data,"Sending data failed (%d)",err);
360: }
361:
362: printoption(conn->data, "SENT", cmd, option);
363: }
364:
365: static
366: void set_remote_option(struct connectdata *conn, int option, int newstate)
367: {
368: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
369: if(newstate == CURL_YES) {
370: switch(tn->him[option]) {
371: case CURL_NO:
372: tn->him[option] = CURL_WANTYES;
373: send_negotiation(conn, CURL_DO, option);
374: break;
375:
376: case CURL_YES:
377: /* Already enabled */
378: break;
379:
380: case CURL_WANTNO:
381: switch(tn->himq[option]) {
382: case CURL_EMPTY:
383: /* Already negotiating for CURL_YES, queue the request */
384: tn->himq[option] = CURL_OPPOSITE;
385: break;
386: case CURL_OPPOSITE:
387: /* Error: already queued an enable request */
388: break;
389: }
390: break;
391:
392: case CURL_WANTYES:
393: switch(tn->himq[option]) {
394: case CURL_EMPTY:
395: /* Error: already negotiating for enable */
396: break;
397: case CURL_OPPOSITE:
398: tn->himq[option] = CURL_EMPTY;
399: break;
400: }
401: break;
402: }
403: }
404: else { /* NO */
405: switch(tn->him[option]) {
406: case CURL_NO:
407: /* Already disabled */
408: break;
409:
410: case CURL_YES:
411: tn->him[option] = CURL_WANTNO;
412: send_negotiation(conn, CURL_DONT, option);
413: break;
414:
415: case CURL_WANTNO:
416: switch(tn->himq[option]) {
417: case CURL_EMPTY:
418: /* Already negotiating for NO */
419: break;
420: case CURL_OPPOSITE:
421: tn->himq[option] = CURL_EMPTY;
422: break;
423: }
424: break;
425:
426: case CURL_WANTYES:
427: switch(tn->himq[option]) {
428: case CURL_EMPTY:
429: tn->himq[option] = CURL_OPPOSITE;
430: break;
431: case CURL_OPPOSITE:
432: break;
433: }
434: break;
435: }
436: }
437: }
438:
439: static
440: void rec_will(struct connectdata *conn, int option)
441: {
442: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
443: switch(tn->him[option]) {
444: case CURL_NO:
445: if(tn->him_preferred[option] == CURL_YES) {
446: tn->him[option] = CURL_YES;
447: send_negotiation(conn, CURL_DO, option);
448: }
449: else
450: send_negotiation(conn, CURL_DONT, option);
451:
452: break;
453:
454: case CURL_YES:
455: /* Already enabled */
456: break;
457:
458: case CURL_WANTNO:
459: switch(tn->himq[option]) {
460: case CURL_EMPTY:
461: /* Error: DONT answered by WILL */
462: tn->him[option] = CURL_NO;
463: break;
464: case CURL_OPPOSITE:
465: /* Error: DONT answered by WILL */
466: tn->him[option] = CURL_YES;
467: tn->himq[option] = CURL_EMPTY;
468: break;
469: }
470: break;
471:
472: case CURL_WANTYES:
473: switch(tn->himq[option]) {
474: case CURL_EMPTY:
475: tn->him[option] = CURL_YES;
476: break;
477: case CURL_OPPOSITE:
478: tn->him[option] = CURL_WANTNO;
479: tn->himq[option] = CURL_EMPTY;
480: send_negotiation(conn, CURL_DONT, option);
481: break;
482: }
483: break;
484: }
485: }
486:
487: static
488: void rec_wont(struct connectdata *conn, int option)
489: {
490: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
491: switch(tn->him[option]) {
492: case CURL_NO:
493: /* Already disabled */
494: break;
495:
496: case CURL_YES:
497: tn->him[option] = CURL_NO;
498: send_negotiation(conn, CURL_DONT, option);
499: break;
500:
501: case CURL_WANTNO:
502: switch(tn->himq[option]) {
503: case CURL_EMPTY:
504: tn->him[option] = CURL_NO;
505: break;
506:
507: case CURL_OPPOSITE:
508: tn->him[option] = CURL_WANTYES;
509: tn->himq[option] = CURL_EMPTY;
510: send_negotiation(conn, CURL_DO, option);
511: break;
512: }
513: break;
514:
515: case CURL_WANTYES:
516: switch(tn->himq[option]) {
517: case CURL_EMPTY:
518: tn->him[option] = CURL_NO;
519: break;
520: case CURL_OPPOSITE:
521: tn->him[option] = CURL_NO;
522: tn->himq[option] = CURL_EMPTY;
523: break;
524: }
525: break;
526: }
527: }
528:
529: static void
530: set_local_option(struct connectdata *conn, int option, int newstate)
531: {
532: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
533: if(newstate == CURL_YES) {
534: switch(tn->us[option]) {
535: case CURL_NO:
536: tn->us[option] = CURL_WANTYES;
537: send_negotiation(conn, CURL_WILL, option);
538: break;
539:
540: case CURL_YES:
541: /* Already enabled */
542: break;
543:
544: case CURL_WANTNO:
545: switch(tn->usq[option]) {
546: case CURL_EMPTY:
547: /* Already negotiating for CURL_YES, queue the request */
548: tn->usq[option] = CURL_OPPOSITE;
549: break;
550: case CURL_OPPOSITE:
551: /* Error: already queued an enable request */
552: break;
553: }
554: break;
555:
556: case CURL_WANTYES:
557: switch(tn->usq[option]) {
558: case CURL_EMPTY:
559: /* Error: already negotiating for enable */
560: break;
561: case CURL_OPPOSITE:
562: tn->usq[option] = CURL_EMPTY;
563: break;
564: }
565: break;
566: }
567: }
568: else { /* NO */
569: switch(tn->us[option]) {
570: case CURL_NO:
571: /* Already disabled */
572: break;
573:
574: case CURL_YES:
575: tn->us[option] = CURL_WANTNO;
576: send_negotiation(conn, CURL_WONT, option);
577: break;
578:
579: case CURL_WANTNO:
580: switch(tn->usq[option]) {
581: case CURL_EMPTY:
582: /* Already negotiating for NO */
583: break;
584: case CURL_OPPOSITE:
585: tn->usq[option] = CURL_EMPTY;
586: break;
587: }
588: break;
589:
590: case CURL_WANTYES:
591: switch(tn->usq[option]) {
592: case CURL_EMPTY:
593: tn->usq[option] = CURL_OPPOSITE;
594: break;
595: case CURL_OPPOSITE:
596: break;
597: }
598: break;
599: }
600: }
601: }
602:
603: static
604: void rec_do(struct connectdata *conn, int option)
605: {
606: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
607: switch(tn->us[option]) {
608: case CURL_NO:
609: if(tn->us_preferred[option] == CURL_YES) {
610: tn->us[option] = CURL_YES;
611: send_negotiation(conn, CURL_WILL, option);
612: if(tn->subnegotiation[option] == CURL_YES)
613: /* transmission of data option */
614: sendsuboption(conn, option);
615: }
616: else if(tn->subnegotiation[option] == CURL_YES) {
617: /* send information to achieve this option*/
618: tn->us[option] = CURL_YES;
619: send_negotiation(conn, CURL_WILL, option);
620: sendsuboption(conn, option);
621: }
622: else
623: send_negotiation(conn, CURL_WONT, option);
624: break;
625:
626: case CURL_YES:
627: /* Already enabled */
628: break;
629:
630: case CURL_WANTNO:
631: switch(tn->usq[option]) {
632: case CURL_EMPTY:
633: /* Error: DONT answered by WILL */
634: tn->us[option] = CURL_NO;
635: break;
636: case CURL_OPPOSITE:
637: /* Error: DONT answered by WILL */
638: tn->us[option] = CURL_YES;
639: tn->usq[option] = CURL_EMPTY;
640: break;
641: }
642: break;
643:
644: case CURL_WANTYES:
645: switch(tn->usq[option]) {
646: case CURL_EMPTY:
647: tn->us[option] = CURL_YES;
648: if(tn->subnegotiation[option] == CURL_YES) {
649: /* transmission of data option */
650: sendsuboption(conn, option);
651: }
652: break;
653: case CURL_OPPOSITE:
654: tn->us[option] = CURL_WANTNO;
655: tn->himq[option] = CURL_EMPTY;
656: send_negotiation(conn, CURL_WONT, option);
657: break;
658: }
659: break;
660: }
661: }
662:
663: static
664: void rec_dont(struct connectdata *conn, int option)
665: {
666: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
667: switch(tn->us[option]) {
668: case CURL_NO:
669: /* Already disabled */
670: break;
671:
672: case CURL_YES:
673: tn->us[option] = CURL_NO;
674: send_negotiation(conn, CURL_WONT, option);
675: break;
676:
677: case CURL_WANTNO:
678: switch(tn->usq[option]) {
679: case CURL_EMPTY:
680: tn->us[option] = CURL_NO;
681: break;
682:
683: case CURL_OPPOSITE:
684: tn->us[option] = CURL_WANTYES;
685: tn->usq[option] = CURL_EMPTY;
686: send_negotiation(conn, CURL_WILL, option);
687: break;
688: }
689: break;
690:
691: case CURL_WANTYES:
692: switch(tn->usq[option]) {
693: case CURL_EMPTY:
694: tn->us[option] = CURL_NO;
695: break;
696: case CURL_OPPOSITE:
697: tn->us[option] = CURL_NO;
698: tn->usq[option] = CURL_EMPTY;
699: break;
700: }
701: break;
702: }
703: }
704:
705:
706: static void printsub(struct Curl_easy *data,
707: int direction, /* '<' or '>' */
708: unsigned char *pointer, /* where suboption data is */
709: size_t length) /* length of suboption data */
710: {
711: if(data->set.verbose) {
712: unsigned int i = 0;
713: if(direction) {
714: infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
715: if(length >= 3) {
716: int j;
717:
718: i = pointer[length-2];
719: j = pointer[length-1];
720:
721: if(i != CURL_IAC || j != CURL_SE) {
722: infof(data, "(terminated by ");
723: if(CURL_TELOPT_OK(i))
724: infof(data, "%s ", CURL_TELOPT(i));
725: else if(CURL_TELCMD_OK(i))
726: infof(data, "%s ", CURL_TELCMD(i));
727: else
728: infof(data, "%u ", i);
729: if(CURL_TELOPT_OK(j))
730: infof(data, "%s", CURL_TELOPT(j));
731: else if(CURL_TELCMD_OK(j))
732: infof(data, "%s", CURL_TELCMD(j));
733: else
734: infof(data, "%d", j);
735: infof(data, ", not IAC SE!) ");
736: }
737: }
738: length -= 2;
739: }
740: if(length < 1) {
741: infof(data, "(Empty suboption?)");
742: return;
743: }
744:
745: if(CURL_TELOPT_OK(pointer[0])) {
746: switch(pointer[0]) {
747: case CURL_TELOPT_TTYPE:
748: case CURL_TELOPT_XDISPLOC:
749: case CURL_TELOPT_NEW_ENVIRON:
750: case CURL_TELOPT_NAWS:
751: infof(data, "%s", CURL_TELOPT(pointer[0]));
752: break;
753: default:
754: infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
755: break;
756: }
757: }
758: else
759: infof(data, "%d (unknown)", pointer[i]);
760:
761: switch(pointer[0]) {
762: case CURL_TELOPT_NAWS:
763: if(length > 4)
764: infof(data, "Width: %d ; Height: %d", (pointer[1]<<8) | pointer[2],
765: (pointer[3]<<8) | pointer[4]);
766: break;
767: default:
768: switch(pointer[1]) {
769: case CURL_TELQUAL_IS:
770: infof(data, " IS");
771: break;
772: case CURL_TELQUAL_SEND:
773: infof(data, " SEND");
774: break;
775: case CURL_TELQUAL_INFO:
776: infof(data, " INFO/REPLY");
777: break;
778: case CURL_TELQUAL_NAME:
779: infof(data, " NAME");
780: break;
781: }
782:
783: switch(pointer[0]) {
784: case CURL_TELOPT_TTYPE:
785: case CURL_TELOPT_XDISPLOC:
786: pointer[length] = 0;
787: infof(data, " \"%s\"", &pointer[2]);
788: break;
789: case CURL_TELOPT_NEW_ENVIRON:
790: if(pointer[1] == CURL_TELQUAL_IS) {
791: infof(data, " ");
792: for(i = 3; i < length; i++) {
793: switch(pointer[i]) {
794: case CURL_NEW_ENV_VAR:
795: infof(data, ", ");
796: break;
797: case CURL_NEW_ENV_VALUE:
798: infof(data, " = ");
799: break;
800: default:
801: infof(data, "%c", pointer[i]);
802: break;
803: }
804: }
805: }
806: break;
807: default:
808: for(i = 2; i < length; i++)
809: infof(data, " %.2x", pointer[i]);
810: break;
811: }
812: }
813: if(direction)
814: infof(data, "\n");
815: }
816: }
817:
818: static CURLcode check_telnet_options(struct connectdata *conn)
819: {
820: struct curl_slist *head;
821: struct curl_slist *beg;
822: char option_keyword[128] = "";
823: char option_arg[256] = "";
824: struct Curl_easy *data = conn->data;
825: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
826: CURLcode result = CURLE_OK;
827: int binary_option;
828:
829: /* Add the user name as an environment variable if it
830: was given on the command line */
831: if(conn->bits.user_passwd) {
832: msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
833: beg = curl_slist_append(tn->telnet_vars, option_arg);
834: if(!beg) {
835: curl_slist_free_all(tn->telnet_vars);
836: tn->telnet_vars = NULL;
837: return CURLE_OUT_OF_MEMORY;
838: }
839: tn->telnet_vars = beg;
840: tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
841: }
842:
843: for(head = data->set.telnet_options; head; head = head->next) {
844: if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
845: option_keyword, option_arg) == 2) {
846:
847: /* Terminal type */
848: if(strcasecompare(option_keyword, "TTYPE")) {
849: strncpy(tn->subopt_ttype, option_arg, 31);
850: tn->subopt_ttype[31] = 0; /* String termination */
851: tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
852: continue;
853: }
854:
855: /* Display variable */
856: if(strcasecompare(option_keyword, "XDISPLOC")) {
857: strncpy(tn->subopt_xdisploc, option_arg, 127);
858: tn->subopt_xdisploc[127] = 0; /* String termination */
859: tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
860: continue;
861: }
862:
863: /* Environment variable */
864: if(strcasecompare(option_keyword, "NEW_ENV")) {
865: beg = curl_slist_append(tn->telnet_vars, option_arg);
866: if(!beg) {
867: result = CURLE_OUT_OF_MEMORY;
868: break;
869: }
870: tn->telnet_vars = beg;
871: tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
872: continue;
873: }
874:
875: /* Window Size */
876: if(strcasecompare(option_keyword, "WS")) {
877: if(sscanf(option_arg, "%hu%*[xX]%hu",
878: &tn->subopt_wsx, &tn->subopt_wsy) == 2)
879: tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
880: else {
881: failf(data, "Syntax error in telnet option: %s", head->data);
882: result = CURLE_TELNET_OPTION_SYNTAX;
883: break;
884: }
885: continue;
886: }
887:
888: /* To take care or not of the 8th bit in data exchange */
889: if(strcasecompare(option_keyword, "BINARY")) {
890: binary_option = atoi(option_arg);
891: if(binary_option != 1) {
892: tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
893: tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
894: }
895: continue;
896: }
897:
898: failf(data, "Unknown telnet option %s", head->data);
899: result = CURLE_UNKNOWN_OPTION;
900: break;
901: }
902: failf(data, "Syntax error in telnet option: %s", head->data);
903: result = CURLE_TELNET_OPTION_SYNTAX;
904: break;
905: }
906:
907: if(result) {
908: curl_slist_free_all(tn->telnet_vars);
909: tn->telnet_vars = NULL;
910: }
911:
912: return result;
913: }
914:
915: /*
916: * suboption()
917: *
918: * Look at the sub-option buffer, and try to be helpful to the other
919: * side.
920: */
921:
922: static void suboption(struct connectdata *conn)
923: {
924: struct curl_slist *v;
925: unsigned char temp[2048];
926: ssize_t bytes_written;
927: size_t len;
928: int err;
929: char varname[128] = "";
930: char varval[128] = "";
931: struct Curl_easy *data = conn->data;
932: struct TELNET *tn = (struct TELNET *)data->req.protop;
933:
934: printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn) + 2);
935: switch(CURL_SB_GET(tn)) {
936: case CURL_TELOPT_TTYPE:
937: len = strlen(tn->subopt_ttype) + 4 + 2;
938: msnprintf((char *)temp, sizeof(temp),
939: "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
940: CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
941: bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
942: if(bytes_written < 0) {
943: err = SOCKERRNO;
944: failf(data,"Sending data failed (%d)",err);
945: }
946: printsub(data, '>', &temp[2], len-2);
947: break;
948: case CURL_TELOPT_XDISPLOC:
949: len = strlen(tn->subopt_xdisploc) + 4 + 2;
950: msnprintf((char *)temp, sizeof(temp),
951: "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
952: CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
953: bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
954: if(bytes_written < 0) {
955: err = SOCKERRNO;
956: failf(data,"Sending data failed (%d)",err);
957: }
958: printsub(data, '>', &temp[2], len-2);
959: break;
960: case CURL_TELOPT_NEW_ENVIRON:
961: msnprintf((char *)temp, sizeof(temp),
962: "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
963: CURL_TELQUAL_IS);
964: len = 4;
965:
966: for(v = tn->telnet_vars; v; v = v->next) {
967: size_t tmplen = (strlen(v->data) + 1);
968: /* Add the variable only if it fits */
969: if(len + tmplen < (int)sizeof(temp)-6) {
970: if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
971: msnprintf((char *)&temp[len], sizeof(temp) - len,
972: "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
973: CURL_NEW_ENV_VALUE, varval);
974: len += tmplen;
975: }
976: }
977: }
978: msnprintf((char *)&temp[len], sizeof(temp) - len,
979: "%c%c", CURL_IAC, CURL_SE);
980: len += 2;
981: bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
982: if(bytes_written < 0) {
983: err = SOCKERRNO;
984: failf(data,"Sending data failed (%d)",err);
985: }
986: printsub(data, '>', &temp[2], len-2);
987: break;
988: }
989: return;
990: }
991:
992:
993: /*
994: * sendsuboption()
995: *
996: * Send suboption information to the server side.
997: */
998:
999: static void sendsuboption(struct connectdata *conn, int option)
1000: {
1001: ssize_t bytes_written;
1002: int err;
1003: unsigned short x, y;
1004: unsigned char *uc1, *uc2;
1005:
1006: struct Curl_easy *data = conn->data;
1007: struct TELNET *tn = (struct TELNET *)data->req.protop;
1008:
1009: switch(option) {
1010: case CURL_TELOPT_NAWS:
1011: /* We prepare data to be sent */
1012: CURL_SB_CLEAR(tn);
1013: CURL_SB_ACCUM(tn, CURL_IAC);
1014: CURL_SB_ACCUM(tn, CURL_SB);
1015: CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
1016: /* We must deal either with little or big endian processors */
1017: /* Window size must be sent according to the 'network order' */
1018: x = htons(tn->subopt_wsx);
1019: y = htons(tn->subopt_wsy);
1020: uc1 = (unsigned char *)&x;
1021: uc2 = (unsigned char *)&y;
1022: CURL_SB_ACCUM(tn, uc1[0]);
1023: CURL_SB_ACCUM(tn, uc1[1]);
1024: CURL_SB_ACCUM(tn, uc2[0]);
1025: CURL_SB_ACCUM(tn, uc2[1]);
1026:
1027: CURL_SB_ACCUM(tn, CURL_IAC);
1028: CURL_SB_ACCUM(tn, CURL_SE);
1029: CURL_SB_TERM(tn);
1030: /* data suboption is now ready */
1031:
1032: printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
1033: CURL_SB_LEN(tn)-2);
1034:
1035: /* we send the header of the suboption... */
1036: bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
1037: if(bytes_written < 0) {
1038: err = SOCKERRNO;
1039: failf(data, "Sending data failed (%d)", err);
1040: }
1041: /* ... then the window size with the send_telnet_data() function
1042: to deal with 0xFF cases ... */
1043: send_telnet_data(conn, (char *)tn->subbuffer + 3, 4);
1044: /* ... and the footer */
1045: bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
1046: if(bytes_written < 0) {
1047: err = SOCKERRNO;
1048: failf(data, "Sending data failed (%d)", err);
1049: }
1050: break;
1051: }
1052: }
1053:
1054:
1055: static
1056: CURLcode telrcv(struct connectdata *conn,
1057: const unsigned char *inbuf, /* Data received from socket */
1058: ssize_t count) /* Number of bytes received */
1059: {
1060: unsigned char c;
1061: CURLcode result;
1062: int in = 0;
1063: int startwrite = -1;
1064: struct Curl_easy *data = conn->data;
1065: struct TELNET *tn = (struct TELNET *)data->req.protop;
1066:
1067: #define startskipping() \
1068: if(startwrite >= 0) { \
1069: result = Curl_client_write(conn, \
1070: CLIENTWRITE_BODY, \
1071: (char *)&inbuf[startwrite], \
1072: in-startwrite); \
1073: if(result) \
1074: return result; \
1075: } \
1076: startwrite = -1
1077:
1078: #define writebyte() \
1079: if(startwrite < 0) \
1080: startwrite = in
1081:
1082: #define bufferflush() startskipping()
1083:
1084: while(count--) {
1085: c = inbuf[in];
1086:
1087: switch(tn->telrcv_state) {
1088: case CURL_TS_CR:
1089: tn->telrcv_state = CURL_TS_DATA;
1090: if(c == '\0') {
1091: startskipping();
1092: break; /* Ignore \0 after CR */
1093: }
1094: writebyte();
1095: break;
1096:
1097: case CURL_TS_DATA:
1098: if(c == CURL_IAC) {
1099: tn->telrcv_state = CURL_TS_IAC;
1100: startskipping();
1101: break;
1102: }
1103: else if(c == '\r')
1104: tn->telrcv_state = CURL_TS_CR;
1105: writebyte();
1106: break;
1107:
1108: case CURL_TS_IAC:
1109: process_iac:
1110: DEBUGASSERT(startwrite < 0);
1111: switch(c) {
1112: case CURL_WILL:
1113: tn->telrcv_state = CURL_TS_WILL;
1114: break;
1115: case CURL_WONT:
1116: tn->telrcv_state = CURL_TS_WONT;
1117: break;
1118: case CURL_DO:
1119: tn->telrcv_state = CURL_TS_DO;
1120: break;
1121: case CURL_DONT:
1122: tn->telrcv_state = CURL_TS_DONT;
1123: break;
1124: case CURL_SB:
1125: CURL_SB_CLEAR(tn);
1126: tn->telrcv_state = CURL_TS_SB;
1127: break;
1128: case CURL_IAC:
1129: tn->telrcv_state = CURL_TS_DATA;
1130: writebyte();
1131: break;
1132: case CURL_DM:
1133: case CURL_NOP:
1134: case CURL_GA:
1135: default:
1136: tn->telrcv_state = CURL_TS_DATA;
1137: printoption(data, "RCVD", CURL_IAC, c);
1138: break;
1139: }
1140: break;
1141:
1142: case CURL_TS_WILL:
1143: printoption(data, "RCVD", CURL_WILL, c);
1144: tn->please_negotiate = 1;
1145: rec_will(conn, c);
1146: tn->telrcv_state = CURL_TS_DATA;
1147: break;
1148:
1149: case CURL_TS_WONT:
1150: printoption(data, "RCVD", CURL_WONT, c);
1151: tn->please_negotiate = 1;
1152: rec_wont(conn, c);
1153: tn->telrcv_state = CURL_TS_DATA;
1154: break;
1155:
1156: case CURL_TS_DO:
1157: printoption(data, "RCVD", CURL_DO, c);
1158: tn->please_negotiate = 1;
1159: rec_do(conn, c);
1160: tn->telrcv_state = CURL_TS_DATA;
1161: break;
1162:
1163: case CURL_TS_DONT:
1164: printoption(data, "RCVD", CURL_DONT, c);
1165: tn->please_negotiate = 1;
1166: rec_dont(conn, c);
1167: tn->telrcv_state = CURL_TS_DATA;
1168: break;
1169:
1170: case CURL_TS_SB:
1171: if(c == CURL_IAC)
1172: tn->telrcv_state = CURL_TS_SE;
1173: else
1174: CURL_SB_ACCUM(tn, c);
1175: break;
1176:
1177: case CURL_TS_SE:
1178: if(c != CURL_SE) {
1179: if(c != CURL_IAC) {
1180: /*
1181: * This is an error. We only expect to get "IAC IAC" or "IAC SE".
1182: * Several things may have happened. An IAC was not doubled, the
1183: * IAC SE was left off, or another option got inserted into the
1184: * suboption are all possibilities. If we assume that the IAC was
1185: * not doubled, and really the IAC SE was left off, we could get
1186: * into an infinite loop here. So, instead, we terminate the
1187: * suboption, and process the partial suboption if we can.
1188: */
1189: CURL_SB_ACCUM(tn, CURL_IAC);
1190: CURL_SB_ACCUM(tn, c);
1191: tn->subpointer -= 2;
1192: CURL_SB_TERM(tn);
1193:
1194: printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
1195: suboption(conn); /* handle sub-option */
1196: tn->telrcv_state = CURL_TS_IAC;
1197: goto process_iac;
1198: }
1199: CURL_SB_ACCUM(tn, c);
1200: tn->telrcv_state = CURL_TS_SB;
1201: }
1202: else {
1203: CURL_SB_ACCUM(tn, CURL_IAC);
1204: CURL_SB_ACCUM(tn, CURL_SE);
1205: tn->subpointer -= 2;
1206: CURL_SB_TERM(tn);
1207: suboption(conn); /* handle sub-option */
1208: tn->telrcv_state = CURL_TS_DATA;
1209: }
1210: break;
1211: }
1212: ++in;
1213: }
1214: bufferflush();
1215: return CURLE_OK;
1216: }
1217:
1218: /* Escape and send a telnet data block */
1219: static CURLcode send_telnet_data(struct connectdata *conn,
1220: char *buffer, ssize_t nread)
1221: {
1222: ssize_t escapes, i, outlen;
1223: unsigned char *outbuf = NULL;
1224: CURLcode result = CURLE_OK;
1225: ssize_t bytes_written, total_written;
1226:
1227: /* Determine size of new buffer after escaping */
1228: escapes = 0;
1229: for(i = 0; i < nread; i++)
1230: if((unsigned char)buffer[i] == CURL_IAC)
1231: escapes++;
1232: outlen = nread + escapes;
1233:
1234: if(outlen == nread)
1235: outbuf = (unsigned char *)buffer;
1236: else {
1237: ssize_t j;
1238: outbuf = malloc(nread + escapes + 1);
1239: if(!outbuf)
1240: return CURLE_OUT_OF_MEMORY;
1241:
1242: j = 0;
1243: for(i = 0; i < nread; i++) {
1244: outbuf[j++] = buffer[i];
1245: if((unsigned char)buffer[i] == CURL_IAC)
1246: outbuf[j++] = CURL_IAC;
1247: }
1248: outbuf[j] = '\0';
1249: }
1250:
1251: total_written = 0;
1252: while(!result && total_written < outlen) {
1253: /* Make sure socket is writable to avoid EWOULDBLOCK condition */
1254: struct pollfd pfd[1];
1255: pfd[0].fd = conn->sock[FIRSTSOCKET];
1256: pfd[0].events = POLLOUT;
1257: switch(Curl_poll(pfd, 1, -1)) {
1258: case -1: /* error, abort writing */
1259: case 0: /* timeout (will never happen) */
1260: result = CURLE_SEND_ERROR;
1261: break;
1262: default: /* write! */
1263: bytes_written = 0;
1264: result = Curl_write(conn, conn->sock[FIRSTSOCKET],
1265: outbuf + total_written,
1266: outlen - total_written,
1267: &bytes_written);
1268: total_written += bytes_written;
1269: break;
1270: }
1271: }
1272:
1273: /* Free malloc copy if escaped */
1274: if(outbuf != (unsigned char *)buffer)
1275: free(outbuf);
1276:
1277: return result;
1278: }
1279:
1280: static CURLcode telnet_done(struct connectdata *conn,
1281: CURLcode status, bool premature)
1282: {
1283: struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
1284: (void)status; /* unused */
1285: (void)premature; /* not used */
1286:
1287: if(!tn)
1288: return CURLE_OK;
1289:
1290: curl_slist_free_all(tn->telnet_vars);
1291: tn->telnet_vars = NULL;
1292:
1293: Curl_safefree(conn->data->req.protop);
1294:
1295: return CURLE_OK;
1296: }
1297:
1298: static CURLcode telnet_do(struct connectdata *conn, bool *done)
1299: {
1300: CURLcode result;
1301: struct Curl_easy *data = conn->data;
1302: curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
1303: #ifdef USE_WINSOCK
1304: HMODULE wsock2;
1305: WSOCK2_FUNC close_event_func;
1306: WSOCK2_EVENT create_event_func;
1307: WSOCK2_FUNC event_select_func;
1308: WSOCK2_FUNC enum_netevents_func;
1309: WSAEVENT event_handle;
1310: WSANETWORKEVENTS events;
1311: HANDLE stdin_handle;
1312: HANDLE objs[2];
1313: DWORD obj_count;
1314: DWORD wait_timeout;
1315: DWORD readfile_read;
1316: int err;
1317: #else
1318: int interval_ms;
1319: struct pollfd pfd[2];
1320: int poll_cnt;
1321: curl_off_t total_dl = 0;
1322: curl_off_t total_ul = 0;
1323: #endif
1324: ssize_t nread;
1325: struct curltime now;
1326: bool keepon = TRUE;
1327: char *buf = data->state.buffer;
1328: struct TELNET *tn;
1329:
1330: *done = TRUE; /* unconditionally */
1331:
1332: result = init_telnet(conn);
1333: if(result)
1334: return result;
1335:
1336: tn = (struct TELNET *)data->req.protop;
1337:
1338: result = check_telnet_options(conn);
1339: if(result)
1340: return result;
1341:
1342: #ifdef USE_WINSOCK
1343: /*
1344: ** This functionality only works with WinSock >= 2.0. So,
1345: ** make sure we have it.
1346: */
1347: result = check_wsock2(data);
1348: if(result)
1349: return result;
1350:
1351: /* OK, so we have WinSock 2.0. We need to dynamically */
1352: /* load ws2_32.dll and get the function pointers we need. */
1353: wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
1354: if(wsock2 == NULL) {
1355: failf(data, "failed to load WS2_32.DLL (%u)", GetLastError());
1356: return CURLE_FAILED_INIT;
1357: }
1358:
1359: /* Grab a pointer to WSACreateEvent */
1360: create_event_func =
1361: CURLX_FUNCTION_CAST(WSOCK2_EVENT,
1362: (GetProcAddress(wsock2, "WSACreateEvent")));
1363: if(create_event_func == NULL) {
1364: failf(data, "failed to find WSACreateEvent function (%u)", GetLastError());
1365: FreeLibrary(wsock2);
1366: return CURLE_FAILED_INIT;
1367: }
1368:
1369: /* And WSACloseEvent */
1370: close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
1371: if(close_event_func == NULL) {
1372: failf(data, "failed to find WSACloseEvent function (%u)", GetLastError());
1373: FreeLibrary(wsock2);
1374: return CURLE_FAILED_INIT;
1375: }
1376:
1377: /* And WSAEventSelect */
1378: event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
1379: if(event_select_func == NULL) {
1380: failf(data, "failed to find WSAEventSelect function (%u)", GetLastError());
1381: FreeLibrary(wsock2);
1382: return CURLE_FAILED_INIT;
1383: }
1384:
1385: /* And WSAEnumNetworkEvents */
1386: enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
1387: if(enum_netevents_func == NULL) {
1388: failf(data, "failed to find WSAEnumNetworkEvents function (%u)",
1389: GetLastError());
1390: FreeLibrary(wsock2);
1391: return CURLE_FAILED_INIT;
1392: }
1393:
1394: /* We want to wait for both stdin and the socket. Since
1395: ** the select() function in winsock only works on sockets
1396: ** we have to use the WaitForMultipleObjects() call.
1397: */
1398:
1399: /* First, create a sockets event object */
1400: event_handle = (WSAEVENT)create_event_func();
1401: if(event_handle == WSA_INVALID_EVENT) {
1402: failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
1403: FreeLibrary(wsock2);
1404: return CURLE_FAILED_INIT;
1405: }
1406:
1407: /* Tell winsock what events we want to listen to */
1408: if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
1409: SOCKET_ERROR) {
1410: close_event_func(event_handle);
1411: FreeLibrary(wsock2);
1412: return CURLE_OK;
1413: }
1414:
1415: /* The get the Windows file handle for stdin */
1416: stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
1417:
1418: /* Create the list of objects to wait for */
1419: objs[0] = event_handle;
1420: objs[1] = stdin_handle;
1421:
1422: /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
1423: else use the old WaitForMultipleObjects() way */
1424: if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
1425: data->set.is_fread_set) {
1426: /* Don't wait for stdin_handle, just wait for event_handle */
1427: obj_count = 1;
1428: /* Check stdin_handle per 100 milliseconds */
1429: wait_timeout = 100;
1430: }
1431: else {
1432: obj_count = 2;
1433: wait_timeout = 1000;
1434: }
1435:
1436: /* Keep on listening and act on events */
1437: while(keepon) {
1438: const DWORD buf_size = (DWORD)data->set.buffer_size;
1439: DWORD waitret = WaitForMultipleObjects(obj_count, objs,
1440: FALSE, wait_timeout);
1441: switch(waitret) {
1442: case WAIT_TIMEOUT:
1443: {
1444: for(;;) {
1445: if(data->set.is_fread_set) {
1446: size_t n;
1447: /* read from user-supplied method */
1448: n = data->state.fread_func(buf, 1, buf_size, data->state.in);
1449: if(n == CURL_READFUNC_ABORT) {
1450: keepon = FALSE;
1451: result = CURLE_READ_ERROR;
1452: break;
1453: }
1454:
1455: if(n == CURL_READFUNC_PAUSE)
1456: break;
1457:
1458: if(n == 0) /* no bytes */
1459: break;
1460:
1461: /* fall through with number of bytes read */
1462: readfile_read = (DWORD)n;
1463: }
1464: else {
1465: /* read from stdin */
1466: if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
1467: &readfile_read, NULL)) {
1468: keepon = FALSE;
1469: result = CURLE_READ_ERROR;
1470: break;
1471: }
1472:
1473: if(!readfile_read)
1474: break;
1475:
1476: if(!ReadFile(stdin_handle, buf, buf_size,
1477: &readfile_read, NULL)) {
1478: keepon = FALSE;
1479: result = CURLE_READ_ERROR;
1480: break;
1481: }
1482: }
1483:
1484: result = send_telnet_data(conn, buf, readfile_read);
1485: if(result) {
1486: keepon = FALSE;
1487: break;
1488: }
1489: }
1490: }
1491: break;
1492:
1493: case WAIT_OBJECT_0 + 1:
1494: {
1495: if(!ReadFile(stdin_handle, buf, buf_size,
1496: &readfile_read, NULL)) {
1497: keepon = FALSE;
1498: result = CURLE_READ_ERROR;
1499: break;
1500: }
1501:
1502: result = send_telnet_data(conn, buf, readfile_read);
1503: if(result) {
1504: keepon = FALSE;
1505: break;
1506: }
1507: }
1508: break;
1509:
1510: case WAIT_OBJECT_0:
1511:
1512: events.lNetworkEvents = 0;
1513: if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
1514: err = SOCKERRNO;
1515: if(err != EINPROGRESS) {
1516: infof(data, "WSAEnumNetworkEvents failed (%d)", err);
1517: keepon = FALSE;
1518: result = CURLE_READ_ERROR;
1519: }
1520: break;
1521: }
1522: if(events.lNetworkEvents & FD_READ) {
1523: /* read data from network */
1524: result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
1525: /* read would've blocked. Loop again */
1526: if(result == CURLE_AGAIN)
1527: break;
1528: /* returned not-zero, this an error */
1529: else if(result) {
1530: keepon = FALSE;
1531: break;
1532: }
1533: /* returned zero but actually received 0 or less here,
1534: the server closed the connection and we bail out */
1535: else if(nread <= 0) {
1536: keepon = FALSE;
1537: break;
1538: }
1539:
1540: result = telrcv(conn, (unsigned char *) buf, nread);
1541: if(result) {
1542: keepon = FALSE;
1543: break;
1544: }
1545:
1546: /* Negotiate if the peer has started negotiating,
1547: otherwise don't. We don't want to speak telnet with
1548: non-telnet servers, like POP or SMTP. */
1549: if(tn->please_negotiate && !tn->already_negotiated) {
1550: negotiate(conn);
1551: tn->already_negotiated = 1;
1552: }
1553: }
1554: if(events.lNetworkEvents & FD_CLOSE) {
1555: keepon = FALSE;
1556: }
1557: break;
1558:
1559: }
1560:
1561: if(data->set.timeout) {
1562: now = Curl_now();
1563: if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1564: failf(data, "Time-out");
1565: result = CURLE_OPERATION_TIMEDOUT;
1566: keepon = FALSE;
1567: }
1568: }
1569: }
1570:
1571: /* We called WSACreateEvent, so call WSACloseEvent */
1572: if(!close_event_func(event_handle)) {
1573: infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
1574: }
1575:
1576: /* "Forget" pointers into the library we're about to free */
1577: create_event_func = NULL;
1578: close_event_func = NULL;
1579: event_select_func = NULL;
1580: enum_netevents_func = NULL;
1581:
1582: /* We called LoadLibrary, so call FreeLibrary */
1583: if(!FreeLibrary(wsock2))
1584: infof(data, "FreeLibrary(wsock2) failed (%u)", GetLastError());
1585: #else
1586: pfd[0].fd = sockfd;
1587: pfd[0].events = POLLIN;
1588:
1589: if(data->set.is_fread_set) {
1590: poll_cnt = 1;
1591: interval_ms = 100; /* poll user-supplied read function */
1592: }
1593: else {
1594: /* really using fread, so infile is a FILE* */
1595: pfd[1].fd = fileno((FILE *)data->state.in);
1596: pfd[1].events = POLLIN;
1597: poll_cnt = 2;
1598: interval_ms = 1 * 1000;
1599: }
1600:
1601: while(keepon) {
1602: switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
1603: case -1: /* error, stop reading */
1604: keepon = FALSE;
1605: continue;
1606: case 0: /* timeout */
1607: pfd[0].revents = 0;
1608: pfd[1].revents = 0;
1609: /* FALLTHROUGH */
1610: default: /* read! */
1611: if(pfd[0].revents & POLLIN) {
1612: /* read data from network */
1613: result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
1614: /* read would've blocked. Loop again */
1615: if(result == CURLE_AGAIN)
1616: break;
1617: /* returned not-zero, this an error */
1618: if(result) {
1619: keepon = FALSE;
1620: break;
1621: }
1622: /* returned zero but actually received 0 or less here,
1623: the server closed the connection and we bail out */
1624: else if(nread <= 0) {
1625: keepon = FALSE;
1626: break;
1627: }
1628:
1629: total_dl += nread;
1630: Curl_pgrsSetDownloadCounter(data, total_dl);
1631: result = telrcv(conn, (unsigned char *)buf, nread);
1632: if(result) {
1633: keepon = FALSE;
1634: break;
1635: }
1636:
1637: /* Negotiate if the peer has started negotiating,
1638: otherwise don't. We don't want to speak telnet with
1639: non-telnet servers, like POP or SMTP. */
1640: if(tn->please_negotiate && !tn->already_negotiated) {
1641: negotiate(conn);
1642: tn->already_negotiated = 1;
1643: }
1644: }
1645:
1646: nread = 0;
1647: if(poll_cnt == 2) {
1648: if(pfd[1].revents & POLLIN) { /* read from in file */
1649: nread = read(pfd[1].fd, buf, data->set.buffer_size);
1650: }
1651: }
1652: else {
1653: /* read from user-supplied method */
1654: nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
1655: data->state.in);
1656: if(nread == CURL_READFUNC_ABORT) {
1657: keepon = FALSE;
1658: break;
1659: }
1660: if(nread == CURL_READFUNC_PAUSE)
1661: break;
1662: }
1663:
1664: if(nread > 0) {
1665: result = send_telnet_data(conn, buf, nread);
1666: if(result) {
1667: keepon = FALSE;
1668: break;
1669: }
1670: total_ul += nread;
1671: Curl_pgrsSetUploadCounter(data, total_ul);
1672: }
1673: else if(nread < 0)
1674: keepon = FALSE;
1675:
1676: break;
1677: } /* poll switch statement */
1678:
1679: if(data->set.timeout) {
1680: now = Curl_now();
1681: if(Curl_timediff(now, conn->created) >= data->set.timeout) {
1682: failf(data, "Time-out");
1683: result = CURLE_OPERATION_TIMEDOUT;
1684: keepon = FALSE;
1685: }
1686: }
1687:
1688: if(Curl_pgrsUpdate(conn)) {
1689: result = CURLE_ABORTED_BY_CALLBACK;
1690: break;
1691: }
1692: }
1693: #endif
1694: /* mark this as "no further transfer wanted" */
1695: Curl_setup_transfer(data, -1, -1, FALSE, -1);
1696:
1697: return result;
1698: }
1699: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>