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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16