1 /*************************************************************************
2 * TinyFugue - programmable mud client
3 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2002, 2003, 2004, 2005, 2006-2007 Ken Keys
4 *
5 * TinyFugue (aka "tf") is protected under the terms of the GNU
6 * General Public License. See the file "COPYING" for details.
7 ************************************************************************/
8 static const char RCSid[] = "$Id: socket.c,v 35004.288 2007/01/13 23:12:39 kkeys Exp $";
9
10
11 /***************************************************************
12 * Fugue socket handling
13 *
14 * Written by Ken Keys
15 * Reception and transmission through sockets is handled here.
16 * This module also contains the main loop.
17 * Multiple sockets handled here.
18 * Autologin handled here.
19 ***************************************************************/
20
21 #include "tfconfig.h"
22 #include <sys/types.h>
23 #if HAVE_SYS_SELECT_H
24 # include <sys/select.h>
25 #endif
26 /* #include <sys/time.h> */
27 #include <fcntl.h>
28 #include <sys/file.h> /* for FNONBLOCK on SVR4, hpux, ... */
29 #include <sys/socket.h>
30 #include <signal.h> /* for killing resolver child process */
31
32 #if HAVE_SSL
33 # include <openssl/ssl.h>
34 # include <openssl/err.h>
35 SSL_CTX *ssl_ctx;
36 #endif
37
38 #ifdef NETINET_IN_H
39 # include NETINET_IN_H
40 #else
41 /* Last resort - we'll assume the "normal" stuff. */
42 struct in_addr {
43 unsigned long s_addr;
44 };
45 struct sockaddr_in {
46 short sin_family;
47 unsigned short sin_port;
48 struct in_addr sin_addr;
49 char sin_zero[8];
50 };
51 #define htons(x) (x) /* assume big-endian machine */
52 #endif
53
54 #ifdef ARPA_INET_H
55 # include ARPA_INET_H
56 #endif
57
58 #if HAVE_MCCP
59 # include <zlib.h>
60 #endif
61
62 #include "port.h"
63 #include "tf.h"
64 #include "util.h"
65 #include "pattern.h"
66 #include "search.h"
67 #include "tfio.h"
68 #include "tfselect.h"
69 #include "history.h"
70 #include "world.h"
71 #include "socket.h"
72 #include "output.h"
73 #include "attr.h"
74 #include "process.h"
75 #include "macro.h"
76 #include "keyboard.h"
77 #include "cmdlist.h"
78 #include "command.h"
79 #include "signals.h"
80 #include "variable.h" /* set_var_by_*() */
81
82 #ifdef _POSIX_VERSION
83 # include <sys/wait.h>
84 #endif
85
86 #if !defined(AF_INET6) || !defined(IN6_ADDR) || !HAVE_GETADDRINFO
87 # undef ENABLE_INET6
88 # define ENABLE_INET6 0
89 #endif
90
91 #ifndef INET_ADDRSTRLEN
92 #define INET_ADDRSTRLEN 16
93 #endif
94 #ifndef INET6_ADDRSTRLEN
95 #define INET6_ADDRSTRLEN 46
96 #endif
97
98 #ifdef PLATFORM_OS2
99 # define NONBLOCKING_GETHOST
100 #endif
101
102 #ifdef PLATFORM_UNIX
103 # ifndef __CYGWIN32__
104 # if HAVE_WAITPID
105 # define NONBLOCKING_GETHOST
106 # endif
107 # endif
108 #endif
109
110 #include NETDB_H
111
112 #if !HAVE_GAI_STRERROR || !defined(AI_NUMERICHOST) || !defined(EAI_SERVICE)
113 /* System's implementation is incomplete. Avoid it. */
114 # undef HAVE_GETADDRINFO
115 #endif
116
117 #define TF_EAI_ADDRFAMILY -1 /* address family for hostname not supported */
118 #define TF_EAI_AGAIN -2 /* temporary failure in name resolution */
119 #define TF_EAI_BADFLAGS -3 /* invalid value for ai_flags */
120 #define TF_EAI_FAIL -4 /* non-recoverable failure in name resolution */
121 #define TF_EAI_FAMILY -5 /* ai_family not supported */
122 #define TF_EAI_MEMORY -6 /* memory allocation failure */
123 #define TF_EAI_NODATA -7 /* no address associated with hostname */
124 #define TF_EAI_NONAME -8 /* hostname nor servname provided, or not known */
125 #define TF_EAI_SERVICE -9 /* servname not supported for ai_socktype */
126 #define TF_EAI_SOCKTYPE -10 /* ai_socktype not supported */
127 #define TF_EAI_SYSTEM -11 /* system error returned in errno */
128 #define TF_EAI_BADHINTS -12
129 #define TF_EAI_PROTOCOL -13
130 #define TF_EAI_MAX -14
131
132 static const char *tf_gai_errlist[] = {
133 "Error 0",
134 "address family for hostname not supported",
135 "temporary failure in name resolution",
136 "invalid value for ai_flags",
137 "non-recoverable failure in name resolution",
138 "ai_family not supported",
139 "memory allocation failure",
140 "no address associated with hostname",
141 "hostname nor servname provided, or not known",
142 "unknown service (port) name",
143 "ai_socktype not supported",
144 "system error returned in errno",
145 };
146
147 #if HAVE_GETADDRINFO
148 /* The standard message for EAI_SERVICE is horrible. We override it. */
149 # define gai_strerror(err) \
150 ((err) == EAI_SERVICE ? tf_gai_errlist[-TF_EAI_SERVICE] : (gai_strerror)(err))
151
152 #else /* !HAVE_GETADDRINFO */
153 /* Partial implementation of getaddrinfo() and friends */
154 # define addrinfo tfaddrinfo
155 # define getaddrinfo tfgetaddrinfo
156 # define freeaddrinfo tffreeaddrinfo
157
158 struct tfaddrinfo {
159 int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
160 int ai_family; /* PF_xxx */
161 int ai_socktype; /* SOCK_xxx */
162 int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
163 size_t ai_addrlen; /* length of ai_addr */
164 char *ai_canonname; /* canonical name for nodename */
165 struct sockaddr *ai_addr; /* binary address */
166 struct addrinfo *ai_next; /* next structure in linked list */
167 };
168
169 #define AI_NUMERICHOST 0x00000004 /* prevent name resolution */
170 #define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */
171
172 # if !HAVE_HSTRERROR
173 static const char *h_errlist[] = {
174 "Error 0",
175 "Unknown host",
176 "Host name lookup failure",
177 "Unknown server error",
178 "No address associated with name"
179 };
180 # define hstrerror(err) ((err) <= 4 ? h_errlist[(err)] : "unknown error")
181 # endif /* !HAVE_HSTRERROR */
182
183 #if HAVE_H_ERRNO
184 /* extern int h_errno; */ /* this could conflict */
185 #elif !defined(h_errno)
186 # define h_errno 1
187 #endif
188
189 # define gai_strerror(err) ((err) < 0 ? tf_gai_errlist[-(err)] : hstrerror(err))
190
191 #endif /* !HAVE_GETADDRINFO */
192
193 #ifdef NONBLOCKING_GETHOST
194 # ifndef PLATFORM_OS2
195 # include <sys/uio.h> /* child uses writev() */
196 # endif
197 static void waitforhostname(int fd, const char *name, const char *port);
198 static int nonblocking_gethost(const char *name, const char *port,
199 struct addrinfo **addrs, pid_t *pidp, const char **what);
200 #endif
201
202 #ifndef INADDR_NONE
203 # define INADDR_NONE 0xffffffff /* should be in <netinet/in.h> */
204 #endif
205
206
207 /* Nonblocking connect.
208 * Legend for comment columns:
209 * W = works, N = not defined, F = defined but fails, ? = unknown
210 * Nonblocking connect will work on a system if the column contains a 'W'
211 * and there is no 'F' above it; 'N' does not matter. The order of the
212 * tests is arranged to keep the 'F's below the 'W's.
213 *
214 * S
215 * o
216 * P L S l H
217 * O S i u a I P
218 * S B Y A n n r R /
219 * I S S I u O i I U
220 * X D V X x S s X X
221 */
222 #ifdef FNONBLOCK /* N ? W W N ? W W W */
223 # define TF_NONBLOCK FNONBLOCK
224 #else
225 # ifdef O_NONBLOCK /* W ? ? W W ? W W ? */
226 # define TF_NONBLOCK O_NONBLOCK
227 # else
228 # ifdef FNDELAY /* ? W ? F W ? W W ? */
229 # define TF_NONBLOCK FNDELAY
230 # else
231 # ifdef O_NDELAY /* ? W ? F W ? W W ? */
232 # define TF_NONBLOCK O_NDELAY
233 # else
234 # ifdef FNBIO /* ? ? W N N F N N ? */
235 # define TF_NONBLOCK FNBIO
236 # else
237 # ifdef FNONBIO /* ? ? ? N N F N N ? */
238 # define TF_NONBLOCK FNONBIO
239 # else
240 # ifdef FNONBLK /* ? ? ? N N ? N W ? */
241 # define TF_NONBLOCK FNONBLK
242 # else
243 # define TF_NONBLOCK 0
244 # endif
245 # endif
246 # endif
247 # endif
248 # endif
249 # endif
250 #endif
251
252
253 #ifdef TF_AIX_DECLS
254 extern int connect(int, struct sockaddr *, int);
255 #endif
256
257 #if SOCKS
258 # ifndef SOCKS_NONBLOCK
259 # define TF_NONBLOCK 0
260 # endif
261 #endif
262
263 /* connection states */
264 typedef enum {
265 SS_NEW, /* brand spanking new */
266 SS_RESOLVING, /* hostname resolution is pending */
267 SS_RESOLVED, /* hostname resolution is complete */
268 SS_CONNECTING, /* connection is pending */
269 SS_CONNECTED, /* connection is established */
270 SS_OPEN, /* open, without a connection */
271 SS_ZOMBIE, /* connection dead, but some text may be unseen */
272 SS_DEAD /* connection dead, and all text has been seen */
273 } constate_t;
274
275 /* flags */
276 #define SOCKLOGIN 0x01 /* autologin requested by user */
277 #define SOCKPROMPT 0x02 /* last prompt was definitely a prompt */
278 #define SOCKPROXY 0x04 /* indirect connection through proxy server */
279 #define SOCKTELNET 0x08 /* server supports telnet protocol */
280 #define SOCKMAYTELNET 0x10 /* server might support telnet protocol */
281 #define SOCKCOMPRESS 0x20 /* server has enabled MCCP v1 or v2 */
282 #define SOCKALLOCADDRS 0x40 /* addrs allocated by tf, not getaddrinfo */
283 #define SOCKECHO 0x80 /* receive all sent text (loopback) */
284
285 VEC_TYPEDEF(telnet_opts, 256);
286
287 typedef struct Sock { /* an open connection to a server */
288 int fd; /* socket to server, or pipe to name resolver */
289 const char *host, *port; /* server address, human readable */
290 struct addrinfo *addrs; /* possible server addresses */
291 struct addrinfo *addr; /* actual server address */
292 const char *myhost; /* explicit client address, human readable */
293 struct addrinfo *myaddr; /* explicit client address */
294 telnet_opts tn_us; /* our telnet options */
295 telnet_opts tn_us_tog; /* our telnet options we want changed */
296 telnet_opts tn_them; /* server's telnet options */
297 telnet_opts tn_them_tog; /* server's telnet options we want changed */
298 constate_t constate; /* connection state */
299 unsigned char flags; /* SOCK* flags */
300 short numquiet; /* # of lines to gag after connecting */
301 struct World *world; /* world to which socket is connected */
302 struct Sock *next, *prev; /* next/prev sockets in linked list */
303 Stringp buffer; /* buffer for incoming characters */
304 Stringp subbuffer; /* buffer for incoming characters */
305 Queue queue; /* queue of incoming lines */
306 conString *prompt; /* prompt from server */
307 struct timeval prompt_timeout; /* when does unterm'd line become a prompt */
308 int ttype; /* index into enum_ttype[] */
309 attr_t attrs; /* current text attributes */
310 attr_t prepromptattrs; /* text attributes before implicit prompt */
311 unsigned long alert_id; /* id of last alert on this socket */
312 struct timeval time[2]; /* time of last receive/send */
313 char fsastate; /* parser finite state automaton state */
314 char substate; /* parser fsa state for telnet subnegotiation */
315 pid_t pid; /* OS pid of name resolution process */
316 #if HAVE_MCCP
317 z_stream *zstream; /* state of compressed stream */
318 #endif
319 #if HAVE_SSL
320 SSL *ssl; /* SSL state */
321 #endif
322 } Sock;
323
324 typedef struct {
325 int err;
326 size_t size;
327 } nbgai_hdr_t;
328
329 static Sock *find_sock(const char *name);
330 static void wload(World *w);
331 static int fg_sock(Sock *sock, int quiet);
332 static int get_host_address(Sock *sock, const char **what, int *errp);
333 #if !HAVE_GETADDRINFO
334 static int tfgetaddrinfo(const char *nodename, const char *port,
335 const struct addrinfo *hints, struct addrinfo **res);
336 #endif
337 static int opensock(World *world, int flags);
338 static int openconn(Sock *new);
339 static int establish(Sock *new);
340 #if 0
341 static void fg_live_sock(void);
342 #endif
343 static void nuke_dead_socks(void);
344 static void nukesock(Sock *sock);
345 static void handle_prompt(String *str, int offset, int confirmed);
346 static void handle_implicit_prompt(void);
347 static void unprompt(Sock *sock, int update);
348 static void test_prompt(void);
349 static void schedule_prompt(Sock *sock);
350 static void handle_socket_lines(void);
351 static int handle_socket_input(const char *simbuffer, int simlen);
352 static int transmit(const char *s, unsigned int len);
353 static void telnet_send(String *cmd);
354 static void telnet_subnegotiation(void);
355 static void f_telnet_recv(int cmd, int opt);
356 static int is_quiet(const char *str);
357 static int is_bamf(const char *str);
358 static void do_naws(Sock *sock);
359 static void telnet_debug(const char *dir, const char *str, int len);
360 static void preferred_telnet_options(void);
361 static void killsock(Sock *sock);
362
363 #define zombiesock(sock) killsock(sock)
364 #define flushxsock() \
365 do { if (xsock->queue.list.head) handle_socket_lines(); } while (0)
366
367 #define telnet_recv(cmd, opt) f_telnet_recv((UCHAR)cmd, (UCHAR)opt);
368 #define no_reply(str) telnet_debug("sent", "[no reply (" str ")", 0)
369
370 #ifndef CONN_WAIT
371 #define CONN_WAIT 400000
372 #endif
373
374 #ifndef PROC_WAIT
375 #define PROC_WAIT 100000
376 #endif
377
378 #define SPAM (4*1024) /* break loop if this many chars are received */
379
380 static fd_set readers; /* input file descriptors */
381 static fd_set active; /* active file descriptors */
382 static fd_set writers; /* pending connections */
383 static fd_set connected; /* completed connections */
384 static unsigned int nfds; /* max # of readers/writers */
385 static Sock *hsock = NULL; /* head of socket list */
386 static Sock *tsock = NULL; /* tail of socket list */
387 static Sock *fsock = NULL; /* foreground socket */
388 static int dead_socks = 0; /* Number of unnuked dead sockets */
389 static int socks_with_lines = 0;/* Number of socks with queued received lines */
390 static struct timeval prompt_timeout = {0,0};
391 static const char *telnet_label[0x100];
392 STATIC_BUFFER(telbuf);
393
394 #define MAXQUIET 25 /* max # of lines to suppress during login */
395
396 /* Note: many telnet servers send DO ECHO and DO SGA together to mean
397 * character-at-a-time mode.
398 */
399
400 /* TELNET special characters (RFC 854) */
401 #define TN_EOR ((char)239) /* end of record (RFC 885) */
402 #define TN_SE ((char)240) /* subnegotiation end */
403 #define TN_NOP ((char)241) /* no operation */
404 #define TN_DATA_MARK ((char)242) /* (not used) */
405 #define TN_BRK ((char)243) /* break (not used) */
406 #define TN_IP ((char)244) /* interrupt process (not used) */
407 #define TN_AO ((char)245) /* abort output (not used) */
408 #define TN_AYT ((char)246) /* are you there? (not used) */
409 #define TN_EC ((char)247) /* erase character (not used) */
410 #define TN_EL ((char)248) /* erase line (not used) */
411 #define TN_GA ((char)249) /* go ahead */
412 #define TN_SB ((char)250) /* subnegotiation begin */
413 #define TN_WILL ((char)251) /* I offer to ~, or ack for DO */
414 #define TN_WONT ((char)252) /* I will stop ~ing, or nack for DO */
415 #define TN_DO ((char)253) /* Please do ~?, or ack for WILL */
416 #define TN_DONT ((char)254) /* Stop ~ing!, or nack for WILL */
417 #define TN_IAC ((char)255) /* telnet Is A Command character */
418
419 /* TELNET options (RFC 855) */ /* RFC# - description */
420 #define TN_BINARY ((char)0) /* 856 - transmit binary */
421 #define TN_ECHO ((char)1) /* 857 - echo */
422 #define TN_SGA ((char)3) /* 858 - suppress GA (not used) */
423 #define TN_STATUS ((char)5) /* 859 - (not used) */
424 #define TN_TIMING_MARK ((char)6) /* 860 - (not used) */
425 #define TN_TTYPE ((char)24) /* 1091 - terminal type */
426 #define TN_SEND_EOR ((char)25) /* 885 - transmit EOR */
427 #define TN_NAWS ((char)31) /* 1073 - negotiate about window size */
428 #define TN_TSPEED ((char)32) /* 1079 - terminal speed (not used) */
429 #define TN_FLOWCTRL ((char)33) /* 1372 - (not used) */
430 #define TN_LINEMODE ((char)34) /* 1184 - (not used) */
431 #define TN_XDISPLOC ((char)35) /* 1096 - (not used) */
432 #define TN_ENVIRON ((char)36) /* 1408 - (not used) */
433 #define TN_AUTH ((char)37) /* 1416 - (not used) */
434 #define TN_NEW_ENVIRON ((char)39) /* 1572 - (not used) */
435 #define TN_CHARSET ((char)42) /* 2066 - (not used) */
436 /* 85 & 86 are not standard. See http://www.randomly.org/projects/MCCP/ */
437 #define TN_COMPRESS ((char)85) /* MCCP v1 */
438 #define TN_COMPRESS2 ((char)86) /* MCCP v2 */
439
440 #define UCHAR unsigned char
441
442 #define tn_send_opt(cmd, opt) \
443 ( Sprintf(telbuf, "%c%c%c", TN_IAC, (cmd), (opt)), telnet_send(telbuf) )
444
445 #define TELOPT(sock, field, opt) \
446 VEC_ISSET((UCHAR)(opt), &(sock)->tn_ ## field)
447 #define SET_TELOPT(sock, field, opt) \
448 VEC_SET((UCHAR)(opt), &(sock)->tn_ ## field)
449 #define CLR_TELOPT(sock, field, opt) \
450 VEC_CLR((UCHAR)(opt), &(sock)->tn_ ## field)
451
452 #define DO(opt) ( tn_send_opt(TN_DO, (opt)) )
453 #define DONT(opt) ( tn_send_opt(TN_DONT, (opt)) )
454 #define WILL(opt) ( tn_send_opt(TN_WILL, (opt)) )
455 #define WONT(opt) ( tn_send_opt(TN_WONT, (opt)) )
456
457 #define ANSI_CSI '\233' /* ANSI terminal Command Sequence Intro */
458
459 #if HAVE_MCCP /* hack for broken MCCPv1 subnegotiation */
460 char mccp1_subneg[] = { TN_IAC, TN_SB, TN_COMPRESS, TN_WILL, TN_SE };
461 #endif
462
463 Sock *xsock = NULL; /* current (transmission) socket */
464 int quit_flag = FALSE; /* Are we all done? */
465 int active_count = 0; /* # of (non-current) active sockets */
466 String *incoming_text = NULL;
467 const int feature_IPv6 = ENABLE_INET6 - 0;
468 const int feature_MCCPv1 = HAVE_MCCP - 0;
469 const int feature_MCCPv2 = HAVE_MCCP - 0;
470 const int feature_ssl = HAVE_SSL - 0;
471 const int feature_SOCKS = SOCKS - 0;
472
473 static const char *CONFAIL_fmt = "%% Connection to %s failed: %s: %s";
474 static const char *ICONFAIL_fmt = "%% Intermediate connection to %s failed: %s: %s";
475
476 #define ICONFAIL_AI(sock, why) \
477 ICONFAIL((sock), printai((sock)->addr, NULL), (why))
478
479 #define CONFAILHP(sock, why) \
480 do { \
481 do_hook(H_CONFAIL, "%% Unable to connect to %s: %s %s: %s", "%s %s %s: %s", \
482 (sock)->world->name, (sock)->world->host, (sock)->world->port, (why)); \
483 oflush(); \
484 } while (0)
485
486 #define CONFAIL(sock, what, why) \
487 do { \
488 do_hook(H_CONFAIL, CONFAIL_fmt, "%s %s %s", \
489 (sock)->world->name, (what), (why)); \
490 oflush(); \
491 } while (0)
492
493 #define DISCON(where, what, why) \
494 do_hook(H_DISCONNECT, "%% Connection to %s closed: %s: %s", "%s %s: %s", \
495 where, what, why)
496
497 #define ROUND_UP_LENGTH(len) ((len + 7) & -8)
498
499 #if HAVE_SSL
ssl_err(const char * str)500 static void ssl_err(const char *str)
501 {
502 unsigned long e;
503 while ((e = ERR_get_error()))
504 eprintf("%s: %s", str, ERR_error_string(e, NULL));
505 }
506
ssl_io_err(Sock * sock,int ret,int hook)507 static void ssl_io_err(Sock *sock, int ret, int hook)
508 {
509 /* NB: sock->addr may have already been changed by setupnextconn() */
510 int err;
511 const char *fmt;
512
513 flushxsock();
514
515 switch (hook) {
516 case H_CONFAIL: fmt = CONFAIL_fmt; break;
517 case H_ICONFAIL: fmt = ICONFAIL_fmt; break;
518 case H_DISCONNECT: fmt = "%% Connection to %s closed: %s: %s"; break;
519 }
520
521 #define ssl_io_err_hook(what, why) \
522 do_hook(hook, fmt, "%s %s %s", xsock->world->name, what, why);
523
524 err = SSL_get_error(sock->ssl, ret);
525 switch (err) {
526 case SSL_ERROR_NONE:
527 break;
528 case SSL_ERROR_ZERO_RETURN:
529 ssl_io_err_hook("SSL", "SSL_ERROR_ZERO_RETURN");
530 break;
531 case SSL_ERROR_WANT_READ:
532 ssl_io_err_hook("SSL", "SSL_ERROR_WANT_READ");
533 break;
534 case SSL_ERROR_WANT_WRITE:
535 ssl_io_err_hook("SSL", "SSL_ERROR_WANT_WRITE");
536 break;
537 case SSL_ERROR_WANT_CONNECT:
538 ssl_io_err_hook("SSL", "SSL_ERROR_WANT_CONNECT");
539 break;
540 case SSL_ERROR_SYSCALL:
541 if (ret == 0) {
542 ssl_io_err_hook("SSL/system", "invalid EOF");
543 } else if (ret == -1) {
544 ssl_io_err_hook("SSL/system", strerror(errno));
545 } else {
546 while ((err = ERR_get_error())) {
547 ssl_io_err_hook("SSL/system", ERR_error_string(err, NULL));
548 }
549 }
550 break;
551 case SSL_ERROR_SSL:
552 while ((err = ERR_get_error())) {
553 ssl_io_err_hook("SSL/lib", ERR_error_string(err, NULL));
554 }
555 break;
556 }
557 }
558
init_ssl(void)559 static void init_ssl(void)
560 {
561 SSL_load_error_strings();
562 SSL_library_init();
563 /* XXX seed PRNG */
564 ssl_ctx = SSL_CTX_new(SSLv23_client_method());
565 if (!ssl_ctx) {
566 ssl_err("SSL_CTX_new");
567 return;
568 }
569 if (!SSL_CTX_set_cipher_list(ssl_ctx, "ALL")) {
570 ssl_err("SSL_CTX_set_cipher_list");
571 return;
572 }
573 }
574 #endif
575
576 /* initialize socket.c data */
init_sock(void)577 void init_sock(void)
578 {
579 int i;
580
581 FD_ZERO(&readers);
582 FD_ZERO(&active);
583 FD_ZERO(&writers);
584 FD_ZERO(&connected);
585 FD_SET(STDIN_FILENO, &readers);
586 nfds = 1;
587
588 set_var_by_id(VAR_async_conn, !!TF_NONBLOCK);
589 #ifdef NONBLOCKING_GETHOST
590 set_var_by_id(VAR_async_name, 1);
591 #endif
592
593 for (i = 0; i < 0x100; i++) telnet_label[i] = NULL;
594
595 telnet_label[(UCHAR)TN_BINARY] = "BINARY";
596 telnet_label[(UCHAR)TN_ECHO] = "ECHO";
597 telnet_label[(UCHAR)TN_SGA] = "SUPPRESS-GO-AHEAD";
598 telnet_label[(UCHAR)TN_STATUS] = "STATUS";
599 telnet_label[(UCHAR)TN_TIMING_MARK] = "TIMING-MARK";
600 telnet_label[(UCHAR)TN_TTYPE] = "TERMINAL-TYPE";
601 telnet_label[(UCHAR)TN_SEND_EOR] = "SEND-EOR";
602 telnet_label[(UCHAR)TN_NAWS] = "NAWS";
603 telnet_label[(UCHAR)TN_TSPEED] = "TSPEED";
604 telnet_label[(UCHAR)TN_FLOWCTRL] = "TOGGLE-FLOW-CONTROL";
605 telnet_label[(UCHAR)TN_LINEMODE] = "LINEMODE";
606 telnet_label[(UCHAR)TN_XDISPLOC] = "XDISPLOC";
607 telnet_label[(UCHAR)TN_ENVIRON] = "ENVIRON";
608 telnet_label[(UCHAR)TN_AUTH] = "AUTHENTICATION";
609 telnet_label[(UCHAR)TN_NEW_ENVIRON] = "NEW-ENVIRON";
610 telnet_label[(UCHAR)TN_CHARSET] = "CHARSET";
611 telnet_label[(UCHAR)TN_COMPRESS] = "COMPRESS";
612 telnet_label[(UCHAR)TN_COMPRESS2] = "COMPRESS2";
613 telnet_label[(UCHAR)TN_EOR] = "EOR";
614 telnet_label[(UCHAR)TN_SE] = "SE";
615 telnet_label[(UCHAR)TN_NOP] = "NOP";
616 telnet_label[(UCHAR)TN_DATA_MARK] = "DATA-MARK";
617 telnet_label[(UCHAR)TN_BRK] = "BRK";
618 telnet_label[(UCHAR)TN_IP] = "IP";
619 telnet_label[(UCHAR)TN_AO] = "AO";
620 telnet_label[(UCHAR)TN_AYT] = "AYT";
621 telnet_label[(UCHAR)TN_EC] = "EC";
622 telnet_label[(UCHAR)TN_EL] = "EL";
623 telnet_label[(UCHAR)TN_GA] = "GA";
624 telnet_label[(UCHAR)TN_SB] = "SB";
625 telnet_label[(UCHAR)TN_WILL] = "WILL";
626 telnet_label[(UCHAR)TN_WONT] = "WONT";
627 telnet_label[(UCHAR)TN_DO] = "DO";
628 telnet_label[(UCHAR)TN_DONT] = "DONT";
629 telnet_label[(UCHAR)TN_IAC] = "IAC";
630
631 #if HAVE_SSL
632 init_ssl();
633 #endif
634 }
635
636 #define set_min_earliest(tv) \
637 do { \
638 if (earliest.tv_sec == 0 || (tvcmp(&tv, &earliest) < 0)) { \
639 earliest = tv; \
640 } \
641 } while (0)
642
643 /* main_loop
644 * Here we mostly sit in select(), waiting for something to happen.
645 * The select timeout is set for the earliest process, mail check,
646 * or refresh event. Signal processing and garbage collection is
647 * done at the beginning of each loop, where we're in a "clean" state.
648 */
main_loop(void)649 void main_loop(void)
650 {
651 static struct timeval now, earliest; /* static, for recursion */
652 Sock *sock = NULL; /* loop index */
653 static int count; /* select count; remembered across recursion */
654 int received;
655 Sock *stopsock;
656 static int depth = 0;
657 struct timeval tv, *tvp;
658 struct timeval refresh_tv;
659 STATIC_STRING(low_memory_msg,
660 "% WARNING: memory is low. Try reducing history sizes.", 0);
661
662 depth++;
663 while (!quit_flag) {
664 if (depth > 1 && interrupted()) break;
665
666 /* deal with pending signals */
667 /* at loop beginning in case of signals before main_loop() */
668 process_signals();
669
670 /* run processes */
671 /* at loop beginning in case of processes before main_loop() */
672 gettime(&now);
673 if (proctime.tv_sec && tvcmp(&proctime, &now) <= 0)
674 runall(0, NULL); /* run timed processes */
675
676 if (low_memory_warning) {
677 low_memory_warning = 0;
678 tfputline(low_memory_msg, tferr);
679 }
680
681 if (quit_flag) break;
682
683 /* figure out when next event is so select() can timeout then */
684 gettime(&now);
685 earliest = proctime;
686 #if 1 /* XXX debugging */
687 {
688 Sock *s;
689 int n = 0;
690 for (s = hsock; s; s = s->next)
691 if (s->queue.list.head) n++;
692 if (n != socks_with_lines) {
693 internal_error(__FILE__, __LINE__,
694 "socks_with_lines (%d) is not correct (%d)!",
695 socks_with_lines, n);
696 socks_with_lines = n;
697 }
698 }
699 #endif
700 if (socks_with_lines)
701 earliest = now;
702 if (maillist && tvcmp(&maildelay, &tvzero) > 0) {
703 if (tvcmp(&now, &mail_update) >= 0) {
704 check_mail();
705 tvadd(&mail_update, &now, &maildelay);
706 }
707 set_min_earliest(mail_update);
708 }
709 if (visual && alert_timeout.tv_sec > 0) {
710 if (tvcmp(&alert_timeout, &now) < 0) {
711 clear_alert();
712 } else {
713 set_min_earliest(alert_timeout);
714 }
715 }
716 if (visual && clock_update.tv_sec > 0) {
717 if (now.tv_sec >= clock_update.tv_sec)
718 update_status_field(NULL, STAT_CLOCK);
719 set_min_earliest(clock_update);
720 }
721 if (prompt_timeout.tv_sec > 0) {
722 set_min_earliest(prompt_timeout);
723 }
724
725 /* flush pending display_screen output */
726 /* must be after all possible output and before select() */
727 oflush();
728
729 if (pending_input || pending_line) {
730 tvp = &tv;
731 tv = tvzero;
732 } else if (earliest.tv_sec) {
733 tvp = &tv;
734 if (tvcmp(&earliest, &now) <= 0) {
735 tv = tvzero;
736 } else {
737 tvsub(&tv, &earliest, &now);
738 #if !HAVE_GETTIMEOFDAY
739 /* We can't read microseconds, so we get within the right
740 * second and then start polling. */
741 if (proctime.tv_sec) {
742 if ((--tv.tv_sec) == 0)
743 tv.tv_usec = PROC_WAIT;
744 }
745 #endif
746 }
747 } else tvp = NULL;
748
749 if (need_refresh) {
750 if (!visual) {
751 refresh_tv.tv_sec = refreshtime / 1000000;
752 refresh_tv.tv_usec = refreshtime % 1000000;
753 } else {
754 refresh_tv = tvzero;
755 }
756
757 if (!tvp || refresh_tv.tv_sec < tvp->tv_sec ||
758 (refresh_tv.tv_sec == tvp->tv_sec &&
759 refresh_tv.tv_usec < tvp->tv_usec))
760 {
761 tvp = &refresh_tv;
762 }
763 }
764
765 if (visual && need_more_refresh) {
766 if (!tvp || 1 < tvp->tv_sec ||
767 (1 == tvp->tv_sec && 0 < tvp->tv_usec))
768 {
769 refresh_tv.tv_sec = 1;
770 refresh_tv.tv_usec = 0;
771 tvp = &refresh_tv;
772 }
773 }
774
775 /* Wait for next event.
776 * descriptor read: user input, socket input, or /quote !
777 * descriptor write: nonblocking connect()
778 * timeout: time for runall() or do_refresh()
779 * Note: if the same descriptor appears in more than one fd_set, some
780 * systems count it only once, some count it once for each occurance.
781 */
782 active = readers;
783 connected = writers;
784 count = tfselect(nfds, &active, &connected, NULL, tvp);
785
786 if (count < 0) {
787 /* select() must have exited due to error or interrupt. */
788 if (errno != EINTR) core(strerror(errno), __FILE__, __LINE__, 0);
789 /* In case we're in a kb tfgetS(), clear things for parent loop. */
790 FD_ZERO(&active);
791 FD_ZERO(&connected);
792 /* In case the dreaded solaris select bug caused tf to remove stdin
793 * from readers, user will probably panic and hit ^C, so we add
794 * stdin back to readers, and recover. */
795 FD_SET(STDIN_FILENO, &readers);
796
797 } else {
798 if (count == 0) {
799 /* select() must have exited due to timeout. */
800 do_refresh();
801 }
802
803 /* check for user input */
804 if (pending_input || FD_ISSET(STDIN_FILENO, &active)) {
805 if (FD_ISSET(STDIN_FILENO, &active)) count--;
806 do_refresh();
807 if (!handle_keyboard_input(FD_ISSET(STDIN_FILENO, &active))) {
808 /* input is at EOF, stop reading it */
809 FD_CLR(STDIN_FILENO, &readers);
810 }
811 }
812
813 /* Check for socket completion/activity. We pick up where we
814 * left off last time, so sockets near the end of the list aren't
815 * starved. We stop when we've gone through the list once, or
816 * when we've received a lot of data (so spammy sockets don't
817 * degrade interactive response too much).
818 */
819 if (hsock) {
820 received = 0;
821 if (!sock) sock = hsock;
822 stopsock = sock;
823 /* note: count may have been zeroed by nested main_loop */
824 while (count > 0 || socks_with_lines > 0 ||
825 prompt_timeout.tv_sec > 0)
826 {
827 xsock = sock;
828 if (sock->constate >= SS_OPEN) {
829 /* do nothing */
830 } else if (FD_ISSET(xsock->fd, &connected)) {
831 count--;
832 establish(xsock);
833 } else if (FD_ISSET(xsock->fd, &active)) {
834 count--;
835 if (xsock->constate == SS_RESOLVING) {
836 openconn(xsock);
837 } else if (xsock->constate == SS_CONNECTING) {
838 establish(xsock);
839 } else if (xsock == fsock || background) {
840 received += handle_socket_input(NULL, 0);
841 } else {
842 FD_CLR(xsock->fd, &readers);
843 }
844 }
845 if (xsock->queue.list.head)
846 handle_socket_lines();
847
848 /* If there's a partial line that's past prompt_timeout,
849 * make it a prompt. */
850 if (xsock->prompt_timeout.tv_sec) {
851 gettime(&now);
852 if (tvcmp(&xsock->prompt_timeout, &now) < 0) {
853 handle_implicit_prompt();
854 }
855 }
856
857 sock = sock->next ? sock->next : hsock;
858 if (sock == stopsock || received >= SPAM) break;
859 }
860
861 /* fsock and/or xsock may have changed during loop above. */
862 xsock = fsock;
863
864 if (prompt_timeout.tv_sec > 0) {
865 /* reset global prompt timeout */
866 Sock *psock;
867 prompt_timeout = tvzero;
868 for (psock = hsock; psock; psock = psock->next) {
869 schedule_prompt(psock);
870 }
871 }
872 }
873
874 #if !NO_PROCESS
875 /* other active fds must be from command /quotes. */
876 if (count) gettime(&proctime);
877 #endif
878 }
879
880 if (pending_line && read_depth) { /* end of tf read() */
881 pending_line = FALSE;
882 break;
883 }
884
885 #if 0
886 if (fsock && fsock->constate >= SS_ZOMBIE && auto_fg &&
887 !(fsock->world->screen->nnew || fsock->queue.list.head))
888 {
889 fg_live_sock();
890 }
891 #endif
892
893 /* garbage collection */
894 if (depth == 1) {
895 if (sock && sock->constate == SS_DEAD) sock = NULL;
896 if (dead_socks) nuke_dead_socks(); /* at end in case of quitdone */
897 nuke_dead_macros();
898 nuke_dead_procs();
899 }
900 }
901
902 /* end of loop */
903 if (!--depth) {
904 fsock = NULL;
905 xsock = NULL;
906 while (hsock) nukesock(hsock);
907 #if HAVE_SSL
908 SSL_CTX_free(ssl_ctx);
909 #endif
910 }
911
912 /* If exiting recursive main_loop, count, active, and connected in the
913 * parent main_loop are invalid. Set count to 0 to indicate that. */
914 count = 0;
915 }
916
sockecho(void)917 int sockecho(void)
918 {
919 return !xsock || (xsock && !TELOPT(xsock, them, TN_ECHO));
920 }
921
close_all(void)922 void close_all(void)
923 {
924 while (nfds > 3)
925 close(--nfds);
926 }
927
is_active(int fd)928 int is_active(int fd)
929 {
930 return FD_ISSET(fd, &active);
931 }
932
readers_clear(int fd)933 void readers_clear(int fd)
934 {
935 FD_CLR(fd, &readers);
936 }
937
readers_set(int fd)938 void readers_set(int fd)
939 {
940 FD_SET(fd, &readers);
941 if (fd >= nfds) nfds = fd + 1;
942 }
943
tog_bg(Var * var)944 int tog_bg(Var *var)
945 {
946 Sock *sock;
947 if (background)
948 for (sock = hsock; sock; sock = sock->next)
949 if (sock->constate == SS_CONNECTED)
950 FD_SET(sock->fd, &readers);
951 return 1;
952 }
953
tog_keepalive(Var * var)954 int tog_keepalive(Var *var)
955 {
956 Sock *sock;
957 int flags;
958
959 flags = keepalive;
960 for (sock = hsock; sock; sock = sock->next) {
961 if (sock->constate != SS_CONNECTED) continue;
962 if (setsockopt(sock->fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&flags,
963 sizeof(flags)) < 0)
964 {
965 wprintf("setsockopt KEEPALIVE: %s", strerror(errno));
966 }
967 }
968 return 1;
969 }
970
971 /* get name of foreground world */
fgname(void)972 const char *fgname(void)
973 {
974 return fsock ? fsock->world->name : NULL;
975 }
976
977 /* get current operational world */
xworld(void)978 World *xworld(void)
979 {
980 return xsock ? xsock->world : NULL;
981 }
982
xsock_is_fg(void)983 int xsock_is_fg(void)
984 {
985 return xsock == fsock;
986 }
987
have_active_socks(void)988 int have_active_socks(void)
989 {
990 Sock *sock;
991
992 for (sock = hsock; sock; sock = sock->next) {
993 if (sock->world->screen->nnew || sock->queue.list.head)
994 return 1;
995 }
996 return 0;
997 }
998
999 /* set alert_id on xsock, so fg_sock can decide whether to clear alert */
xsock_alert_id(void)1000 void xsock_alert_id(void)
1001 {
1002 if (xsock)
1003 xsock->alert_id = alert_id;
1004 }
1005
socktime(const char * name,int dir)1006 struct timeval *socktime(const char *name, int dir)
1007 {
1008 Sock *sock;
1009 sock = *name ? find_sock(name) : xsock;
1010 if (!sock) return NULL;
1011 return &sock->time[dir];
1012 }
1013
find_sock(const char * name)1014 static Sock *find_sock(const char *name)
1015 {
1016 Sock *sock;
1017
1018 /* It is possible to (briefly) have multiple sockets with the same name,
1019 * if at most one is alive. The alive socket is the most interesting,
1020 * and it will be closer to the tail, so we search backwards.
1021 */
1022 for (sock = tsock; sock; sock = sock->prev)
1023 if (sock->world && cstrcmp(sock->world->name, name) == 0)
1024 return sock;
1025 return NULL;
1026 }
1027
1028 /* load macro file for a world */
wload(World * w)1029 static void wload(World *w)
1030 {
1031 const char *mfile;
1032 if (restriction >= RESTRICT_FILE) return;
1033 if ((mfile = world_mfile(w)))
1034 do_file_load(mfile, FALSE);
1035 }
1036
world_hook(const char * fmt,const char * name)1037 int world_hook(const char *fmt, const char *name)
1038 {
1039 return do_hook(H_WORLD, virtscreen ? NULL : fmt, "%s",
1040 name ? name : "");
1041 }
1042
1043 /* bring a socket into the foreground */
fg_sock(Sock * sock,int quiet)1044 static int fg_sock(Sock *sock, int quiet)
1045 {
1046 static int depth = 0;
1047
1048 if (depth) {
1049 eprintf("illegal reentry");
1050 return 0;
1051 }
1052
1053 if (sockecho() != (!sock || !TELOPT(sock, them, TN_ECHO)))
1054 set_refresh_pending(REF_LOGICAL);
1055
1056 xsock = sock;
1057 if (sock == fsock) return 2; /* already there */
1058
1059 if (fsock) { /* the socket being backgrounded... */
1060 /* ...has new text */
1061 if (fsock->world->screen->nnew || fsock->queue.list.head) {
1062 fsock->world->screen->active = 1;
1063 ++active_count;
1064 update_status_field(NULL, STAT_ACTIVE);
1065 /* ...is dead, with all text seen */
1066 } else if (fsock->constate == SS_ZOMBIE) {
1067 fsock->constate = SS_DEAD;
1068 dead_socks++;
1069 }
1070 }
1071 fsock = sock;
1072 depth++;
1073
1074 if (!virtscreen) update_status_field(NULL, STAT_WORLD);
1075 hide_screen(NULL);
1076
1077 if (sock) {
1078 if (sock->alert_id == alert_id) {
1079 clear_alert();
1080 sock->alert_id = 0;
1081 }
1082 if (sock->constate == SS_CONNECTED)
1083 FD_SET(sock->fd, &readers);
1084 if (sock->world->screen->active) {
1085 sock->world->screen->active = 0;
1086 --active_count;
1087 update_status_field(NULL, STAT_ACTIVE);
1088 }
1089 fg_screen = sock->world->screen;
1090 unhide_screen(fg_screen); /* must do before hook which might oflush */
1091 world_hook((sock->constate >= SS_ZOMBIE) ?
1092 "---- World %s (dead) ----" : "---- World %s ----",
1093 sock->world->name);
1094 switch_screen(quiet || !bg_output);
1095 tog_lp(NULL);
1096 update_prompt(sock->prompt, 1);
1097 if (sockmload) wload(sock->world);
1098 } else {
1099 fg_screen = default_screen;
1100 unhide_screen(fg_screen);
1101 world_hook("---- No world ----", NULL);
1102 switch_screen(quiet || !bg_output);
1103 update_prompt(NULL, 1);
1104 }
1105 depth--;
1106 return 1;
1107 }
1108
handle_fg_command(String * args,int offset)1109 struct Value *handle_fg_command(String *args, int offset)
1110 {
1111 int opt, nosock = FALSE, noerr = FALSE, quiet = FALSE;
1112 int num = 0;
1113 ValueUnion uval;
1114 Sock *sock;
1115
1116 startopt(CS(args), "nlqs<>c#");
1117 while ((opt = nextopt(NULL, &uval, NULL, &offset))) {
1118 switch (opt) {
1119 case 'n': nosock = TRUE; break;
1120 case 's': noerr = TRUE; break;
1121 case 'l': break; /* accepted and ignored */
1122 case 'q': quiet = TRUE; break;
1123 case '<': num = -1; break;
1124 case '>': num = 1; break;
1125 case 'c': num = uval.ival; break;
1126 default: return shareval(val_zero);
1127 }
1128 }
1129
1130 if (nosock) {
1131 return newint(fg_sock(NULL, quiet));
1132
1133 } else if (num) {
1134 Sock *stop;
1135 if (!hsock) return shareval(val_zero);
1136 stop = sock = (fsock ? fsock : hsock);
1137 do {
1138 sock = (num > 0) ?
1139 (sock->next ? sock->next : hsock) :
1140 (sock->prev ? sock->prev : tsock);
1141 num += (num<0) ? 1 : -1;
1142 } while (num && sock != stop);
1143 return newint(fg_sock(sock, quiet));
1144 }
1145
1146 sock = (!(args->len - offset)) ? hsock : find_sock(args->data + offset);
1147 if (!sock) {
1148 if (!noerr) eprintf("no socket named '%s'", args->data + offset);
1149 return shareval(val_zero);
1150 }
1151 return newint(fg_sock(sock, quiet));
1152 }
1153
1154 /* openworld
1155 * If (name && port), they are used as hostname and port number.
1156 * If (!port), name is used as the name of a world. A NULL or empty name
1157 * corresponds to the first defined world. A NULL name should be used for
1158 * the initial automatic connection, an empty name should be used for any
1159 * other unspecified connection.
1160 */
openworld(const char * name,const char * port,int flags)1161 int openworld(const char *name, const char *port, int flags)
1162 {
1163 World *world = NULL;
1164
1165 if (!(flags & (CONN_FG | CONN_BG)))
1166 flags |= (xsock == fsock) ? CONN_FG : CONN_BG;
1167 xsock = NULL;
1168 if (!port) {
1169 world = find_world(name);
1170 if (!world) {
1171 if (name) {
1172 /* not H_CONFAIL (it needs a Sock, we haven't made one yet) */
1173 eprintf("%s: %s",
1174 *name ? name : "default world", "no such world");
1175 } else {
1176 world_hook("---- No world ----", NULL);
1177 }
1178 }
1179 } else {
1180 if (restriction >= RESTRICT_WORLD)
1181 eprintf("arbitrary connections restricted");
1182 else {
1183 world = new_world(NULL, "", name, port, "", "", "",
1184 WORLD_TEMP | ((flags & CONN_SSL) ? WORLD_SSL : 0), "");
1185 }
1186 }
1187
1188 return world ? opensock(world, flags) : 0;
1189 }
1190
opensock(World * world,int flags)1191 static int opensock(World *world, int flags)
1192 {
1193 int gai_err;
1194 const char *what;
1195
1196 if (world->sock) {
1197 if (world->sock->constate < SS_ZOMBIE) {
1198 eprintf("socket to %s already exists", world->name);
1199 return 0;
1200 }
1201 /* recycle existing Sock */
1202 if (world->sock->constate == SS_DEAD)
1203 dead_socks--;
1204 xsock = world->sock;
1205 #if HAVE_SSL
1206 if (xsock->ssl) {
1207 SSL_free(xsock->ssl); /* killsock() closed it, but didn't free it */
1208 xsock->ssl = NULL;
1209 }
1210 #endif
1211
1212 } else {
1213 /* create and initialize new Sock */
1214 if (!(xsock = world->sock = (Sock *) MALLOC(sizeof(struct Sock)))) {
1215 eprintf("opensock: not enough memory");
1216 return 0;
1217 }
1218 if (!world->screen)
1219 world->screen = new_screen(hist_getsize(world->history));
1220 xsock->world = world;
1221 xsock->prev = tsock;
1222 tsock = *(tsock ? &tsock->next : &hsock) = xsock;
1223 xsock->prompt = NULL;
1224 xsock->prompt_timeout = tvzero;
1225 xsock->next = NULL;
1226 xsock->myhost = NULL;
1227 xsock->myaddr = NULL;
1228 xsock->addrs = NULL;
1229 xsock->addr = NULL;
1230 #if HAVE_SSL
1231 xsock->ssl = NULL;
1232 #endif
1233 }
1234 Stringninit(xsock->buffer, 80); /* data must be allocated */
1235 Stringninit(xsock->subbuffer, 1);
1236 init_queue(&xsock->queue);
1237 xsock->host = NULL;
1238 xsock->port = NULL;
1239 xsock->ttype = -1;
1240 xsock->fd = -1;
1241 xsock->pid = -1;
1242 xsock->fsastate = '\0';
1243 xsock->substate = '\0';
1244 xsock->attrs = 0;
1245 xsock->prepromptattrs = 0;
1246 xsock->alert_id = 0;
1247 #if HAVE_MCCP
1248 xsock->zstream = NULL;
1249 #endif
1250 VEC_ZERO(&xsock->tn_them);
1251 VEC_ZERO(&xsock->tn_them_tog);
1252 VEC_ZERO(&xsock->tn_us);
1253 VEC_ZERO(&xsock->tn_us_tog);
1254 xsock->constate = SS_NEW;
1255 xsock->flags = 0;
1256 gettime(&xsock->time[SOCK_SEND]);
1257 xsock->time[SOCK_RECV] = xsock->time[SOCK_SEND];
1258
1259 if ((flags & CONN_QUIETLOGIN) && (flags & CONN_AUTOLOGIN) &&
1260 world_character(world))
1261 {
1262 xsock->numquiet = MAXQUIET;
1263 } else {
1264 xsock->numquiet = 0;
1265 }
1266
1267 if (flags & CONN_FG)
1268 fg_sock(xsock, FALSE); /* XXX 2nd arg??? */
1269
1270 if (flags & CONN_AUTOLOGIN) xsock->flags |= SOCKLOGIN;
1271 if (world->flags & WORLD_ECHO) xsock->flags |= SOCKECHO;
1272 if ((flags & CONN_SSL) || (world->flags & WORLD_SSL)) {
1273 #if HAVE_SSL
1274 xsock->ssl = SSL_new(ssl_ctx);
1275 #else
1276 CONFAIL(xsock, "ssl", "not supported");
1277 #endif
1278 }
1279
1280 if (!world->host) {
1281 /* opening a connectionless socket */
1282 xsock->constate = SS_OPEN;
1283 return establish(xsock);
1284 } else if (!(world->flags & WORLD_NOPROXY) && proxy_host && *proxy_host) {
1285 /* open a connection through a proxy */
1286 xsock->flags |= SOCKPROXY;
1287 xsock->host = STRDUP(proxy_host);
1288 xsock->port = (proxy_port && *proxy_port) ? proxy_port : "23";
1289 xsock->port = STRDUP(xsock->port);
1290 } else {
1291 /* open a connection directly */
1292 xsock->host = STRDUP(world->host);
1293 xsock->port = STRDUP(world->port);
1294 }
1295
1296 xsock->flags |= SOCKMAYTELNET;
1297
1298 if (world->myhost && *world->myhost)
1299 xsock->myhost = STRDUP(world->myhost);
1300 else if (tfhost)
1301 xsock->myhost = STRDUP(tfhost);
1302 else
1303 xsock->myhost = NULL;
1304
1305 if (xsock->myhost) {
1306 /* We don't bother with nonblocking: this feature is rarely used,
1307 * and the address should be numeric or resolvable locally (quickly)
1308 * anyway, so it's not worth the complications of nonblocking. */
1309 struct addrinfo hints;
1310 int err;
1311 memset(&hints, 0, sizeof(hints));
1312 hints.ai_family = PF_UNSPEC;
1313 hints.ai_socktype = SOCK_STREAM;
1314 err = getaddrinfo(xsock->myhost, NULL, &hints, &xsock->myaddr);
1315
1316 if (err) {
1317 CONFAIL(xsock, xsock->myhost, gai_strerror(err));
1318 killsock(xsock); /* can't nukesock(), this Sock may be recycled. */
1319 return 0;
1320 }
1321 }
1322
1323 xsock->constate = SS_RESOLVING;
1324 xsock->fd = get_host_address(xsock, &what, &gai_err);
1325 if (xsock->fd == 0) {
1326 /* The name lookup succeeded */
1327 xsock->constate = SS_RESOLVED;
1328 xsock->addr = xsock->addrs;
1329 return openconn(xsock);
1330 #ifdef NONBLOCKING_GETHOST
1331 } else if (xsock->fd > 0) {
1332 /* The name lookup is pending. We wait for it for a fraction of a
1333 * second here so "relatively fast" looks "immediate" to the user.
1334 */
1335 fd_set readable;
1336 struct timeval tv;
1337 FD_ZERO(&readable);
1338 FD_SET(xsock->fd, &readable);
1339 tv.tv_sec = 0;
1340 tv.tv_usec = CONN_WAIT;
1341 if (select(xsock->fd + 1, &readable, NULL, NULL, &tv) > 0) {
1342 /* The lookup completed. */
1343 return openconn(xsock);
1344 }
1345 /* select() returned 0, or -1 and errno==EINTR. Either way, the
1346 * lookup needs more time. So we add the fd to the set being
1347 * watched by main_loop(), and don't block here any longer.
1348 */
1349 readers_set(xsock->fd);
1350 do_hook(H_PENDING, "%% Hostname lookup for %s in progress.", "%s",
1351 xsock->world->name);
1352 return 2;
1353 #endif /* NONBLOCKING_GETHOST */
1354 } else {
1355 /* The name lookup failed */
1356 /* Note, some compilers can't handle (herr ? hsterror() : literal) */
1357 if (what)
1358 CONFAIL(xsock, what, strerror(errno));
1359 else if (gai_err)
1360 CONFAILHP(xsock, gai_strerror(gai_err));
1361 else
1362 CONFAILHP(xsock, "name lookup failed");
1363 killsock(xsock); /* can't nukesock(), this may be a recycled Sock. */
1364 return 0;
1365 }
1366 }
1367
1368
printai(struct addrinfo * ai,const char * fmt_hp)1369 static const char *printai(struct addrinfo *ai, const char *fmt_hp)
1370 {
1371 static char buf[1024];
1372 static char hostbuf[INET6_ADDRSTRLEN+1];
1373 const void *hostaddr = NULL;
1374 unsigned short port = 0;
1375 const char *host = NULL;
1376
1377 if (!fmt_hp) fmt_hp = "%s %d";
1378
1379 switch (ai->ai_family) {
1380 case AF_INET:
1381 hostaddr = &((struct sockaddr_in*)ai->ai_addr)->sin_addr;
1382 port = ((struct sockaddr_in*)ai->ai_addr)->sin_port;
1383 host = inet_ntoa(*(struct in_addr*)hostaddr);
1384 break;
1385 #if ENABLE_INET6
1386 case AF_INET6:
1387 hostaddr = &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr;
1388 port = ((struct sockaddr_in6*)ai->ai_addr)->sin6_port;
1389 host = inet_ntop(ai->ai_family, hostaddr, hostbuf, sizeof(hostbuf));
1390 break;
1391 #endif
1392 }
1393 sprintf(buf, port ? fmt_hp : "%s", host ? host : "?", ntohs(port));
1394 return buf;
1395 }
1396
ai_connect(int s,struct addrinfo * ai)1397 static inline int ai_connect(int s, struct addrinfo *ai)
1398 {
1399 do_hook(H_PENDING, "%% Trying to connect to %s: %s.", "%s %s",
1400 xsock->world->name, printai(ai, NULL));
1401 return connect(s, ai->ai_addr, ai->ai_addrlen);
1402 }
1403
setupnextconn(Sock * sock)1404 static void setupnextconn(Sock *sock)
1405 {
1406 struct addrinfo *ai, *next = sock->addr;
1407
1408 if (sock->fd >= 0)
1409 close(sock->fd);
1410 retry:
1411 next = next->ai_next;
1412 /* if next address is a duplicate of one we've already done, skip it */
1413 for (ai = sock->addrs; next && ai != next; ai = ai->ai_next) {
1414 if (memcmp(ai->ai_addr, next->ai_addr, ai->ai_addrlen) == 0) {
1415 goto retry;
1416 }
1417 }
1418 sock->addr = next;
1419 }
1420
1421 /* If there are more addresses to try, hook ICONFAIL and try the next;
1422 * otherwise, hook CONFAIL and give up. */
ICONFAIL(Sock * sock,const char * what,const char * why)1423 static int ICONFAIL(Sock *sock, const char *what, const char *why)
1424 {
1425 setupnextconn(sock);
1426
1427 if (sock->addr) {
1428 do_hook(H_ICONFAIL, ICONFAIL_fmt, "%s %s: %s",
1429 (sock)->world->name, (what), (why));
1430 oflush();
1431 return openconn(sock);
1432 }
1433 do_hook(H_CONFAIL, "%% Connection to %s failed: %s: %s", "%s %s: %s",
1434 (sock)->world->name, (what), (why));
1435 oflush();
1436 killsock(sock);
1437 return 0;
1438 }
1439
openconn(Sock * sock)1440 static int openconn(Sock *sock)
1441 {
1442 int flags;
1443
1444 xsock = sock;
1445 #ifdef NONBLOCKING_GETHOST
1446 if (xsock->constate == SS_RESOLVING) {
1447 nbgai_hdr_t info = { 0, 0 };
1448 struct addrinfo *ai;
1449 FD_CLR(xsock->fd, &readers);
1450 if (read(xsock->fd, &info, sizeof(info)) < 0 || info.err != 0) {
1451 if (!info.err)
1452 CONFAIL(xsock, "read", strerror(errno));
1453 else
1454 CONFAILHP(xsock, gai_strerror(info.err));
1455 close(xsock->fd);
1456 xsock->fd = -1;
1457 # ifdef PLATFORM_UNIX
1458 if (xsock->pid >= 0)
1459 if (waitpid(xsock->pid, NULL, 0) < 0)
1460 tfprintf(tferr, "waitpid %ld: %s", xsock->pid, strerror(errno));
1461 xsock->pid = -1;
1462 # endif /* PLATFORM_UNIX */
1463 killsock(xsock);
1464 return 0;
1465 }
1466 if (info.size <= 0) { /* shouldn't happen */
1467 xsock->addrs = NULL;
1468 } else {
1469 xsock->addrs = XMALLOC(info.size);
1470 read(xsock->fd, (char*)xsock->addrs, info.size);
1471 }
1472 close(xsock->fd);
1473 # ifdef PLATFORM_UNIX
1474 if (xsock->pid >= 0)
1475 if (waitpid(xsock->pid, NULL, 0) < 0)
1476 tfprintf(tferr, "waitpid: %ld: %s", xsock->pid, strerror(errno));
1477 xsock->pid = -1;
1478 # endif /* PLATFORM_UNIX */
1479 xsock->constate = SS_RESOLVED;
1480 for (ai = xsock->addrs; ai; ai = ai->ai_next) {
1481 ai->ai_addr = (struct sockaddr*)((char*)ai + sizeof(*ai));
1482 if (ai->ai_next != 0) {
1483 ai->ai_next =
1484 (struct addrinfo*)((char*)ai->ai_addr + ROUND_UP_LENGTH(ai->ai_addrlen));
1485 }
1486 }
1487 xsock->addr = xsock->addrs;
1488 }
1489 #endif /* NONBLOCKING_GETHOST */
1490
1491 #if 0
1492 /* Jump back here if we start a nonblocking connect and then discover
1493 * that the platform has a broken read() or select().
1494 */
1495 retry:
1496 #endif
1497
1498 if (!xsock->addr) {
1499 CONFAILHP(xsock, "no usable addresses");
1500 killsock(xsock);
1501 return 0;
1502 }
1503
1504 xsock->fd = socket(xsock->addr->ai_family, xsock->addr->ai_socktype,
1505 xsock->addr->ai_protocol);
1506 if (xsock->fd < 0) {
1507 if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)
1508 return ICONFAIL(xsock, "socket", strerror(errno));
1509 CONFAIL(xsock, "socket", strerror(errno));
1510 killsock(xsock);
1511 return 0;
1512 }
1513
1514 if (xsock->myaddr && bind(xsock->fd, xsock->myaddr->ai_addr,
1515 xsock->myaddr->ai_addrlen) < 0)
1516 {
1517 CONFAIL(xsock, printai(xsock->myaddr, NULL), strerror(errno));
1518 killsock(xsock);
1519 return 0;
1520 }
1521
1522 #if HAVE_SSL
1523 if (xsock->ssl && SSL_set_fd(xsock->ssl, xsock->fd) <= 0) {
1524 CONFAIL(xsock, "SSL", ERR_error_string(ERR_get_error(), NULL));
1525 killsock(xsock);
1526 return 0;
1527 }
1528 #endif
1529
1530 if (xsock->fd >= nfds) nfds = xsock->fd + 1;
1531
1532 if (!TF_NONBLOCK) {
1533 set_var_by_id(VAR_async_conn, 0);
1534 } else if (async_conn) {
1535 /* note: 3rd arg to fcntl() is optional on Unix, but required by OS/2 */
1536 if ((flags = fcntl(xsock->fd, F_GETFL, 0)) < 0) {
1537 operror("Can't make socket nonblocking: F_GETFL fcntl");
1538 set_var_by_id(VAR_async_conn, 0);
1539 } else if ((fcntl(xsock->fd, F_SETFL, flags | TF_NONBLOCK)) < 0) {
1540 operror("Can't make socket nonblocking: F_SETFL fcntl");
1541 set_var_by_id(VAR_async_conn, 0);
1542 }
1543 }
1544
1545 if (keepalive) {
1546 flags = 1;
1547 if (setsockopt(xsock->fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&flags,
1548 sizeof(flags)) < 0)
1549 {
1550 wprintf("setsockopt KEEPALIVE: %s", strerror(errno));
1551 }
1552 }
1553
1554 xsock->constate = SS_CONNECTING;
1555 if (ai_connect(xsock->fd, xsock->addr) == 0) {
1556 /* The connection completed successfully. */
1557 xsock->constate = SS_CONNECTED;
1558 return establish(xsock);
1559
1560 #ifdef EINPROGRESS
1561 } else if (errno == EINPROGRESS) {
1562 /* The connection needs more time. It will select() as writable when
1563 * it has connected, or readable when it has failed. We select() it
1564 * briefly here so "fast" looks synchronous to the user.
1565 */
1566 fd_set writeable;
1567 struct timeval tv;
1568 FD_ZERO(&writeable);
1569 FD_SET(xsock->fd, &writeable);
1570 tv.tv_sec = 0;
1571 tv.tv_usec = CONN_WAIT;
1572 if (select(xsock->fd + 1, NULL, &writeable, NULL, &tv) > 0) {
1573 /* The connection completed. */
1574 return establish(xsock);
1575 }
1576 /* select() returned 0, or -1 and errno==EINTR. Either way, the
1577 * connection needs more time. So we add the fd to the set being
1578 * watched by main_loop(), and don't block here any longer.
1579 */
1580 FD_SET(xsock->fd, &writers);
1581 FD_SET(xsock->fd, &readers);
1582 return 2;
1583 #endif /* EINPROGRESS */
1584
1585 #if 0 /* this can cause problems on nonbuggy systems, so screw the sysv bug */
1586 } else if (can_nonblock && (errno == EAGAIN
1587 # ifdef EWOULDBLOCK
1588 || errno == EWOULDBLOCK
1589 # endif
1590 )) {
1591 /* A bug in SVR4.2 causes nonblocking connect() to (sometimes?)
1592 * incorrectly fail with EAGAIN. The only thing we can do about
1593 * it is to try a blocking connect().
1594 */
1595 close(xsock->fd);
1596 can_nonblock = FALSE;
1597 goto retry; /* try again */
1598 #endif /* 0 */
1599 }
1600
1601 /* The connection failed; try the next address. */
1602 return ICONFAIL_AI(xsock, strerror(errno));
1603 }
1604
1605 #if !HAVE_GETADDRINFO
1606 /* Partial implementation of getaddrinfo(): returns a single address for an
1607 * IPv6 address OR IPv4 address OR a name that resolves to an IPv4 address.
1608 * Ignores hints except for AI_NUMERICHOST. Port is optional.
1609 */
tfgetaddrinfo(const char * nodename,const char * port,const struct addrinfo * hints,struct addrinfo ** res)1610 static int tfgetaddrinfo(const char *nodename, const char *port,
1611 const struct addrinfo *hints, struct addrinfo **res)
1612 {
1613 struct servent *service;
1614 struct hostent *host;
1615 unsigned short portnum = 0, sa_len = 0;
1616 int err = 0;
1617 struct {
1618 struct addrinfo ai;
1619 union {
1620 struct sockaddr sa;
1621 struct sockaddr_in sin4;
1622 # if ENABLE_INET6
1623 struct sockaddr_in6 sin6;
1624 # endif
1625 } sa;
1626 } *blob;
1627
1628 blob = MALLOC(sizeof(*blob));
1629 if (!blob) return TF_EAI_MEMORY;
1630
1631 /* translate/look up port */
1632 if (port) {
1633 if (is_digit(*port)) {
1634 portnum = htons(atoi(port));
1635 # ifdef NETDB_H
1636 } else if ((service = getservbyname(port, "tcp"))) {
1637 portnum = service->s_port;
1638 # endif
1639 } else {
1640 err = TF_EAI_SERVICE;
1641 goto error;
1642 }
1643 }
1644
1645 # if ENABLE_INET6
1646 /* translate numeric IPv6 address */
1647 if (inet_pton(AF_INET6, nodename, &blob->sa.sin6.sin6_addr)) {
1648 sa_len = sizeof(blob->sa.sin6);
1649 blob->sa.sa.sa_family = PF_INET6;
1650 blob->sa.sin6.sin6_port = portnum;
1651 goto found;
1652 }
1653 # endif
1654
1655 /* translate numeric IPv4 address */
1656 # if HAVE_INET_ATON
1657 if (inet_aton(nodename, &blob->sa.sin4.sin_addr))
1658 # elif !defined(dgux)
1659 /* Most versions of inet_addr() return a long. */
1660 blob->sa.sin4.sin_addr.s_addr = inet_addr(nodename);
1661 if (blob->sa.sin4.sin_addr.s_addr != INADDR_NONE)
1662 # else
1663 /* DGUX's inet_addr() returns a struct in_addr. */
1664 blob->sa.sin4.sin_addr.s_addr = inet_addr(nodename).s_addr;
1665 if (blob->sa.sin4.sin_addr.s_addr != INADDR_NONE)
1666 # endif /* HAVE_INET_ATON */
1667 {
1668 sa_len = sizeof(blob->sa.sin4);
1669 blob->sa.sa.sa_family = PF_INET;
1670 blob->sa.sin4.sin_port = portnum;
1671 goto found;
1672 }
1673
1674 if (hints->ai_flags & AI_NUMERICHOST) {
1675 FREE(blob);
1676 *res = NULL;
1677 return TF_EAI_NODATA;
1678 }
1679
1680 /* look up text address (IPv4 only) */
1681 host = gethostbyname(nodename);
1682 if (!host) {
1683 err = h_errno;
1684 goto error;
1685 }
1686 sa_len = sizeof(blob->sa.sin4);
1687 blob->sa.sa.sa_family = PF_INET;
1688 blob->sa.sin4.sin_port = portnum;
1689 memcpy((void *)&blob->sa.sin4.sin_addr, (void *)host->h_addr,
1690 sizeof(blob->sa.sin4.sin_addr));
1691
1692 found:
1693 # if HAVE_SOCKADDR_SA_LEN
1694 blob->sa.sa.sa_len = sa_len;
1695 # endif
1696 blob->ai.ai_family = blob->sa.sa.sa_family;
1697 blob->ai.ai_socktype = SOCK_STREAM;
1698 blob->ai.ai_protocol = IPPROTO_TCP;
1699 blob->ai.ai_addrlen = sa_len;
1700 blob->ai.ai_canonname = NULL;
1701 blob->ai.ai_addr = (struct sockaddr*)&blob->sa;
1702 blob->ai.ai_next = NULL;
1703 *res = &blob->ai;
1704 return 0;
1705
1706 error:
1707 FREE(blob);
1708 return err;
1709 }
1710 #endif /* !HAVE_GETADDRINFO */
1711
tffreeaddrinfo(struct addrinfo * ai)1712 static void tffreeaddrinfo(struct addrinfo *ai)
1713 {
1714 /* ai and all contents were allocated in single chunk by tfgetaddrinfo()
1715 * or completed nonblocking resolution in openconn() */
1716 FREE(ai);
1717 }
1718
1719 /* Convert name or ip number string to a list of struct addrinfo.
1720 * Returns -1 for failure, 0 for success, or a positive file descriptor
1721 * connected to a pending name lookup process or thread.
1722 */
get_host_address(Sock * sock,const char ** what,int * errp)1723 static int get_host_address(Sock *sock, const char **what, int *errp)
1724 {
1725 struct addrinfo hints;
1726 memset(&hints, 0, sizeof(hints));
1727 hints.ai_family = PF_UNSPEC;
1728 hints.ai_socktype = SOCK_STREAM;
1729 hints.ai_flags = AI_NUMERICHOST;
1730 #if 0 /* AI_ADDRCONFIG is defined on FreeBSD 4.2, but causes an error in
1731 getaddrinfo() (this was fixed by 4.8). It's not important to
1732 use the flag, so it's easier to not use it and avoid the problem. */
1733 # ifdef AI_ADDRCONFIG
1734 hints.ai_flags |= AI_ADDRCONFIG;
1735 # endif
1736 #endif
1737 *errp = getaddrinfo(sock->host, sock->port, &hints, &sock->addrs);
1738 *what = NULL;
1739 if (*errp == 0) return 0;
1740
1741 #ifdef NONBLOCKING_GETHOST
1742 if (async_name) {
1743 /* do nonblocking for non-numeric */
1744 *errp = 0;
1745 *what = NULL;
1746 sock->flags |= SOCKALLOCADDRS;
1747 return nonblocking_gethost(sock->host, sock->port, &sock->addrs,
1748 &sock->pid, what);
1749 } else
1750 #endif
1751 {
1752 hints.ai_flags &= ~AI_NUMERICHOST;
1753 *errp = getaddrinfo(sock->host, sock->port, &hints, &sock->addrs);
1754 *what = NULL;
1755 if (*errp == 0) return 0;
1756 }
1757 return -1;
1758 }
1759
1760 #ifdef NETDB_H
1761 #ifdef NONBLOCKING_GETHOST
1762
waitforhostname(int fd,const char * name,const char * port)1763 static void waitforhostname(int fd, const char *name, const char *port)
1764 {
1765 /* Uses writev() so the write is atomic, to avoid race condition between
1766 * writer and reader processes. (Really, the reader should loop reading
1767 * until EOF.)
1768 */
1769 struct addrinfo *res, *ai;
1770 struct addrinfo hints;
1771 nbgai_hdr_t hdr;
1772 #define NIOV 1+2*16
1773 struct iovec iov[NIOV];
1774 int niov;
1775
1776 memset(&hints, 0, sizeof(hints));
1777 hints.ai_family = PF_UNSPEC;
1778 hints.ai_socktype = SOCK_STREAM;
1779
1780 hdr.err = getaddrinfo(name, port, &hints, &res);
1781
1782 if (!hdr.err) {
1783 hdr.size = 0;
1784 iov[0].iov_base = (char*)&hdr;
1785 iov[0].iov_len = sizeof(hdr);
1786 niov = 1;
1787 for (ai = res; ai && niov < NIOV; ai = ai->ai_next) {
1788 static const char zeros[ 8 ] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1789 size_t padded = ROUND_UP_LENGTH(ai->ai_addrlen);
1790 hdr.size += sizeof(*ai) + padded;
1791 iov[niov].iov_base = (char*)ai;
1792 iov[niov].iov_len = sizeof(*ai);
1793 niov++;
1794 iov[niov].iov_base = (char*)ai->ai_addr;
1795 iov[niov].iov_len = ai->ai_addrlen;
1796 niov++;
1797 if (padded != ai->ai_addrlen) {
1798 /* padding */
1799 iov[niov].iov_base = (char*)zeros;
1800 iov[niov].iov_len = padded - ai->ai_addrlen;
1801 niov++;
1802 }
1803 }
1804 writev(fd, iov, niov);
1805 if (res) freeaddrinfo(res);
1806 } else {
1807 hdr.size = 0;
1808 write(fd, &hdr, sizeof(hdr));
1809 }
1810 close(fd);
1811 }
1812
1813 # ifdef PLATFORM_OS2
1814 typedef struct _threadpara {
1815 const char *hostname;
1816 const char *port;
1817 int fd;
1818 } threadpara;
1819
os2waitforhostname(threadpara * targs)1820 void os2waitforhostname(threadpara *targs)
1821 {
1822 waitforhostname(targs->fd, targs->hostname, targs->port);
1823 FREE(targs->hostname);
1824 FREE(targs->port);
1825 FREE(targs);
1826 }
1827 # endif /* PLATFORM_OS2 */
1828
nonblocking_gethost(const char * name,const char * port,struct addrinfo ** res,pid_t * pidp,const char ** what)1829 static int nonblocking_gethost(const char *name, const char *port,
1830 struct addrinfo **res, pid_t *pidp, const char **what)
1831 {
1832 int fds[2];
1833 int err;
1834
1835 *what = "pipe";
1836 if (pipe(fds) < 0) return -1;
1837
1838 #ifdef PLATFORM_UNIX
1839 {
1840 *what = "fork";
1841 *pidp = fork();
1842 if (*pidp > 0) { /* parent */
1843 close(fds[1]);
1844 return fds[0];
1845 } else if (*pidp == 0) { /* child */
1846 close(fds[0]);
1847 waitforhostname(fds[1], name, port);
1848 exit(0);
1849 }
1850 }
1851 #endif
1852 #ifdef PLATFORM_OS2
1853 {
1854 threadpara *tpara;
1855
1856 if ((tpara = XMALLOC(sizeof(threadpara)))) {
1857 setmode(fds[0],O_BINARY);
1858 setmode(fds[1],O_BINARY);
1859 tpara->fd = fds[1];
1860 tpara->hostname = STRDUP(name);
1861 tpara->port = STRDUP(port);
1862
1863 /* BUG: gethostbyname() isn't threadsafe! */
1864 *what = "_beginthread";
1865 if (_beginthread(os2waitforhostname,NULL,0x8000,(void*)tpara) != -1)
1866 return(fds[0]);
1867 }
1868 }
1869 #endif
1870
1871 /* failed */
1872 err = errno;
1873 close(fds[0]);
1874 close(fds[1]);
1875 errno = err;
1876 return -1;
1877 }
1878 #endif /* NONBLOCKING_GETHOST */
1879 #endif /* NETDB_H */
1880
1881
1882 /* Establish a sock for which connect() has completed. */
establish(Sock * sock)1883 static int establish(Sock *sock)
1884 {
1885 xsock = sock;
1886 #if TF_NONBLOCK
1887 if (xsock->constate == SS_CONNECTING) {
1888 int err = 0, flags;
1889 socklen_t len = sizeof(err);
1890
1891 /* Old Method 1: If read(fd, buf, 0) fails, the connect() failed, and
1892 * errno will explain why. Problem: on some systems, a read() of
1893 * 0 bytes is always successful, even if socket is not connected.
1894 */
1895 /* Old Method 2: If a second connect() fails with EISCONN, the first
1896 * connect() worked. On the slim chance that the first failed, but
1897 * the second worked, use that. Otherwise, use getsockopt(SO_ERROR)
1898 * to find out why the first failed. If SO_ERROR isn't available,
1899 * use read() to get errno. This method works for all systems, as
1900 * well as SOCKS 4.2beta. Problems: Some socket implementations
1901 * give the wrong errno; extra net traffic on failure.
1902 */
1903 /* CURRENT METHOD: If possible, use getsockopt(SO_ERROR) to test for
1904 * an error. This avoids the overhead of a second connect(), and the
1905 * possibility of getting the error value from the second connect()
1906 * (linux). (Potential problem: it's possible that some systems
1907 * don't clear the SO_ERROR value for successful connect().)
1908 * If SO_ERROR is not available or we are using SOCKS, we try to read
1909 * 0 bytes. If it fails, the connect() must have failed. If it
1910 * succeeds, we can't know if it's because the connection really
1911 * succeeded, or the read() did a no-op for the 0 size, so we try a
1912 * second connect(). If the second connect() fails with EISCONN, the
1913 * first connect() worked. If it works (unlikely), use it. Otherwise,
1914 * use read() to get the errno.
1915 * Tested on: Linux, HP-UX, Solaris, Solaris with SOCKS5...
1916 */
1917 /* Alternative: replace second connect() with getpeername(), and
1918 * check for ENOTCONN. Disadvantage: doesn't work with SOCKS, etc.
1919 */
1920
1921 #ifdef SO_ERROR
1922 # if !SOCKS
1923 # define USE_SO_ERROR
1924 # endif
1925 #endif
1926
1927 #ifdef USE_SO_ERROR
1928 if (getsockopt(xsock->fd, SOL_SOCKET, SO_ERROR, (void*)&err, &len) < 0)
1929 {
1930 return ICONFAIL(xsock, "getsockopt", strerror(errno));
1931 }
1932
1933 #else
1934 {
1935 char ch;
1936 if (read(xsock->fd, &ch, 0) < 0) {
1937 return ICONFAIL(xsock, "nonblocking connect/read", strerror(errno));
1938 } else if ((ai_connect(xsock->fd, xsock->addr) < 0) &&
1939 errno != EISCONN)
1940 {
1941 read(xsock->fd, &ch, 1); /* must fail */
1942 return ICONFAIL(xsock, "nonblocking connect 2/read", strerror(errno));
1943 }
1944 }
1945 #endif
1946 if (err != 0) {
1947 return ICONFAIL_AI(xsock, strerror(err));
1948 }
1949
1950 /* connect() worked. Clear the pending stuff, and get on with it. */
1951 xsock->constate = SS_CONNECTED;
1952 FD_CLR(xsock->fd, &writers);
1953
1954 /* Turn off nonblocking (this should help on buggy systems). */
1955 /* note: 3rd arg to fcntl() is optional on Unix, but required by OS/2 */
1956 if ((flags = fcntl(xsock->fd, F_GETFL, 0)) >= 0)
1957 fcntl(xsock->fd, F_SETFL, flags & ~TF_NONBLOCK);
1958 }
1959 #endif /* TF_NONBLOCK */
1960
1961 if (xsock->constate == SS_CONNECTED)
1962 FD_SET(xsock->fd, &readers);
1963
1964 /* hack: sockaddr_in.sin_port and sockaddr_in6.sin6_port coincide */
1965 if (xsock->addr &&
1966 ntohs(((struct sockaddr_in*)xsock->addr->ai_addr)->sin_port) == 23)
1967 xsock->flags |= SOCKTELNET;
1968
1969 #if HAVE_SSL
1970 if (xsock->ssl) {
1971 int sslret;
1972 sslret = SSL_connect(xsock->ssl);
1973 if (sslret <= 0) {
1974 setupnextconn(xsock);
1975 ssl_io_err(xsock, sslret, xsock->addr ? H_ICONFAIL : H_CONFAIL);
1976 if (xsock->addr)
1977 return openconn(xsock);
1978 killsock(xsock);
1979 return 0;
1980 }
1981 }
1982 #endif
1983
1984 /* atomicness ends here */
1985
1986 if (xsock == fsock) /* possible for a recycled zombie */
1987 update_status_field(NULL, STAT_WORLD);
1988
1989 if (xsock->flags & SOCKTELNET)
1990 preferred_telnet_options();
1991
1992 if (sock->flags & SOCKPROXY) {
1993 FREE(sock->host);
1994 FREE(sock->port);
1995 sock->host = STRDUP(sock->world->host);
1996 sock->port = STRDUP(sock->world->port);
1997 do_hook(H_PROXY, "", "%s", sock->world->name);
1998 }
1999
2000 wload(sock->world);
2001
2002 if (!(sock->flags & SOCKPROXY)) {
2003 #if HAVE_SSL
2004 if (sock->ssl)
2005 do_hook(H_CONNECT, "%% Connected to %s using cipher %s.", "%s %s",
2006 sock->world->name, SSL_get_cipher_name(sock->ssl));
2007 else
2008 #endif
2009 do_hook(H_CONNECT, "%% Connected to %s.", "%s", sock->world->name);
2010
2011 if (login && sock->flags & SOCKLOGIN) {
2012 if (world_character(sock->world) && world_pass(sock->world))
2013 do_hook(H_LOGIN, NULL, "%s %s %s", sock->world->name,
2014 world_character(sock->world), world_pass(sock->world));
2015 sock->flags &= ~SOCKLOGIN;
2016 }
2017 }
2018
2019 return 1;
2020 }
2021
2022 /* clear most of sock's fields, but leave it consistent and extant */
killsock(Sock * sock)2023 static void killsock(Sock *sock)
2024 {
2025 if (sock->constate >= SS_ZOMBIE) return;
2026 #if 0 /* There may be a disconnect hook AFTER this function... */
2027 if (sock == fsock || sock->queue.list.head || sock->world->screen->nnew) {
2028 sock->constate = SS_ZOMBIE;
2029 } else {
2030 sock->constate = SS_DEAD;
2031 dead_socks++;
2032 }
2033 #else /* ... so we must unconditionally enter ZOMBIE state. */
2034 sock->constate = SS_ZOMBIE;
2035 #endif
2036 sock->fsastate = '\0';
2037 sock->attrs = 0;
2038 VEC_ZERO(&sock->tn_them);
2039 VEC_ZERO(&sock->tn_them_tog);
2040 VEC_ZERO(&sock->tn_us);
2041 VEC_ZERO(&sock->tn_us_tog);
2042 Stringfree(sock->buffer);
2043 Stringfree(sock->subbuffer);
2044
2045 unprompt(sock, sock==fsock);
2046
2047 if (sock->host) FREE(sock->host);
2048 if (sock->port) FREE(sock->port);
2049 if (sock->myhost) FREE(sock->myhost);
2050 sock->host = sock->port = sock->myhost = NULL;
2051
2052 if (sock->addrs) {
2053 if (sock->flags & SOCKALLOCADDRS)
2054 tffreeaddrinfo(sock->addrs);
2055 else
2056 freeaddrinfo(sock->addrs);
2057 sock->addrs = NULL;
2058 }
2059 if (sock->myaddr) {
2060 freeaddrinfo(sock->myaddr);
2061 sock->myaddr = NULL;
2062 }
2063 #if HAVE_SSL
2064 if (sock->ssl) {
2065 SSL_shutdown(sock->ssl);
2066 /* Don't SSL_free() yet: we still need to be able to use SSL_error() */
2067 }
2068 #endif
2069 if (sock->fd >= 0) {
2070 FD_CLR(sock->fd, &readers);
2071 FD_CLR(sock->fd, &writers);
2072 close(sock->fd);
2073 sock->fd = -1;
2074 }
2075 #if HAVE_MCCP
2076 if (sock->zstream) {
2077 inflateEnd(sock->zstream);
2078 FREE(sock->zstream);
2079 }
2080 #endif
2081 #ifdef NONBLOCKING_GETHOST
2082 # ifdef PLATFORM_UNIX
2083 if (sock->pid >= 0) {
2084 kill(sock->pid, SIGTERM);
2085 if (waitpid(sock->pid, NULL, 0) < 0)
2086 tfprintf(tferr, "waitpid: %ld: %s", sock->pid, strerror(errno));
2087 sock->pid = -1;
2088 }
2089 # endif /* PLATFORM_UNIX */
2090 #endif /* NONBLOCKING_GETHOST */
2091 if (sock == fsock)
2092 update_status_field(NULL, STAT_WORLD);
2093 }
2094
2095 /* nukesock
2096 * Remove socket from list and free memory. Should only be called on a
2097 * Sock which is known to have no references other than the socket list.
2098 */
nukesock(Sock * sock)2099 static void nukesock(Sock *sock)
2100 {
2101 if (sock->queue.list.head) {
2102 internal_error(__FILE__, __LINE__, "socket %s has unprocessed lines",
2103 !sock ? "!sock" :
2104 !sock->world ? "!sock->world" :
2105 sock->world->name);
2106 socks_with_lines--;
2107 }
2108 if (sock == xsock) xsock = NULL;
2109 sock->world->sock = NULL;
2110 killsock(sock);
2111 *((sock == hsock) ? &hsock : &sock->prev->next) = sock->next;
2112 *((sock == tsock) ? &tsock : &sock->next->prev) = sock->prev;
2113 if (sock->world->screen->active) {
2114 sock->world->screen->active = 0;
2115 --active_count;
2116 update_status_field(NULL, STAT_ACTIVE);
2117 }
2118 if (sock->world->flags & WORLD_TEMP) {
2119 nuke_world(sock->world);
2120 sock->world = NULL;
2121 }
2122 #if HAVE_SSL
2123 if (sock->ssl) {
2124 SSL_free(sock->ssl);
2125 sock->ssl = NULL;
2126 }
2127 #endif
2128 FREE(sock);
2129 }
2130
2131 #if 0
2132 static void fg_live_sock(void)
2133 {
2134 /* If the fg sock is dead, find another sock to put in fg. Since this
2135 * is called from main_loop(), xsock must be the same as fsock. We must
2136 * keep it that way. Note that a user hook in fg_sock() could kill the
2137 * new fg sock, so we must loop until the new fg sock stays alive.
2138 */
2139 while (fsock && (fsock->constate >= SS_ZOMBIE)) {
2140 for (xsock = hsock; xsock; xsock = xsock->next) {
2141 if (xsock->constate < SS_ZOMBIE)
2142 break;
2143 }
2144 fg_sock(xsock, FALSE);
2145 }
2146 }
2147 #endif
2148
2149 /* delete all dead sockets */
nuke_dead_socks(void)2150 static void nuke_dead_socks(void)
2151 {
2152 Sock *sock, *next;
2153
2154 for (sock = hsock; sock; sock = next) {
2155 next = sock->next;
2156 if (sock->constate == SS_ZOMBIE) {
2157 if (sock->fd >= 0)
2158 FD_CLR(sock->fd, &readers);
2159 } else if (sock->constate == SS_DEAD) {
2160 nukesock(sock);
2161 dead_socks--;
2162 }
2163 }
2164 if (quitdone && !hsock) quit_flag = 1;
2165 }
2166
queue_socket_line(Sock * sock,const conString * line,int offset,attr_t attr)2167 static void queue_socket_line(Sock *sock, const conString *line, int offset,
2168 attr_t attr)
2169 {
2170 String *new;
2171 (new = StringnewM(NULL, line->len - offset, 0, sock->world->md))->links++;
2172 SStringocat(new, line, offset);
2173 new->attrs |= attr;
2174 gettime(&new->time);
2175 sock->time[SOCK_RECV] = new->time;
2176 new->attrs &= ~F_GAG; /* in case gagged line was passed via fake_recv() */
2177 if (!sock->queue.list.head)
2178 socks_with_lines++;
2179 enqueue(&sock->queue, new);
2180 }
2181
dc(Sock * s)2182 static void dc(Sock *s)
2183 {
2184 String *buffer = Stringnew(NULL, -1, 0);
2185 Sock *oldxsock = xsock;
2186 xsock = s;
2187 flushxsock();
2188 Sprintf(buffer, "%% Connection to %s closed.", s->world->name);
2189 world_output(s->world, CS(buffer));
2190 if (xsock != fsock) oputline(CS(buffer));
2191 zombiesock(xsock);
2192 xsock = oldxsock;
2193 }
2194
2195 /* disconnect a socket */
handle_dc_command(String * args,int offset)2196 struct Value *handle_dc_command(String *args, int offset)
2197 {
2198 Sock *s;
2199
2200 if (!(args->len - offset)) {
2201 if (!xsock) {
2202 eprintf("no current socket");
2203 return shareval(val_zero);
2204 }
2205 dc(xsock);
2206 } else if (cstrcmp(args->data + offset, "-all") == 0) {
2207 for (s = hsock; s; s = s->next)
2208 if (s->constate < SS_DEAD)
2209 dc(s);
2210 } else {
2211 if ((s = find_sock(args->data + offset)) && (s->constate < SS_DEAD)) {
2212 dc(s);
2213 } else {
2214 eprintf("Not connected to %s", args->data + offset);
2215 return shareval(val_zero);
2216 }
2217 }
2218 return shareval(val_one);
2219 }
2220
socklinescmp(const void * a,const void * b)2221 static int socklinescmp(const void *a, const void *b) {
2222 return (*(Sock**)a)->world->screen->nnew -
2223 (*(Sock**)b)->world->screen->nnew;
2224 }
2225
sockidlecmp(const void * a,const void * b)2226 static int sockidlecmp(const void *a, const void *b) {
2227 return tvcmp(&(*(Sock**)b)->time[SOCK_RECV],
2228 &(*(Sock**)a)->time[SOCK_RECV]);
2229 }
2230
socknamecmp(const void * a,const void * b)2231 static int socknamecmp(const void *a, const void *b) {
2232 return nullcstrcmp((*(Sock**)a)->world->name, (*(Sock**)b)->world->name);
2233 }
2234
socktypecmp(const void * a,const void * b)2235 static int socktypecmp(const void *a, const void *b) {
2236 return nullcstrcmp((*(Sock**)a)->world->type, (*(Sock**)b)->world->type);
2237 }
2238
sockhostcmp(const void * a,const void * b)2239 static int sockhostcmp(const void *a, const void *b) {
2240 return nullcstrcmp((*(Sock**)a)->world->host, (*(Sock**)b)->world->host);
2241 }
2242
sockportcmp(const void * a,const void * b)2243 static int sockportcmp(const void *a, const void *b) {
2244 return nullcstrcmp((*(Sock**)a)->world->port, (*(Sock**)b)->world->port);
2245 }
2246
sockcharcmp(const void * a,const void * b)2247 static int sockcharcmp(const void *a, const void *b) {
2248 return nullcstrcmp((*(Sock**)a)->world->character,
2249 (*(Sock**)b)->world->character);
2250 }
2251
2252 /* display list of open sockets and their state. */
handle_listsockets_command(String * args,int offset)2253 struct Value *handle_listsockets_command(String *args, int offset)
2254 {
2255 Sock *sock;
2256 Vector socks = vector_init(32);
2257 char idlebuf[16], linebuf[16], addrbuf[64], state;
2258 const char *ptr;
2259 time_t now;
2260 int t, n, opt, i, nnew, nold;
2261 int error = 0, shortflag = FALSE, mflag = matching, numeric = 0;
2262 Pattern pat_name, pat_type;
2263 int typewidth = 11, namewidth = 15, hostwidth = 26;
2264 int (*cmp)(const void *, const void *) = NULL;
2265
2266 init_pattern_str(&pat_name, NULL);
2267 init_pattern_str(&pat_type, NULL);
2268
2269 startopt(CS(args), "m:sT:nS:");
2270 while ((opt = nextopt(&ptr, NULL, NULL, &offset))) {
2271 switch(opt) {
2272 case 'm':
2273 if ((mflag = enum2int(ptr, 0, enum_match, "-m")) < 0)
2274 goto listsocket_error;
2275 break;
2276 case 's':
2277 shortflag = TRUE;
2278 break;
2279 case 'T':
2280 free_pattern(&pat_type);
2281 error += !init_pattern_str(&pat_type, ptr);
2282 break;
2283 case 'n':
2284 numeric = 1;
2285 break;
2286 case 'S':
2287 n = strlen(ptr);
2288 if (n == 0 || cstrncmp(ptr, "name", n) == 0)
2289 cmp = socknamecmp;
2290 else if (cstrncmp(ptr, "lines", n) == 0)
2291 cmp = socklinescmp;
2292 else if (cstrncmp(ptr, "idle", n) == 0)
2293 cmp = sockidlecmp;
2294 else if (cstrncmp(ptr, "type", n) == 0)
2295 cmp = socktypecmp;
2296 else if (cstrncmp(ptr, "host", n) == 0)
2297 cmp = sockhostcmp;
2298 else if (cstrncmp(ptr, "port", n) == 0)
2299 cmp = sockportcmp;
2300 else if (cstrncmp(ptr, "character", n) == 0)
2301 cmp = sockcharcmp;
2302 else if (cstrncmp(ptr, "-", n) == 0)
2303 cmp = NULL;
2304 else { eprintf("invalid sort criterion"); error++; }
2305 break;
2306 default:
2307 goto listsocket_error;
2308 }
2309 }
2310 if (error) goto listsocket_error;
2311 init_pattern_mflag(&pat_type, mflag, 'T');
2312 Stringstriptrail(args);
2313 if (args->len > offset)
2314 error += !init_pattern(&pat_name, args->data + offset, mflag);
2315 if (error) goto listsocket_error;
2316
2317 if (!hsock) {
2318 if (!shortflag) eprintf("Not connected to any sockets.");
2319 goto listsocket_error;
2320 }
2321
2322 /* collect matching socks */
2323 for (sock = hsock; sock; sock = sock->next) {
2324 if (pat_type.str &&
2325 !patmatch(&pat_type, NULL,
2326 sock->world->type ? sock->world->type : ""))
2327 continue;
2328 if (args->len - offset && !patmatch(&pat_name, NULL, sock->world->name))
2329 continue;
2330 vector_add(&socks, sock);
2331 }
2332
2333 if (cmp)
2334 vector_sort(&socks, cmp);
2335
2336 if (numeric) {
2337 namewidth += 3;
2338 typewidth += 3;
2339 hostwidth = 20;
2340 }
2341
2342 now = time(NULL);
2343
2344 if (!shortflag)
2345 oprintf(" %8s %4s %-*s %-*s %-*s %s",
2346 "LINES", "IDLE", typewidth, "TYPE", namewidth, "NAME",
2347 hostwidth, "HOST", "PORT");
2348 for (i = 0; i < socks.size; i++) {
2349 sock = socks.ptrs[i];
2350 nnew = sock->world->screen->nnew;
2351 nold = sock->world->screen->nback - nnew;
2352 if (shortflag) {
2353 oputs(sock->world->name);
2354 continue;
2355 }
2356 if (sock == fsock)
2357 sprintf(linebuf, "%8s", "fg");
2358 else {
2359 if (nold) {
2360 if (nold > 999)
2361 sprintf(linebuf, "%2dk", nold / 1000);
2362 else
2363 sprintf(linebuf, "%3d", nold);
2364 if (nnew > 9999)
2365 sprintf(linebuf+3, "+%3dk", nnew / 1000);
2366 else
2367 sprintf(linebuf+3, "+%4d", nnew);
2368 } else {
2369 if (nnew > 99999)
2370 sprintf(linebuf, "%7dk", nnew / 1000);
2371 else
2372 sprintf(linebuf, "%8d", nnew);
2373 }
2374 }
2375 t = now - sock->time[SOCK_RECV].tv_sec;
2376 if (t < (60))
2377 sprintf(idlebuf, "%3ds", t);
2378 else if ((t /= 60) < 60)
2379 sprintf(idlebuf, "%3dm", t);
2380 else if ((t /= 60) < 24)
2381 sprintf(idlebuf, "%3dh", t);
2382 else if ((t /= 24) < 1000)
2383 sprintf(idlebuf, "%3dd", t);
2384 else
2385 sprintf(idlebuf, "long");
2386
2387 state =
2388 sock->constate < SS_CONNECTED ? '?' :
2389 sock->constate >= SS_ZOMBIE ? '!' :
2390 sock->constate == SS_OPEN ? 'O' :
2391 sock->constate == SS_CONNECTED && sock->fsastate == TN_SB ? 'S' :
2392 #if HAVE_SSL
2393 sock->constate == SS_CONNECTED && sock->ssl ? 'X' :
2394 #endif
2395 sock->constate == SS_CONNECTED ? 'C' :
2396 '#' /* shouldn't happen */;
2397 if (sock->flags & SOCKCOMPRESS)
2398 state = lcase(state);
2399 if (!numeric && sock->addr)
2400 sprintf(addrbuf, "%-*.*s %.6s",
2401 hostwidth, hostwidth, sock->host, sock->port);
2402 oprintf("%c%c%c"
2403 " %s %s %-*.*s %-*.*s %s",
2404 (sock == xsock ? '*' : ' '),
2405 state,
2406 (sock->flags & SOCKPROXY ? 'P' : ' '),
2407 linebuf, idlebuf,
2408 typewidth, typewidth, sock->world->type,
2409 namewidth, namewidth, sock->world->name,
2410 !sock->addr ? "" : numeric ? printai(sock->addr, "%-20.20s %d") :
2411 addrbuf);
2412 }
2413
2414 listsocket_error:
2415 free_pattern(&pat_name);
2416 free_pattern(&pat_type);
2417
2418 return newint(socks.size);
2419 }
2420
handle_send_function(conString * string,const char * world,const char * flags)2421 int handle_send_function(conString *string, const char *world,
2422 const char *flags)
2423 {
2424 const char *p;
2425 int result = 0, eol_flag = 1, hook_flag = 0;
2426 Sock *old_xsock = xsock;
2427
2428 for (p = flags; *p; p++) {
2429 switch (*p) {
2430 case 'o': /* for backward compatability */
2431 break;
2432 case '1': case 'n': /* for backward compatability */
2433 eol_flag = 1; break;
2434 case 'u': /* fall through */
2435 case '0': case 'f': /* for backward compatability */
2436 eol_flag = 0; break;
2437 case 'h':
2438 hook_flag = 1; break;
2439 default:
2440 eprintf("invalid flag %c", *p);
2441 return 0;
2442 }
2443 }
2444
2445 xsock = (!world || !*world) ? xsock : find_sock(world);
2446 if (!hook_flag || !do_hook(H_SEND, NULL, "%S", string))
2447 result = send_line(string->data, string->len, eol_flag);
2448 xsock = old_xsock;
2449 return result;
2450 }
2451
handle_fake_recv_function(conString * string,const char * world,const char * flags)2452 int handle_fake_recv_function(conString *string, const char *world,
2453 const char *flags)
2454 {
2455 Sock *sock;
2456 int raw = 0;
2457 const char *p;
2458
2459 for (p = flags; *p; p++) {
2460 switch (*p) {
2461 case 'r': raw = 1; break;
2462 default:
2463 eprintf("invalid flag %c", *p);
2464 return 0;
2465 }
2466 }
2467
2468 sock = (!world || !*world) ? xsock : find_sock(world);
2469 if (!sock ||
2470 sock->constate <= SS_CONNECTING || sock->constate >= SS_ZOMBIE)
2471 {
2472 eprintf("no open world %s", world ? world : "");
2473 return 0;
2474 }
2475 if (raw)
2476 handle_socket_input(string->data, string->len);
2477 else
2478 queue_socket_line(sock, string, 0, 0);
2479 return 1;
2480 }
2481
2482
2483 /* tramsmit text to current socket */
transmit(const char * str,unsigned int numtowrite)2484 static int transmit(const char *str, unsigned int numtowrite)
2485 {
2486 int numwritten, err;
2487
2488 if (!xsock || xsock->constate != SS_CONNECTED)
2489 return 0;
2490 while (numtowrite) {
2491 #if HAVE_SSL
2492 if (xsock->ssl) {
2493 numwritten = SSL_write(xsock->ssl, str, numtowrite);
2494 if (numwritten <= 0) {
2495 zombiesock(xsock); /* before hook, so sock state is correct */
2496 ssl_io_err(xsock, numwritten, H_DISCONNECT);
2497 return 0;
2498 }
2499 } else
2500 #endif /* HAVE_SSL */
2501 {
2502 numwritten = send(xsock->fd, str, numtowrite, 0);
2503 if (numwritten < 0) {
2504 err = errno;
2505 /* Socket is blocking; EAGAIN and EWOULDBLOCK are impossible. */
2506 if (err == EINTR) {
2507 return 0;
2508 } else if (err == EHOSTUNREACH || err == ENETUNREACH) {
2509 /* XXX there should be an UNREACHABLE hook here */
2510 eprintf("%s: send: %s", xsock->world->name, strerror(err));
2511 return 0;
2512 } else {
2513 flushxsock();
2514 zombiesock(xsock); /* before hook, so state is correct */
2515 DISCON(xsock->world->name, "send", strerror(err));
2516 return 0;
2517 }
2518 }
2519 }
2520 numtowrite -= numwritten;
2521 str += numwritten;
2522 gettime(&xsock->time[SOCK_SEND]);
2523 }
2524 return 1;
2525 }
2526
2527 /* send_line
2528 * Send a line to the server on the current socket. If there is a prompt
2529 * associated with the current socket, clear it.
2530 * RFCs 854 and 1123 technically forbid sending 8-bit data in non-BINARY mode;
2531 * but if the user types it, we send it regardless of BINARY mode, and trust
2532 * the user to know what he's doing. Some servers accept it, some strip the
2533 * high bit, some ignore the characters.
2534 */
send_line(const char * src,unsigned int len,int eol_flag)2535 int send_line(const char *src, unsigned int len, int eol_flag)
2536 {
2537 int max;
2538 int i = 0, j = 0;
2539 static char *buf = NULL;
2540 static int buflen = 0;
2541
2542 if (!xsock ||
2543 (xsock->constate != SS_CONNECTED && !(xsock->flags & SOCKECHO)))
2544 {
2545 eprintf("Not connected.");
2546 return 0;
2547 }
2548
2549 if (xsock && xsock->prompt) {
2550 /* Not the same as unprompt(): we keep attrs, and delete buffer. */
2551 if (!(xsock->flags & SOCKPROMPT)) {
2552 /* Prompt was implicit, so there's still a copy in xsock->buffer */
2553 Stringtrunc(xsock->buffer, 0);
2554 } else {
2555 /* Prompt was explicit, so anything in xsock->buffer is an
2556 * unrelated partial line that we must keep. */
2557 }
2558 conStringfree(xsock->prompt);
2559 xsock->prompt = NULL;
2560 xsock->prepromptattrs = 0;
2561 if (xsock == fsock) update_prompt(xsock->prompt, 1);
2562 }
2563
2564 if (secho) {
2565 String *str = Stringnew(NULL, 0, 0);
2566 Sprintf(str, "%S%.*s%A", sprefix, len, src, getattrvar(VAR_secho_attr));
2567 world_output(xsock->world, CS(str));
2568 }
2569
2570 max = 2 * len + 3;
2571 if (buflen < max) {
2572 buf = XREALLOC(buf, buflen = max);
2573 }
2574 while (j < len) {
2575 if (xsock->flags & SOCKTELNET && src[j] == TN_IAC)
2576 buf[i++] = TN_IAC; /* double IAC */
2577 buf[i] = unmapchar(src[j]);
2578 i++, j++;
2579 }
2580
2581 if (eol_flag) {
2582 /* In telnet NVT mode, append CR LF; in telnet BINARY mode,
2583 * append LF, CR, or CR LF, according to variable.
2584 */
2585 if (!TELOPT(xsock, us, TN_BINARY) || binary_eol != EOL_LF)
2586 buf[i++] = '\r';
2587 if (!TELOPT(xsock, us, TN_BINARY) || binary_eol != EOL_CR)
2588 buf[i++] = '\n';
2589 }
2590
2591 if (xsock->flags & SOCKECHO)
2592 handle_socket_input(buf, i);
2593 if (xsock->constate == SS_CONNECTED)
2594 return transmit(buf, i);
2595 return 1;
2596 }
2597
handle_socket_lines(void)2598 static void handle_socket_lines(void)
2599 {
2600 static int depth = 0;
2601 conString *line;
2602 int is_prompt;
2603
2604 if (depth) return; /* don't recurse */
2605 if (!(line = dequeue(&xsock->queue)))
2606 return;
2607 depth++;
2608 do {
2609 if (!xsock->queue.list.head) /* just dequeued the last line */
2610 socks_with_lines--;
2611
2612 if (line->attrs & (F_TFPROMPT)) {
2613 incoming_text = line;
2614 handle_prompt(incoming_text, 0, TRUE);
2615 continue;
2616 }
2617
2618 incoming_text = decode_ansi(line->data, xsock->attrs, emulation,
2619 &xsock->attrs);
2620 incoming_text->time = line->time;
2621 is_prompt = line->attrs & F_SERVPROMPT;
2622 conStringfree(line);
2623 incoming_text->links++;
2624
2625 if (is_prompt) {
2626 if (do_hook(H_PROMPT, NULL, "%S", incoming_text)) {
2627 Stringfree(incoming_text);
2628 } else {
2629 handle_prompt(incoming_text, 0, TRUE);
2630 }
2631
2632 } else {
2633 if (borg || hilite || gag) {
2634 if (find_and_run_matches(NULL, -1, &incoming_text, xworld(),
2635 TRUE, 0))
2636 {
2637 if (xsock != fsock)
2638 do_hook(H_BGTRIG, "%% Trigger in world %s", "%s %S",
2639 xsock->world->name, incoming_text);
2640 }
2641 }
2642
2643 if (is_bamf(incoming_text->data) || is_quiet(incoming_text->data) ||
2644 is_watchdog(xsock->world->history, incoming_text) ||
2645 is_watchname(xsock->world->history, incoming_text))
2646 {
2647 incoming_text->attrs |= F_GAG;
2648 }
2649
2650 world_output(xsock->world, CS(incoming_text));
2651 Stringfree(incoming_text);
2652 }
2653 } while ((line = dequeue(&xsock->queue)));
2654 depth--;
2655
2656 /* We just emptied the queue; there may be a partial line pending */
2657 test_prompt();
2658 }
2659
2660 /* log, record, and display line as if it came from sock */
world_output(World * world,conString * line)2661 void world_output(World *world, conString *line)
2662 {
2663 Sock *saved_xsock = xsock;
2664 xsock = world ? world->sock : NULL;
2665 line->links++;
2666 recordline(world->history, line);
2667 record_global(line);
2668 if (world->sock && (world->sock->constate < SS_DEAD) &&
2669 !(gag && (line->attrs & F_GAG)))
2670 {
2671 if (world->sock == fsock) {
2672 screenout(line);
2673 } else {
2674 static int preactivity_depth = 0; /* avoid recursion */
2675 /* line was already tested for gag, so it WILL print */
2676 if (!preactivity_depth && !world->screen->active) {
2677 preactivity_depth++;
2678 do_hook(H_PREACTIVITY, NULL, "%s", world->name);
2679 preactivity_depth--;
2680 }
2681 enscreen(world->screen, line); /* ignores preactivity_depth */
2682 if (!preactivity_depth) {
2683 if (!world->screen->active && !(line->attrs & F_NOACTIVITY)) {
2684 world->screen->active = 1;
2685 ++active_count;
2686 update_status_field(NULL, STAT_ACTIVE);
2687 do_hook(H_ACTIVITY, "%% Activity in world %s", "%s",
2688 world->name);
2689 }
2690 do_hook(H_BGTEXT, NULL, "%s", world->name);
2691 }
2692 }
2693 }
2694 conStringfree(line);
2695 xsock = saved_xsock;
2696 }
2697
2698 /* get the prompt for the fg sock */
fgprompt(void)2699 conString *fgprompt(void)
2700 {
2701 return (fsock) ? fsock->prompt : NULL;
2702 }
2703
tog_lp(Var * var)2704 int tog_lp(Var *var)
2705 {
2706 if (!fsock) {
2707 /* do nothing */
2708 } else if (lpflag) {
2709 if (!fsock->queue.list.head && fsock->buffer->len) {
2710 fsock->prompt = CS(decode_ansi(fsock->buffer->data, fsock->attrs,
2711 emulation, &fsock->attrs));
2712 fsock->prompt->links++;
2713 set_refresh_pending(REF_PHYSICAL);
2714 }
2715 } else {
2716 if (fsock->prompt && !(fsock->flags & SOCKPROMPT)) {
2717 unprompt(fsock, 1);
2718 set_refresh_pending(REF_PHYSICAL);
2719 }
2720 }
2721 return 1;
2722 }
2723
handle_prompt_func(conString * str)2724 int handle_prompt_func(conString *str)
2725 {
2726 if (xsock)
2727 queue_socket_line(xsock, str, 0, F_TFPROMPT);
2728 return !!xsock;
2729 }
2730
handle_prompt(String * str,int offset,int confirmed)2731 static void handle_prompt(String *str, int offset, int confirmed)
2732 {
2733 runall(1, xsock->world); /* run prompted processes */
2734 if (xsock->prompt) {
2735 unprompt(xsock, 0);
2736 }
2737 assert(str->links == 1);
2738 xsock->prompt = CS(str);
2739 /* Old versions did trigger checking here. Removing it breaks
2740 * compatibility, but I doubt many users will care. Leaving
2741 * it in would not be right for /prompt.
2742 */
2743 if (xsock == fsock) update_prompt(xsock->prompt, 1);
2744 if (confirmed) xsock->flags |= SOCKPROMPT;
2745 else xsock->flags &= ~SOCKPROMPT;
2746 xsock->numquiet = 0;
2747 }
2748
handle_implicit_prompt(void)2749 static void handle_implicit_prompt(void)
2750 {
2751 String *new;
2752
2753 xsock->prompt_timeout = tvzero;
2754 xsock->prepromptattrs = xsock->attrs; /* save attrs for unprompt() */
2755
2756 new = decode_ansi(xsock->buffer->data, xsock->attrs, emulation,
2757 &xsock->attrs);
2758 new->links++;
2759
2760 handle_prompt(new, 0, FALSE);
2761 }
2762
2763 /* undo the effects of a false prompt */
unprompt(Sock * sock,int update)2764 static void unprompt(Sock *sock, int update)
2765 {
2766 if (!sock || !sock->prompt || !(sock->flags & SOCKPROMPT)) return;
2767 sock->attrs = sock->prepromptattrs; /* restore original attrs */
2768 conStringfree(sock->prompt);
2769 sock->prompt = NULL;
2770 sock->prepromptattrs = 0;
2771 if (update) update_prompt(sock->prompt, 1);
2772 }
2773
schedule_prompt(Sock * sock)2774 static void schedule_prompt(Sock *sock)
2775 {
2776 if (prompt_timeout.tv_sec == 0 ||
2777 tvcmp(&sock->prompt_timeout, &prompt_timeout) < 0)
2778 {
2779 prompt_timeout = sock->prompt_timeout;
2780 }
2781 }
2782
test_prompt(void)2783 static void test_prompt(void)
2784 {
2785 if (lpflag && !xsock->queue.list.head && xsock->buffer->len) {
2786 if (do_hook(H_PROMPT, NULL, "%S", xsock->buffer)) {
2787 /* The hook took care of the unterminated line. */
2788 Stringtrunc(xsock->buffer, 0);
2789 } else if (lpflag) {
2790 /* Wait for prompt_wait before treating unterm'd line as prompt. */
2791 struct timeval now;
2792 gettime(&now);
2793 tvadd(&xsock->prompt_timeout, &now, &prompt_wait);
2794 schedule_prompt(xsock);
2795 }
2796 }
2797 }
2798
telnet_subnegotiation(void)2799 static void telnet_subnegotiation(void)
2800 {
2801 char *p;
2802 int ttype;
2803 static conString enum_ttype[] = {
2804 STRING_LITERAL("TINYFUGUE"),
2805 STRING_LITERAL("ANSI-ATTR"),
2806 STRING_LITERAL("ANSI"), /* a lie, but probably has the desired effect */
2807 STRING_LITERAL("UNKNOWN"),
2808 STRING_NULL };
2809
2810 telnet_debug("recv", xsock->subbuffer->data, xsock->subbuffer->len);
2811 Stringtrunc(xsock->subbuffer, xsock->subbuffer->len - 2);
2812 p = xsock->subbuffer->data + 2;
2813 switch (*p) {
2814 case TN_TTYPE:
2815 if (!TELOPT(xsock, us, *p)) {
2816 no_reply("option was not agreed on");
2817 break;
2818 }
2819 if (*++p != '\01' || xsock->subbuffer->len != 4) {
2820 no_reply("invalid syntax");
2821 break;
2822 }
2823 Sprintf(telbuf, "%c%c%c%c", TN_IAC, TN_SB, TN_TTYPE, '\0');
2824 ttype = ++xsock->ttype;
2825 if (!enum_ttype[ttype].data) { ttype--; xsock->ttype = -1; }
2826 SStringcat(telbuf, &enum_ttype[ttype]);
2827 Sappendf(telbuf, "%c%c", TN_IAC, TN_SE);
2828 telnet_send(telbuf);
2829 break;
2830 case TN_COMPRESS:
2831 case TN_COMPRESS2:
2832 if (!TELOPT(xsock, them, *p)) {
2833 no_reply("option was not agreed on");
2834 break;
2835 }
2836 xsock->flags |= SOCKCOMPRESS;
2837 break;
2838 default:
2839 no_reply("unknown option");
2840 break;
2841 }
2842 Stringtrunc(xsock->subbuffer, 0);
2843 }
2844
f_telnet_recv(int cmd,int opt)2845 static void f_telnet_recv(int cmd, int opt)
2846 {
2847 if (telopt) {
2848 char buf[4];
2849 sprintf(buf, "%c%c%c", TN_IAC, cmd, opt);
2850 telnet_debug("recv", buf,
2851 (cmd==(UCHAR)TN_DO || cmd==(UCHAR)TN_DONT ||
2852 cmd==(UCHAR)TN_WILL || cmd==(UCHAR)TN_WONT) ?
2853 3 : 2);
2854 }
2855 }
2856
2857 #if HAVE_MCCP
new_zstream(void)2858 static z_stream *new_zstream(void)
2859 {
2860 z_stream *zstream;
2861 if (!(zstream = MALLOC(sizeof(z_stream))))
2862 return NULL;
2863 zstream->zalloc = Z_NULL;
2864 zstream->zfree = Z_NULL;
2865 zstream->opaque = Z_NULL;
2866 if (inflateInit(zstream) == Z_OK)
2867 return zstream;
2868 if (zstream->msg)
2869 eprintf("unable to start compressed stream: %s", zstream->msg);
2870 FREE(zstream);
2871 return NULL;
2872 }
2873 #endif /* HAVE_MCCP */
2874
2875 /* handle input from current socket */
handle_socket_input(const char * simbuffer,int simlen)2876 static int handle_socket_input(const char *simbuffer, int simlen)
2877 {
2878 char rawchar, localchar, inbuffer[4096];
2879 const char *buffer, *place;
2880 #if HAVE_MCCP
2881 char outbuffer[4096];
2882 #endif
2883 fd_set readfds;
2884 int count, n, received = 0;
2885 struct timeval timeout;
2886
2887 if (xsock->constate <= SS_CONNECTING || xsock->constate >= SS_ZOMBIE)
2888 return 0;
2889
2890 if (xsock->prompt && !(xsock->flags & SOCKPROMPT)) {
2891 /* We assumed last text was a prompt, but now we have more text, so
2892 * we now assume that they are both part of the same long line. (If
2893 * we're wrong, the previous prompt appears as output. But if we did
2894 * the opposite, a real begining of a line would never appear in the
2895 * output window; that would be a worse mistake.)
2896 * Note that a terminated (EOR or GOAHEAD) prompt will NOT be cleared
2897 * when new text arrives (it will only be cleared when there is a new
2898 * prompt).
2899 */
2900 unprompt(xsock, xsock==fsock);
2901 }
2902 xsock->prompt_timeout = tvzero;
2903
2904 do { /* while there are more data to be processed */
2905 if (simbuffer) {
2906 buffer = simbuffer;
2907 count = simlen;
2908 } else {
2909 #if HAVE_MCCP
2910 if (xsock->zstream && xsock->zstream->avail_in) {
2911 count = 0; /* no reading */
2912 } else
2913 #endif
2914 #if HAVE_SSL
2915 if (xsock->ssl) {
2916 count = SSL_read(xsock->ssl, inbuffer, sizeof(inbuffer));
2917 if (count == 0 &&
2918 SSL_get_error(xsock->ssl, 0) == SSL_ERROR_SYSCALL &&
2919 ERR_peek_error() == 0)
2920 {
2921 /* Treat a count of 0 with no errors as a normal EOF */
2922 goto eof;
2923 } else if (count <= 0) {
2924 /* Treat an error or a bad EOF as an error */
2925 zombiesock(xsock); /* before hook, so state is correct */
2926 ssl_io_err(xsock, count, H_DISCONNECT);
2927 return received;
2928 }
2929 } else
2930 #endif
2931 {
2932 /* We could loop while (count < 0 && errno == EINTR), but if we
2933 * got here because of a mistake in the active fdset and there
2934 * is really nothing to read, the loop would be unbreakable. */
2935 count = recv(xsock->fd, inbuffer, sizeof(inbuffer), 0);
2936 eof:
2937 if (count <= 0) {
2938 int err = errno;
2939 constate_t state = xsock->constate;
2940 if (count < 0 && errno == EINTR)
2941 return 0;
2942 /* Socket is blocking; EAGAIN and EWOULDBLOCK impossible. */
2943 if (xsock->buffer->len) {
2944 queue_socket_line(xsock, CS(xsock->buffer), 0, 0);
2945 Stringtrunc(xsock->buffer, 0);
2946 }
2947 flushxsock();
2948 /* On some systems, a socket that failed nonblocking connect
2949 * selects readable instead of writable. If SS_CONNECTING,
2950 * that's what happened, so we do CONFAIL not DISCONNECT.
2951 */
2952 zombiesock(xsock); /* before hook, so constate is correct */
2953 if (state == SS_CONNECTING)
2954 CONFAIL(xsock, "recv", strerror(err));
2955 else do_hook(H_DISCONNECT, (count < 0) ?
2956 "%% Connection to %s closed: %s: %s" :
2957 "%% Connection to %s closed by foreign host.",
2958 (count < 0) ? "%s %s %s" : "%s",
2959 xsock->world->name, "recv", strerror(err));
2960 return received;
2961 }
2962 }
2963 #if HAVE_MCCP
2964 if (xsock->zstream) {
2965 int zret;
2966 if (count) {
2967 xsock->zstream->next_in = (Bytef*)inbuffer;
2968 xsock->zstream->avail_in = count;
2969 }
2970 xsock->zstream->next_out = (Bytef*)(buffer = outbuffer);
2971 xsock->zstream->avail_out = sizeof(outbuffer);
2972 zret = inflate(xsock->zstream, Z_PARTIAL_FLUSH);
2973 switch (zret) {
2974 case Z_OK:
2975 count = (char*)xsock->zstream->next_out - outbuffer;
2976 break;
2977 case Z_STREAM_END:
2978 /* handle stuff inflated before stream end */
2979 count = (char*)xsock->zstream->next_out - outbuffer;
2980 received += handle_socket_input(outbuffer, count);
2981 /* prepare to handle noncompressed stuff after stream end */
2982 buffer = (char*)xsock->zstream->next_in;
2983 count = xsock->zstream->avail_in;
2984 /* clean up zstream */
2985 inflateEnd(xsock->zstream);
2986 FREE(xsock->zstream);
2987 xsock->zstream = NULL;
2988 xsock->flags &= ~SOCKCOMPRESS;
2989 break;
2990 default:
2991 flushxsock();
2992 zombiesock(xsock); /* before hook, so constate is correct */
2993 DISCON(xsock->world->name, "inflate",
2994 xsock->zstream->msg ? xsock->zstream->msg : "unknown");
2995 return received;
2996 }
2997 } else
2998 #endif
2999 buffer = inbuffer;
3000 }
3001
3002 for (place = buffer; place - buffer < count; place++) {
3003
3004 /* We always accept 8-bit data, even though RFCs 854 and 1123
3005 * say server shouldn't transmit it unless in BINARY mode. What
3006 * we do with it depends on the locale.
3007 */
3008 rawchar = *place;
3009 localchar = localize(rawchar);
3010
3011 /* Telnet processing
3012 * If we're not sure yet whether server speaks telnet protocol,
3013 * we still accept it, but if an invalid telnet command arrives,
3014 * we leave it alone and disable telnet processing.
3015 */
3016 if (xsock->fsastate == TN_IAC &&
3017 xsock->flags & (SOCKTELNET | SOCKMAYTELNET))
3018 {
3019 int valid = 0;
3020 switch (xsock->fsastate = rawchar) {
3021 case TN_GA: case TN_EOR:
3022 /* This is definitely a prompt. */
3023 telnet_recv(rawchar, 0);
3024 queue_socket_line(xsock, CS(xsock->buffer), 0, F_SERVPROMPT);
3025 Stringtrunc(xsock->buffer, 0);
3026 break;
3027 case TN_SB:
3028 if (!(xsock->flags & SOCKTELNET)) {
3029 /* Telnet subnegotiation can't happen without a
3030 * previous telnet option negotation, so treat the
3031 * IAC SB as non-telnet, and disable telnet. */
3032 xsock->flags &= ~SOCKMAYTELNET;
3033 place--;
3034 rawchar = xsock->fsastate;
3035 goto non_telnet;
3036 }
3037 Sprintf(xsock->subbuffer, "%c%c", TN_IAC, TN_SB);
3038 xsock->substate = '\0';
3039 break;
3040 case TN_WILL: case TN_WONT:
3041 case TN_DO: case TN_DONT:
3042 /* just change state */
3043 break;
3044 case TN_IAC:
3045 Stringadd(xsock->buffer, localchar); /* literal IAC */
3046 xsock->fsastate = '\0';
3047 break;
3048
3049 case TN_NOP:
3050 case TN_DATA_MARK:
3051 case TN_BRK:
3052 case TN_IP:
3053 case TN_AO:
3054 case TN_AYT:
3055 case TN_EC:
3056 case TN_EL:
3057 valid = 1;
3058 /* Unsupported. Fall through to default case. */
3059 default:
3060 if (xsock->flags & SOCKTELNET ||
3061 (xsock->flags & SOCKMAYTELNET && valid))
3062 {
3063 /* unsupported or invalid telnet command */
3064 telnet_recv(rawchar, 0);
3065 xsock->fsastate = '\0';
3066 break;
3067 }
3068 /* Invalid telnet command, and telnet protocol hasn't been
3069 * established, so treat the IAC and rawchar as non-telnet,
3070 * and disable telnet. */
3071 xsock->flags &= ~SOCKMAYTELNET;
3072 place--;
3073 rawchar = xsock->fsastate;
3074 goto non_telnet;
3075 }
3076
3077 if (!(xsock->flags & SOCKTELNET)) {
3078 /* We now know server groks TELNET */
3079 xsock->flags |= SOCKTELNET;
3080 preferred_telnet_options();
3081 }
3082 continue; /* avoid non-telnet processing */
3083
3084 } else if (xsock->fsastate == TN_SB) {
3085 if (xsock->subbuffer->len > 255) {
3086 /* It shouldn't take this long; server is broken. Abort. */
3087 SStringcat(xsock->buffer, CS(xsock->subbuffer));
3088 Stringtrunc(xsock->subbuffer, 0);
3089 } else if (xsock->substate == TN_IAC) {
3090 if (rawchar == TN_SE) {
3091 Sappendf(xsock->subbuffer, "%c%c", TN_IAC, TN_SE);
3092 xsock->fsastate = '\0';
3093 telnet_subnegotiation();
3094 } else {
3095 Stringadd(xsock->subbuffer, rawchar);
3096 xsock->substate = '\0';
3097 }
3098 } else if (rawchar == TN_IAC) {
3099 xsock->substate = TN_IAC;
3100 } else {
3101 Stringadd(xsock->subbuffer, rawchar);
3102 xsock->substate = '\0';
3103 #if HAVE_MCCP /* hack for broken MCCPv1 subnegotiation */
3104 if (xsock->subbuffer->len == 5 &&
3105 memcmp(xsock->subbuffer->data, mccp1_subneg, 5) == 0)
3106 {
3107 xsock->fsastate = '\0';
3108 telnet_subnegotiation();
3109 }
3110 #endif
3111 }
3112 #if HAVE_MCCP
3113 if (xsock->flags & SOCKCOMPRESS && !xsock->zstream) {
3114 /* compression was just enabled. */
3115 xsock->zstream = new_zstream();
3116 if (!xsock->zstream) {
3117 zombiesock(xsock);
3118 } else {
3119 xsock->zstream->next_in = (Bytef*)++place;
3120 xsock->zstream->avail_in = count - (place - buffer);
3121 }
3122 count = 0; /* abort the buffer scan */
3123 }
3124 #endif
3125 continue; /* avoid non-telnet processing */
3126
3127 } else if (xsock->fsastate == TN_WILL) {
3128 xsock->fsastate = '\0';
3129 telnet_recv(TN_WILL, rawchar);
3130 if (TELOPT(xsock, them, rawchar)) { /* already there, ignore */
3131 no_reply("option was already agreed on");
3132 CLR_TELOPT(xsock, them_tog, rawchar);
3133 } else if (
3134 #if 0 /* many servers think DO SGA means character-at-a-time mode */
3135 rawchar == TN_SGA ||
3136 #endif
3137 #if HAVE_MCCP
3138 (rawchar == TN_COMPRESS && mccp) ||
3139 (rawchar == TN_COMPRESS2 && mccp) ||
3140 #endif
3141 rawchar == TN_ECHO ||
3142 rawchar == TN_SEND_EOR ||
3143 rawchar == TN_BINARY) /* accept any of these */
3144 {
3145 SET_TELOPT(xsock, them, rawchar); /* set state */
3146 if (TELOPT(xsock, them_tog, rawchar)) {/* we requested it */
3147 CLR_TELOPT(xsock, them_tog, rawchar); /* done */
3148 } else {
3149 DO(rawchar); /* acknowledge their request */
3150 }
3151 } else {
3152 DONT(rawchar); /* refuse their request */
3153 }
3154 continue; /* avoid non-telnet processing */
3155
3156 } else if (xsock->fsastate == TN_WONT) {
3157 xsock->fsastate = '\0';
3158 telnet_recv(TN_WONT, rawchar);
3159 if (!TELOPT(xsock, them, rawchar)) { /* already there, ignore */
3160 no_reply("option was already agreed on");
3161 CLR_TELOPT(xsock, them_tog, rawchar);
3162 } else {
3163 CLR_TELOPT(xsock, them, rawchar); /* set state */
3164 if (TELOPT(xsock, them_tog, rawchar)) { /* we requested */
3165 CLR_TELOPT(xsock, them_tog, rawchar); /* done */
3166 } else {
3167 DONT(rawchar); /* acknowledge their request */
3168 }
3169 }
3170 continue; /* avoid non-telnet processing */
3171
3172 } else if (xsock->fsastate == TN_DO) {
3173 xsock->fsastate = '\0';
3174 telnet_recv(TN_DO, rawchar);
3175 if (TELOPT(xsock, us, rawchar)) { /* already there, ignore */
3176 no_reply("option was already agreed on");
3177 CLR_TELOPT(xsock, them_tog, rawchar);
3178 } else if (
3179 rawchar == TN_NAWS ||
3180 rawchar == TN_TTYPE ||
3181 rawchar == TN_BINARY)
3182 {
3183 SET_TELOPT(xsock, us, rawchar); /* set state */
3184 if (TELOPT(xsock, us_tog, rawchar)) { /* we requested it */
3185 CLR_TELOPT(xsock, us_tog, rawchar); /* done */
3186 } else {
3187 WILL(rawchar); /* acknowledge their request */
3188 }
3189 if (rawchar == TN_NAWS) do_naws(xsock);
3190 } else {
3191 WONT(rawchar); /* refuse their request */
3192 }
3193 continue; /* avoid non-telnet processing */
3194
3195 } else if (xsock->fsastate == TN_DONT) {
3196 xsock->fsastate = '\0';
3197 telnet_recv(TN_DONT, rawchar);
3198 if (!TELOPT(xsock, us, rawchar)) { /* already there, ignore */
3199 no_reply("option was already agreed on");
3200 CLR_TELOPT(xsock, us_tog, rawchar);
3201 } else {
3202 CLR_TELOPT(xsock, us, rawchar); /* set state */
3203 if (TELOPT(xsock, us_tog, rawchar)) { /* we requested */
3204 CLR_TELOPT(xsock, us_tog, rawchar); /* done */
3205 } else {
3206 WONT(rawchar); /* acknowledge their request */
3207 }
3208 }
3209 continue; /* avoid non-telnet processing */
3210
3211 } else if (rawchar == TN_IAC &&
3212 xsock->flags & (SOCKTELNET | SOCKMAYTELNET))
3213 {
3214 xsock->fsastate = rawchar;
3215 continue; /* avoid non-telnet processing */
3216 }
3217
3218 /* non-telnet processing*/
3219 non_telnet:
3220 if (rawchar == '\n') {
3221 /* Complete line received. Queue it. */
3222 queue_socket_line(xsock, CS(xsock->buffer), 0, 0);
3223 Stringtrunc(xsock->buffer, 0);
3224 xsock->fsastate = rawchar;
3225
3226 } else if (emulation == EMUL_DEBUG) {
3227 if (localchar != rawchar)
3228 Stringcat(xsock->buffer, "M-");
3229 if (is_print(localchar))
3230 Stringadd(xsock->buffer, localchar);
3231 else {
3232 Stringadd(xsock->buffer, '^');
3233 Stringadd(xsock->buffer, CTRL(localchar));
3234 }
3235 xsock->fsastate = '\0';
3236
3237 } else if (rawchar == '\r' || rawchar == '\0') {
3238 /* Ignore CR and NUL. */
3239 xsock->fsastate = rawchar;
3240
3241 } else if (rawchar == '\b' && emulation >= EMUL_PRINT &&
3242 xsock->fsastate == '*')
3243 {
3244 /* "*\b" is an LP editor prompt. */
3245 queue_socket_line(xsock, CS(xsock->buffer), 0, F_SERVPROMPT);
3246 Stringtrunc(xsock->buffer, 0);
3247 xsock->fsastate = '\0';
3248 /* other occurances of '\b' are handled by decode_ansi(), so
3249 * ansi codes aren't clobbered before they're interpreted */
3250
3251 } else {
3252 /* Normal character. */
3253 const char *end;
3254 Stringadd(xsock->buffer, localchar);
3255 end = ++place;
3256 /* Quickly skip characters that can't possibly be special. */
3257 while (is_print(*end) && *end != TN_IAC && end - buffer < count)
3258 end++;
3259 Stringfncat(xsock->buffer, (char*)place, end - place);
3260 place = end - 1;
3261 xsock->fsastate = (*place == '*') ? '*' : '\0';
3262 }
3263 }
3264
3265 /* See if anything arrived while we were parsing */
3266
3267 received += count;
3268
3269 #if HAVE_MCCP
3270 /* If there's still un-inflated stuff, we must process it before we
3271 * exit this loop.
3272 */
3273 if (xsock->zstream && xsock->zstream->avail_in) {
3274 n = xsock->zstream->avail_in;
3275 continue;
3276 }
3277 #endif
3278
3279 if (simbuffer || received > SPAM) break; /* after uninflated check */
3280
3281 FD_ZERO(&readfds);
3282 FD_SET(xsock->fd, &readfds);
3283 timeout = tvzero; /* don't use tvzero directly, select may modify it */
3284 if ((n = select(xsock->fd + 1, &readfds, NULL, NULL, &timeout)) < 0) {
3285 if (errno != EINTR) die("handle_socket_input: select", errno);
3286 }
3287
3288 if (interrupted()) break;
3289
3290 } while (n > 0);
3291
3292 test_prompt();
3293
3294 return received;
3295 }
3296
3297
is_quiet(const char * str)3298 static int is_quiet(const char *str)
3299 {
3300 if (!xsock->numquiet) return 0;
3301 if (!--xsock->numquiet) return 1;
3302 /* This should not be hard coded. */
3303 if ((strncmp("Use the WHO command", str, 19) == 0) ||
3304 (strcmp("### end of messages ###", str) == 0))
3305 xsock->numquiet = 0;
3306 return 1;
3307 }
3308
is_bamf(const char * str)3309 static int is_bamf(const char *str)
3310 {
3311 smallstr name, host, port;
3312 STATIC_BUFFER(buffer);
3313 World *world;
3314 Sock *callingsock; /* like find_and_run_matches(), we must restore xsock */
3315
3316 callingsock = xsock;
3317
3318 if (!bamf || restriction >= RESTRICT_WORLD) return 0;
3319 if (sscanf(str,
3320 "#### Please reconnect to %64[^ @]@%64s (%*64[^ )]) port %64s ####",
3321 name, host, port) != 3)
3322 return 0;
3323
3324 Stringtrunc(buffer, 0);
3325 if (bamf == BAMF_UNTER) Stringadd(buffer, '@');
3326 Stringcat(buffer, name);
3327 if (!(world = find_world(buffer->data))) {
3328 if (bamf == BAMF_UNTER && xsock) {
3329 world = new_world(buffer->data, xsock->world->type,
3330 host, port, xsock->world->character, xsock->world->pass,
3331 xsock->world->mfile, WORLD_TEMP, xsock->world->myhost);
3332 } else {
3333 world = new_world(buffer->data,"",host,port,"","","",WORLD_TEMP,"");
3334 }
3335 }
3336
3337 do_hook(H_BAMF, "%% Bamfing to %s", "%s", name);
3338 if (bamf == BAMF_UNTER && xsock) killsock(xsock);
3339 if (!opensock(world, CONN_AUTOLOGIN))
3340 eputs("% Connection through portal failed.");
3341 xsock = callingsock;
3342 return 1;
3343 }
3344
do_naws(Sock * sock)3345 static void do_naws(Sock *sock)
3346 {
3347 unsigned int width, height, i;
3348 UCHAR octet[4];
3349 Sock *old_xsock;
3350
3351 width = (emulation != EMUL_RAW && wrapflag && wrapsize) ?
3352 wrapsize : columns;
3353 height = winlines() + !visual;
3354
3355 Sprintf(telbuf, "%c%c%c", TN_IAC, TN_SB, TN_NAWS);
3356 octet[0] = (width >> 8);
3357 octet[1] = (width & 0xFF);
3358 octet[2] = (height >> 8);
3359 octet[3] = (height & 0xFF);
3360 for (i = 0; i < 4; i++) {
3361 if (octet[i] == (UCHAR)TN_IAC) Stringadd(telbuf, TN_IAC);
3362 Stringadd(telbuf, octet[i]);
3363 }
3364 Sappendf(telbuf, "%c%c", TN_IAC, TN_SE);
3365
3366 old_xsock = xsock;;
3367 xsock = sock;
3368 telnet_send(telbuf);
3369 xsock = old_xsock;
3370 }
3371
telnet_debug(const char * dir,const char * str,int len)3372 static void telnet_debug(const char *dir, const char *str, int len)
3373 {
3374 String *buffer;
3375 int state;
3376
3377 if (telopt) {
3378 buffer = Stringnew(NULL, 0, 0);
3379 Sprintf(buffer, "%% %s:", dir);
3380 if (len == 0)
3381 Stringcat(buffer, str);
3382 else {
3383 for (state = 0; len; len--, str++) {
3384 if (*str == TN_IAC || state == TN_IAC || state == TN_SB ||
3385 state == TN_WILL || state == TN_WONT ||
3386 state == TN_DO || state == TN_DONT)
3387 {
3388 if (telnet_label[(UCHAR)*str])
3389 Sappendf(buffer, " %s", telnet_label[(UCHAR)*str]);
3390 else
3391 Sappendf(buffer, " %d", (unsigned int)*str);
3392 state = *str;
3393 } else if (state == TN_TTYPE) {
3394 if (*str == (char)0) {
3395 Stringcat(buffer, " IS \"");
3396 while (len--, str++, is_print(*str) && !(*str & 0x80))
3397 Stringadd(buffer, *str);
3398 Stringadd(buffer, '\"');
3399 len++, str--;
3400 } else if (*str == (char)1) {
3401 Stringcat(buffer, " SEND");
3402 }
3403 state = 0;
3404 } else {
3405 Sappendf(buffer, " %u", (unsigned char)*str);
3406 state = 0;
3407 }
3408 }
3409 }
3410 nolog++;
3411 /* norecord++; */
3412 world_output(xsock->world, CS(buffer));
3413 /* norecord--; */
3414 nolog--;
3415 }
3416 }
3417
telnet_send(String * cmd)3418 static void telnet_send(String *cmd)
3419 {
3420 transmit(cmd->data, cmd->len);
3421 telnet_debug("sent", cmd->data, cmd->len);
3422 }
3423
local_echo(int flag)3424 int local_echo(int flag)
3425 {
3426 if (flag < 0)
3427 return sockecho();
3428 if (!xsock || !(xsock->flags & SOCKTELNET))
3429 return 0;
3430
3431 if (flag != sockecho()) {
3432 /* request a change */
3433 SET_TELOPT(xsock, them_tog, TN_ECHO);
3434 if (flag)
3435 DONT(TN_ECHO);
3436 else
3437 DO(TN_ECHO);
3438 }
3439 return 1;
3440 }
3441
3442
transmit_window_size(void)3443 void transmit_window_size(void)
3444 {
3445 Sock *sock;
3446
3447 for (sock = hsock; sock; sock = sock->next)
3448 if (TELOPT(sock, us, TN_NAWS))
3449 do_naws(sock);
3450 }
3451
preferred_telnet_options(void)3452 static void preferred_telnet_options(void)
3453 {
3454 SET_TELOPT(xsock, us_tog, TN_NAWS);
3455 WILL(TN_NAWS);
3456 #if 0
3457 SET_TELOPT(xsock, us_tog, TN_BINARY);
3458 WILL(TN_BINARY); /* allow us to send 8-bit data */
3459 SET_TELOPT(xsock, them_tog, TN_BINARY);
3460 DO(TN_BINARY); /* allow server to send 8-bit data */
3461 #endif
3462 }
3463
3464 /* Find the named world (current world if name is blank) or print an error */
named_or_current_world(const char * name)3465 World *named_or_current_world(const char *name)
3466 {
3467 World *world;
3468 if (!(world = (*name) ? find_world(name) : xworld())) {
3469 eprintf("No world %s", name);
3470 }
3471 return world;
3472 }
3473
world_info(const char * worldname,const char * fieldname)3474 const char *world_info(const char *worldname, const char *fieldname)
3475 {
3476 World *world;
3477 const char *result;
3478
3479 world = worldname ? find_world(worldname) : xworld();
3480 if (!world) return ""; /* not an error */
3481
3482 if (!fieldname || strcmp("name", fieldname) == 0) {
3483 result = world->name;
3484 } else if (strcmp("type", fieldname) == 0) {
3485 result = world_type(world);
3486 } else if (strcmp("character", fieldname) == 0) {
3487 result = world_character(world);
3488 } else if (strcmp("password", fieldname) == 0) {
3489 result = world_pass(world);
3490 } else if (strcmp("host", fieldname) == 0) {
3491 result = worldname ? world->host : world->sock->host;
3492 } else if (strcmp("port", fieldname) == 0) {
3493 result = worldname ? world->port : world->sock->port;
3494 } else if (strcmp("mfile", fieldname) == 0) {
3495 result = world_mfile(world);
3496 } else if (strcmp("login", fieldname) == 0) {
3497 result = world->sock && world->sock->flags & SOCKLOGIN ? "1" : "0";
3498 } else if (strcmp("proxy", fieldname) == 0) {
3499 result = world->sock && world->sock->flags & SOCKPROXY ? "1" : "0";
3500 } else if (strcmp("src", fieldname) == 0) {
3501 result = worldname ? world->myhost : world->sock->myhost;
3502 } else if (strcmp("cipher", fieldname) == 0) {
3503 result =
3504 #if HAVE_SSL
3505 (world->sock && world->sock->ssl) ?
3506 SSL_get_cipher_name(world->sock->ssl) :
3507 #endif
3508 "";
3509 } else return NULL;
3510 return result ? result : "";
3511 }
3512
is_open(const char * worldname)3513 int is_open(const char *worldname)
3514 {
3515 World *w;
3516
3517 if (!worldname || !*worldname) {
3518 if (!xsock) return 0;
3519 w = xsock->world;
3520 } else if (!(w = find_world(worldname))) {
3521 return 0;
3522 }
3523 return (w->sock && (w->sock->constate >= SS_CONNECTED) &&
3524 (w->sock->constate < SS_ZOMBIE));
3525 }
3526
is_connected(const char * worldname)3527 int is_connected(const char *worldname)
3528 {
3529 World *w;
3530
3531 if (!worldname || !*worldname) {
3532 if (!xsock) return 0;
3533 w = xsock->world;
3534 } else if (!(w = find_world(worldname))) {
3535 return 0;
3536 }
3537 return (w->sock && (w->sock->constate == SS_CONNECTED));
3538 }
3539
nactive(const char * worldname)3540 int nactive(const char *worldname)
3541 {
3542 World *w;
3543
3544 if (!worldname || !*worldname)
3545 return active_count;
3546 if (!(w = find_world(worldname)) || !w->sock)
3547 return 0;
3548 return w->screen->active ? w->screen->nnew : 0;
3549 }
3550
3551