1 char *cknetv = "Network support, 8.0.283, 7 Feb 2004";
3 /* C K C N E T -- Network support */
6 Copyright (C) 1985, 2004,
7 Trustees of Columbia University in the City of New York.
8 All rights reserved. See the C-Kermit COPYING.TXT file or the
9 copyright text in the ckcmai.c module for disclaimer and permissions.
13 REMINDER: Any changes made to this file that other modules depend must
14 also be made to cklnet.c (for VOS) until such time as cklnet.c and this
15 module are merged back together.
17 NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
18 C-Kermit source files, must be compatible with C preprocessors that support
19 only #ifdef, #else, #endif, #define, and #undef. Please do not use #if,
20 logical operators, or other preprocessor features in this module. Also,
21 don't use any ANSI C constructs except within #ifdef CK_ANSIC..#endif.
25 Frank da Cruz (fdc@columbia.edu),
26 Columbia University Academic Information Systems, New York City.
27 Jeffrey E Altman (jaltman@secure-endpoints.com) -- Primary
28 maintainer/developer since about 1996.
29 netopen() routine for TCP/IP originally by Ken Yap, Rochester University
30 (ken@cs.rochester.edu) (no longer at that address).
31 Missing pieces for Excelan sockets library from William Bader.
32 Telnet protocol by Frank da Cruz and Jeffrey Altman.
33 Rlogin protocol by Jeffrey E Altman.
34 SSL support adapted by Jeffrey E Altman from work done by
35 Tim Hudson <tjh@cryptosoft.com> +61 7 32781581
36 TLS support by Jeffrey E Altman.
37 HTTP support by Jeffrey E Altman.
38 TGV MultiNet code by Frank da Cruz.
39 MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
40 MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
41 TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
42 CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
43 X.25 support by Marcello Frutig, Catholic University,
44 Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from
45 Stefaan Eeckels, Eurokom, Luxembourg.
46 David Lane added support for Stratus VOS X.25 1996.
47 Stephen Riehm added support for IBM AIX X.25 in April 1998.
48 Other contributions as indicated in the code.
55 #ifdef I386IX /* Has to come before ckcnet.h in */
56 #include <errno.h> /* this version, but after in others */
58 #include "ckcnet.h" /* which includes ckctel.h */
68 /* !Error OS/2 does not support DNS Service Records. */
71 #include <arpa/inet.h>
72 #ifdef USE_NAMESER_COMPAT
73 #include <arpa/nameser_compat.h>
74 #endif /* USE_NAMESER_COMPAT */
75 #include <arpa/nameser.h>
94 /* for old Unixes and friends ... */
95 #ifndef MAXHOSTNAMELEN
96 #define MAXHOSTNAMELEN 64
97 #endif /* MAXHOSTNAMELEN */
99 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
100 #endif /* CK_DNS_SRV */
105 #endif /* TCPIPLIB */
114 #endif /* HPUX5WINTCP */
115 #endif /* datageneral */
116 #endif /* NOMHHOST */
119 struct in_addr inaddrx;
122 int ttnet = NET_NONE; /* Network type */
123 int ttnproto = NP_DEFAULT; /* Network virtual terminal protocol */
125 /* 0 = don't lowercase username for Rlogin/Telnet protocol */
126 /* nonzero = do lowercase it. Add a SET command if necessary... */
133 extern int /* External variables */
134 duplex, debses, seslog, sessft, wasclosed,
135 ttyfd, quiet, msgflg, what, nettype, ttmdm;
140 char myipaddr[20] = { '\0' }; /* Global copy of my IP address */
143 /* Don't need any of this if there is no network support. */
146 NETLEBUF is (must be) defined for those platforms that call this
147 module to do network i/o (e.g. netinc(), nettchk(), etc) rather
148 than doing it themselves (ttinc(), ttchk(), etc). In this case
149 the Telnet local-echo buffers and routines are defined and referenced
150 here, rather than in the ck?tio.c module.
153 #define LEBUFSIZ 4096
154 int ttpush = -1, le_data = 0; /* These are seen from outside */
155 static CHAR le_buf[LEBUFSIZ]; /* These are used internally */
156 static int le_start = 0, le_end = 0;
157 int tt_push_inited = 0;
158 #endif /* NETLEBUF */
160 #ifdef CK_SOCKS /* SOCKS Internet relay package */
161 #ifdef CK_SOCKS5 /* SOCKS 5 */
162 #define accept SOCKSaccept
163 #define bind SOCKSbind
164 #define connect SOCKSconnect
165 #define getsockname SOCKSgetsockname
166 #define listen SOCKSlisten
167 #else /* Not SOCKS 5 */
168 #define accept Raccept
170 #define connect Rconnect
171 #define getsockname Rgetsockname
172 #define listen Rlisten
173 #endif /* CK_SOCKS5 */
174 #endif /* CK_SOCKS */
179 #endif /* DEC_TCPIP */
181 /* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
184 #ifndef HPUX7 /* HPUX 7.00 doesn't have it */
185 #include <arpa/inet.h> /* For inet_ntoa() prototype */
191 #endif /* CMU_TCPIP */
194 #ifdef DCLTIMEVAL /* UnixWare 7 */
195 struct timeval { /* And define these ourselves. */
196 long tv_sec; /* (see comments in ckutio.c) */
203 #endif /* DCLTIMEVAL */
204 #endif /* NODCLTIMEVAL */
210 #include <sys/time.h>
212 The WIN/TCP code path is the same as that for MultiNet.
213 Only the routine names have changed ...
215 #define socket_read netread
216 #define socket_ioctl ioctl
217 #define socket_write netwrite
218 #define socket_close netclose
220 #ifdef OLD_TWG /* some routines have evolved */
221 extern int vmserrno, uerrno;
222 #define socket_errno uerrno
223 #define socket_perror perror /* which uses errno, not uerrno! */
225 #define socket_errno errno
226 #define socket_perror win$perror
229 #else /* Not WINTCP */
235 #endif /* _NO_PROTO */
236 #endif /* CK_ANSIC */
240 #include <errno.h> /* Already included above */
243 #include <signal.h> /* Everybody needs this */
245 #ifdef ZILOG /* Zilog has different name for this */
253 #ifdef datageneral /* Data General AOS/VS */
254 #include <:usr:include:vs_tcp_errno.h>
255 #include <:usr:include:sys:vs_tcp_types.h>
258 NOTE: This can be compiled and linked OK with SELECT defined
259 but it doesn't work at all. Anybody who cares and knows how
260 to fix it, feel free.
262 #include <:usr:include:sys:vs_tcp_time.h>
264 #include <:usr:include:sys:socket.h>
265 #include <:usr:include:netinet:in.h>
266 #include <:usr:include:netdb.h>
267 #endif /* datageneral */
270 #define socket_errno errno
271 #endif /* socket_errno */
277 int tcp_rdns = /* Reverse DNS lookup */
279 SET_OFF /* Doesn't seem to work in UCX */
282 #endif /* DEC_TCPIP */
285 int tcp_dns_srv = SET_OFF;
286 #endif /* CK_DNS_SRV */
288 _PROTOTYP( char * cmcvtdate, (char *, int) );
291 _PROTOTYP( int rlog_ctrl, (CHAR *, int) );
292 _PROTOTYP( static int rlog_oob, (CHAR *, int) );
294 _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
295 #endif /* TCPIPLIB */
296 _PROTOTYP( static int rlog_ini, (CHAR *, int,
297 struct sockaddr_in *,
298 struct sockaddr_in *) );
299 int rlog_mode = RL_COOKED;
300 int rlog_stopped = 0;
302 #endif /* RLOGCODE */
305 extern int doconx; /* CONNECT-class command active */
309 /* This variable should probably be generalised for true client/server
310 * support - ie: the fd of the listening server, accepted calls should
311 * be forked or at least handled via a second fd (for IBM's X.25 -
312 * ttyfd always holds the active fd - ie the server becomes inactive
313 * as long as a client is connected, and becomes active again when the
314 * connection is closed)
316 int x25serverfd = 0; /* extern in ckcnet.h */
317 int x25seqno = 0; /* Connection sequence number */
318 int x25lastmsg = -1; /* A cheapskate's state table */
320 #define X25_CLOSED 0 /* Default state: no connection, no STREAM */
321 #define X25_SETUP 1 /* X.25 has been set up (no connection) */
322 #define X25_CONNECTED 2 /* X.25 connection has been established */
323 int x25_state = X25_CLOSED; /* Default state */
330 #ifdef CK_NAWS /* Negotiate About Window Size */
332 _PROTOTYP( int rlog_naws, (void) );
333 #endif /* RLOGCODE */
336 #ifdef OS2 /* For terminal type name string */
343 extern int tt_type, max_tt;
344 extern struct tt_info_rec tt_info[];
345 extern char ttname[];
347 #ifdef CK_AUTHENTICATION
349 #endif /* CK_AUTHENTICATION */
353 extern int winsock_version;
356 #ifdef CK_AUTHENTICATION
358 #endif /* CK_AUTHENTICATION */
362 #ifndef OS2 /* For timeout longjumps */
363 static ckjmpbuf njbuf;
366 #define NAMECPYL 1024 /* Local copy of hostname */
367 char namecopy[NAMECPYL]; /* Referenced by ckctel.c */
368 char namecopy2[NAMECPYL]; /* Referenced by ckctel.c */
370 char http_host_port[NAMECPYL]; /* orig host/port necessary for http */
371 char http_ip[20] = { '\0' }; /* ip address of host */
374 char * http_agent = 0;
375 int httpfd = -1; /* socket for http connections */
377 #define HTTPBUFLEN 1024
378 char http_reply_str[HTTPBUFLEN] = "";
381 char ipaddr[20] = { '\0' }; /* Global copy of IP address */
382 unsigned long myxipaddr = 0L; /* Ditto as a number */
385 char *tcp_address = NULL; /* Preferred IP Address */
386 extern char uidbuf[]; /* User ID buffer */
387 extern char pwbuf[]; /* Password buffer */
390 char * tcp_http_proxy = NULL; /* Name[:port] of http proxy server */
391 int tcp_http_proxy_errno = 0;
392 char * tcp_http_proxy_user = NULL;
393 char * tcp_http_proxy_pwd = NULL;
394 char * tcp_http_proxy_agent = NULL;
395 #define HTTPCPYL 1024
396 static char proxycopy[HTTPCPYL];
400 extern int tt_rows[], tt_cols[];
401 extern int tt_status[VNUM];
403 extern int tt_rows, tt_cols; /* Everybody has this */
406 extern int cmd_cols, cmd_rows;
408 #ifdef STREAMING /* Use blocking writes for streaming */
409 extern int streaming;
410 #endif /* STREAMING */
413 extern int WSASafeToCancel;
414 int win95selectbug = 0; /* For TCP/IP stacks whose select() */
415 /* always fails on write requests such as Cisco and Quarterdeck */
416 #define stricmp _stricmp
421 /* Skip all this if NOTCPOPTS specified. */
426 int tcp_nodelay = 0; /* Nagle algorithm TCP_NODELAY */
427 #endif /* TCP_NODELAY */
430 int tcp_dontroute = 0;
431 #endif /* SO_DONTROUTE */
434 int tcp_linger = 0; /* SO_LINGER */
435 int tcp_linger_tmo = 0; /* SO_LINGER timeout */
436 #endif /* SO_LINGER */
438 #ifdef HPUX /* But the data structures */
439 #ifndef HPUX8 /* needed for linger are not */
440 #ifndef HPUX9 /* defined in HP-UX versions */
441 #ifndef HPUX10 /* prior to 8.00. */
444 #endif /* SO_LINGER */
450 #ifndef SO_OOBINLINE /* Hopefully only HP-UX 7.0 */
451 #define SO_OOBINLINE 0x0100
452 #endif /* SO_OOBINLINE */
457 #define TCPSNDBUFSIZ 16384
460 #endif /* TCPSNDBUFSIZ */
463 #define TCPSNDBUFSIZ -1
464 #endif /* TCPSNDBUFSIZ */
467 int tcp_sendbuf = TCPSNDBUFSIZ;
468 #endif /* SO_SNDBUF */
471 int tcp_recvbuf = -1;
472 #endif /* SO_RCVBUF */
475 int tcp_keepalive = 1;
476 #endif /* SO_KEEPALIVE */
478 #endif /* SOL_SOCKET */
479 #endif /* NOTCPOPTS */
483 Network support not defined.
484 Dummy functions here in case #ifdef's forgotten elsewhere.
486 int /* Open network connection */
487 netopen(name, lcl, nett) char *name; int *lcl, nett; {
490 int /* Close network connection */
494 int /* Check network input buffer */
498 int /* Flush network input buffer */
502 int /* Send network BREAK */
506 int /* Input character from network */
507 netinc(timo) int timo; {
510 int /* Output character to network */
515 #endif /* CK_ANSIC */
520 nettol(s,n) CHAR *s; int n; {
524 #else /* NETCONN is defined (much of this module...) */
528 le_init() { /* LocalEchoInit() */
530 for (i = 0; i < LEBUFSIZ; i++)
539 le_clean() { /* LocalEchoCleanup() */
547 if (le_start != le_end) {
550 LEBUFSIZ) % LEBUFSIZ;
559 le_putchar(ch) CHAR ch;
560 #endif /* CK_ANSIC */
562 if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
563 debug(F110,"le_putchar","buffer is full",0);
566 le_buf[le_end++] = ch;
567 if (le_end == LEBUFSIZ)
575 le_puts(CHAR * s, int n)
577 le_puts(s,n) CHAR * s; int n;
578 #endif /* CK_ANSIC */
582 CHAR * p = (CHAR *)"le_puts";
584 for (i = 0; i < n; i++)
585 rc = le_putchar((char)s[i]);
586 debug(F101,"le_puts","",rc);
594 le_putstr(s) CHAR * s;
595 #endif /* CK_ANSIC */
599 p = (CHAR *)"le_putstr";
600 hexdump(p,s,(int)strlen((char *)s));
601 for (p = s; *p && !rc; p++)
608 le_getchar(CHAR * pch)
610 le_getchar(pch) CHAR * pch;
611 #endif /* CK_ANSIC */
614 if (le_start != le_end) {
615 *pch = le_buf[le_start];
616 le_buf[le_start] = 0;
619 if (le_start == LEBUFSIZ)
622 if (le_start == le_end) {
631 #endif /* NETLEBUF */
635 In edit 190, we moved tn_ini() to be called from within netopen().
636 But tn_ini() calls ttol(), and ttol() checks to see if it's a net
637 connection, but the flag for that isn't set until after netopen()
638 is finished. Since, in this module, we are always doing network
639 output anyway, we just call nettol() directly, instead of going thru
640 ttol(). Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
641 net connections just like regular connections in ttol(), and OS/2
642 has a special routine for this.
651 char * krb5_d_principal = NULL; /* Default principal */
652 char * krb5_d_instance = NULL; /* Default instance */
653 char * krb5_d_realm = NULL; /* Default realm */
654 char * krb5_d_cc = NULL; /* Default credentials cache */
655 char * krb5_d_srv = NULL; /* Default Service */
656 int krb5_d_lifetime = 600; /* Default lifetime (10 hours) */
657 int krb5_d_forwardable = 0; /* creds not forwardable */
658 int krb5_d_proxiable = 0; /* creds not proxiable */
659 int krb5_d_renewable = 0; /* creds not renewable (0 min) */
660 int krb5_autoget = 1; /* Autoget TGTs */
661 int krb5_autodel = 0; /* Auto delete TGTs */
662 int krb5_d_getk4 = 0; /* K5 Kinit gets K4 TGTs */
663 int krb5_checkaddrs = 1; /* Check TGT Addrs */
664 int krb5_d_no_addresses = 0; /* Do not include IP Addresses */
665 char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
666 int krb5_errno = 0; /* Last K5 errno */
667 char * krb5_errmsg = NULL; /* Last K5 errmsg */
668 char * k5_keytab = NULL;
670 char * krb4_d_principal = NULL; /* Default principal */
671 char * krb4_d_realm = NULL; /* Default realm */
672 char * krb4_d_srv = NULL; /* Default Service */
673 int krb4_d_lifetime = 600; /* Default lifetime (10 hours) */
674 int krb4_d_preauth = 1; /* Use preauth requests */
675 char * krb4_d_instance = NULL; /* Default instance */
676 int krb4_autoget = 1; /* Autoget TGTs */
677 int krb4_autodel = 0; /* Auto delete TGTs */
678 int krb4_checkaddrs = 1; /* Check TGT Addrs */
679 char * k4_keytab = NULL;
681 int krb4_errno = 0; /* Last K4 errno */
682 char * krb4_errmsg = NULL; /* Last K4 errmsg */
684 struct krb_op_data krb_op = { /* Operational data structure */
685 0, NULL /* (version, cachefile) */
688 struct krb4_init_data krb4_init = { /* Kerberos 4 INIT data structure */
689 0, NULL, NULL, NULL, NULL
692 struct krb5_init_data krb5_init = { /* Kerberos 5 INIT data structure */
693 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
694 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
695 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
699 struct krb5_list_cred_data krb5_lc = { /* List Credentials data structure */
703 int krb_action = -1; /* Kerberos action to perform */
705 #ifndef CK_AUTHENTICATION
711 ck_krb5_getrealm(cc) char * cc; {
715 ck_krb4_getprincipal() {
719 ck_krb5_getprincipal(cc) char * cc; {
722 #endif /* CK_AUTHENTICATION */
724 /* I N I _ K E R B -- Initialize Kerberos data */
730 krb_action = -1; /* No action specified */
732 krb_op.version = 0; /* Kerberos version (none) */
733 krb_op.cache = NULL; /* Cache file (none) */
737 krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
738 krb5_init.proxiable = krb5_d_proxiable;
739 krb5_init.lifetime = krb5_d_lifetime;
741 krb5_init.renewable = krb5_d_renewable;
742 krb5_init.validate = 0;
743 krb5_init.no_addresses = krb5_d_no_addresses;
744 krb5_init.getk4 = krb5_d_getk4;
745 if (krb5_init.postdate) {
746 free(krb5_init.postdate);
747 krb5_init.postdate = NULL;
749 if (krb5_init.service) {
750 free(krb5_init.service);
751 krb5_init.service = NULL;
753 if (!krb5_d_cc || !krb5_d_cc[0]) { /* Set default cache */
755 p = ck_krb5_get_cc_name();
756 makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
758 if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
760 p = ck_krb5_getrealm(krb5_d_cc);
761 makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
763 makestr(&krb5_init.instance,krb5_d_instance);
764 makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
765 if (krb5_init.password) {
766 memset(krb5_init.password,0xFF,strlen(krb5_init.password));
767 free(krb5_init.password);
768 krb5_init.password = NULL;
770 if (!krb5_d_principal) { /* Default principal */
771 /* a Null principal indicates the user should be prompted */
772 char * p = ck_krb5_getprincipal(krb5_d_cc);
774 p = (char *)uidbuf; /* Principal = user */
775 makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
777 makestr(&krb5_init.principal,krb5_d_principal);
778 for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
779 if (krb5_init.addrs[i])
780 free(krb5_init.addrs[i]);
781 krb5_init.addrs[i] = NULL;
783 for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
784 makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
789 krb4_init.lifetime = krb4_d_lifetime;
790 krb4_init.preauth = krb4_d_preauth;
791 makestr(&krb4_init.instance,krb4_d_instance);
792 if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
794 p = ck_krb4_getrealm();
795 makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
797 makestr(&krb4_init.realm,krb4_d_realm);
798 if (krb4_init.password) {
799 memset(krb4_init.password,0xFF,strlen(krb4_init.password));
800 free(krb4_init.password);
801 krb4_init.password = NULL;
803 if (!krb4_d_principal) { /* Default principal */
804 /* a Null principal indicates the user should be prompted */
805 char * p = ck_krb4_getprincipal();
807 p = (char *)uidbuf; /* Principal = user */
808 makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
810 makestr(&(krb4_init.principal),krb4_d_principal);
813 /* D O A U T H -- AUTHENTICATE action routine */
816 doauth(cx) int cx; { /* AUTHENTICATE action routine */
817 int rc = 0; /* Return code */
819 #ifdef CK_AUTHENTICATION
821 if (!ck_security_loaddll()) /* Load various DLLs */
824 if (krb_op.version == 4) { /* Version = 4 */
826 sho_auth(AUTHTYPE_KERBEROS_V4);
828 if (!ck_krb4_is_installed()) {
829 printf("?Kerberos 4 is not installed\n");
832 switch (krb_action) { /* Perform V4 functions */
833 case KRB_A_IN: /* INIT */
834 rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
836 case KRB_A_DE: /* DESTROY */
837 rc |= !(ck_krb4_destroy(&krb_op) < 0);
839 case KRB_A_LC: /* LIST-CREDENTIALS */
840 rc |= !(ck_krb4_list_creds(&krb_op) < 0);
844 if (krb_op.version == 5) { /* V5 functions */
846 sho_auth(AUTHTYPE_KERBEROS_V5);
848 if (!ck_krb5_is_installed()) {
849 printf("?Kerberos 5 is not installed\n");
852 switch (krb_action) {
853 case KRB_A_IN: /* INIT */
854 rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
855 krb5_init.getk4 ? &krb4_init : 0) < 0);
857 case KRB_A_DE: /* DESTROY */
858 rc |= !(ck_krb5_destroy(&krb_op) < 0);
860 case KRB_A_LC: /* LIST-CREDENTIALS */
861 if (krb_op.version == 0)
863 rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
870 rc = sho_auth(0); /* Show all */
873 #endif /* CK_AUTHENTICATION */
876 #endif /* CK_KERBEROS */
880 #ifndef NOLISTEN /* For incoming connections */
884 #endif /* INADDR_ANY */
886 _PROTOTYP( int ttbufr, ( VOID ) );
887 _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
889 static unsigned short tcpsrv_port = 0;
891 #endif /* NOLISTEN */
894 static char svcbuf[80]; /* TCP service string */
895 static int svcnum = 0; /* TCP port number */
897 #endif /* TCPSOCKET */
900 TCPIPLIB means use separate socket calls for i/o, while on UNIX the
901 normal file system calls are used for TCP/IP sockets too.
902 Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
907 /* For buffered network reads... */
909 If the buffering code is written right, it shouldn't matter
910 how long this buffer is.
914 #define TTIBUFL 64240 /* 44 * 1460 (MSS) */
916 #define TTIBUFL 32120 /* 22 * 1460 (MSS) */
919 #define TTIBUFL 8191 /* Let's use 8K. */
922 CHAR ttibuf[TTIBUFL+1];
925 select() is used in preference to alarm()/signal(), but different systems
926 use different forms of select()...
928 #ifndef NOSELECT /* Option to override BSDSELECT */
931 Note: Although BELLV10 does have TCP/IP support, and does use the unique
932 form of select() that is evident in this module (and in ckutio.c), it does
933 not have a sockets library and so we can't build Kermit TCP/IP support for
934 it. For this, somebody would have to write TCP/IP streams code.
938 #define FD_SETSIZE 128
939 #endif /* FD_SETSIZE */
941 #ifdef WINTCP /* VMS with Wollongong WIN/TCP */
942 #ifndef OLD_TWG /* TWG 3.2 has only select(read) */
946 #ifdef CMU_TCPIP /* LIBCMU can do select */
952 #ifdef OS2 /* OS/2 with TCP/IP */
959 #endif /* DEC_TCPIP */
960 #endif /* CMU_TCPIP */
963 #endif /* NOSELECT */
965 Others (TGV, TCPware, ...) use alarm()/signal(). The BSDSELECT case does not
966 compile at all; the IBMSELECT case compiles and links but crashes at runtime.
967 NOTE: If any of these can be converted to select(), they should be for two
968 reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
969 their socket_read() calls to be interrupted; subsequent socket_read()'s tend
970 to fail with EBUSY. This happened in the UCX case before it was converted
975 static /* These are used in CKVTIO.C */
976 #endif /* VMS */ /* And in CKONET.C */
982 Read bytes from network into internal buffer ttibuf[].
983 To be called when input buffer is empty, i.e. when ttibn == 0.
985 Other network reading routines, like ttinc, ttinl, ttxin, should check the
986 internal buffer first, and call this routine for a refill if necessary.
988 Returns -1 on error, 0 if nothing happens. When data is read successfully,
989 returns number of bytes read, and sets global ttibn to that number and
990 ttibp (the buffer pointer) to zero.
992 _PROTOTYP( int ttbufr, ( VOID ) );
994 ttbufr() { /* TT Buffer Read */
997 if (ttnet != NET_TCPB) /* First make sure current net is */
998 return(-1); /* TCP/IP; if not, do nothing. */
1001 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1004 if (ttibn > 0) { /* Our internal buffer is not empty, */
1006 ReleaseTCPIPMutex();
1008 return(ttibn); /* so keep using it. */
1011 if (ttyfd == -1) { /* No connection, error */
1013 ReleaseTCPIPMutex();
1018 ttibp = 0; /* Else reset pointer to beginning */
1021 count = 512; /* This works for WIN/TCP */
1024 count = 512; /* UCX */
1028 #else /* Multinet, etc. */
1029 count = ttchk(); /* Check network input buffer, */
1030 if (ttibn > 0) { /* which can put a char there! */
1031 debug(F111,"ttbufr","ttchk() returns",count);
1033 ReleaseTCPIPMutex();
1037 if (count < 0) { /* Read error - connection closed */
1039 ReleaseTCPIPMutex();
1043 else if (count > TTIBUFL) /* Too many to read */
1045 else if (count == 0) /* None, so force blocking read */
1048 #endif /* DEC_TCPIP */
1050 debug(F101,"ttbufr count 1","",count);
1053 if (ssl_active_flag || tls_active_flag) {
1056 if (ssl_active_flag)
1057 count = SSL_read(ssl_con, ttibuf, count);
1059 count = SSL_read(tls_con, ttibuf, count);
1060 error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
1062 case SSL_ERROR_NONE:
1063 debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
1065 ttibp = 0; /* Reset buffer pointer. */
1068 ReleaseTCPIPMutex();
1070 return(ttibn); /* Return buffer count. */
1071 } else if (count < 0) {
1073 ReleaseTCPIPMutex();
1079 ReleaseTCPIPMutex();
1083 case SSL_ERROR_WANT_WRITE:
1084 debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
1086 ReleaseTCPIPMutex();
1089 case SSL_ERROR_WANT_READ:
1090 debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
1092 ReleaseTCPIPMutex();
1095 case SSL_ERROR_SYSCALL:
1096 if ( count == 0 ) { /* EOF */
1099 ReleaseTCPIPMutex();
1105 int gle = GetLastError();
1106 debug(F111,"ttbufr SSL_ERROR_SYSCALL",
1107 "GetLastError()",gle);
1108 rc = os2socketerror(gle);
1111 else if ( rc == -2 )
1115 ReleaseTCPIPMutex();
1119 case SSL_ERROR_WANT_X509_LOOKUP:
1120 debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
1123 ReleaseTCPIPMutex();
1127 if (bio_err!=NULL) {
1129 extern char ssl_err[];
1130 BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
1131 ERR_print_errors(bio_err);
1132 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
1133 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
1134 debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
1137 } else if (ssl_debug_flag) {
1138 debug(F100,"ttbufr SSL_ERROR_SSL","",0);
1140 fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
1141 ERR_print_errors_fp(stderr);
1145 #endif /* COMMENT */
1147 ReleaseTCPIPMutex();
1150 case SSL_ERROR_ZERO_RETURN:
1151 debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
1154 ReleaseTCPIPMutex();
1158 debug(F100,"ttbufr SSL_ERROR_?????","",0);
1161 ReleaseTCPIPMutex();
1170 This is for nonblocking reads, which we don't do any more. This code didn't
1171 work anyway, in the sense that a broken connection was never sensed.
1173 if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
1174 if (count == -1 && socket_errno == EWOULDBLOCK) {
1175 debug(F100,"ttbufr finds nothing","",0);
1177 ReleaseTCPIPMutex();
1181 debug(F101,"ttbufr socket_read error","",socket_errno);
1183 ReleaseTCPIPMutex();
1188 } else if (count == 0) {
1189 debug(F100,"ttbufr socket eof","",0);
1191 ReleaseTCPIPMutex();
1197 /* This is for blocking reads */
1204 if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
1211 FD_SET(ttyfd, &efds);
1212 tv.tv_sec = tv.tv_usec = 0L;
1213 debug(F100,"Out-of-Band BSDSELECT","",0);
1215 WSASafeToCancel = 1;
1217 if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
1218 FD_ISSET(ttyfd, &efds))
1221 WSASafeToCancel = 0;
1223 #else /* !BSDSELECT */
1225 /* Is used by OS/2 ... */
1226 /* ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set */
1227 /* and timeval stuff since this is the only place where it is used. */
1229 debug(F100,"Out-of-Band IBMSELECT","",0);
1230 if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
1232 #else /* !IBMSELECT */
1234 If we can't use select(), then we use the regular alarm()/signal()
1237 debug(F101,"Out-of-Band data not supported","",0);
1240 #endif /* IBMSELECT */
1241 #endif /* BSDSELECT */
1242 #endif /* BELLSELECT */
1244 /* Get the Urgent Data */
1245 /* if OOBINLINE is disabled this should be only a single byte */
1246 /* MS Winsock has a bug in Windows 95. Extra bytes are delivered */
1247 /* That were never sent. */
1249 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1251 count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
1253 ReleaseTCPIPMutex();
1256 int s_errno = socket_errno;
1257 debug(F101, "ttbufr socket_recv MSG_OOB","",count);
1258 debug(F101, "ttbufr socket_errno","",s_errno);
1260 if (count < 0 && (s_errno == 0 || s_errno == 23)) {
1261 /* These appear in OS/2 - don't know why */
1262 /* ignore it and read as normal data */
1263 /* and break, then we will attempt to read */
1264 /* the port using normal read() techniques */
1265 debug(F100,"ttbufr handing as in-band data","",0);
1268 netclos(); /* *** *** */
1270 ReleaseTCPIPMutex();
1275 netclos(); /* *** *** */
1277 ReleaseTCPIPMutex();
1280 #endif /* OS2ONLY */
1281 } else { /* we got out-of-band data */
1282 hexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
1285 #endif /* BETADEBUG */
1286 #ifdef RLOGCODE /* blah */
1287 if (ttnproto == NP_RLOGIN ||
1288 ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
1289 ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) &&
1294 When urgent data is read with MSG_OOB and not OOBINLINE
1295 then urgent data and normal data are not mixed. So
1296 treat the entire buffer as urgent data.
1298 rlog_oob(&ttibuf[ttibp+ttibn], count);
1300 ReleaseTCPIPMutex();
1304 #endif /* RLOGCODE */ /* blah */
1307 I haven't written this yet, nor do I know what it should do
1309 if (ttnproto == NP_TELNET) {
1312 ReleaseTCPIPMutex();
1316 #endif /* COMMENT */
1318 /* For any protocols we don't have a special out-of-band */
1319 /* handler for, just put the bytes in the normal buffer */
1322 ttibp += 0; /* Reset buffer pointer. */
1325 /* Got some bytes. */
1326 debug(F101,"ttbufr count 2","",count);
1328 ttibuf[ttibp+ttibn] = '\0';
1329 debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
1332 ReleaseTCPIPMutex();
1334 return(ttibn); /* Return buffer count. */
1339 #endif /* SO_OOBINLINE */
1342 count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
1344 int s_errno = socket_errno;
1345 debug(F101,"ttbufr socket_read","",count);
1346 debug(F101,"ttbufr socket_errno","",s_errno);
1348 if (count == 0 || os2socketerror(s_errno) < 0) {
1350 ReleaseTCPIPMutex();
1353 ReleaseTCPIPMutex();
1356 netclos(); /* *** *** */
1360 #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
1362 ttibp = 0; /* Reset buffer pointer. */
1365 debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
1367 ttibuf[ttibp+ttibn] = '\0';
1368 debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
1372 ReleaseTCPIPMutex();
1374 return(ttibn); /* Return buffer count. */
1377 #endif /* TCPIPLIB */
1381 #ifndef BSDSELECT /* Non-TCPIPLIB case */
1385 #endif /* BSDSELECT */
1386 #endif /* BELLSELECT */
1387 #endif /* IBMSELECT */
1389 #define TELNET_PORT 23 /* Should do lookup, but it won't change */
1390 #define RLOGIN_PORT 513
1391 #define KERMIT_PORT 1649
1392 #define KLOGIN_PORT 543
1393 #define EKLOGIN_PORT 2105
1397 C-Kermit network open/close functions for BSD-sockets.
1398 Much of this code shared by SunLink X.25, which also uses the socket library.
1401 /* N E T O P N -- Open a network connection. */
1404 name of host (or host:service),
1405 lcl - local-mode flag to be set if this function succeeds,
1406 network type - value defined in ckunet.h.
1411 ck_copyhostent(struct hostent * h)
1412 #else /* CK_ANSIC */
1413 ck_copyhostent(h) struct hostent * h;
1414 #endif /* CK_ANSIC */
1417 * The hostent structure is dynamic in nature.
1420 * char * * h_aliases;
1423 * char * * h_addr_list;
1424 * #define h_addr h_addr_list[0]
1426 #define HOSTENTCNT 5
1427 static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
1428 {NULL,NULL,0,0,NULL},
1429 {NULL,NULL,0,0,NULL},
1430 {NULL,NULL,0,0,NULL},
1431 {NULL,NULL,0,0,NULL}};
1432 static int next = 0;
1439 if (next == HOSTENTCNT)
1442 if ( hosts[next].h_name ) {
1443 free(hosts[next].h_name);
1444 hosts[next].h_name = NULL;
1446 if ( hosts[next].h_aliases ) {
1447 pp = hosts[next].h_aliases;
1452 free(hosts[next].h_aliases);
1455 if ( hosts[next].h_addr_list ) {
1456 pp = hosts[next].h_addr_list;
1461 free(hosts[next].h_addr_list);
1463 #endif /* HADDRLIST */
1465 makestr(&hosts[next].h_name,h->h_name);
1467 for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
1468 /* The following can give warnings in non-ANSI builds */
1469 hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
1470 for ( i=0; i<cnt; i++) {
1471 hosts[next].h_aliases[i] = NULL;
1472 makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
1474 hosts[next].h_aliases[i] = NULL;
1476 hosts[next].h_aliases = NULL;
1478 hosts[next].h_addrtype = h->h_addrtype;
1479 hosts[next].h_length = h->h_length;
1483 if (h->h_addr_list) {
1484 for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
1485 /* The following can give warnings non-ANSI builds */
1486 hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
1487 for ( i=0; i<cnt; i++) {
1488 hosts[next].h_addr_list[i] = malloc(h->h_length);
1489 bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
1491 hosts[next].h_addr_list[i] = NULL;
1493 hosts[next].h_addr_list = NULL;
1495 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1497 #else /* HADDRLIST */
1498 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1499 #endif /* HADDRLIST */
1501 return(&hosts[next++]);
1506 Most other BSD sockets implementations define these in header files
1510 unsigned short s_port;
1515 struct in_addr h_addr;
1520 getservbyname(service, connection) char *service,*connection; {
1521 static struct servent servrec;
1525 if (strcmp(service, "telnet") == 0) port = 23;
1526 else if (strcmp(service, "smtp") == 0) port = 25;
1527 else port = atoi(service);
1529 debug(F101,"getservbyname return port ","",port);
1532 servrec.s_port = htons(port);
1535 return((struct servent *) NULL);
1539 gethostbyname(hostname) char *hostname; {
1540 return((struct hostent *) NULL);
1544 inet_addr(name) char *name; {
1547 addr = rhost(&name);
1548 debug(F111,"inet_addr ",name,(int)addr);
1553 inet_ntoa(in) struct in_addr in; {
1554 static char name[80];
1555 ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
1556 ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
1560 #ifdef DEC_TCPIP /* UCX */
1562 int ucx_port_bug = 0; /* Explained below */
1564 #ifndef __DECC /* VAXC or GCC */
1566 #define getservbyname my_getservbyname
1569 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1570 extern void C$$TRANSLATE();
1571 extern void C$$SOCK_TRANSLATE();
1573 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1574 extern VOID C$$TRANSLATE();
1575 extern VOID C$$SOCK_TRANSLATE();
1576 #endif /* CK_ANSIC */
1579 my_getservbyname (service, proto) char *service, *proto; {
1580 static struct servent sent;
1583 unsigned long status;
1584 unsigned short st[2];
1586 unsigned long spare;
1594 char sbuf[30], pbuf[30];
1597 debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
1600 ckstrncpy(p, service, 29);
1601 while (*p = toupper(*p), *p++) {}
1603 ckstrncpy(p, proto, 29);
1604 while (*p = toupper(*p), *p++) {}
1610 /* reset file pointer or something like that!?!? */
1611 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1613 par.prot = pbuf; /* that is don't care */
1614 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1617 if ((e & 1) == 0L) {
1621 if ((s.sb.st[0] & 1) == 0) {
1622 C$$SOCK_TRANSLATE(&s.sb.st[0]);
1626 sent.s_port is supposed to be returned by UCX in network byte order.
1627 However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
1628 But there is no way of knowing which UCX version, so we have a user-settable
1629 runtime variable. Note: UCX 2.0 was only for the VAX.
1631 debug(F101,"UCX getservbyname port","",sent.s_port);
1632 debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
1634 sent.s_port = htons(sent.s_port);
1635 debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
1636 debug(F101,"UCX swapped port","",sent.s_port);
1637 debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
1642 #endif /* DEC_TCPIP */
1643 #endif /* EXCELAN */
1644 #endif /* TCPSOCKET */
1649 ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
1651 The following, from William Bader, turns off the socket linger parameter,
1652 which makes a close() block until all data is sent. "I don't think that
1653 disabling linger can ever cause kermit to lose data, but you telnet to a
1654 flaky server (or to our modem server when the modem is in use), disabling
1655 linger prevents kermit from hanging on the close if you try to exit."
1657 Modified by Jeff Altman to be generally useful.
1661 struct linger set_linger_opt;
1662 struct linger get_linger_opt;
1669 nettype != NET_TCPA && nettype != NET_TCPB &&
1670 nettype != NET_SSH || ttmdm >= 0) {
1672 tcp_linger_tmo = timo;
1675 x = sizeof(get_linger_opt);
1676 if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
1677 (char *)&get_linger_opt, &x)) {
1678 debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1679 } else if (x != sizeof(get_linger_opt)) {
1684 } get_linger_opt16, set_linger_opt16;
1685 if ( x == sizeof(get_linger_opt16) ) {
1686 debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
1687 if (getsockopt(sock,
1688 SOL_SOCKET, SO_LINGER,
1689 (char *)&get_linger_opt16, &x)
1692 "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1693 } else if (get_linger_opt16.s_onoff != onoff ||
1694 get_linger_opt16.s_linger != timo)
1696 set_linger_opt16.s_onoff = onoff;
1697 set_linger_opt16.s_linger = timo;
1698 if (setsockopt(sock,
1701 (char *)&set_linger_opt16,
1702 sizeof(set_linger_opt16))
1705 "TCP ck_linger can't set SO_LINGER",
1709 tcp_linger = get_linger_opt16.s_onoff;
1710 tcp_linger_tmo = get_linger_opt16.s_linger;
1713 "TCP ck_linger new SO_LINGER","",
1714 set_linger_opt16.s_onoff);
1715 tcp_linger = set_linger_opt16.s_onoff;
1716 tcp_linger_tmo = set_linger_opt16.s_linger;
1720 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1721 get_linger_opt16.s_onoff);
1722 tcp_linger = get_linger_opt16.s_onoff;
1723 tcp_linger_tmo = get_linger_opt16.s_linger;
1729 debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
1730 debug(F111,"TCP ck_linger SO_LINGER",
1731 "expected len",sizeof(get_linger_opt));
1732 debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
1733 get_linger_opt.l_onoff);
1734 debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
1735 get_linger_opt.l_linger);
1736 } else if (get_linger_opt.l_onoff != onoff ||
1737 get_linger_opt.l_linger != timo) {
1738 set_linger_opt.l_onoff = onoff;
1739 set_linger_opt.l_linger = timo;
1740 if (setsockopt(sock,
1743 (char *)&set_linger_opt,
1744 sizeof(set_linger_opt))) {
1745 debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
1746 tcp_linger = get_linger_opt.l_onoff;
1747 tcp_linger_tmo = get_linger_opt.l_linger;
1750 "TCP ck_linger new SO_LINGER",
1752 set_linger_opt.l_onoff
1754 tcp_linger = set_linger_opt.l_onoff;
1755 tcp_linger_tmo = set_linger_opt.l_linger;
1759 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1760 get_linger_opt.l_onoff);
1761 tcp_linger = get_linger_opt.l_onoff;
1762 tcp_linger_tmo = get_linger_opt.l_linger;
1766 debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
1767 #endif /* SO_LINGER */
1769 debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
1770 #endif /* SOL_SOCKET */
1775 sendbuf(sock,size) int sock; int size; {
1777 The following, from William Bader, allows changing of socket buffer sizes,
1778 in case that might affect performance.
1780 Modified by Jeff Altman to be generally useful.
1791 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1797 if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1798 debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
1799 } else if (x != sizeof(i)) {
1802 if (x == sizeof(i16)) {
1803 debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
1804 if (getsockopt(sock,
1805 SOL_SOCKET, SO_SNDBUF,
1808 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
1810 } else if (size <= 0) {
1812 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
1814 } else if (i16 != size) {
1816 if (setsockopt(sock,
1822 debug(F111,"TCP sendbuf can't set SO_SNDBUF",
1825 debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
1826 debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
1831 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
1838 debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
1839 debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
1840 debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
1841 } else if (size <= 0) {
1843 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
1845 } else if (i != size) {
1847 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
1848 debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
1851 debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
1852 debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
1857 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
1862 debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
1863 #endif /* SO_SNDBUF */
1865 debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
1866 #endif /* SOL_SOCKET */
1871 recvbuf(sock,size) int sock; int size; {
1873 The following, from William Bader, allows changing of socket buffer sizes,
1874 in case that might affect performance.
1876 Modified by Jeff Altman to be generally useful.
1887 nettype != NET_TCPA && nettype != NET_TCPB &&
1888 nettype != NET_SSH || ttmdm >= 0) {
1893 if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1894 debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
1895 } else if (x != sizeof(i)) {
1898 if ( x == sizeof(i16) ) {
1899 debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
1900 if (getsockopt(sock,
1901 SOL_SOCKET, SO_RCVBUF,
1904 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
1906 } else if (size <= 0) {
1908 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
1910 } else if (i16 != size) {
1912 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
1914 debug(F111,"TCP recvbuf can' set SO_RCVBUF",
1917 debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
1918 debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
1923 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
1930 debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
1931 debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
1932 debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
1933 } else if (size <= 0) {
1935 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
1937 } else if (i != size) {
1939 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
1940 debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
1943 debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
1944 debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
1949 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
1954 debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
1955 #endif /* SO_RCVBUF */
1957 debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
1958 #endif /* SOL_SOCKET */
1963 keepalive(sock,onoff) int sock; int onoff; {
1966 int get_keepalive_opt;
1967 int set_keepalive_opt;
1970 debug(F111,"TCP keepalive","sock",sock);
1971 debug(F111,"TCP keepalive","nettype",nettype);
1972 debug(F111,"TCP keepalive","ttmdm",ttmdm);
1978 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1980 tcp_keepalive = onoff;
1983 x = sizeof(get_keepalive_opt);
1984 if (getsockopt(sock,
1985 SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
1986 debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
1987 } else if (x != sizeof(get_keepalive_opt)) {
1989 short get_keepalive_opt16;
1990 short set_keepalive_opt16;
1991 if (x == sizeof(get_keepalive_opt16)) {
1992 debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
1994 if (getsockopt(sock,
1995 SOL_SOCKET, SO_KEEPALIVE,
1996 (char *)&get_keepalive_opt16, &x)
1999 "TCP keepalive can't get SO_KEEPALIVE",
2003 } else if (get_keepalive_opt16 != onoff) {
2004 set_keepalive_opt16 = onoff;
2005 if (setsockopt(sock,
2008 (char *)&set_keepalive_opt16,
2009 sizeof(set_keepalive_opt16))
2012 "TCP keepalive can't clear SO_KEEPALIVE",
2016 tcp_keepalive = get_keepalive_opt16;
2019 "TCP keepalive new SO_KEEPALIVE","",
2020 set_keepalive_opt16);
2021 tcp_keepalive = set_keepalive_opt16;
2025 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
2026 get_keepalive_opt16);
2027 tcp_keepalive = onoff;
2033 debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
2035 "TCP keepalive SO_KEEPALIVE",
2037 sizeof(get_keepalive_opt)
2040 "TCP keepalive SO_KEEPALIVE",
2044 } else if (get_keepalive_opt != onoff) {
2045 set_keepalive_opt = onoff;
2046 if (setsockopt(sock,
2049 (char *)&set_keepalive_opt,
2050 sizeof(set_keepalive_opt))
2053 "TCP keepalive can't clear SO_KEEPALIVE",
2057 tcp_keepalive = get_keepalive_opt;
2060 "TCP keepalive new SO_KEEPALIVE",
2064 tcp_keepalive = onoff;
2068 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
2072 tcp_keepalive = onoff;
2076 debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
2077 #endif /* SO_KEEPALIVE */
2079 debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
2080 #endif /* SOL_SOCKET */
2085 dontroute(sock,onoff) int sock; int onoff; {
2088 int get_dontroute_opt;
2089 int set_dontroute_opt;
2096 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2098 tcp_dontroute = onoff;
2101 x = sizeof(get_dontroute_opt);
2102 if (getsockopt(sock,
2103 SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
2104 debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
2105 } else if (x != sizeof(get_dontroute_opt)) {
2107 short get_dontroute_opt16;
2108 short set_dontroute_opt16;
2109 if (x == sizeof(get_dontroute_opt16)) {
2110 debug(F111,"TCP dontroute warning: SO_DONTROUTE",
2112 if (getsockopt(sock,
2113 SOL_SOCKET, SO_DONTROUTE,
2114 (char *)&get_dontroute_opt16, &x)
2117 "TCP dontroute can't get SO_DONTROUTE",
2121 } else if (get_dontroute_opt16 != onoff) {
2122 set_dontroute_opt16 = onoff;
2123 if (setsockopt(sock,
2126 (char *)&set_dontroute_opt16,
2127 sizeof(set_dontroute_opt16))
2130 "TCP dontroute can't clear SO_DONTROUTE",
2134 tcp_dontroute = get_dontroute_opt16;
2137 "TCP dontroute new SO_DONTROUTE","",
2138 set_dontroute_opt16);
2139 tcp_dontroute = set_dontroute_opt16;
2143 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
2144 get_dontroute_opt16);
2145 tcp_dontroute = onoff;
2151 debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
2153 "TCP dontroute SO_DONTROUTE",
2155 sizeof(get_dontroute_opt)
2158 "TCP dontroute SO_DONTROUTE",
2162 } else if (get_dontroute_opt != onoff) {
2163 set_dontroute_opt = onoff;
2164 if (setsockopt(sock,
2167 (char *)&set_dontroute_opt,
2168 sizeof(set_dontroute_opt))
2171 "TCP dontroute can't clear SO_DONTROUTE",
2175 tcp_dontroute = get_dontroute_opt;
2178 "TCP dontroute new SO_DONTROUTE",
2182 tcp_dontroute = onoff;
2186 debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
2190 tcp_dontroute = onoff;
2194 debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
2195 #endif /* SO_DONTROUTE */
2197 debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
2198 #endif /* SOL_SOCKET */
2203 no_delay(sock,onoff) int sock; int onoff; {
2206 int get_nodelay_opt;
2207 int set_nodelay_opt;
2214 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2216 tcp_nodelay = onoff;
2219 x = sizeof(get_nodelay_opt);
2220 if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
2221 (char *)&get_nodelay_opt,&x)) {
2223 "TCP no_delay can't get TCP_NODELAY",
2226 } else if (x != sizeof(get_nodelay_opt)) {
2228 short get_nodelay_opt16;
2229 short set_nodelay_opt16;
2230 if (x == sizeof(get_nodelay_opt16)) {
2231 debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
2232 if (getsockopt(sock,
2233 IPPROTO_TCP, TCP_NODELAY,
2234 (char *)&get_nodelay_opt16, &x)
2237 "TCP no_delay can't get TCP_NODELAY",
2240 } else if (get_nodelay_opt16 != onoff) {
2241 set_nodelay_opt16 = onoff;
2242 if (setsockopt(sock,
2245 (char *)&set_nodelay_opt16,
2246 sizeof(set_nodelay_opt16))
2249 "TCP no_delay can't clear TCP_NODELAY",
2252 tcp_nodelay = get_nodelay_opt16;
2255 "TCP no_delay new TCP_NODELAY",
2258 tcp_nodelay = onoff;
2262 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
2264 tcp_nodelay = onoff;
2270 debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
2271 debug(F111,"TCP no_delay TCP_NODELAY","expected len",
2272 sizeof(get_nodelay_opt));
2273 debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
2274 } else if (get_nodelay_opt != onoff) {
2275 set_nodelay_opt = onoff;
2276 if (setsockopt(sock,
2279 (char *)&set_nodelay_opt,
2280 sizeof(set_nodelay_opt))) {
2282 "TCP no_delay can't clear TCP_NODELAY",
2286 tcp_nodelay = get_nodelay_opt;
2288 debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
2289 tcp_nodelay = onoff;
2293 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
2294 tcp_nodelay = onoff;
2298 debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
2299 #endif /* TCP_NODELAY */
2301 debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
2302 #endif /* SOL_SOCKET */
2305 #endif /* datageneral */
2306 #endif /* NOTCPOPTS */
2309 #ifndef X25_WR_FACILITY
2310 /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
2312 bzero(s,n) char *s; int n; {
2315 #endif /* X25_WR_FACILITY */
2326 #ifdef hp9000s500 /* HP-9000/500 HP-U 5.21 */
2330 /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
2331 * ------------------------------------------------------
2333 * Due to OS9's Lack of a select() call, the following seems to be
2334 * enough to fool the rest of the code into compiling. The only
2335 * effect that I can see is using control L to refresh the status
2336 * display gets qued up until some network packets arrive.
2338 * This solution is by no means elegant but works enough to be
2341 * Also with the defines I had specified in my makefile I had to
2342 * have an #endif right at the end of the file when compiling.
2343 * I did not bother speding time to find out why.
2345 * COPTS = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
2346 * -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
2347 * -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
2348 * -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
2349 * -l=termlib.l -l=math.l -l=sys_clib.l
2351 * stever@ozemail.com.au
2355 #define BSDSELECT /* switch on BSD select code */
2356 #define FD_SETSIZE 32 /* Max # of paths in OS9 */
2357 #define FD_ZERO(p) ((*p)=0)
2358 #define FD_SET(n,b) ((*b)|=(1<<(n)))
2359 #define FD_ISSET(n,b) 1 /* always say data is ready */
2360 #define select(a,b,c,d,e) 1 /* always say 1 path has data */
2361 typedef int fd_set; /* keep BSD Code Happy */
2362 struct timeval {int tv_sec,tv_usec;}; /* keep BSD Code Happy */
2364 /****** END OF OS9 MODS FROM STEVE RANCE **************************/
2367 #include <sys/time.h>
2368 #endif /* hp9000s500 */
2369 #endif /* datageneral */
2370 #endif /* BELLV10 */
2373 #include <sys/select.h>
2374 #endif /* SELECT_H */
2375 #endif /* BSDSELECT */
2379 #include <sys/select.h>
2380 #endif /* CK_SCOV5 */
2384 /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
2387 tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
2389 static struct servent *service, servrec;
2390 static struct hostent *host;
2391 static struct sockaddr_in saddr;
2410 #endif /* BELLSELECT */
2411 #endif /* BSDSELECT */
2413 debug(F101,"tcpsocket_open nett","",nett);
2416 if (nett != NET_TCPB)
2417 return(-1); /* BSD socket support */
2419 netclos(); /* Close any previous connection. */
2420 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2421 if (ttnproto != NP_TCPRAW)
2422 ttnproto = NP_NONE; /* No protocol selected yet. */
2423 debug(F110,"tcpsocket_open namecopy",namecopy,0);
2425 /* Assign the socket number to ttyfd and then fill in tcp structures */
2426 ttyfd = atoi(&name[1]);
2427 debug(F111,"tcpsocket_open","ttyfd",ttyfd);
2431 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2435 no_delay(ttyfd,tcp_nodelay);
2436 #endif /* TCP_NODELAY */
2438 keepalive(ttyfd,tcp_keepalive);
2439 #endif /* SO_KEEPALIVE */
2441 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2442 #endif /* SO_LINGER */
2444 sendbuf(ttyfd,tcp_sendbuf);
2445 #endif /* SO_SNDBUF */
2447 recvbuf(ttyfd,tcp_recvbuf);
2448 #endif /* SO_RCVBUF */
2449 #endif /* datageneral */
2450 #endif /* SOL_SOCKET */
2451 #endif /* NOTCPOPTS */
2453 #ifdef NT_TCP_OVERLAPPED
2454 OverlappedWriteInit();
2455 OverlappedReadInit();
2456 #endif /* NT_TCP_OVERLAPPED */
2459 /* Get the name of the host we are connected to */
2461 saddrlen = sizeof(saddr);
2462 getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
2464 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2466 if (tcp_rdns == SET_ON
2468 || tcp_rdns == SET_AUTO &&
2469 (ck_krb5_is_installed() || ck_krb4_is_installed())
2470 #endif /* CK_KERBEROS */
2472 && (tcp_http_proxy == NULL)
2475 && !(ssl_only_flag || tls_only_flag)
2477 ) { /* Reverse DNS */
2479 printf(" Reverse DNS Lookup... ");
2482 host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
2483 debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
2485 host = ck_copyhostent(host);
2486 debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
2491 ckstrncpy(name, host->h_name, 80);
2492 ckstrncat(name, ":", 80);
2493 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
2499 printf("%s connected on port %d\n",
2501 ntohs(saddr.sin_port)
2508 if (tcp_rdns != SET_ON || !host) {
2509 ckstrncpy(name,ipaddr,80);
2510 ckstrncat(name,":",80);
2511 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2517 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2519 if (!quiet) fflush(stdout);
2520 ttnet = nett; /* TCP/IP (sockets) network */
2523 if (ntohs(saddr.sin_port) == 513)
2524 ttnproto = NP_LOGIN;
2526 #endif /* RLOGCODE */
2527 /* Assume the service is TELNET. */
2528 if (ttnproto != NP_TCPRAW)
2529 ttnproto = NP_TELNET; /* Yes, set global flag. */
2531 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2532 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2533 host->h_name : ipaddr,
2538 #endif /* CK_SECURITY */
2539 if (tn_ini() < 0) /* Start/Reset TELNET negotiations */
2540 if (ttchk() < 0) /* Did it fail due to connect loss? */
2543 if (*lcl < 0) *lcl = 1; /* Local mode. */
2545 return(0); /* Done. */
2547 #endif /* NOTUSED */
2549 /* T C P S R V _ O P E N -- Open a TCP/IP Server connection */
2551 Calling conventions same as ttopen(), except third argument is network
2552 type rather than modem type.
2555 tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
2559 int ready_to_accept = 0;
2560 static struct servent *service, *service2, servrec;
2561 static struct hostent *host;
2562 static struct sockaddr_in saddr;
2563 struct sockaddr_in l_addr;
2566 static u_int saddrlen;
2568 static SOCKOPT_T saddrlen;
2583 #endif /* BELLSELECT */
2584 #endif /* BSDSELECT */
2589 debug(F101,"tcpsrv_open nett","",nett);
2592 if (nett != NET_TCPB)
2593 return(-1); /* BSD socket support */
2595 netclos(); /* Close any previous connection. */
2596 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2598 /* Don't do this. */
2599 if (ttnproto != NP_TCPRAW)
2600 ttnproto = NP_NONE; /* No protocol selected yet. */
2601 #endif /* COMMENT */
2602 debug(F110,"tcpsrv_open namecopy",namecopy,0);
2604 p = namecopy; /* Was a service requested? */
2605 while (*p != '\0' && *p != ':')
2606 p++; /* Look for colon */
2607 if (*p == ':') { /* Have a colon */
2608 *p++ = '\0'; /* Get service name or number */
2609 } else { /* Otherwise use kermit */
2612 debug(F110,"tcpsrv_open service requested",p,0);
2613 if (isdigit(*p)) { /* Use socket number without lookup */
2615 service->s_port = htons((unsigned short)atoi(p));
2616 } else { /* Otherwise lookup the service name */
2617 service = getservbyname(p, "tcp");
2619 if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
2621 service->s_port = htons(1649);
2624 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
2626 " Warning: login service on port %d instead of port 513\n",
2627 ntohs(service->s_port));
2628 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
2629 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
2631 #endif /* RLOGCODE */
2633 fprintf(stderr, "Cannot find port for service: %s\n", p);
2634 debug(F111,"tcpsrv_open can't get service",p,errno);
2635 errno = 0; /* rather than mislead */
2639 /* If we currently have a listen active but port has changed then close */
2641 debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
2642 debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
2643 if (tcpsrfd != -1 &&
2644 tcpsrv_port != ntohs((unsigned short)service->s_port)) {
2645 debug(F100,"tcpsrv_open closing previous connection","",0);
2647 socket_close(tcpsrfd);
2650 #endif /* TCPIPLIB */
2653 debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
2654 if (tcpsrfd == -1) {
2656 /* Set up socket structure and get host address */
2658 bzero((char *)&saddr, sizeof(saddr));
2659 debug(F100,"tcpsrv_open bzero ok","",0);
2660 saddr.sin_family = AF_INET;
2663 inaddrx = inet_addr(tcp_address);
2664 saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
2666 saddr.sin_addr.s_addr = inet_addr(tcp_address);
2667 #endif /* INADDRX */
2669 saddr.sin_addr.s_addr = INADDR_ANY;
2671 /* Get a file descriptor for the connection. */
2673 saddr.sin_port = service->s_port;
2676 debug(F100,"tcpsrv_open calling socket","",0);
2677 if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2678 perror("TCP socket error");
2679 debug(F101,"tcpsrv_open socket error","",errno);
2684 /* Specify the Port may be reused */
2686 debug(F100,"tcpsrv_open calling setsockopt","",0);
2687 x = setsockopt(tcpsrfd,
2688 SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
2689 debug(F101,"tcpsrv_open setsockopt","",x);
2691 /* Now bind to the socket */
2692 printf("\nBinding socket to port %d ...\n",
2693 ntohs((unsigned short)service->s_port));
2694 if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
2695 i = errno; /* Save error code */
2697 socket_close(tcpsrfd);
2698 #else /* TCPIPLIB */
2700 #endif /* TCPIPLIB */
2705 errno = i; /* and report this error */
2706 debug(F101,"tcpsrv_open bind errno","",errno);
2707 printf("?Unable to bind to socket (errno = %d)\n",errno);
2710 debug(F100,"tcpsrv_open bind OK","",0);
2711 printf("Listening ...\n");
2712 if (listen(tcpsrfd, 15) < 0) {
2713 i = errno; /* Save error code */
2715 socket_close(tcpsrfd);
2716 #else /* TCPIPLIB */
2718 #endif /* TCPIPLIB */
2723 errno = i; /* And report this error */
2724 debug(F101,"tcpsrv_open listen errno","",errno);
2727 debug(F100,"tcpsrv_open listen OK","",0);
2728 tcpsrv_port = ntohs((unsigned short)service->s_port);
2732 if (ck_ssleay_is_installed()) {
2733 if (!ssl_tn_init(SSL_SERVER)) {
2735 if (bio_err!=NULL) {
2736 BIO_printf(bio_err,"do_ssleay_init() failed\n");
2737 ERR_print_errors(bio_err);
2740 fprintf(stderr,"do_ssleay_init() failed\n");
2741 ERR_print_errors_fp(stderr);
2743 if (tls_only_flag || ssl_only_flag) {
2745 socket_close(ttyfd);
2746 socket_close(tcpsrfd);
2747 #else /* TCPIPLIB */
2750 #endif /* TCPIPLIB */
2757 /* we will continue to accept the connection */
2758 /* without SSL or TLS support unless required. */
2759 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2760 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2761 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2762 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2763 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2764 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2765 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2766 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2771 printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
2772 ntohs((unsigned short)service->s_port));
2773 saddrlen = sizeof(saddr);
2776 tv.tv_sec = tv.tv_usec = 0L;
2778 tv.tv_usec = (long) -timo * 10000L;
2781 debug(F101,"tcpsrv_open BSDSELECT","",timo);
2783 debug(F101,"tcpsrv_open not BSDSELECT","",timo);
2784 #endif /* BSDSELECT */
2787 while (!ready_to_accept) {
2790 FD_SET(tcpsrfd, &rfds);
2792 ((select(FD_SETSIZE,
2799 #endif /* HPUX1010 */
2805 &rfds, NULL, NULL, &tv) > 0) &&
2806 FD_ISSET(tcpsrfd, &rfds));
2807 #else /* BSDSELECT */
2809 #define ck_sleepint 250
2811 (select(&tcpsrfd, 1, 0, 0,
2813 (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
2818 FD_SET(tcpsrfd, rfds);
2820 ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
2821 (timo > 0 ? timo * 1000L)) > 0) &&
2822 FD_ISSET(tcpsrfd, rfds));
2824 /* Try this - what's the worst that can happen... */
2827 FD_SET(tcpsrfd, &rfds);
2829 ((select(FD_SETSIZE,
2830 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
2831 FD_ISSET(tcpsrfd, &rfds));
2833 #endif /* BELLSELECT */
2834 #endif /* IBMSELECT */
2835 #endif /* BSDSELECT */
2838 if (ready_to_accept || timo == 0) {
2839 if ((ttyfd = accept(tcpsrfd,
2840 (struct sockaddr *)&saddr,&saddrlen)) < 0) {
2841 i = errno; /* save error code */
2843 socket_close(tcpsrfd);
2844 #else /* TCPIPLIB */
2846 #endif /* TCPIPLIB */
2851 errno = i; /* and report this error */
2852 debug(F101,"tcpsrv_open accept errno","",errno);
2855 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2861 no_delay(ttyfd,tcp_nodelay);
2862 debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
2863 #endif /* TCP_NODELAY */
2865 keepalive(ttyfd,tcp_keepalive);
2866 debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
2867 #endif /* SO_KEEPALIVE */
2869 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2870 debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
2871 #endif /* SO_LINGER */
2873 sendbuf(ttyfd,tcp_sendbuf);
2874 #endif /* SO_SNDBUF */
2876 recvbuf(ttyfd,tcp_recvbuf);
2877 #endif /* SO_RCVBUF */
2878 #endif /* SOL_SOCKET */
2879 #endif /* datageneral */
2880 #endif /* NOTCPOPTS */
2882 ttnet = nett; /* TCP/IP (sockets) network */
2883 tcp_incoming = 1; /* This is an incoming connection */
2884 sstelnet = 1; /* Do server-side Telnet protocol */
2886 /* See if the service is TELNET. */
2887 x = (unsigned short)service->s_port;
2888 service2 = getservbyname("telnet", "tcp");
2889 if (service2 && x == service2->s_port) {
2890 if (ttnproto != NP_TCPRAW) /* Yes and if raw port not requested */
2891 ttnproto = NP_TELNET; /* Set protocol to TELNET. */
2894 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2897 printf(" Reverse DNS Lookup... ");
2900 if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
2901 host = ck_copyhostent(host);
2902 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
2908 ckstrncpy(&name[1],host->h_name,78);
2909 strncat(name,":",80-strlen(name));
2910 strncat(name,p,80-strlen(name));
2916 printf("%s connected on port %s\n",host->h_name,p);
2918 if (!quiet) printf("Failed.\n");
2920 } else if (!quiet) printf("(OK)\n");
2922 if (!tcp_rdns || !host) {
2923 ckstrncpy(name,ipaddr,80);
2924 ckstrncat(name,":",80);
2925 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2931 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2933 if (!quiet) fflush(stdout);
2936 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2937 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2938 (char *)host->h_name : ipaddr,
2943 #endif /* CK_SECURITY */
2946 if (ck_ssleay_is_installed() && !ssl_failed) {
2947 if (ck_ssl_incoming(ttyfd) < 0) {
2949 socket_close(ttyfd);
2950 socket_close(tcpsrfd);
2951 #else /* TCPIPLIB */
2954 #endif /* TCPIPLIB */
2965 /* Find out our own IP address. */
2966 l_slen = sizeof(l_addr);
2967 bzero((char *)&l_addr, l_slen);
2969 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
2970 char * s = (char *)inet_ntoa(l_addr.sin_addr);
2971 ckstrncpy(myipaddr, s,20);
2972 debug(F110,"getsockname",myipaddr,0);
2974 #endif /* EXCELAN */
2975 #endif /* datageneral */
2977 if (tn_ini() < 0) /* Start TELNET negotiations. */
2978 if (ttchk() < 0) { /* Disconnected? */
2979 i = errno; /* save error code */
2981 socket_close(tcpsrfd);
2982 #else /* TCPIPLIB */
2984 #endif /* TCPIPLIB */
2989 errno = i; /* and report this error */
2990 debug(F101,"tcpsrv_open accept errno","",errno);
2993 debug(F101,"tcpsrv_open service","",x);
2994 if (*lcl < 0) /* Set local mode. */
2999 if ( ttnproto == NP_K5U2U ) {
3000 if (k5_user_to_user_server_auth() != 0) {
3001 i = errno; /* save error code */
3003 socket_close(tcpsrfd);
3004 #else /* TCPIPLIB */
3006 #endif /* TCPIPLIB */
3011 errno = i; /* and report this error */
3012 debug(F101,"tcpsrv_open accept errno","",errno);
3016 #endif /* KRB5_U2U */
3017 #endif /* CK_KERBEROS */
3018 return(0); /* Done. */
3020 i = errno; /* save error code */
3022 socket_close(tcpsrfd);
3023 #else /* TCPIPLIB */
3025 #endif /* TCPIPLIB */
3030 errno = i; /* and report this error */
3031 debug(F101,"tcpsrv_open accept errno","",errno);
3035 #endif /* NOLISTEN */
3037 #endif /* TCPSOCKET */
3042 ckname2addr(name) char * name;
3047 struct hostent *host;
3049 if (name == NULL || *name == '\0')
3052 host = gethostbyname(name);
3054 host = ck_copyhostent(host);
3055 return(inet_ntoa(*((struct in_addr *) host->h_addr)));
3062 ckaddr2name(addr) char * addr;
3067 struct hostent *host;
3068 struct in_addr sin_addr;
3070 if (addr == NULL || *addr == '\0')
3073 sin_addr.s_addr = inet_addr(addr);
3074 host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
3076 host = ck_copyhostent(host);
3077 return((char *)host->h_name);
3082 #endif /* TCPSOCKET */
3084 unsigned long peerxipaddr = 0L;
3089 static char namebuf[256];
3090 static struct hostent *host;
3091 static struct sockaddr_in saddr;
3093 static size_t saddrlen;
3096 /* It's size_t in 4.2 but int in 4.1 and earlier. */
3097 /* Note: the 4.2 man page lies; believe socket.h. */
3098 static size_t saddrlen;
3101 static size_t saddrlen;
3102 #else /* UNIXWARE */
3104 static unsigned int saddrlen;
3106 static int saddrlen;
3108 #endif /* UNIXWARE */
3111 saddrlen = sizeof(saddr);
3112 if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
3113 debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
3116 host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
3118 host = ck_copyhostent(host);
3119 ckstrncpy(namebuf,(char *)host->h_name,80);
3121 ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
3123 peerxipaddr = ntohl(saddr.sin_addr.s_addr);
3124 debug(F111,"ckgetpeer",namebuf,peerxipaddr);
3128 #endif /* TCPSOCKET */
3131 /* Get fully qualified IP hostname */
3136 ckgetfqhostname(char * name)
3138 ckgetfqhostname(name) char * name;
3139 #endif /* CK_ANSIC */
3141 #ifdef NOCKGETFQHOST
3145 #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
3147 static char namebuf[256];
3148 struct hostent *host=NULL;
3149 struct sockaddr_in r_addr;
3152 debug(F110,"ckgetfqhn()",name,0);
3154 ckstrncpy(namebuf,name,256);
3155 namebuf[255] = '\0';
3156 i = ckindex(":",namebuf,0,0,0);
3158 namebuf[i-1] = '\0';
3160 bzero((char *)&r_addr, sizeof(r_addr));
3162 host = gethostbyname(namebuf);
3164 host = ck_copyhostent(host);
3165 debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
3166 r_addr.sin_family = host->h_addrtype;
3169 /* This is for trying multiple IP addresses - see <netdb.h> */
3170 if (!(host->h_addr_list))
3172 bcopy(host->h_addr_list[0],
3173 (caddr_t)&r_addr.sin_addr,
3177 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3179 #else /* HADDRLIST */
3180 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3181 #endif /* HADDRLIST */
3183 debug(F111,"BCOPY","host->h_addr",host->h_addr);
3184 #endif /* EXCELAN */
3185 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
3186 (caddr_t)&r_addr.sin_addr);
3187 debug(F111,"BCOPY","host->h_length",host->h_length);
3190 /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
3191 /* provided DNS functions. Otherwise, the TTL of the DNS response */
3196 host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
3198 host = ck_copyhostent(host);
3199 debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
3200 ckstrncpy(namebuf, host->h_name, 256);
3208 #endif /* HADDRLIST */
3211 strncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
3212 debug(F110,"ckgetfqhn()",namebuf,0);
3214 #endif /* NOCKGETFQHOST */
3221 setnproto(p) char * p;
3222 #endif /* CK_ANSIC */
3225 if (!strcmp("kermit",p))
3226 ttnproto = NP_KERMIT;
3227 else if (!strcmp("telnet",p))
3228 ttnproto = NP_TELNET;
3229 else if (!strcmp("http",p))
3230 ttnproto = NP_TCPRAW;
3232 else if (!strcmp("login",p))
3233 ttnproto = NP_RLOGIN;
3234 #endif /* RLOGCODE */
3236 /* Commonly used SSL ports (might not be in services file) */
3237 else if (!strcmp("https",p)) {
3240 } else if (!strcmp("ssl-telnet",p)) {
3241 ttnproto = NP_TELNET;
3243 } else if (!strcmp("telnets",p)) {
3244 ttnproto = NP_TELNET;
3250 else if (!strcmp("klogin",p)) {
3251 if (ck_krb5_is_installed())
3252 ttnproto = NP_K5LOGIN;
3253 else if (ck_krb4_is_installed())
3254 ttnproto = NP_K4LOGIN;
3256 ttnproto = NP_RLOGIN;
3257 } else if (!strcmp("eklogin",p)) {
3258 if (ck_krb5_is_installed())
3259 ttnproto = NP_EK5LOGIN;
3260 else if (ck_krb4_is_installed())
3261 ttnproto = NP_EK4LOGIN;
3263 ttnproto = NP_RLOGIN;
3265 #endif /* RLOGCODE */
3266 #endif /* CK_KERBEROS */
3271 case 23: /* Telnet */
3272 ttnproto = NP_TELNET;
3275 ttnproto = NP_RLOGIN;
3278 ttnproto = NP_KERMIT;
3287 ttnproto = NP_TELNET;
3293 if (ck_krb5_is_installed())
3294 ttnproto = NP_K5LOGIN;
3295 else if (ck_krb4_is_installed())
3296 ttnproto = NP_K4LOGIN;
3298 ttnproto = NP_RLOGIN;
3301 if (ck_krb5_is_installed())
3302 ttnproto = NP_EK5LOGIN;
3303 else if (ck_krb4_is_installed())
3304 ttnproto = NP_EK4LOGIN;
3306 ttnproto = NP_RLOGIN;
3308 #endif /* CK_KERBEROS */
3310 ttnproto = NP_TCPRAW;
3319 /* ckgetservice() is used to determine the port number for a given */
3320 /* service taking into account the use of DNS SRV records. */
3322 static struct servent servrec;
3323 static struct servent *
3324 ckgetservice(hostname, servicename, ip, iplen)
3325 char *hostname; char * servicename; char * ip; int iplen;
3327 struct servent * service = NULL;
3329 struct sockaddr * dns_addrs = NULL;
3331 #endif /* CK_DNS_SRV */
3333 if (isdigit(*servicename)) { /* Use socket number without lookup */
3335 service->s_port = htons((unsigned short)atoi(servicename));
3336 } else { /* Otherwise lookup the service name */
3338 if (tcp_dns_srv && !quiet) {
3339 printf(" DNS SRV Lookup... ");
3343 locate_srv_dns(hostname,
3350 /* Use the first one. Eventually we should cycle through all */
3351 /* the returned IP addresses and port numbers. */
3352 struct sockaddr_in *sin = NULL;
3356 for ( i=0;i<dns_naddrs;i++ ) {
3357 sin = (struct sockaddr_in *) &dns_addrs[i];
3358 printf("dns_addrs[%d] = %s %d\r\n", i,
3359 (char *)inet_ntoa(sin->sin_addr),
3360 ntohs(sin->sin_port));
3362 #endif /* BETADEBUG */
3363 sin = (struct sockaddr_in *) &dns_addrs[0];
3364 if ( ip && iplen > 0 )
3365 ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
3367 service->s_port = sin->sin_port;
3373 #endif /* CK_DNS_SRV */
3374 service = getservbyname(servicename, "tcp");
3377 if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
3379 service->s_port = htons(1649);
3380 } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
3382 service->s_port = htons(23);
3383 } else if (!ckstrcmp("http",servicename,-1,0)) {
3385 service->s_port = htons(80);
3388 else if (!ckstrcmp("login",servicename,-1,0)) {
3390 service->s_port = htons(513);
3392 #endif /* RLOGCODE */
3394 /* Commonly used SSL ports (might not be in services file) */
3395 else if (!ckstrcmp("https",servicename,-1,0)) {
3397 service->s_port = htons(443);
3398 } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
3400 service->s_port = htons(151);
3401 } else if (!ckstrcmp("telnets",servicename,-1,0)) {
3403 service->s_port = htons(992);
3408 else if (!ckstrcmp("klogin",servicename,-1,0)) {
3410 service->s_port = htons(543);
3411 } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
3413 service->s_port = htons(2105);
3415 #endif /* RLOGCODE */
3416 #endif /* CK_KERBEROS */
3421 /* N E T O P E N -- Open a network connection */
3423 Calling conventions same as ttopen(), except third argument is network
3424 type rather than modem type. Designed to be called from within ttopen.
3428 netopen(name, lcl, nett) char *name; int *lcl, nett; {
3435 #endif /* SO_OOBINLINE */
3436 struct servent *service=NULL;
3437 struct hostent *host=NULL;
3438 struct sockaddr_in r_addr;
3439 struct sockaddr_in sin;
3440 struct sockaddr_in l_addr;
3443 struct sockaddr_in send_socket;
3444 #endif /* EXCELAN */
3447 /* inet_addr() is of type struct in_addr */
3449 extern struct in_addr inet_addr();
3452 extern struct in_addr inet_addr();
3453 #endif /* HPUX5WINTCP */
3454 #endif /* datageneral */
3459 #else /* INADDR_NONE */
3461 #endif /* INADDR_NONE */
3462 #endif /* INADDRX */
3463 #endif /* TCPSOCKET */
3466 /* This causes big trouble */
3468 #define INADDR_NONE 0xffffffff
3469 #endif /* INADDR_NONE */
3470 #endif /* COMMENT */
3472 #ifdef SUNX25 /* Code for SunLink X.25 support */
3473 #define X29PID 1 /* X.29 Protocol ID */
3474 _PROTOTYP(SIGTYP x25oobh, (int) );
3476 #ifndef X25_WR_FACILITY
3479 FACILITY_DB x25facil;
3480 #endif /* X25_WR_FACILITY */
3481 static int needh = 1;
3483 extern int linkid, lcn, x25ver;
3486 extern int revcall, closgr, cudata;
3487 extern char udata[];
3490 #ifdef IBMX25 /* Variables for IBM X25 */
3491 extern int x25port; /* Logical port to use */
3492 extern x25addr_t local_nua; /* Local X.25 address */
3493 extern x25addr_t remote_nua; /* Remote X.25 address */
3494 extern char x25name[]; /* X25 device name (sx25a0) */
3495 extern char x25dev[]; /* X25 device file /dev/x25pkt */
3496 ulong bind_flags = 0; /* Flags for binding the X25 stream */
3497 ulong token = 0; /* Temporary return code */
3500 debug(F101,"netopen nett","",nett);
3501 *ipaddr = '\0'; /* Initialize IP address string */
3504 if (nett == NET_SX25) { /* If network type is X.25 */
3505 netclos(); /* Close any previous net connection */
3506 ttnproto = NP_NONE; /* No protocol selected yet */
3508 /* Set up host structure */
3509 bzero((char *)&x25host,sizeof(x25host));
3510 if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
3511 fprintf (stderr,"Invalid X.121 host address %s\n",name);
3515 x25host.datalen = X29PIDLEN;
3516 x25host.data[0] = X29PID;
3518 /* Set call user data if specified */
3520 ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
3521 x25host.datalen += (int)strlen(udata);
3524 /* Open SunLink X.25 socket */
3525 if (!quiet && *name) {
3526 printf(" Trying %s... ", name);
3529 if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
3530 debug(F101,"netopen socket error","",errno);
3531 perror ("X.25 socket error");
3535 /* Setting X.25 out-of-band data handler */
3537 if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
3538 perror("X.25 set process group id error");
3541 (VOID) signal(SIGURG,x25oobh);
3543 /* Set reverse charge call and closed user group if requested */
3544 bzero ((char *)&x25facil,sizeof(x25facil));
3546 #ifndef X25_WR_FACILITY
3547 /* New SunLink (7.0 or 8.0, not sure which)... */
3548 x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
3549 x25facil.f_reverse_charge = revcall ? 1 : 0;
3550 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3551 perror ("Setting X.25 reverse charge");
3554 if (closgr > -1) { /* Closed User Group (Outgoing) */
3555 bzero ((char *)&x25facil,sizeof(x25facil));
3556 x25facil.type = T_CUG;
3557 x25facil.f_cug_req = CUG_REQ_ACS;
3558 x25facil.f_cug_index = closgr;
3559 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3560 perror ("Setting X.25 closed user group");
3565 /* Old SunLink 6.0 (or 7.0?)... */
3566 if (revcall) x25facil.reverse_charge = revcall;
3568 x25facil.cug_req = 1;
3569 x25facil.cug_index = closgr;
3571 if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
3572 perror ("Setting X.25 facilities");
3575 #endif /* X25_WR_FACILITY */
3577 /* Need X.25 header with bits Q and M */
3578 if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
3579 perror ("Setting X.25 header");
3583 /* Connects to remote host via SunLink X.25 */
3584 if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
3586 debug(F101,"netopen connect errno","",i);
3588 perror("netopen x25 connect");
3599 /* Get X.25 link identification used for the connection */
3600 if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
3601 perror ("Getting X.25 link id");
3605 /* Get X.25 logical channel number used for the connection */
3606 if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
3607 perror ("Getting X.25 lcn");
3611 /* Get SunLink X.25 version */
3612 if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
3613 perror ("Getting SunLink X.25 version");
3616 ttnet = nett; /* Sunlink X.25 network */
3617 ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */
3618 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3620 } else /* Note that SUNX25 support can coexist with TCP/IP support. */
3625 if (nett == NET_IX25) { /* IBM AIX X.25 */
3626 netclos(); /* Close any previous net connection */
3627 ttnproto = NP_NONE; /* No protocol selected yet */
3629 /* find out who we are - this is not so easy on AIX */
3630 /* riehm: need to write the code that finds this out
3631 * automatically, or at least allow it to be configured
3634 if (!local_nua[0] && !x25local_nua(local_nua)) {
3638 /* Initialise the X25 API (once per process? once per connection?) */
3640 debug(F110, "Opening ", x25dev, 0 );
3641 /* set O_NDELAY to allow polling? */
3642 if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
3643 perror ("X.25 device open error");
3644 debug(F101,"netopen: device open error","",errno);
3648 /* push the NPI onto the STREAM */
3649 if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
3653 perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
3654 debug(F101,"netopen: can't push npi on the X25 stream","",errno);
3658 /* set up server mode - bind the x25 port and wait for
3659 * incoming connections
3661 if (name[0] == '*') { /* Server */
3662 /* set up a server - see the warning in x25bind() */
3663 bind_flags |= TOKEN_REQUEST;
3665 /* bind kermit to the local X25 address */
3666 token = x25bind(ttyfd,
3669 (int)strlen( udata ),
3675 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3679 /* Currently not connected to a remote host */
3681 remote_nua[0] = '\0';
3683 /* store the fd so that incoming calls can have their own fd
3684 * This is almost support for a true server (ie: a'la ftpd)
3685 * but we're not quite there yet.
3688 x25serverfd = ttyfd;
3690 * wait for an incoming call
3691 * this should happen in the "server" command and not in
3692 * the "set host *" command.
3694 if ((ttyfd = x25getcall(ttyfd)) < 0) {
3698 } else { /* Client */
3699 /* Bind kermit to the local X25 address */
3710 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3714 /* riehm: this should be done via the CONNECT command, not HOST! */
3717 /* call the remote host */
3718 /* name == address of remote host as char* */
3719 if (x25call(ttyfd, name, udata) < 0 ) {
3721 "netopen: couldn't connect to remote X25 address",
3726 strcpy(remote_nua, name);
3729 ttnet = nett; /* AIX X.25 network */
3730 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3733 } else /* Note that IBMX25 support can coexist with TCP/IP support. */
3736 /* Add support for other networks here. */
3738 if (nett != NET_TCPB) return(-1); /* BSD socket support */
3741 netclos(); /* Close any previous connection. */
3742 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
3743 debug(F110,"netopen namecopy",namecopy,0);
3747 return(tcpsrv_open(name, lcl, nett, 0));
3748 #endif /* NOLISTEN */
3750 p = namecopy; /* Was a service requested? */
3751 while (*p != '\0' && *p != ':') p++; /* Look for colon */
3752 if (*p == ':') { /* Have a colon */
3753 debug(F110,"netopen name has colon",namecopy,0);
3754 *p++ = '\0'; /* Get service name or number */
3757 Here we have to check for various popular syntaxes:
3758 host:port (our original syntax)
3759 URL such as telnet:host or telnet://host/
3760 Or even telnet://user:password@host:port/path/
3761 Or a malformed URL such as generated by Netscape 4.0 like:
3762 telnet:telnet or telnet::host.
3766 * REPLACE THIS CODE WITH urlparse() but not on the day of the
3767 * C-Kermit 8.0 RELEASE.
3770 if (*p == ':') /* a second colon */
3771 *p++ = '\0'; /* get rid of that one too */
3772 while (*p == '/') *p++ = '\0'; /* and slashes */
3773 x = strlen(p); /* Length of remainder */
3774 if (p[x-1] == '/') /* If there is a trailing slash */
3775 p[x-1] = '\0'; /* remove it. */
3776 debug(F110,"netopen namecopy after stripping",namecopy,0);
3777 debug(F110,"netopen p after stripping",p,0);
3778 service = getservbyname(namecopy,"tcp");
3781 !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
3782 #endif /* RLOGCODE */
3784 !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
3786 !ckstrcmp("iksd",namecopy,NAMECPYL,0)
3788 char temphost[256], tempservice[80], temppath[256];
3789 char * q = p, *r = p, *w = p;
3791 extern char pwbuf[];
3792 extern int pwflg, pwcrypt;
3794 if (ttnproto == NP_DEFAULT)
3795 setnproto(namecopy);
3797 /* Check for userid and possibly password */
3798 while (*p != '\0' && *p != '@')
3799 p++; /* look for @ */
3801 /* found username and perhaps password */
3802 debug(F110,"netopen namecopy found @","",0);
3805 while (*w != '\0' && *w != ':')
3809 /* r now points to username, save it and the password */
3810 debug(F110,"netopen namecopy username",r,0);
3811 debug(F110,"netopen namecopy password",w,0);
3813 if ( strcmp(uidbuf,r) || *w )
3814 ckstrncpy(pwbuf,w,PWBUFL+1);
3815 ckstrncpy(uidbuf,r,UIDBUFLEN);
3818 q = p; /* Host after user and pwd */
3820 p = q; /* No username or password */
3822 /* Now we must look for the optional port. */
3823 debug(F110,"netopen x p",p,0);
3824 debug(F110,"netopen x q",q,0);
3826 /* Look for the port/service or a file/directory path */
3827 while (*p != '\0' && *p != ':' && *p != '/')
3830 debug(F110,"netopen found port",q,0);
3831 *p++ = '\0'; /* Found a port name or number */
3834 /* Look for the end of port/service or a file/directory path */
3835 while (*p != '\0' && *p != '/')
3840 debug(F110,"netopen port",r,0);
3841 ckstrncpy(tempservice,r,80);
3842 ckstrncpy(temphost,q,256);
3843 ckstrncpy(temppath,p,256);
3844 ckstrncpy(namecopy,temphost,NAMECPYL);
3845 debug(F110,"netopen tempservice",tempservice,0);
3846 debug(F110,"netopen temphost",temphost,0);
3847 debug(F110,"netopen temppath",temppath,0);
3849 /* move port/service to a buffer that won't go away */
3850 x = strlen(namecopy);
3851 p = namecopy + x + 1;
3852 ckstrncpy(p, tempservice, NAMECPYL - x);
3854 /* Handle a path if we found one */
3857 ckstrncpy(temppath,p,256);
3859 /* We didn't find another port, but if q is a service */
3860 /* then assume that namecopy is actually a host. */
3861 if (getservbyname(q,"tcp")) {
3865 /* rlogin is not a valid service */
3866 if (!ckstrcmp("rlogin",namecopy,6,0)) {
3867 ckstrncpy(namecopy,"login",NAMECPYL);
3869 #endif /* RLOGCODE */
3870 /* iksd is not a valid service */
3871 if (!ckstrcmp("iksd",namecopy,6,0)) {
3872 ckstrncpy(namecopy,"kermit",NAMECPYL);
3874 /* Reconstruct namecopy */
3875 ckstrncpy(tempservice,namecopy,80);
3876 ckstrncpy(temphost,q,256);
3877 ckstrncpy(namecopy,temphost,NAMECPYL);
3878 debug(F110,"netopen tempservice",tempservice,0);
3879 debug(F110,"netopen temphost",temphost,0);
3880 debug(F110,"netopen temppath",temppath,0);
3882 /* move port/service to a buffer that won't go away */
3883 x = strlen(namecopy);
3884 p = namecopy + x + 1;
3885 ckstrncpy(p, tempservice, NAMECPYL - x - 1);
3888 debug(F110,"netopen URL result: host",namecopy,0);
3889 debug(F110,"netopen URL result: service",p,0);
3890 debug(F110,"netopen URL result: path",temppath,0);
3893 /* If we have set a path specified, we need to try to GET it */
3894 /* But we have another problem, we have to login first. How */
3895 /* do we specify that a login must be done before the GET? */
3896 /* The user's name if specified is in 'userid' and the */
3897 /* password if any is in 'pwbuf'. */
3898 if ( temppath[0] ) {
3900 extern char * cmarg;
3903 /* If no userid was specified as part of the URL but
3904 * a path was specified, then we
3905 * set the user name to anonymous and the password
3906 * to the current userid.
3908 ckstrncpy(pwbuf,uidbuf,PWBUFL);
3909 ckstrncat(pwbuf,"@",PWBUFL);
3912 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
3916 * If a file path was specified we perform the GET
3917 * operation and then terminate the connection.
3919 * If a directory was given instead of a file, then
3920 * we should REMOTE CD to the directory and list its
3921 * contents. But how do we tell the difference?
3923 makestr(&cmarg,temppath);
3926 #endif /* IKS_GET */
3929 } else { /* Otherwise use telnet */
3933 By the time we get here, namecopy[] should hold the null-terminated
3934 hostname or address, and p should point to the service name or number.
3936 debug(F110,"netopen host",namecopy,0);
3937 debug(F110,"netopen service requested",p,0);
3939 /* Use the service port to set the default protocol type if necessary */
3940 if (ttnproto == NP_DEFAULT)
3943 ckstrncpy(namecopy2,namecopy,NAMECPYL);
3944 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
3946 fprintf(stderr, "Can't find port for service %s\n", p);
3948 debug(F101,"netopen can't get service","",socket_errno);
3950 debug(F101,"netopen can't get service","",errno);
3951 #endif /* TGVORWIN */
3952 errno = 0; /* (rather than mislead) */
3955 if (!ckstrcmp(namecopy,namecopy2,-1,0))
3956 namecopy2[0] = '\0';
3957 ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
3958 debug(F110,"netopen service ok",svcbuf,0);
3962 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
3964 " Warning: login service on port %d instead of port 513\n",
3965 ntohs(service->s_port)
3967 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
3968 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
3970 #endif /* RLOGCODE */
3973 /* For HTTP connections we must preserve the original hostname and */
3974 /* service requested so we can include them in the Host header. */
3975 ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
3976 ckitoa(ntohs(service->s_port)),NULL);
3978 /* 'namecopy' contains the name of the host to which we want to connect */
3979 /* 'svcbuf' contains the service name */
3980 /* 'service->s_port' contains the port number in network byte order */
3982 /* If we are using an http proxy, we need to create a buffer containing */
3983 /* hostname:port-number */
3984 /* to pass to the http_connect() function. Then we need to replace */
3985 /* 'namecopy' with the name of the proxy server and the service->s_port */
3986 /* with the port number of the proxy (default port 80). */
3988 if ( tcp_http_proxy ) {
3989 ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
3990 ckuitoa(ntohs(service->s_port)),NULL);
3991 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
3993 p = namecopy; /* Was a service requested? */
3994 while (*p != '\0' && *p != ':') p++; /* Look for colon */
3995 if (*p == ':') { /* Have a colon */
3996 debug(F110,"netopen name has colon",namecopy,0);
3997 *p++ = '\0'; /* Get service name or number */
4002 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4004 fprintf(stderr, "Can't find port for service %s\n", p);
4006 debug(F101,"netopen can't get service for proxy","",socket_errno);
4008 debug(F101,"netopen can't get service for proxy","",errno);
4009 #endif /* TGVORWIN */
4010 errno = 0; /* (rather than mislead) */
4013 ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
4018 /* Set up socket structure and get host address */
4020 bzero((char *)&r_addr, sizeof(r_addr));
4021 debug(F100,"netopen bzero ok","",0);
4023 NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
4024 all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
4025 address without going through the multihomed host sequence and winding up
4026 at a different place than the one requested.
4029 debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
4030 #else /* INADDR_NONE */
4031 debug(F100,"netopen INADDR_NONE not defined","",0);
4032 #endif /* INADDR_NONE */
4034 debug(F100,"netopen INADDRX defined","",0);
4036 debug(F100,"netopen INADDRX not defined","",0);
4037 #endif /* INADDRX */
4041 iax = inet_addr(namecopy);
4042 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4045 iax.s_addr = inet_addr(namecopy);
4046 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4047 #else /* INADDR_NONE */
4049 iax = (unsigned int) inet_addr(namecopy);
4052 #endif /* datageneral */
4053 debug(F111,"netopen inet_addr",namecopy,iax);
4054 #endif /* INADDR_NONE */
4055 #endif /* INADDRX */
4060 /* This might give warnings on 64-bit platforms but they should be harmless */
4061 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
4062 /* probably superfluous -- not sure why it's even there, maybe it should be */
4064 iax.s_addr == INADDR_NONE || iax.s_addr == (unsigned long) -1L
4065 #else /* INADDR_NONE */
4067 #endif /* INADDR_NONE */
4070 printf(" DNS Lookup... ");
4073 if ((host = gethostbyname(namecopy)) != NULL) {
4074 debug(F100,"netopen gethostbyname != NULL","",0);
4075 host = ck_copyhostent(host);
4076 dns = 1; /* Remember we performed dns lookup */
4077 r_addr.sin_family = host->h_addrtype;
4078 if (tcp_rdns && host->h_name && host->h_name[0]
4080 && (tcp_http_proxy == NULL)
4082 ) { /* Copying into our argument? */
4083 ckstrncpy(name,host->h_name,80); /* Bad Bad Bad */
4084 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4085 strncat(name,":",80-strlen(name));
4086 strncat(name,svcbuf,80-strlen(name));
4092 /* This is for trying multiple IP addresses - see <netdb.h> */
4093 if (!(host->h_addr_list))
4095 bcopy(host->h_addr_list[0],
4096 (caddr_t)&r_addr.sin_addr,
4100 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4102 #else /* HADDRLIST */
4103 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4104 #endif /* HADDRLIST */
4106 debug(F111,"BCOPY","host->h_addr",host->h_addr);
4107 #endif /* EXCELAN */
4108 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
4109 (caddr_t)&r_addr.sin_addr);
4110 debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
4111 r_addr.sin_addr.s_addr);
4112 debug(F111,"BCOPY","host->h_length",host->h_length);
4115 #endif /* NOMHHOST */
4119 /* inet_addr() is of type struct in_addr */
4122 debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
4123 ina = inet_addr(namecopy);
4124 uu = *(unsigned int *)&ina;
4125 #else /* Not INADDRX */
4126 /* inet_addr() is unsigned long */
4128 debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
4129 uu = inet_addr(namecopy);
4130 #endif /* INADDRX */
4131 debug(F101,"netopen uu","",uu);
4134 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
4135 #else /* INADDR_NONE */
4136 uu != ((unsigned long)-1)
4137 #endif /* INADDR_NONE */
4139 r_addr.sin_addr.s_addr = uu;
4140 r_addr.sin_family = AF_INET;
4143 fprintf(stdout, "\r\n"); /* complete any previous message */
4145 fprintf(stderr, "Can't get address for %s\n", namecopy);
4147 debug(F101,"netopen can't get address","",socket_errno);
4149 debug(F101,"netopen can't get address","",errno);
4150 #endif /* TGVORWIN */
4151 errno = 0; /* Rather than mislead */
4156 /* Get a file descriptor for the connection. */
4158 r_addr.sin_port = service->s_port;
4159 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4160 debug(F110,"netopen trying",ipaddr,0);
4161 if (!quiet && *ipaddr) {
4162 printf(" Trying %s... ", ipaddr);
4166 /* Loop to try additional IP addresses, if any. */
4170 send_socket.sin_family = AF_INET;
4171 send_socket.sin_addr.s_addr = 0;
4172 send_socket.sin_port = 0;
4173 if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
4174 &send_socket, SO_REUSEADDR)) < 0)
4179 Must make sure that all sockets are opened in
4180 Non-overlapped mode since we use the standard
4181 C RTL functions to read and write data.
4182 But it doesn't seem to work as planned.
4185 int optionValue = SO_SYNCHRONOUS_NONALERT;
4186 if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
4187 (char *) &optionValue, sizeof(optionValue))
4191 #endif /* COMMENT */
4194 if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
4195 #endif /* EXCELAN */
4198 experror("TCP socket error");
4201 fprintf(stdout, "\r\n"); /* complete any previous stdout */
4205 errno = socket_errno;
4206 #endif /* OLD_TWG */
4207 socket_perror("TCP socket error");
4208 debug(F101,"netopen socket error","",socket_errno);
4210 perror("TCP socket error");
4211 debug(F101,"netopen socket error","",errno);
4212 #endif /* TGVORWIN */
4213 #endif /* EXCELAN */
4219 /* Not part of the RLOGIN RFC, but the BSD implementation */
4220 /* requires that the client port be a priviliged port (<1024) */
4221 /* on a Unix system this would require SuperUser permissions */
4222 /* thereby saying that the root of the Unix system has given */
4223 /* permission for this connection to be created */
4224 if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
4225 static unsigned short lport = 1024; /* max reserved port */
4230 lport--; /* Make sure we do not reuse a port */
4234 sin.sin_family = AF_INET;
4237 inaddrx = inet_addr(tcp_address);
4238 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4240 sin.sin_addr.s_addr = inet_addr(tcp_address);
4241 #endif /* INADDRX */
4243 sin.sin_addr.s_addr = INADDR_ANY;
4245 sin.sin_port = htons(lport);
4246 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
4249 s_errno = socket_errno;
4250 if (s_errno && /* OS2 bind fails with 0, if already in use */
4252 s_errno != WSAEADDRINUSE
4254 s_errno != SOCEADDRINUSE &&
4255 s_errno != (SOCEADDRINUSE - SOCBASEERR)
4260 if (socket_errno != EADDRINUSE)
4262 if (errno != EADDRINUSE)
4263 #endif /* TGVORWIN */
4267 printf("\nBind failed with errno %d for port %d.\n",
4275 #endif /* TGVORWIN */
4280 debug(F101,"rlogin bind failed","",s_errno);
4283 debug(F101,"rlogin bind failed","",socket_errno);
4285 errno = socket_errno;
4286 #endif /* OLD_TWG */
4287 socket_perror("rlogin bind");
4289 debug(F101,"rlogin bind failed","",errno);
4290 perror("rlogin bind");
4291 #endif /* TGVORWIN */
4295 debug(F101,"rlogin bind s_errno","",s_errno);
4296 perror("rlogin bind");
4299 printf("\r\n"); /* complete any previous message */
4302 debug(F101,"rlogin bind socket_errno","",socket_errno);
4304 errno = socket_errno;
4305 #endif /* OLD_TWG */
4306 socket_perror("rlogin bind");
4308 debug(F101,"rlogin bind errno","",errno);
4309 perror("rlogin bind");
4310 #endif /* TGVORWIN */
4312 debug(F101,"rlogin local port","",lport);
4313 #endif /* COMMENT */
4318 if (lport == 512 /* lowest reserved port to use */ ) {
4319 printf("\nNo reserved ports available.\n");
4324 debug(F101,"rlogin lport","",lport);
4325 ttnproto = NP_RLOGIN;
4327 #endif /* RLOGCODE */
4329 /* If a specific TCP address on the local host is desired we */
4330 /* must bind it to the socket. */
4335 debug(F110,"netopen binding socket to",tcp_address,0);
4336 bzero((char *)&sin,sizeof(sin));
4337 sin.sin_family = AF_INET;
4339 inaddrx = inet_addr(tcp_address);
4340 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4342 sin.sin_addr.s_addr = inet_addr(tcp_address);
4343 #endif /* INADDRX */
4345 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
4346 s_errno = socket_errno; /* Save error code */
4348 socket_close(ttyfd);
4349 #else /* TCPIPLIB */
4351 #endif /* TCPIPLIB */
4354 errno = s_errno; /* and report this error */
4355 debug(F101,"netopen bind errno","",errno);
4359 #endif /* datageneral */
4361 /* Now connect to the socket on the other end. */
4364 if (connect(ttyfd, &r_addr) < 0)
4367 WSASafeToCancel = 1;
4369 if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
4370 #endif /* EXCELAN */
4373 WSASafeToCancel = 0;
4381 i = errno; /* Save error code */
4382 #endif /* TGVORWIN */
4387 i && /* OS2 bind fails with 0, if already in use */
4391 (i == SOCEADDRINUSE ||
4392 i == (SOCEADDRINUSE - SOCBASEERR))
4396 socket_errno == EADDRINUSE
4399 #endif /* TGVORWIN */
4401 && ttnproto == NP_RLOGIN) {
4403 socket_close(ttyfd); /* Close it. */
4406 #endif /* TCPIPLIB */
4407 continue; /* Try a different lport */
4409 #endif /* RLOGCODE */
4412 if (host && host->h_addr_list && host->h_addr_list[1]) {
4414 host->h_addr_list++;
4415 bcopy(host->h_addr_list[0],
4416 (caddr_t)&r_addr.sin_addr,
4419 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4420 debug(F110,"netopen h_addr_list",ipaddr,0);
4421 if (!quiet && *ipaddr) {
4422 printf(" Trying %s... ", ipaddr);
4426 socket_close(ttyfd); /* Close it. */
4429 #endif /* TCPIPLIB */
4433 #endif /* HADDRLIST */
4438 errno = i; /* And report this error */
4440 if (errno) experror("netopen connect");
4443 debug(F101,"netopen connect error","",socket_errno);
4444 /* if (errno) socket_perror("netopen connect"); */
4446 errno = socket_errno;
4447 #endif /* OLD_TWG */
4449 socket_perror("netopen connect");
4450 #else /* TGVORWIN */
4451 debug(F101,"netopen connect errno","",errno);
4454 perror("\r\nFailed");
4461 perror("netopen connect");
4462 #endif /* DEC_TCPIP */
4465 perror("netopen connect");
4466 #endif /* CMU_TCPIP */
4467 #endif /* TGVORWIN */
4468 #endif /* EXCELAN */
4472 WSASafeToCancel = 0;
4475 } while (!isconnect);
4479 x = socket_ioctl(ttyfd,FIONBIO,&on);
4480 debug(F101,"netopen FIONBIO","",x);
4481 #endif /* NON_BLOCK_IO */
4483 #ifdef NT_TCP_OVERLAPPED
4484 OverlappedWriteInit();
4485 OverlappedReadInit();
4486 #endif /* NT_TCP_OVERLAPPED */
4488 ttnet = nett; /* TCP/IP (sockets) network */
4491 /* We have succeeded in connecting to the HTTP PROXY. So now we */
4492 /* need to attempt to connect through the proxy to the actual host */
4493 /* If that is successful, we have to pretend that we made a direct */
4494 /* connection to the actual host. */
4496 if ( tcp_http_proxy ) {
4498 char * agent = "Kermit 95"; /* Default user agent */
4500 char * agent = "C-Kermit";
4503 if (http_connect(ttyfd,
4504 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
4506 tcp_http_proxy_user,
4515 ckstrncpy(namecopy,proxycopy,NAMECPYL);
4516 p = namecopy; /* Was a service requested? */
4517 while (*p != '\0' && *p != ':') p++; /* Look for colon */
4522 /* Jeff - Does this next block of code that set's the protocol */
4523 /* need to be here anymore? 5/10/2000 */
4525 /* There are certain magic port numbers that when used require */
4526 /* the use of specific protocols. Check this now before we */
4527 /* set the SO_OOBINLINE state or we might get it wrong. */
4528 x = ntohs((unsigned short)service->s_port);
4530 /* See if the service is TELNET. */
4531 if (x == TELNET_PORT) {
4532 /* Yes, so if raw port not requested */
4533 if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
4534 ttnproto = NP_TELNET; /* Select TELNET protocol. */
4537 else if (x == RLOGIN_PORT) {
4538 ttnproto = NP_RLOGIN;
4541 /* There is no good way to do this. If the user didn't tell */
4542 /* which one to use up front. We may guess wrong if the user */
4543 /* has both Kerberos versions installed and valid TGTs for each */
4544 else if (x == KLOGIN_PORT &&
4545 ttnproto != NP_K4LOGIN &&
4546 ttnproto != NP_K5LOGIN) {
4547 if (ck_krb5_is_installed() &&
4548 ck_krb5_is_tgt_valid())
4549 ttnproto = NP_K5LOGIN;
4550 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4551 ttnproto = NP_K4LOGIN;
4553 ttnproto = NP_K4LOGIN;
4554 } else if (x == EKLOGIN_PORT &&
4555 ttnproto != NP_EK4LOGIN &&
4556 ttnproto != NP_EK5LOGIN) {
4557 if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
4558 ttnproto = NP_EK5LOGIN;
4559 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4560 ttnproto = NP_EK4LOGIN;
4562 ttnproto = NP_EK4LOGIN;
4564 #endif /* CK_KERBEROS */
4565 #endif /* RLOGCODE */
4567 else if (x == KERMIT_PORT) { /* IKS uses Telnet protocol */
4568 if (ttnproto == NP_NONE)
4569 ttnproto = NP_KERMIT;
4571 #endif /* IKS_OPTION */
4575 The symbol SO_OOBINLINE is not known to Ultrix 2.0.
4576 It means "leave out of band data inline". The normal value is 0x0100,
4577 but don't try this on systems where the symbol is undefined.
4580 Note from Jeff Altman: 12/13/95
4581 In implementing rlogin protocol I have come to the conclusion that it is
4582 a really bad idea to read out-of-band data inline.
4583 At least Windows and OS/2 does not handle this well.
4584 And if you need to know that data is out-of-band, then it becomes
4585 absolutely pointless.
4587 Therefore, at least on OS2 and Windows (NT) I have changed the value of
4588 on to 0, so that out-of-band data stays out-of-band.
4591 Actually, OOB data should be read inline when possible. Especially with
4592 protocols that don't care about the Urgent flag. This is true with Telnet.
4593 With Rlogin, you need to be able to catch OOB data. However, the best
4594 way to do this is to set a signal handler on SIGURG. This isn't possible
4595 on OS/2 and Windows. But it is in UNIX. We will also need OOB data for
4596 FTP so better create a general mechanism.
4598 The reason for making OOB data be inline is that the standard ttinc/ttoc
4599 calls can be used for reading that data on UNIX systems. If we didn't
4600 have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
4605 if (ttnproto == NP_RLOGIN
4607 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4608 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4609 #endif /* CK_KERBEROS */
4612 #else /* TCPIPLIB */
4613 if (ttnproto == NP_RLOGIN
4615 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4616 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4617 #endif /* CK_KERBEROS */
4619 debug(F100,"Installing rlogoobh on SIGURG","",0);
4620 signal(SIGURG, rlogoobh);
4623 debug(F100,"Ignoring SIGURG","",0);
4624 signal(SIGURG, SIG_DFL);
4626 #endif /* TCPIPLIB */
4627 #endif /* RLOGCODE */
4630 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4633 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4636 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4639 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4642 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4646 Maybe this applies to all SVR4 versions, but the other (else) way has been
4647 compiling and working fine on all the others, so best not to change it.
4649 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4652 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4657 rc = setsockopt(ttyfd,
4663 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
4666 #ifdef VMS /* or, at least, VMS with gcc */
4667 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4670 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4672 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
4677 #endif /* SOLARIS */
4678 #endif /* MOTSV88R4 */
4682 #endif /* datageneral */
4683 #endif /* SO_OOBINLINE */
4689 no_delay(ttyfd,tcp_nodelay);
4690 #endif /* TCP_NODELAY */
4692 keepalive(ttyfd,tcp_keepalive);
4693 #endif /* SO_KEEPALIVE */
4695 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
4696 #endif /* SO_LINGER */
4698 sendbuf(ttyfd,tcp_sendbuf);
4699 #endif /* SO_SNDBUF */
4701 recvbuf(ttyfd,tcp_recvbuf);
4702 #endif /* SO_RCVBUF */
4703 #endif /* SOL_SOCKET */
4704 #endif /* datageneral */
4705 #endif /* NOTCPOPTS */
4708 /* Find out our own IP address. */
4709 /* We need the l_addr structure for [E]KLOGIN. */
4710 l_slen = sizeof(l_addr);
4711 bzero((char *)&l_addr, l_slen);
4713 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
4714 char * s = (char *)inet_ntoa(l_addr.sin_addr);
4715 ckstrncpy(myipaddr, s, 20);
4716 debug(F110,"getsockname",myipaddr,0);
4718 #endif /* EXCELAN */
4719 #endif /* datageneral */
4722 This is really only needed for Kerberos IV but is useful information in any
4723 case. If we connect to a name that is really a pool, we need to get the
4724 name of the machine we are actually connecting to for K4 to authenticate
4725 properly. This way we also update the names properly.
4727 However, it is a security hole when used with insecure DNS.
4729 Note: This does not work on Windows 95 or Windows NT 3.5x. This is because
4730 of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
4731 and Winsock 2.0 on those platforms. Their algorithm is:
4733 1. Check the HOSTENT cache.
4734 2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
4735 3. Do a DNS query if the DNS server is configured for name resolution.
4736 4. Do an additional NetBIOS remote adapter status to an IP address for its
4737 NetBIOS name table. This step is specific only to the Windows NT version
4738 3.51 implementation.
4740 The problem is the use of the HOSTENT cache. It means that gethostbyaddr()
4741 can not be used to resolve the real name of machine if it was originally
4742 accessed by an alias used to represent a cluster.
4744 if ((tcp_rdns && dns || tcp_rdns == SET_ON
4746 || tcp_rdns == SET_AUTO &&
4747 (ck_krb5_is_installed() || ck_krb4_is_installed())
4748 #endif /* CK_KERBEROS */
4751 && (tcp_http_proxy == NULL)
4754 && !(ssl_only_flag || tls_only_flag)
4762 printf(" Reverse DNS Lookup... ");
4765 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
4767 host = ck_copyhostent(host);
4768 debug(F100,"netopen gethostbyname != NULL","",0);
4774 if (!s) { /* This can happen... */
4775 debug(F100,"netopen host->h_name is NULL","",0);
4778 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
4779 /* The compiler says "Integral value implicitly converted to */
4780 /* pointer in assignment." The prototype is right there */
4781 /* in <arpa/inet.h> so what's the problem? */
4782 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
4783 if (!*s) { /* No name so substitute the address */
4784 debug(F100,"netopen host->h_name is empty","",0);
4785 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
4786 if (!s) /* Trust No 1 */
4788 if (*s) { /* If it worked, use this string */
4789 ckstrncpy(ipaddr,s,20);
4791 s = ipaddr; /* Otherwise stick with the IP */
4792 if (!*s) /* or failing that */
4793 s = namecopy; /* the name we were called with. */
4795 if (*s) { /* Copying into our argument? */
4796 ckstrncpy(name,s,80); /* Bad Bad Bad */
4797 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4798 strncat(name,":",80-strlen(name));
4799 strncat(name,svcbuf,80-strlen(name));
4807 printf(" %s connected on port %s\n",s,p);
4809 /* This is simply for testing the DNS entries */
4810 if (host->h_aliases) {
4811 char ** a = host->h_aliases;
4813 printf(" alias => %s\n",*a);
4817 #endif /* BETADEBUG */
4820 if (!quiet) printf("Failed.\n");
4822 } else if (!quiet) printf("(OK)\n");
4823 if (!quiet) fflush(stdout);
4825 /* This should already have been done but just in case */
4826 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4830 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
4832 if (tcp_http_proxy) {
4833 for (i=strlen(proxycopy); i >= 0 ; i--)
4834 if ( proxycopy[i] == ':' )
4835 proxycopy[i] = '\0';
4840 tcp_http_proxy ? proxycopy :
4842 (tcp_rdns && host && host->h_name && host->h_name[0]) ?
4843 (char *)host->h_name : (namecopy2[0] ? namecopy2 :
4844 (namecopy[0] ? namecopy : ipaddr)),
4849 #endif /* CK_SECURITY */
4851 if (ck_ssleay_is_installed()) {
4852 if (!ssl_tn_init(SSL_CLIENT)) {
4853 debug(F100,"netopen ssl_tn_init() failed","",0);
4854 if (bio_err!=NULL) {
4855 BIO_printf(bio_err,"ssl_tn_init() failed\n");
4856 ERR_print_errors(bio_err);
4859 fprintf(stderr,"ssl_tn_init() failed\n");
4860 ERR_print_errors_fp(stderr);
4862 if (tls_only_flag || ssl_only_flag) {
4863 debug(F100,"netopen ssl/tls required","",0);
4868 /* we will continue to accept the connection */
4869 /* without SSL or TLS support unless required. */
4870 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
4871 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
4872 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
4873 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
4874 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
4875 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
4876 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
4877 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
4878 } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
4879 debug(F100,"ck_ssl_outgoing() failed","",0);
4887 if (ttnproto == NP_RLOGIN
4889 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4890 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4891 #endif /* CK_KERBEROS */
4892 ) { /* Similar deal for rlogin */
4893 if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
4894 (CHAR *)host->h_name : (CHAR *)ipaddr),
4898 debug(F100,"rlogin initialization failed","",0);
4903 #endif /* RLOGCODE */
4904 if (tn_ini() < 0) { /* Start Telnet negotiations. */
4906 return(-1); /* Gone, so open failed. */
4914 if ( ttnproto == NP_K5U2U ) {
4915 if (k5_user_to_user_client_auth()) {
4920 #endif /* KRB5_U2U */
4921 #endif /* CK_KERBEROS */
4923 debug(F101,"netopen service","",svcnum);
4924 debug(F110,"netopen name",name,0);
4926 if (lcl) if (*lcl < 0) /* Local mode. */
4928 #endif /* TCPSOCKET */
4929 return(0); /* Done. */
4932 /* N E T C L O S -- Close current network connection. */
4935 _PROTOTYP(VOID slrestor,(VOID));
4937 int tls_norestore = 0;
4939 #endif /* NOLOCAL */
4943 static int close_in_progress = 0;
4945 debug(F101,"netclos","",ttyfd);
4948 if (!tt_push_inited)
4950 #endif /* NETLEBUF */
4952 if (ttyfd == -1) /* Was open? */
4953 return(0); /* Wasn't. */
4955 if (close_in_progress)
4957 close_in_progress = 1; /* Remember */
4960 /* This function call should not be here since this is a direct call */
4961 /* from an I/O routine to a user interface level function. However, */
4962 /* the reality is that we do not have pure interfaces. If we ever */
4963 /* decide to clean this up the UI level should assign this function */
4964 /* via a pointer assignment. - Jeff 9/10/1999 */
4969 #endif /* NOLOCAL */
4971 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
4973 if (ttyfd > -1) /* Was. */
4977 y = 1; /* Turn on nonblocking reads */
4978 z = socket_ioctl(ttyfd,FIONBIO,&y);
4979 debug(F111,"netclos FIONBIO","on",z);
4982 if (ttnproto == NP_TELNET) {
4983 if ( !TELOPT_ME(TELOPT_LOGOUT) ) {
4984 /* Send LOGOUT option before close */
4985 if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
4986 TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
4987 /* It would be nice to call tn_wait but we can't */
4990 tn_push(); /* Place any waiting data into input*/
4994 if (ssl_active_flag) {
4996 BIO_printf(bio_err,"calling SSL_shutdown\n");
4997 SSL_shutdown(ssl_con);
4998 ssl_active_flag = 0;
5000 if (tls_active_flag) {
5002 BIO_printf(bio_err,"calling SSL_shutdown\n");
5003 SSL_shutdown(tls_con);
5004 tls_active_flag = 0;
5008 ck_cancio(); /* Cancel any outstanding reads. */
5011 x = socket_close(ttyfd); /* Close it. */
5015 if (ttnet == NET_IX25) {
5016 /* riehm: should send a disc_req - but only if link is still OK */
5020 /* we were the passive client of a server, now we
5021 * go back to being the normal client.
5022 * I hope that kermit can cope with the logic that
5023 * there can still be a connection after netclos
5026 ttyfd = x25serverfd;
5029 * need to close the server connection too - because
5030 * all file descriptors connected to the NPI have the
5033 * The problem is that any waiting connections get
5034 * lost, the client doesn't realise, and hangs.
5038 x25_state = X25_CLOSED; /* riehm: dead code? */
5043 #endif /* TCPIPLIB */
5045 ttyfd = -1; /* Mark it as closed. */
5048 ReleaseTCPIPMutex();
5052 fwdx_close_all(); /* Shut down any Forward X sockets */
5053 #endif /* CK_FORWARD_X */
5054 tn_reset(); /* The Reset Telnet Option table. */
5055 debug(F100,"netclose setting tn_init = 0","",0);
5056 tn_init = 0; /* Remember about telnet protocol... */
5057 sstelnet = 0; /* Client-side Telnet */
5059 *ipaddr = '\0'; /* Zero the IP address string */
5060 tcp_incoming = 0; /* No longer incoming */
5061 /* Don't reset ttnproto so that we can remember which protocol is in use */
5065 Empty the internal buffers so they won't be used as invalid input on
5066 the next connect attempt (rlogin).
5070 #endif /* TCPIPLIB */
5072 /* If we are automatically destroying Kerberos credentials on Close */
5075 if (krb4_autodel == KRB_DEL_CL) {
5076 extern struct krb_op_data krb_op;
5078 krb_op.cache = NULL;
5079 ck_krb4_destroy(&krb_op);
5083 if (krb5_autodel == KRB_DEL_CL) {
5084 extern struct krb_op_data krb_op;
5085 extern char * krb5_d_cc;
5087 krb_op.cache = krb5_d_cc;
5088 ck_krb5_destroy(&krb_op);
5091 #endif /* CK_KERBEROS */
5092 close_in_progress = 0; /* Remember we are done. */
5098 os2socketerror( int s_errno ) {
5100 if (s_errno > 0 && s_errno <= SOCBASEERR) {
5101 /* in OS/2, there is a problem with threading in that
5102 * the value of errno is not thread safe. It can be
5103 * set to a value from a previous library call and if
5104 * it was not cleared it will appear here. Only treat
5105 * valid socket error codes as errors in this function.
5107 debug(F100,"os2socketerror errno.h","",0);
5111 #endif /* OS2ONLY */
5114 case 0: /* NO ERROR */
5115 debug(F100,"os2socketerror NOERROR","",0);
5121 case SOCECONNRESET - SOCBASEERR:
5123 debug(F100,"os2socketerror ECONRESET","",0);
5124 tn_debug("ECONRESET");
5125 netclos(); /* *** *** */
5126 return(-1); /* Connection is broken. */
5128 case WSAECONNABORTED:
5130 case SOCECONNABORTED:
5131 case SOCECONNABORTED - SOCBASEERR:
5133 debug(F100,"os2socketerror ECONNABORTED","",0);
5134 tn_debug("ECONNABORTED");
5135 netclos(); /* *** *** */
5136 return(-1); /* Connection is broken. */
5141 case SOCENETRESET - SOCBASEERR:
5143 debug(F100,"os2socketerror ENETRESET","",0);
5144 tn_debug("ENETRESET");
5145 netclos(); /* *** *** */
5146 return(-1); /* Connection is broken. */
5151 case SOCENOTCONN - SOCBASEERR:
5153 debug(F100,"os2socketerror ENOTCONN","",0);
5154 tn_debug("ENOTCONN");
5155 netclos(); /* *** *** */
5156 return(-1); /* Connection is broken. */
5159 debug(F100,"os2socketerror ESHUTDOWN","",0);
5160 tn_debug("ESHUTDOWN");
5161 netclos(); /* *** *** */
5162 return(-1); /* Connection is broken. */
5165 case WSAEWOULDBLOCK:
5167 case SOCEWOULDBLOCK:
5168 case SOCEWOULDBLOCK - SOCBASEERR:
5170 debug(F100,"os2socketerror EWOULDBLOCK","",0);
5173 case ERROR_IO_INCOMPLETE:
5174 case ERROR_IO_PENDING:
5175 case ERROR_OPERATION_ABORTED:
5185 /* N E T T C H K -- Check if network up, and how many bytes can be read */
5187 Returns number of bytes waiting, or -1 if connection has been dropped.
5189 int /* Check how many bytes are ready */
5190 nettchk() { /* for reading from network */
5198 extern int ionoblock; /* For Overlapped I/O */
5201 debug(F101,"nettchk entry ttibn","",ttibn);
5202 debug(F101,"nettchk entry ttibp","",ttibp);
5213 #endif /* NETLEBUF */
5217 socket_errno = 0; /* This is a function call in NT, and BeOS */
5222 debug(F100,"nettchk socket is closed","",0);
5226 Note: this socket_ioctl() call does NOT return an error if the
5227 connection has been broken. (At least not in MultiNet.)
5230 /* Another trick that can be tried here is something like this: */
5232 if (ttnet == NET_TCPB) {
5234 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5235 if (x < 0) { /* "Connection reset by peer" */
5236 perror("TCP/IP"); /* or somesuch... */
5237 ttclos(0); /* Close our end too. */
5241 #endif /* COMMENT */
5245 if (ssl_active_flag) {
5248 if ( IsConnectMode() ) {
5249 debug(F101,"nettchk (ssl_active_flag) returns","",count);
5253 #endif /* IKSDONLY */
5254 count = SSL_pending(ssl_con);
5256 debug(F111,"nettchk","SSL_pending error",count);
5261 return(count); /* Don't perform a read */
5262 } else if (tls_active_flag) {
5265 if ( IsConnectMode() ) {
5266 debug(F101,"nettchk (tls_active_flag) returns","",count);
5270 #endif /* IKSDONLY */
5271 count = SSL_pending(tls_con);
5273 debug(F111,"nettchk","TLS_pending error",count);
5278 return(count); /* Don't perform a read */
5282 if (socket_ioctl(ttyfd,FIONREAD,
5284 /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
5286 /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
5287 /* Cast needed for DECC 4.1 & later? */
5288 /* Maybe, but __DECC_VER only exists in 5.0 and later */
5291 #endif /* COMMENT */
5294 debug(F101,"nettchk socket_ioctl error","",socket_errno);
5295 /* If the connection is gone, the connection is gone. */
5297 #ifdef NT_TCP_OVERLAPPED
5298 /* Is there anything in the overlapped I/O buffers? */
5299 count += OverlappedDataWaiting();
5300 #endif /* NT_TCP_OVERLAPPED */
5302 return(count>0?count:-1);
5304 debug(F101,"nettchk count","",count);
5305 #ifdef NT_TCP_OVERLAPPED
5306 /* Is there anything in the overlapped I/O buffers? */
5307 count += OverlappedDataWaiting();
5308 debug(F101,"nettchk count w/overlapped","",count);
5309 #endif /* NT_TCP_OVERLAPPED */
5313 if ( IsConnectMode() ) {
5314 debug(F101,"nettchk (FIONREAD) returns","",count);
5317 #endif /* IKSDONLY */
5320 /* For the sake of efficiency, if there is still data in the ttibuf */
5321 /* do not go to the bother of checking to see of the connection is */
5322 /* still valid. The handle is still good, so just return the count */
5323 /* of the bytes that we already have left to process. */
5325 if ( count > 0 || ttibn > 0 ) {
5327 debug(F101,"nettchk (count+ttibn > 0) returns","",count);
5330 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5332 ttibp = 0; /* reset for next read */
5335 if ( count > 0 || ttibn > 0 ) {
5336 debug(F101,"nettchk returns","",count+ttibn);
5337 return(count+ttibn);
5343 The following code works well in most settings, but messes things up in
5344 others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
5345 make it impossible to ever make a new connection to the same host again with
5346 CONNECT, once it has been logged out from the first time. Not even if you
5347 HANGUP first, or SET HOST<CR>, or SET LINE<CR>. Reportedly, however, it
5348 does work OK in later releases of UCX. But there is no way we can
5349 accommodate both old and new -- we might have static linking or dynamic
5350 linking, etc etc. If we have static, I only have access to 2.0, where this
5351 doesn't work, etc etc blah blah.
5353 In the following lines, we define a symbol NOCOUNT for builds where we want
5354 to omit this code. By default, it is omitted for CMU/Tek. You can force
5355 omission of it for other combinations by defining NOCOUNT in CFLAGS. You
5356 can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
5362 #endif /* NOCOUNT */
5367 #endif /* CMU_TCPIP */
5368 #endif /* NOCOUNT */
5369 #endif /* NONOCOUNT */
5372 /* From this point forward we have a possible race condition in K95
5373 * due to its use of multiple threads. Therefore, we must ensure
5374 * that only one thread attempt to read/write from the socket at a
5375 * time. Otherwise, it is possible for a buffer to be overwritten.
5377 /* we know now that count >= 0 and that ttibn == 0 */
5382 && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
5383 #endif /* CK_KERBEROS */
5384 #endif /* RLOGCODE */
5389 Here we need to tell the difference between a 0 count on an active
5390 connection, and a 0 count because the remote end of the socket broke the
5391 connection. There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
5392 the status of the connection, so we have to do a read. -1 means there was
5393 no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
5394 down. But if, by chance, we actually get a character, we have to put it
5395 where it won't be lost.
5397 #ifndef NON_BLOCK_IO
5400 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5403 y = 1; /* Turn on nonblocking reads */
5404 z = socket_ioctl(ttyfd,FIONBIO,&y);
5405 debug(F111,"nettchk FIONBIO","on",z);
5411 #endif /* NON_BLOCK_IO */
5412 #ifdef NT_TCP_OVERLAPPED
5413 ionoblock = 1; /* For Overlapped I/O */
5414 #endif /* NT_TCP_OVERLAPPED */
5416 if ( ssl_active_flag || tls_active_flag ) {
5419 x = SSL_read( ssl_active_flag?ssl_con:tls_con,
5420 &ttibuf[ttibp+ttibn],
5421 TTIBUFL-ttibp-ttibn );
5422 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
5423 case SSL_ERROR_NONE:
5424 debug(F111,"nettchk SSL_ERROR_NONE","x",x);
5426 case SSL_ERROR_WANT_WRITE:
5427 debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
5430 case SSL_ERROR_WANT_READ:
5431 debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
5434 case SSL_ERROR_SYSCALL:
5435 if ( x == 0 ) { /* EOF */
5438 goto nettchk_return;
5441 int gle = GetLastError();
5443 #ifndef NON_BLOCK_IO
5446 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5449 y = 0; /* Turn off nonblocking reads */
5450 z = socket_ioctl(ttyfd,FIONBIO,&y);
5451 debug(F111,"nettchk FIONBIO","off",z);
5457 #endif /* NON_BLOCK_IO */
5458 #ifdef NT_TCP_OVERLAPPED
5459 ionoblock = 0; /* For Overlapped I/O */
5460 #endif /* NT_TCP_OVERLAPPED */
5462 debug(F111,"nettchk SSL_ERROR_SYSCALL",
5463 "GetLastError()",gle);
5464 rc = os2socketerror(gle);
5467 else if ( rc == -2 )
5469 goto nettchk_return;
5473 case SSL_ERROR_WANT_X509_LOOKUP:
5474 debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
5477 if (bio_err!=NULL) {
5479 extern char ssl_err[];
5480 BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
5481 ERR_print_errors(bio_err);
5482 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
5483 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
5484 debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
5487 } else if (ssl_debug_flag) {
5488 debug(F100,"nettchk SSL_ERROR_SSL","",0);
5490 fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
5491 ERR_print_errors_fp(stderr);
5496 goto nettchk_return;
5501 case SSL_ERROR_ZERO_RETURN:
5502 debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
5505 goto nettchk_return;
5507 debug(F100,"nettchk SSL_ERROR_?????","",0);
5510 goto nettchk_return;
5520 x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
5521 TTIBUFL-ttibp-ttibn); /* Returns -1 if no data */
5523 x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */
5526 s_errno = socket_errno; /* socket_errno may be a function */
5527 debug(F101,"nettchk socket_read","",x);
5529 #ifndef NON_BLOCK_IO
5532 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5535 y = 0; /* Turn off nonblocking reads */
5536 z = socket_ioctl(ttyfd,FIONBIO,&y);
5537 debug(F111,"nettchk FIONBIO","off",z);
5543 #endif /* NON_BLOCK_IO */
5544 #ifdef NT_TCP_OVERLAPPED
5545 ionoblock = 0; /* For Overlapped I/O */
5546 #endif /* NT_TCP_OVERLAPPED */
5549 debug(F101,"nettchk socket_read errno","",s_errno);
5551 if (os2socketerror(s_errno) < 0) {
5553 goto nettchk_return;
5556 } else if (x == 0) {
5557 debug(F100,"nettchk connection closed","",0);
5558 netclos(); /* *** *** */
5560 goto nettchk_return;
5562 if (x >= 1) { /* Oops, actually got a byte? */
5564 /* In OS/2 we read directly into ttibuf[] */
5565 hexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5569 if ( ssl_active_flag || tls_active_flag ) {
5570 hexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5575 debug(F101,"nettchk socket_read char","",c);
5576 debug(F101,"nettchk ttibp","",ttibp);
5577 debug(F101,"nettchk ttibn","",ttibn);
5579 In the case of Overlapped I/O the character would have come from
5580 the beginning of the buffer, so put it back.
5587 ttibuf[ttibp+ttibn] = c;
5594 if (ttnet == NET_TCPB) {
5596 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5597 if (x < 0) { /* "Connection reset by peer" */
5598 perror("TCP/IP"); /* or somesuch... */
5599 ttclos(0); /* Close our end too. */
5601 goto nettchk_return;
5604 #endif /* NOCOUNT */
5609 if (ttnproto == NP_EK4LOGIN)
5610 count += krb4_des_avail(ttyfd);
5611 #endif /* RLOGCODE */
5615 if (ttnproto == NP_EK5LOGIN)
5616 count += krb5_des_avail(ttyfd);
5617 #endif /* RLOGCODE */
5619 if (ttnproto == NP_K5U2U)
5620 count += krb5_u2u_avail(ttyfd);
5621 #endif /* KRB5_U2U */
5623 #endif /* CK_KERBEROS */
5625 debug(F101,"nettchk returns","",count+ttibn);
5630 ReleaseTCPIPMutex();
5634 #else /* Not TCPIPLIB */
5636 UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
5640 #endif /* TCPIPLIB */
5642 But what about X.25?
5648 nettout(i) int i; { /* Catch the alarm interrupts */
5649 debug(F100,"nettout caught timeout","",0);
5651 cklongjmp(njbuf, -1);
5659 donetinc(void * threadinfo)
5660 #else /* CK_ANSIC */
5661 donetinc(threadinfo) VOID * threadinfo;
5662 #endif /* CK_ANSIC */
5665 extern int TlsIndex;
5667 if (threadinfo) { /* Thread local storage... */
5668 TlsSetValue(TlsIndex,threadinfo);
5678 #endif /* CK_LOGIN */
5680 if (ttbufr() < 0) /* Keep trying to refill it. */
5681 break; /* Till we get an error. */
5682 if (ttibn > 0) /* Or we get a character. */
5686 #endif /* TCPIPLIB */
5690 failnetinc(void * threadinfo)
5691 #else /* CK_ANSIC */
5692 failnetinc(threadinfo) VOID * threadinfo;
5693 #endif /* CK_ANSIC */
5695 ; /* Nothing to do on an error */
5698 /* N E T X I N -- Input block of characters from network */
5701 netxin(n,buf) int n; CHAR * buf; {
5705 #endif /* TCPIPLIB */
5708 debug(F100,"netxin socket is closed","",0);
5714 if (ttnproto == NP_EK4LOGIN) {
5715 if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
5720 #endif /* RLOGCODE */
5724 if (ttnproto == NP_EK5LOGIN) {
5725 if ((len = krb5_des_read(ttyfd,buf,n,0)) < 0)
5730 #endif /* RLOGCODE */
5732 if (ttnproto == NP_K5U2U) {
5733 if ((len = krb5_u2u_read(ttyfd,buf,n)) < 0)
5738 #endif /* KRB5_U2U */
5740 #endif /* CK_KERBEROS */
5744 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5747 if ((rc = ttbufr()) <= 0) {
5749 ReleaseTCPIPMutex();
5756 memcpy(buf,&ttibuf[ttibp],len); /* safe */
5760 memcpy(buf,&ttibuf[ttibp],n); /* safe */
5766 ReleaseTCPIPMutex();
5768 #else /* TCPIPLIB */
5769 for (i = 0; i < n; i++) {
5770 if ((j = netinc(0)) < 0) {
5779 #endif /* TCPIPLIB */
5782 #ifdef CK_ENCRYPTION
5783 /* This would be great if it worked. But what if the buffer we read */
5784 /* contains a telnet negotiation that changes the state of the */
5785 /* encryption. If so, we would be either decrypting unencrypted text */
5786 /* or not decrypting encrypted text. So we must move this call to */
5787 /* all functions that call ttxin(). In OS2 that means os2_netxin() */
5788 /* where the Telnet Negotiations are handled. */
5790 ck_tn_decrypt(buf,len);
5791 #endif /* CK_ENCRYPTION */
5792 #endif /* COMMENT */
5797 /* N E T I N C -- Input character from network */
5801 #endif /* NETLEBUF */
5804 #endif /* TTLEBUF */
5812 netinc(timo) int timo; {
5814 int x; unsigned char c; /* The locals. */
5818 debug(F111,"netinc","ttpush",ttpush);
5824 if (le_getchar((CHAR *)&c) > 0) {
5825 debug(F111,"netinc le_getchar","c",c);
5829 #endif /* NETLEBUF */
5832 debug(F100,"netinc socket is closed","",0);
5839 if (ttnproto == NP_EK4LOGIN) {
5840 if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
5847 #endif /* RLOGCODE */
5851 if (ttnproto == NP_EK5LOGIN) {
5852 if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
5859 #endif /* RLOGCODE */
5861 if (ttnproto == NP_K5U2U) {
5862 if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
5869 #endif /* KRB5_U2U */
5871 #endif /* CK_KERBEROS */
5874 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5876 if (ttibn > 0) { /* Something in internal buffer? */
5878 debug(F100,"netinc char in buf","",0); /* Yes. */
5879 #endif /* COMMENT */
5880 x = 0; /* Success. */
5881 } else { /* Else must read from network. */
5882 x = -1; /* Assume failure. */
5884 debug(F101,"netinc goes to net, timo","",timo);
5888 * In the case of OpenSSL, it is possible that there is still
5889 * data waiting in the SSL session buffers that has not yet
5890 * been read by Kermit. If this is the case we must process
5891 * it without calling select() because select() will not return
5892 * with an indication that there is data to be read from the
5893 * socket. If there is no data pending in the SSL session
5894 * buffers then fall through to the select() code and wait for
5895 * some data to arrive.
5897 if (ssl_active_flag) {
5898 x = SSL_pending(ssl_con);
5900 debug(F111,"netinc","SSL_pending error",x);
5903 ReleaseTCPIPMutex();
5906 } else if ( x > 0 ) {
5907 if ( ttbufr() >= 0 ) {
5910 ReleaseTCPIPMutex();
5916 } else if (tls_active_flag) {
5917 x = SSL_pending(tls_con);
5919 debug(F111,"netinc","TLS_pending error",x);
5922 ReleaseTCPIPMutex();
5925 } else if ( x > 0 ) {
5926 if ( ttbufr() >= 0 ) {
5929 ReleaseTCPIPMutex();
5938 if (timo == 0) { /* Untimed case. */
5939 while (1) { /* Wait forever if necessary. */
5940 if (ttbufr() < 0) /* Refill buffer. */
5941 break; /* Error, fail. */
5942 if (ttibn > 0) { /* Success. */
5947 } else /* Timed case... */
5950 #ifdef NT_TCP_OVERLAPPED
5951 /* This code is for use on NT when we are using */
5952 /* Overlapped I/O to handle reads. In the case */
5953 /* of outstanding reads select() doesn't work */
5955 if (WaitForOverlappedReadData(timo)) {
5957 if (ttbufr() < 0) /* Keep trying to refill it. */
5958 break; /* Till we get an error. */
5959 if (ttibn > 0) { /* Or we get a character. */
5965 #else /* NT_TCP_OVERLAPPED */
5969 int timeout = timo < 0 ? -timo : 1000 * timo;
5970 debug(F101,"netinc BSDSELECT","",timo);
5972 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
5974 debug(F111,"netinc","timeout",timeout);
5975 /* Don't move select() initialization out of the loop. */
5977 FD_SET(ttyfd, &rfds);
5978 tv.tv_sec = tv.tv_usec = 0L;
5980 tv.tv_usec = (long) 100000L;
5984 WSASafeToCancel = 1;
5986 rc = select(FD_SETSIZE,
5990 &rfds, NULL, NULL, &tv);
5992 int s_errno = socket_errno;
5993 debug(F111,"netinc","select",rc);
5994 debug(F111,"netinc","socket_errno",s_errno);
5997 ReleaseTCPIPMutex();
6002 debug(F111,"netinc","select",rc);
6004 WSASafeToCancel = 0;
6006 if (!FD_ISSET(ttyfd, &rfds)) {
6008 if (le_inbuf() > 0) {
6013 /* If waiting forever we have no way of knowing if the */
6014 /* socket closed so try writing a 0-length TCP packet */
6015 /* which should force an error if the socket is closed */
6017 if ((rc = socket_write(ttyfd,"",0)) < 0) {
6018 int s_errno = socket_errno;
6019 debug(F101,"netinc socket_write error","",s_errno);
6021 if (os2socketerror(s_errno) < 0) {
6022 ReleaseTCPIPMutex();
6025 ReleaseTCPIPMutex();
6027 return(-1); /* Call it an i/o error */
6033 if (ttbufr() < 0) { /* Keep trying to refill it. */
6035 break; /* Till we get an error. */
6037 if (ttibn > 0) { /* Or we get a character. */
6045 WSASafeToCancel = 0;
6047 #else /* !BSDSELECT */
6050 Was used by OS/2, currently not used, but might come in handy some day...
6051 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
6052 and timeval stuff since this is the only place where it is used.
6055 int timeout = timo < 0 ? -timo : 1000 * timo;
6057 debug(F101,"netinc IBMSELECT","",timo);
6058 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6059 if (select(&socket, 1, 0, 0, 100L) == 1) {
6061 if (ttbufr() < 0) { /* Keep trying to refill it. */
6063 break; /* Till we get an error. */
6065 if (ttibn > 0) { /* Or we get a character. */
6073 else if (le_inbuf() > 0) {
6079 #else /* !IBMSELECT */
6081 /* Actually, under WinSock we have a better mechanism than select() */
6082 /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
6083 SOCKET socket = ttyfd;
6084 debug(F101,"netinc NTSELECT","",timo);
6085 if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
6086 sizeof(timo)) == NO_ERROR)
6088 if (ttbufr() < 0) /* Keep trying to refill it. */
6089 break; /* Till we get an error. */
6090 if (ttibn > 0) { /* Or we get a character. */
6097 If we can't use select(), then we use the regular alarm()/signal()
6100 debug(F101,"netinc alarm","",timo);
6101 x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
6102 ttimoff(); /* Timer off. */
6103 #endif /* WINSOCK */
6104 #endif /* IBMSELECT */
6105 #endif /* BSDSELECT */
6106 #endif /* NT_TCP_OVERLAPPED */
6111 if (le_inbuf() > 0) { /* If data was inserted into the */
6112 if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the */
6113 #ifdef OS2 /* was taking place do not mix */
6114 ReleaseTCPIPMutex(); /* the le data with the net data */
6120 if (x < 0) { /* Return -1 if we failed. */
6121 debug(F100,"netinc timed out","",0);
6123 ReleaseTCPIPMutex();
6126 } else { /* Otherwise */
6127 c = ttibuf[ttibp]; /* Return the first char in ttibuf[] */
6130 debug(F101,"netinc returning","",c);
6131 #endif /* COMMENT */
6133 debug(F101,"netinc 0 ttibn","",ttibn);
6134 debug(F101,"netinc 0 ttibp","",ttibp);
6138 extern int tt_type_mode;
6139 if ( !ISVTNT(tt_type_mode) )
6141 hexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
6143 #endif /* BETADEBUG */
6149 ReleaseTCPIPMutex();
6151 #ifdef CK_ENCRYPTION
6152 if (TELOPT_U(TELOPT_ENCRYPTION))
6153 ck_tn_decrypt(&c,1);
6154 #endif /* CK_ENCRYPTION */
6157 #else /* Not using TCPIPLIB */
6159 #endif /* TCPIPLIB */
6162 /* N E T T O L -- Output a string of bytes to the network */
6164 Call with s = pointer to string, n = length.
6165 Returns number of bytes actually written on success, or
6166 -1 on i/o error, -2 if called improperly.
6170 nettol(s,n) CHAR *s; int n; {
6177 debug(F100,"nettol socket is closed","",0);
6180 debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
6182 hexdump("nettol",s,n);
6183 #endif /* COMMENT */
6188 if (ttnproto == NP_EK4LOGIN) {
6189 return(krb4_des_write(ttyfd,s,n));
6191 #endif /* RLOGCODE */
6195 if (ttnproto == NP_EK5LOGIN) {
6196 return(krb5_des_write(ttyfd,s,n,0));
6198 #endif /* RLOGCODE */
6200 if (ttnproto == NP_K5U2U) {
6201 return(krb5_u2u_write(ttyfd,s,n));
6203 #endif /* KRB5_U2U */
6205 #endif /* CK_KERBEROS */
6207 #ifdef CK_ENCRYPTION
6208 if (TELOPT_ME(TELOPT_ENCRYPTION))
6210 #endif /* CK_ENCRYPTION */
6213 if (ssl_active_flag || tls_active_flag) {
6215 /* Write using SSL */
6217 if (ssl_active_flag)
6218 r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
6220 r = SSL_write(tls_con, s, len /* >1024?1024:len */);
6221 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
6222 case SSL_ERROR_NONE:
6223 debug(F111,"nettol","SSL_write",r);
6229 case SSL_ERROR_WANT_WRITE:
6230 debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
6232 case SSL_ERROR_WANT_READ:
6233 debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
6235 case SSL_ERROR_SYSCALL:
6236 if ( r == 0 ) { /* EOF */
6242 int gle = GetLastError();
6243 debug(F111,"nettol SSL_ERROR_SYSCALL",
6244 "GetLastError()",gle);
6245 rc = os2socketerror(gle);
6248 else if ( rc == -2 )
6253 case SSL_ERROR_WANT_X509_LOOKUP:
6254 debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
6258 debug(F100,"nettol SSL_ERROR_SSL","",0);
6259 if (bio_err!=NULL) {
6261 extern char ssl_err[];
6262 BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
6263 ERR_print_errors(bio_err);
6264 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6265 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6266 debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
6269 } else if (ssl_debug_flag) {
6270 debug(F100,"nettol SSL_ERROR_SSL","",0);
6272 fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
6273 ERR_print_errors_fp(stderr);
6281 case SSL_ERROR_ZERO_RETURN:
6282 debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
6286 debug(F100,"nettol SSL_ERROR_?????","",0);
6294 try++; /* Increase the try counter */
6296 if (ttnet == NET_TCPB) {
6301 debug(F101,"nettol BSDSELECT","",0);
6305 WSASafeToCancel = 1;
6309 #endif /* STREAMING */
6311 FD_SET(ttyfd, &wfds);
6312 if (select(FD_SETSIZE, NULL,
6316 #endif /* __DECC_VER */
6318 &wfds, NULL, &tv) < 0) {
6319 int s_errno = socket_errno;
6320 debug(F101,"nettol select failed","",s_errno);
6322 printf("nettol select failed: %d\n", s_errno);
6323 #endif /* BETADEBUG */
6325 WSASafeToCancel = 0;
6326 if (!win95selectbug)
6330 if (!FD_ISSET(ttyfd, &wfds)) {
6334 #endif /* STREAMING */
6335 debug(F111,"nettol","!FD_ISSET",ttyfd);
6337 WSASafeToCancel = 0;
6338 if (!win95selectbug)
6343 WSASafeToCancel = 0;
6345 #else /* BSDSELECT */
6349 debug(F101,"nettol IBMSELECT","",0);
6350 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6352 if (tries++ >= 60) {
6353 /* if after 60 seconds we can't get permission to write */
6354 debug(F101,"nettol select failed","",socket_errno);
6357 if ((count = nettchk()) < 0) {
6358 debug(F111,"nettol","nettchk()",count);
6363 #endif /* IBMSELECT */
6364 #endif /* BSDSELECT */
6365 if ((count = socket_write(ttyfd,s,n)) < 0) {
6366 int s_errno = socket_errno; /* maybe a function */
6367 debug(F101,"nettol socket_write error","",s_errno);
6369 if (os2socketerror(s_errno) < 0)
6372 return(-1); /* Call it an i/o error */
6375 debug(F111,"nettol socket_write",s,count);
6377 /* don't try more than 25 times */
6378 debug(F100,"nettol tried more than 25 times","",0);
6385 debug(F111,"nettol retry",s,n);
6388 debug(F111,"nettol socket_write",s,count);
6389 return(len); /* success - return total length */
6394 debug(F100,"nettol TCPIPLIB not defined","",0);
6396 #endif /* TCPIPLIB */
6399 /* N E T T O C -- Output character to network */
6401 Call with character to be transmitted.
6402 Returns 0 if transmission was successful, or
6403 -1 upon i/o error, or -2 if called improperly.
6410 #endif /* CK_ANSIC */
6418 debug(F100,"nettoc socket is closed","",0);
6422 debug(F101,"nettoc cc","",cc);
6427 if (ttnproto == NP_EK4LOGIN) {
6428 return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
6430 #endif /* RLOGCODE */
6434 if (ttnproto == NP_EK5LOGIN) {
6435 return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
6437 #endif /* RLOGCODE */
6439 if (ttnproto == NP_K5U2U) {
6440 return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
6442 #endif /* KRB5_U2U */
6444 #endif /* CK_KERBEROS */
6446 #ifdef CK_ENCRYPTION
6447 if ( TELOPT_ME(TELOPT_ENCRYPTION) )
6448 ck_tn_encrypt(&cc,1);
6449 #endif /* CK_ENCRYPTION */
6451 if (ssl_active_flag || tls_active_flag) {
6453 /* Write using SSL */
6455 if (ssl_active_flag)
6456 len = SSL_write(ssl_con, &cc, 1);
6458 len = SSL_write(tls_con, &cc, 1);
6459 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
6460 case SSL_ERROR_NONE:
6461 debug(F111,"nettoc","SSL_write",len);
6462 return(len == 1 ? 0 : -1);
6463 case SSL_ERROR_WANT_WRITE:
6464 case SSL_ERROR_WANT_READ:
6466 case SSL_ERROR_SYSCALL:
6467 if ( len == 0 ) { /* EOF */
6473 int gle = GetLastError();
6474 debug(F111,"nettoc SSL_ERROR_SYSCALL",
6475 "GetLastError()",gle);
6476 rc = os2socketerror(gle);
6479 else if ( rc == -2 )
6485 if (bio_err!=NULL) {
6487 extern char ssl_err[];
6488 BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
6489 ERR_print_errors(bio_err);
6490 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6491 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6492 debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
6495 } else if (ssl_debug_flag) {
6496 debug(F100,"nettoc SSL_ERROR_SSL","",0);
6498 fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
6499 ERR_print_errors_fp(stderr);
6503 case SSL_ERROR_WANT_X509_LOOKUP:
6504 case SSL_ERROR_ZERO_RETURN:
6511 if (ttnet == NET_TCPB) {
6516 debug(F101,"nettoc BSDSELECT","",0);
6522 #endif /* STREAMING */
6525 FD_SET(ttyfd, &wfds);
6526 if (select(FD_SETSIZE, NULL,
6530 #endif /* __DECC_VER */
6532 &wfds, NULL, &tv) < 0) {
6533 int s_errno = socket_errno;
6534 debug(F101,"nettoc select failed","",s_errno);
6536 printf("nettoc select failed: %d\n", s_errno);
6537 #endif /* BETADEBUG */
6539 WSASafeToCancel = 0;
6540 if (!win95selectbug)
6544 if (!FD_ISSET(ttyfd, &wfds)) {
6548 #endif /* STREAMING */
6549 debug(F111,"nettoc","!FD_ISSET",ttyfd);
6551 WSASafeToCancel = 0;
6552 if (!win95selectbug)
6557 WSASafeToCancel = 0;
6559 #else /* BSDSELECT */
6563 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6565 if (tries++ >= 60) {
6566 /* if after 60 seconds we can't get permission to write */
6567 debug(F101,"nettoc select failed","",socket_errno);
6570 if ((count = nettchk()) < 0) {
6571 debug(F111,"nettoc","nettchk()",count);
6576 #endif /* IBMSELECT */
6577 #endif /* BSDSELECT */
6578 if (socket_write(ttyfd,&cc,1) < 1) {
6579 int s_errno = socket_errno; /* maybe a function */
6580 debug(F101,"nettoc socket_write error","",s_errno);
6582 if (os2socketerror(s_errno) < 0)
6587 debug(F101,"nettoc socket_write","", cc);
6592 #endif /* TCPIPLIB */
6596 /* N E T F L U I -- Flush network input buffer */
6601 netgetc(int timo) /* Input function to point to... */
6602 #else /* CK_ANSIC */
6603 netgetc(timo) int timo;
6604 #endif /* CK_ANSIC */
6605 { /* ...in the tn_doop() call */
6607 return netinc(timo);
6608 #else /* TCPIPLIB */
6610 #endif /* TCPIPLIB */
6619 ttpush = -1; /* Clear the peek-ahead char */
6620 while (le_data && (le_inbuf() > 0)) {
6622 if (le_getchar(&ch) > 0) {
6623 debug(F101,"ttflui le_inbuf ch","",ch);
6626 #endif /* NETLEBUF */
6630 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6633 if (ttnproto == NP_TELNET) {
6634 /* Netflui must process Telnet negotiations or get out of sync */
6635 if ((n = nettchk()) <= 0)
6640 extern int duplex; /* this really shouldn't be here but ... */
6641 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6642 if (tx == 1) duplex = 1;
6643 else if (tx == 2) duplex = 0;
6650 ttibuf[ttibp+ttibn] = '\0';
6651 debug(F111,"netflui 1",ttibuf,ttibn);
6652 #ifdef CK_ENCRYPTION
6653 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6654 ck_tn_decrypt(&ttibuf[ttibp],ttibn);
6656 #endif /* CK_ENCRYPTION */
6657 ttibn = ttibp = 0; /* Flush internal buffer *FIRST* */
6660 if ((n = nettchk()) > 0) { /* Now see what's waiting on the net */
6661 if (n > TTIBUFL) n = TTIBUFL; /* and sponge it up */
6662 debug(F101,"netflui 2","",n); /* ... */
6663 n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
6664 if (n >= 0) ttibuf[n] = '\0';
6665 debug(F111,"netflui 3",ttibuf,n);
6666 #ifdef CK_ENCRYPTION
6667 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6668 ck_tn_decrypt(&ttibuf[ttibp],n);
6670 #endif /* CK_ENCRYPTION */
6674 #else /* !TCPIPLIB */
6678 if (ttnproto == NP_TELNET) {
6679 if ((n = ttchk()) <= 0)
6682 /* Netflui must process Telnet negotiations or get out of sync */
6685 extern int duplex; /* this really shouldn't be here but ... */
6686 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6687 if (tx == 1) duplex = 1;
6688 else if (tx == 2) duplex = 0;
6694 if ((n = ttchk()) > 0) {
6695 debug(F101,"netflui non-TCPIPLIB","",n);
6696 while ((n--) && ttinc(1) > -1) /* Don't worry, ttinc() is buffered */
6697 ; /* and it handles the decryption... */
6699 #endif /* TCPIPLIB */
6702 ReleaseTCPIPMutex();
6708 /* The following two functions are required for encrypted rlogin */
6709 /* They are called with nettoc() or nettol() are transmitting */
6710 /* encrypted data. They call a function to encrypt the data */
6711 /* and that function needs to be able to write to/read from the */
6712 /* network in an unimpeded manner. Hence, these two simple fns. */
6714 net_write(fd, buf, len)
6716 register const char *buf;
6720 register int wrlen = len;
6723 cc = socket_write(fd, buf, wrlen);
6725 cc = write(fd,buf,wrlen);
6726 #endif /* TCPIPLIB */
6728 int s_errno = socket_errno;
6729 debug(F101,"net_write error","",s_errno);
6731 if (os2socketerror(s_errno) < 0)
6745 } while (wrlen > 0);
6749 net_read(fd, buf, len)
6758 cc = socket_read(fd, buf, len);
6760 cc = read(fd,buf,len);
6763 int s_errno = socket_errno;
6764 debug(F101,"net_read error","",s_errno);
6766 if (os2socketerror(s_errno) < 0)
6769 return(cc); /* errno is already set */
6782 #endif /* CK_KERBEROS */
6785 /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
6786 * If the host is multi-homed it returns only one address.
6788 * Two techniques are used.
6789 * (1) get the local host name and perform a DNS lookup, then take
6791 * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
6792 * no data is sent), then retrieve the local address from the socket.
6793 * Note: the second technique won't work on Microsoft systems. See
6794 * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
6797 /* Technique number one cannot work reliably if the machine is a laptop
6798 * and the hostname is associated with a physical adapter which is not
6799 * installed and a PPP connection is being used instead. This is because
6800 * the hostname DNS lookup will succeed for the physical adapter even though
6801 * it would be impossible to use it. In NT4 SP4, the gethostbyname()
6802 * when given the result of gethostname() returns not the real DNS entries
6803 * for that name+domain. Instead it returns all of the static and dynamic
6804 * IP addresses assigned to any physical or virtual adapter defined in the
6805 * system regardless of whether or not it is installed. The order of the
6806 * addresses is fixed according to the binding order in the NT registry.
6810 * It appears that calling gethostbyname(NULL) is more reliable than
6811 * calling gethostbyname(gethostname()) on Windows. So on Windows we will
6812 * only call gethostbyname(NULL).
6818 struct sockaddr_in l_sa;
6819 struct sockaddr_in r_sa;
6820 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6823 struct in_addr laddr;
6825 /* if still not resolved, then try second strategy */
6826 /* This second strategy does not work on Windows */
6828 memset(&l_sa,0,slen);
6829 memset(&r_sa,0,slen);
6831 /* get a UDP socket */
6832 sock = socket(AF_INET, SOCK_DGRAM, 0);
6834 /* connect to arbirary port and address (NOT loopback) */
6835 r_sa.sin_family = AF_INET;
6836 r_sa.sin_port = htons(IPPORT_ECHO);
6838 /* The following is an "illegal conversion" in AOS/VS */
6839 /* (and who knows where else) */
6842 inaddrx = inet_addr("128.127.50.1");
6843 r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
6845 r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
6846 #endif /* INADDRX */
6847 rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
6848 if (!rc) { /* get local address */
6849 getsockname(sock,(struct sockaddr *)&l_sa,&slen);
6851 socket_close(sock); /* We're done with the socket */
6854 #endif /* TCPIPLIB */
6855 if (l_sa.sin_addr.s_addr != INADDR_ANY) {
6856 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
6857 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
6858 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
6863 return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
6864 #else /* datageneral */
6866 #endif /* datageneral */
6870 getlocalipaddrs(buf,bufsz,index)
6874 /* getlocalipaddrs */ {
6876 char localhost[256];
6877 struct hostent * host=NULL;
6878 struct sockaddr_in l_sa;
6879 struct sockaddr_in r_sa;
6880 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6884 char messageBuf[60];
6885 struct in_addr laddr;
6886 #endif /* COMMENT */
6888 memset(&l_sa,0,slen);
6889 memset(&r_sa,0,slen);
6891 /* init local address (to zero) */
6892 l_sa.sin_addr.s_addr = INADDR_ANY;
6895 rc = gethostname(localhost, 256);
6896 debug(F110,"getlocalipaddrs localhost",localhost,0);
6898 /* This doesn't work on some platforms, e.g. Solaris */
6900 localhost[0] = '\0';
6902 if ( winsock_version < 20 ) {
6903 rc = gethostname(localhost, 256);
6904 debug(F110,"getlocalipaddrs localhost",localhost,0);
6907 #endif /* CKGHNLHOST */
6909 /* resolve host name for local address */
6910 debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
6911 host = gethostbyname(localhost);
6912 debug(F111,"getlocalipaddrs","gethostbyname() returned",host);
6915 host = ck_copyhostent(host);
6916 if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
6920 l_sa.sin_addr.s_addr =
6921 *((unsigned long *) (host->h_addr_list[index]));
6922 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
6923 debug(F110,"getlocalipaddrs setting buf to",buf,0);
6926 /* This is for reporting multiple IP Address */
6927 while (host->h_addr_list && host->h_addr_list[0]) {
6928 l_sa.sin_addr.s_addr =
6929 *((unsigned long *) (host->h_addr_list[0]));
6930 ckstrncpy(messageBuf,
6931 (char *)inet_ntoa(l_sa.sin_addr),60);
6933 if (!strcmp(messageBuf,tcp_address))
6934 ckstrncpy(myipaddr,tcp_address,20);
6936 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
6937 host->h_addr_list++;
6939 #endif /* COMMENT */
6940 #else /* HADDRLIST */
6945 l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
6946 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
6947 debug(F110,"getlocalipaddrs setting buf to",buf,0);
6948 #endif /* HADDRLIST */
6951 "getlocalipaddrs: gethostbyname() failed",
6956 #endif /* datageneral */
6960 #ifdef RLOGCODE /* TCP/IP RLOGIN protocol support code */
6964 unsigned char id[4];
6965 unsigned short rows, cols, ypix, xpix;
6968 if (ttnet != NET_TCPB)
6970 if (ttnproto != NP_RLOGIN
6972 && ttnproto != NP_K4LOGIN
6973 && ttnproto != NP_EK4LOGIN
6974 && ttnproto != NP_K5LOGIN
6975 && ttnproto != NP_EK5LOGIN
6976 #endif /* CK_KERBEROS */
6979 if (!TELOPT_ME(TELOPT_NAWS))
6982 debug(F100,"rlogin Window Size sent","",0);
6984 nawsbuf.id[0] = nawsbuf.id[1] = 0377;
6985 nawsbuf.id[2] = nawsbuf.id[3] = 's';
6987 nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
6988 -(tt_status[VTERM]?1:0)));
6989 nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
6991 nawsbuf.rows = htons((unsigned short) tt_rows);
6992 nawsbuf.cols = htons((unsigned short) tt_cols);
6994 nawsbuf.ypix = htons(0); /* y pixels */
6996 nawsbuf.xpix = htons(0); /* x pixels */
6997 if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
7007 rlog_ini(CHAR * hostname, int port,
7008 struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
7009 #else /* CK_ANSIC */
7010 rlog_ini(hostname, port, l_addr, r_addr)
7013 struct sockaddr_in * l_addr;
7014 struct sockaddr_in * r_addr;
7015 #endif /* CK_ANSIC */
7021 #endif /* RLOGOUTBUF */
7024 #define CONSPDLEN 16
7025 CHAR localuser[UIDBUFLEN+1];
7026 CHAR remoteuser[UIDBUFLEN+1];
7028 CHAR term_speed[TERMLEN+CONSPDLEN+1];
7031 #endif /* CONGSPD */
7033 extern int tt_type, max_tt;
7034 extern struct tt_info_rec tt_info[];
7039 tn_reset(); /* This call will reset all of the Telnet */
7040 /* options and then quit. We need to do */
7041 /* this since we use the Telnet options */
7042 /* to hold various state information */
7043 duplex = 0; /* Rlogin is always remote echo */
7048 But compute the values anyway before the first read since the out-
7049 of-band NAWS request would arrive before the first data byte (NULL).
7052 /* Console terminal screen rows and columns */
7053 debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
7054 -(tt_status[VTERM]?1:0));
7055 debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
7057 if (VscrnGetWidth(VTERM) < 0 ||
7058 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
7059 ttgwsiz(); /* Try to get screen dimensions */
7062 "rlog_ini tt_rows 2",
7064 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
7066 debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
7068 debug(F101,"rlog_ini tt_rows 1","",tt_rows);
7069 debug(F101,"rlog_ini tt_cols 1","",tt_cols);
7070 if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */
7071 ttgwsiz(); /* Try to find out */
7073 debug(F101,"rlog_ini tt_rows 2","",tt_rows);
7074 debug(F101,"rlog_ini tt_cols 2","",tt_cols);
7076 #endif /* CK_TTGWSIZ */
7078 ttflui(); /* Start by flushing the buffers */
7080 rlog_mode = RL_COOKED;
7082 /* Determine the user's local username ... */
7084 localuser[0] = '\0';
7087 char localuid[UIDBUFLEN+1];
7088 ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
7091 if ( !localuser[0] )
7094 char * user = getenv("USER");
7097 userlen = strlen(user);
7098 debug(F111,"rlogin getenv(USER)",user,userlen);
7099 ckstrncpy((char *)localuser,user,UIDBUFLEN);
7100 debug(F110,"rlog_ini localuser 1",localuser,0);
7102 if ( !localuser[0] )
7103 strcpy((char *)localuser,"unknown");
7104 else if (ck_lcname) {
7105 cklower((char *)localuser);
7106 debug(F110,"rlog_ini localuser 2",localuser,0);
7109 /* And the username to login with */
7111 ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
7112 debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
7113 } else if (localuser[0]) {
7114 ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
7115 debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
7117 remoteuser[0] = '\0';
7118 debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
7121 cklower((char *)remoteuser);
7122 debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
7124 /* The command to issue is the terminal type and speed */
7125 term_speed[0] = '\0';
7126 if (tn_term) { /* SET TELNET TERMINAL-TYPE value */
7127 if (*tn_term) { /* (if any) takes precedence. */
7128 ckstrncpy((char *)term_speed, tn_term, TERMLEN);
7131 } else { /* Otherwise the local terminal type */
7133 /* In terminal-emulating versions, it's the SET TERM TYPE value */
7134 ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
7135 tt_info[tt_type].x_name : "network", TERMLEN);
7137 /* In the others, we just look at the TERM environment variable */
7139 char *p = getenv("TERM");
7141 ckstrncpy((char *)term_speed,p,TERMLEN);
7143 term_speed[0] = '\0';
7145 for (p = (char *) term_speed; *p; p++) {
7146 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
7148 else if (isupper(*p))
7156 n = strlen((char *)term_speed);
7157 if (n > 0) { /* We have a terminal type */
7158 if (!flag) { /* If not user-specified */
7159 for (i = 0; i < n; i++) /* then lowercase it. */
7160 if (isupper(term_speed[i]))
7161 term_speed[i] = tolower(term_speed[i]);
7163 debug(F110,"rlog_ini term_speed 1",term_speed,0);
7166 /* conspd() is not yet defined in all ck*tio.c modules */
7169 ckstrncat((char *)term_speed,"/",sizeof(term_speed));
7170 ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
7172 #endif /* CONGSPD */
7173 ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
7174 debug(F110,"rlog_ini term_speed 2",term_speed,0);
7176 term_speed[0] = '\0';
7177 debug(F110,"rlog_ini term_speed 3",term_speed,0);
7181 if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
7182 ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
7183 int kver, encrypt, rc;
7205 rc = ck_krb_rlogin(hostname, port,
7206 localuser, remoteuser, term_speed,
7207 l_addr, r_addr, kver, encrypt);
7208 if (!rc) { /* success */
7209 TELOPT_ME(TELOPT_NAWS) = 1;
7214 #endif /* CK_KERBEROS */
7215 if (ttnproto == NP_RLOGIN) {
7218 * The rcmds start the connection with a series of init data:
7220 * a port number upon which client is listening for stderr data
7221 * the user's name on the client machine
7222 * the user's name on the server machine
7223 * the terminal_type/speed or command to execute
7225 outbuf[outbytes++] = 0;
7226 strcpy((char *)outbuf+outbytes,(char *)localuser);
7227 outbytes += strlen((char *)localuser) + 1;
7228 strcpy((char *)outbuf+outbytes,(char *)remoteuser);
7229 outbytes += strlen((char *)remoteuser) + 1;
7230 strcpy((char *)outbuf+outbytes,(char *)term_speed);
7231 outbytes += strlen((char *)term_speed) + 1;
7232 rc = ttol((CHAR *)outbuf,outbytes);
7233 #else /* RLOGOUTBUF */
7234 ttoc(0); /* Send an initial NUL as wake-up */
7235 /* Send each variable with the trailing NUL */
7236 rc = ttol(localuser,strlen((char *)localuser)+1);
7238 rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
7240 rc = ttol(term_speed,strlen((char *)term_speed)+1);
7241 #endif /* RLOGOUTBUF */
7243 /* Now we are supposed to get back a single NUL as confirmation */
7246 debug(F101,"rlogin first ttinc","",rc);
7248 debug(F101,"rlogin ttinc 1","",rc);
7250 "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
7252 } else if (rc < 0) {
7253 debug(F101,"rlogin ttinc errno","",errno);
7254 /* printf("Network error: %d\n", errno); */
7261 /* two control messages are defined:
7263 a double flag byte of 'o' indicates a one-byte message which is
7264 identical to what was once carried out of band.
7266 a double flag byte of 'q' indicates a zero-byte message. This
7267 message is interpreted as two \377 data bytes. This is just a
7268 quote rule so that binary data from the server does not confuse the
7276 if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
7277 if (rlog_oob(&cp[4],1))
7280 } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
7281 /* this is somewhat of a hack */
7290 rlog_oob(oobdata, count) CHAR * oobdata; int count; {
7294 debug(F111,"rlogin out_of_band","count",count);
7296 for (i = 0; i<count; i++) {
7297 debug(F101,"rlogin out_of_band","",oobdata[i]);
7298 if (oobdata[i] & 0x01)
7301 if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
7302 debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
7304 /* Only flush the data if in fact we are in a mode that won't */
7305 /* get out of sync. Ie, not when we are in protocol mode. */
7317 if (oobdata[i] & 0x10) { /* Switch to RAW mode */
7318 debug(F101,"rlogin Raw Mode command","",oobdata[i]);
7322 if (oobdata[i] & 0x20) { /* Switch to COOKED mode */
7323 debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
7324 rlog_mode = RL_COOKED;
7326 if (oobdata[i] & 0x80)
7327 { /* Send Window Size Info */
7328 debug(F101,"rlogin Window Size command","",oobdata[i]);
7329 /* Remember to send WS Info when Window Size changes */
7330 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7331 TELOPT_ME(TELOPT_NAWS) = 1;
7340 rlogoobh(sig) int sig; {
7342 char /* Or should it be char for all? */
7345 #endif /* SOLARIS */
7348 /* int count = 0; */ /* (not used) */
7350 while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
7352 * We need to do some special processing here.
7353 * Just in case the socket is blocked for input
7363 debug(F101,"rlogin out_of_band","",oobdata);
7364 if (oobdata == 0x02) { /* Flush Buffered Data not yet displayed */
7365 debug(F101,"rlogin Flush Buffered Data command","",oobdata);
7368 if (oobdata & 0x10) { /* Switch to raw mode */
7369 debug(F101,"rlogin Raw Mode command","",oobdata);
7372 if (oobdata & 0x20) { /* Switch to cooked mode */
7373 debug(F101,"rlogin Cooked Mode command","",oobdata);
7374 rlog_mode = RL_COOKED;
7376 if (oobdata & 0x80) { /* Send Window Size Info */
7377 debug(F101,"rlogin Window Size command","",oobdata);
7378 /* Remember to send WS Info when Window Size changes */
7379 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7380 TELOPT_ME(TELOPT_NAWS) = 1;
7385 #endif /* TCPIPLIB */
7386 #endif /* RLOGCODE */
7388 /* Send network BREAK */
7390 Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
7395 if (ttnet == NET_TCPB) {
7396 if (ttnproto == NP_TELNET) {
7398 buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
7401 nettol((char *) buf, 2)
7407 if (tn_deb || debses || deblog) {
7408 extern char tn_msg[];
7409 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
7411 debug(F101,tn_msg,"",BREAK);
7412 if (debses || tn_deb) tn_debug(tn_msg);
7416 debug(F100,"netbreak no TNCODE","",0);
7420 /* Insert other TCP/IP protocols here */
7422 /* Insert other networks here */
7425 #endif /* NETCONN */
7431 SunLink X.25 support by Marcello Frutig, Catholic University,
7432 Rio de Janeiro, Brazil, 1990.
7435 /* PAD X.3, X.28 and X.29 support */
7437 static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
7439 /* Initialize PAD */
7441 extern CHAR padparms[];
7445 padparms[PAD_BREAK_CHARACTER] = 0; /* Break character */
7446 padparms[PAD_ESCAPE] = 1; /* Escape permitted */
7447 padparms[PAD_ECHO] = 1; /* Kermit PAD does echo */
7448 padparms[PAD_DATA_FORWARD_CHAR] = 2; /* forward character CR */
7449 padparms[PAD_DATA_FORWARD_TIMEOUT] = 0; /* no timeout forward condition */
7450 padparms[PAD_FLOW_CONTROL_BY_PAD] = 0; /* not used */
7451 padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1; /* allow PAD service signals */
7452 padparms[PAD_BREAK_ACTION] = 21; /* brk action: INT pk + brk ind*/
7453 padparms[PAD_SUPPRESSION_OF_DATA] = 0; /* no supression of user data */
7454 padparms[PAD_PADDING_AFTER_CR] = 0; /* no padding after CR */
7455 padparms[PAD_LINE_FOLDING] = 0; /* no line fold */
7456 padparms[PAD_LINE_SPEED] = 0; /* line speed - don't care */
7457 padparms[PAD_FLOW_CONTROL_BY_USER] = 0; /* flow cont of PAD - not used */
7458 padparms[PAD_LF_AFTER_CR] = 0; /* no LF insertion after CR */
7459 padparms[PAD_PADDING_AFTER_LF] = 0; /* no padding after LF */
7460 padparms[PAD_EDITING] = 1; /* can edit */
7461 padparms[PAD_CHAR_DELETE_CHAR] = 8; /* character delete character */
7462 padparms[PAD_BUFFER_DELETE_CHAR] = 21; /* buffer delete character */
7463 padparms[PAD_BUFFER_DISPLAY_CHAR] = 18; /* buffer display character */
7466 /* Set PAD parameters */
7469 setpad(s,n) CHAR *s; int n; {
7476 for (i = 0; i < n; i++) {
7477 if (*ps > MAXPADPARMS)
7480 padparms[*ps] = *(ps+1);
7486 /* Read PAD parameters */
7489 readpad(s,n,r) CHAR *s; int n; CHAR *r; {
7494 *pr++ = X29_PARAMETER_INDICATION;
7496 for (i = 0; i < n; i++, ps++) {
7497 if (*ps > MAXPADPARMS) {
7498 x29err[i+2] = *ps++;
7501 *pr++ = padparms[*ps++];
7505 for (i = 1; i < MAXPADPARMS; i++) {
7507 *pr++ = padparms[i];
7513 qbitpkt(s,n) CHAR *s; int n; {
7517 CHAR x29resp[(MAXPADPARMS*2)+1];
7523 if ((int)strlen((char *)x29err) > 2) {
7524 ttol(x29err,(int)strlen((char *)x29err));
7528 case X29_READ_PARMS:
7529 readpad (ps+1,n/2,x29resp);
7531 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7532 if ((int)strlen((char *)x29err) > 2) {
7533 ttol(x29err,(int)strlen((char *)x29err));
7538 case X29_SET_AND_READ_PARMS:
7540 readpad (ps+1,n/2,x29resp);
7542 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7543 if ((int)strlen((char *)x29err) > 2) {
7544 ttol (x29err,(int)strlen((char *)x29err));
7549 case X29_INVITATION_TO_CLEAR:
7552 case X29_INDICATION_OF_BREAK:
7558 /* PAD break action processor */
7562 extern char x25obuf[MAXOX25];
7565 extern unsigned char tosend;
7566 static CHAR indbrk[3] = {
7567 X29_INDICATION_OF_BREAK,
7568 PAD_SUPPRESSION_OF_DATA,
7571 CHAR intudat, cause, diag;
7573 if (x25stat() < 0) return; /* Ignore if no virtual call established */
7575 if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
7576 if (ttol((CHAR *)x25obuf,obufl) < 0) {
7577 perror ("\r\nCan't send characters");
7580 bzero (x25obuf,sizeof(x25obuf));
7585 switch (padparms[PAD_BREAK_ACTION]) {
7587 case 0 : break; /* do nothing */
7588 case 1 : /* send interrupt packet with interrupt user data field = 1 */
7592 case 2 : /* send reset packet with cause and diag = 0 */
7594 x25reset (cause,diag);
7596 case 5 : /* send interrupt packet with interrupt user data field = 0 */
7600 /* send indication of break without a parameter field */
7601 ttoc(X29_INDICATION_OF_BREAK);
7604 case 8 : active = 0; /* leave data transfer */
7607 case 21: /* send interrupt packet with interrupt user data field = 0 */
7610 setpad (indbrk+1,2); /* set pad to discard input */
7612 /* send indication of break with parameter field */
7613 ttol (indbrk,sizeof(indbrk));
7619 /* X.25 support functions */
7621 X25_CAUSE_DIAG diag;
7624 Convert a null-terminated string representing an X.121 address
7625 to a packed BCD form.
7628 pkx121(str,bcd) char *str; CHAR *bcd; {
7634 if (i >= 15 || str [i] < '0' || str [i] > '9')
7646 /* Reads and prints X.25 diagnostic */
7652 bzero ((char *)&diag,sizeof(diag));
7653 if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
7654 perror ("Reading X.25 diagnostic");
7657 if (diag.datalen > 0) {
7658 printf ("X.25 Diagnostic :");
7659 for (i = 0; i < (int)diag.datalen; i++)
7660 printf(" %02h",diag.data[i])+
7666 /* X.25 Out-of-Band Signal Handler */
7669 x25oobh(foo) int foo; {
7674 (VOID) signal(SIGURG,x25oobh);
7676 if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
7677 perror ("Getting signal type");
7682 if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
7683 perror ("Receiving X.25 interrupt data");
7687 printf ("\r\nInterrupt received, data = %d\r\n", t);
7690 printf ("\r\nVirtual circuit reset\r\n");
7694 printf ("\r\nReset timeout\r\n");
7697 printf ("\r\nClear timeout\r\n");
7700 printf ("\r\nMessage discarded, too long\r\n");
7703 if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
7709 /* Send a X.25 interrupt packet */
7715 x25intr(intr) char intr;
7716 #endif /* CK_ANSIC */
7718 if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
7719 debug(F100,"X.25 intr","",0);
7723 /* Reset X.25 virtual circuit */
7726 x25reset(char cause, char diagn)
7728 x25reset(cause, diagn) char cause; char diagn;
7729 #endif /* CK_ANSIC */
7731 bzero ((char *)&diag,sizeof(diag));
7734 diag.data[0] = cause;
7735 diag.data[1] = diagn;
7736 if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
7738 debug(F100,"X.25 reset","",0);
7742 /* Clear X.25 virtual circuit */
7746 debug(F100,"X.25 clear","",0);
7747 bzero ((char *)&diag,sizeof(diag));
7748 diag.flags = (1 << DIAG_TYPE);
7752 ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
7753 return(ttclos(0)); /* Close socket */
7759 if (ttyfd == -1) return (-1);
7766 static int qbiton = 1 << Q_BIT;
7767 ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
7773 static int qbitoff = 0;
7774 ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
7777 /* Read n characters from X.25 circuit into buf */
7780 x25xin(n,buf) int n; CHAR *buf; {
7785 x = read(ttyfd,buf,n);
7786 if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
7787 /* If return -1 : invitation to clear; -2 : PAD changes */
7788 if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
7793 #ifdef COMMENT /* Disabled by Stephen Riehm 19.12.97 */
7795 * if buf[] is full, then this null lands in nirvana!
7796 * I was unable to find any code which needs a trailing null in buf[]
7798 if (x > 0) buf[x] = '\0';
7799 #endif /* COMMENT */
7801 debug(F101,"x25xin x","",x);
7806 #ifdef COMMENT /* NO LONGER NEEDED! */
7807 /* X.25 read a line */
7812 x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
7814 x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
7815 #endif /* CK_ANSIC */
7816 #else /* not PARSENSE */
7818 x25inl(CHAR *dest, int max,int timo, CHAR eol)
7820 x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
7821 #endif /* __SDTC__ */
7822 #endif /*PARSENSE */
7825 int pktype, goteol, rest, n;
7827 extern int ttprty, ttpflg;
7830 ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask */
7832 debug(F101,"x25inl max","",max);
7833 debug(F101,"x25inl eol","",eol);
7838 n = read(ttyfd,pdest,rest);
7840 pktype = *pdest & 0x7f;
7843 if (qbitpkt(pdest+1,--n) < 0) return(-2);
7846 if (flag == 0) { /* if not in packet, search start */
7847 for (i = 1; (i < n) &&
7848 !(flag = ((dest[i] & 0x7f) == start));
7850 if (flag == 0) { /* not found, discard junk */
7851 debug(F101,"x25inl skipping","",n);
7853 } else { /* found, discard junk before start */
7856 for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
7859 for (i = 0; (i < n) && /* search for eol */
7860 !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
7865 } while ((rest > 0) && (!goteol));
7869 debug (F111,"x25inl X.25 got",(char *) dest,n);
7870 if (timo) ttimoff();
7871 if (ttpflg++ == 0 && ttprty == 0) {
7872 if ((ttprty = parchk(dest,start,n)) > 0) {
7874 debug(F101,"x25inl senses parity","",ttprty);
7875 debug(F110,"x25inl packet before",(char *)dest,0);
7877 for (j = 0; j < n; j++)
7878 dest[j] &= 0x7f; /* Strip parity from packet */
7879 debug(F110,"x25inl packet after ",dest,0);
7881 debug(F101,"parchk","",ttprty);
7882 if (ttprty < 0) { ttprty = 0; n = -1; }
7891 #endif /* COMMENT */
7896 * IBM X25 support - using the NPI streams interface
7897 * written by Stephen Riehm, pc-plus, Munich Germany
7900 /* riehm: missing functions / TODO list */
7903 x25intr() - Send an interrupt packet
7906 /* return an error message depending on packet type */
7909 static char buf[30];
7911 case NBADADDR: return "invalid address";
7912 case NBADOPT: return "invalid options";
7913 case NACCESS: return "no permission";
7914 case NNOADDR: return "unable to allocate address";
7915 case NOUTSTATE: return "invalid state";
7916 case NBADSEQ: return "invalid sequence number";
7917 case NSYSERR: return "system error";
7918 case NBADDATA: return "invalid data size";
7919 case NBADFLAG: return "invalid flag";
7920 case NNOTSUPPORT: return "unsupported primitive";
7921 case NBOUND: return "address in use";
7922 case NBADQOSPARAM: return "bad QOS parameters";
7923 case NBADQOSTYPE: return "bad QOS type";
7924 case NBADTOKEN: return "bad token value";
7925 case NNOPROTOID: return "protocol id could not be allocated";
7926 case NODDCUD: return "odd length call user data";
7928 ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
7933 /* turn a meaningless primitive number into a meaningful primitive name */
7936 static char buf[30];
7938 case N_BIND_ACK: return "N_BIND_ACK";
7939 case N_BIND_REQ: return "N_BIND_REQ";
7940 case N_CONN_CON: return "N_CONN_CON";
7941 case N_CONN_IND: return "N_CONN_IND";
7942 case N_CONN_REQ: return "N_CONN_REQ";
7943 case N_CONN_RES: return "N_CONN_RES";
7944 case N_DATACK_IND: return "N_DATAACK_IND";
7945 case N_DATACK_REQ: return "N_DATAACK_REQ";
7946 case N_DATA_IND: return "N_DATA_IND";
7947 case N_DATA_REQ: return "N_DATA_REQ";
7948 case N_DISCON_IND: return "N_DISCON_IND";
7949 case N_DISCON_REQ: return "N_DISCON_REQ";
7950 case N_ERROR_ACK: return "N_ERROR_ACK";
7951 case N_EXDATA_IND: return "N_EXDATA_IND";
7952 case N_EXDATA_REQ: return "N_EXDATA_REQ";
7953 case N_INFO_ACK: return "N_INFO_ACK";
7954 case N_INFO_REQ: return "N_INFO_REQ";
7955 case N_OK_ACK: return "N_OK_ACK";
7956 case N_OPTMGMT_REQ: return "N_OPTMGMT_REQ";
7957 case N_RESET_CON: return "N_RESET_CON";
7958 case N_RESET_IND: return "N_RESET_IND";
7959 case N_RESET_REQ: return "N_RESET_REQ";
7960 case N_RESET_RES: return "N_RESET_RES";
7961 case N_UDERROR_IND: return "N_UDERROR_IND";
7962 case N_UNBIND_REQ: return "N_UNBIND_REQ";
7963 case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
7964 case N_UNITDATA_IND: return "N_UNITDATA_IND";
7966 ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
7971 /*****************************************************************************
7972 * Function: x25getmsg()
7973 * Description: get a STREAMS message, and check it for errors
7976 * fd - file descriptor to x25 device (opened)
7977 * control - control buffer (pre-allocated)
7978 * ctl_size - size of control buffer
7979 * data - data buffer (pre-allocated)
7980 * data_size - size of data buffer
7981 * flags - flags for getmsg()
7982 * expected - expected Primitive type
7985 * >= 0 OK (size of data returned)
7990 x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
7991 int fd; /* X25 device (opened) */
7992 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
7993 int ctl_size; /* size of control buffer */
7994 N_npi_data_t *data; /* data buffer (pre-allocated) */
7995 int data_size; /* size of data buffer */
7996 int *get_flags; /* getmsg() flags */
7997 int expected; /* expected primitive type */
7999 int rc = 0; /* return code */
8000 struct strbuf *get_ctl=NULL; /* getmsg control */
8001 struct strbuf *get_data=NULL; /* getmsg data */
8002 int more = 0; /* flag for more data etc */
8003 int file_status = -1; /* file async status */
8004 N_npi_ctl_t * result; /* pointer to simplify switch() */
8005 int packet_type = -1; /* unknown packet thus far */
8008 printf( "TRACE: entering x25getmsg\n" );
8011 debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
8012 /* prepare the control structures for getmsg */
8014 if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8016 perror("kermit x25getmsg(): get_ctl malloc failed\n");
8017 debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
8020 /* allow getmsg to return an unexpected packet type (which may be
8021 * larger than the expected one)
8023 get_ctl->maxlen = NPI_MAX_CTL;
8025 get_ctl->buf = (char *)control;
8028 "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
8030 debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
8034 if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8036 perror("kermit x25getmsg(): get_data malloc failed\n");
8037 debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
8040 get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
8044 get_data->buf = (char *)data;
8047 /* get an X.25 packet -
8048 * it may be any kind of packet, so check for special cases
8049 * it may be split into multiple parts - so loop if necessary
8053 printf( "kermit: x25getmsg(): getting a message\n" );
8056 if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
8058 printf( "kermit: x25getmsg(): getmsg returned an error\n" );
8059 perror( "getmsg error was" );
8061 debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
8062 if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
8063 /* was in non-blocking mode, nothing to get, but we're
8064 * already waiting for the rest of the packet -
8065 * switch to blocking mode for the next read.
8066 * file_status used to reset file status before returning
8068 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
8069 || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
8071 perror("x25getmsg(): couldn't change x25 blocking mode");
8073 "x25getmsg fcntl returned an error\n", "", errno);
8078 /* loop again into a blocking getmsg() */
8082 /* no data to get in non-blocking mode - return empty handed */
8083 perror( "x25getmsg(): getmsg failed" );
8084 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
8088 } else if (more & MORECTL) {
8089 /* panic - the control information was larger than the
8090 * maximum control buffer size!
8092 /* riehm: close connection? */
8094 printf("x25getmsg(): received partial control packet - panic\n");
8096 debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
8101 if (result = (N_npi_ctl_t *)control) {
8102 packet_type = result->bind_ack.PRIM_type;
8103 if (packet_type != N_OK_ACK) {
8104 x25lastmsg = packet_type;
8108 /* printf( "kermit: x25getmsg(): getting " ); */
8109 if (get_ctl->len > 0) {
8110 x25dump_prim(result);
8113 "x25getmsg got packet ",
8114 x25prim( result->bind_ack.PRIM_type ),
8119 if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
8120 /* not as pretty as a switch(), but switch can't handle
8121 * runtime variable values :-(
8123 if (packet_type == expected ) {
8124 /* got what we wanted, special case for DATA_IND
8126 /* riehm: check Q-bit ? */
8128 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
8130 if (packet_type == N_DATA_IND ) {
8131 /* data received. May be incomplete, even though
8132 * getmsg returned OK
8134 if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
8136 if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
8137 printf( "x25getmsg(): data packet wants ack\n" );
8139 } else if( packet_type == N_DISCON_IND) {
8140 printf( "X25 diconnected\n" );
8141 /* riehm: need to acknowledge a disconnection? */
8143 /* x25unbind( ttyfd ); */
8145 } else if( packet_type == N_ERROR_ACK) {
8146 errno = result->error_ack.UNIX_error;
8147 perror( "X25 error received" );
8150 printf("x25getmsg(): failed %s\n", x25err(packet_type));
8156 /* Panic - no control data */
8157 printf( "kermit: x25getmsg(): no control data with packet\n" );
8160 #endif /* COMMENT */
8162 if (get_data && (get_data->len >= 0)) {
8163 get_data->buf += get_data->len;
8164 get_data->maxlen -= get_data->len;
8167 && (get_data && (get_data->maxlen > 0))
8168 && (more & MOREDATA)
8171 /* return the file status to its original value, unless its still
8172 * set to -1, or one of the fcntl's failed */
8173 if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
8177 * Verify that we received an expected primitive
8178 * there is apparantly an error case where the primitive is set
8179 * correctly, but there is not enough data in the control structure
8181 if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
8183 "x25getmsg(): %s NOT received. Primitive received was %s\n",
8184 x25prim( expected ), x25prim( packet_type ));
8185 debug(F110, "x25getmsg got an unexpected packet ",
8186 x25prim(packet_type),
8193 if (get_data && ( get_data->len >= 0)) {
8198 if (get_ctl) { free(get_ctl); get_ctl = NULL; }
8199 if (get_data) { free(get_data); get_data = NULL; }
8203 printf( "kermit x25getmsg(): returning %d\n", rc );
8205 #endif /* COMMENT */
8206 debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
8209 printf( "TRACE: leaving x25getmsg\n" );
8214 /*****************************************************************************
8215 * Function: x25putmsg()
8218 * send a message to a X25 STREAM
8221 * fd - file descriptor to x25 device (opened)
8222 * control - control buffer (pre-allocated)
8223 * data - data buffer (pre-allocated)
8224 * data_len - length of data to be transmitted
8225 * put_flags - flags for putmsg()
8228 * >= 0 number of bytes transmitted
8232 x25putmsg(fd, control, data, data_len, put_flags)
8233 int fd; /* X25 device (opened) */
8234 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
8235 N_npi_data_t *data; /* data buffer (pre-allocated) */
8236 int data_len; /* length of data (not the size of
8238 int *put_flags; /* putmsg() flags */
8240 int rc = 0; /* return code */
8241 ulong type; /* primitive type */
8242 struct strbuf *put_ctl = NULL; /* putmsg control */
8243 struct strbuf *put_data = NULL; /* putmsg data */
8246 printf( "TRACE: entering x25putmsg\n" );
8250 printf( "kermit: x25putmsg(): putting " );
8251 x25dump_prim( control );
8252 printf( "\tdata:\t\t" );
8253 x25dump_data( data, 0, data_len );
8254 debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
8258 put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8259 if (put_ctl == NULL) {
8260 perror("kermit x25putmsg(): put_ctl malloc failed\n");
8263 put_ctl->maxlen = 0; /* unused by putmsg */
8264 put_ctl->len = NPI_MAX_CTL;
8265 put_ctl->buf = (char *)control;
8267 if (data && ( data_len > 0)) {
8268 put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8269 if( put_data == NULL) {
8270 perror("kermit x25putmsg(): put_data malloc failed\n");
8273 put_data->maxlen = 0; /* unused by putmsg */
8274 put_data->len = data_len;
8275 put_data->buf = (char *)data;
8279 rc = putmsg (fd, put_ctl, put_data, 0);
8281 printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
8282 perror("kermit: x25putmsg(): putmsg failed");
8286 /* riehm: this should perhaps be discounted! */
8287 x25lastmsg = control->PRIM_type;
8291 printf( "kermit debug: x25putmsg() returning %d\n", data_len );
8293 #endif /* COMMENT */
8294 debug( F101, "x25putmsg block size put ", "", data_len);
8297 printf( "TRACE: leaving x25putmsg\n" );
8303 /*****************************************************************************
8305 * Description: The bind submitted to NPI provides the information required
8306 * by the packet layer for it to listen for suitable incoming
8311 * This routine needs to be called in a completely different manner for
8312 * the client and server side. When starting a client, the
8313 * num_waiting_calls and CUD information should all be set to 0! The
8314 * client's CUD must be inserted in the CONN_REQ data block.
8315 * When starting a server, the CUD must be set to a CUD pattern, and
8316 * the number of waiting calls should be set to a number other than 0.
8317 * (num waiting calls is the number of incomming calls which are to be
8318 * put on hold while the server is servicing another client.)
8320 * Who invented this crap?
8323 * fd - X25 device (opened)
8324 * addr - local address
8325 * cud - User Data (null terminated)
8326 * cud_len - User Data length
8327 * num_waiting_calls - number of outstanding calls allowed on this stream
8328 * line - logical port number (1)
8329 * flags - 0, DEFAULT_LISTENER or TOKEN_REQUEST
8332 * if binding is successful, 0 is returned for a client, and a token is
8333 * returned for a server
8335 * Return code: 0 if successful
8336 * -1 if unsuccessful
8337 *****************************************************************************/
8340 x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
8341 int fd; /* X25 device (opened) */
8342 char * addr; /* local address */
8343 char * cud; /* Call User Data (null terminated) */
8344 int cud_len; /* User Data length */
8345 int num_waiting_calls; /* Outstanding calls allowed */
8346 int line; /* logical port number */
8347 ulong bind_flags; /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
8349 ulong rc; /* return code */
8350 int get_flags; /* priority flag passed to getmsg */
8351 int put_flags = 0; /* output flags for putmsg, always 0 */
8352 ulong type; /* primitive type */
8353 N_bind_req_t *bind_req; /* pointer to N_BIND_REQ primitive */
8354 N_bind_ack_t *bind_ack; /* pointer to N_BIND_ACK primitive */
8355 char *addtl_info; /* pointer to info in addition to
8356 * the N_BIND_REQ primitive that is
8357 * passed in the control structure
8359 int addr_len = 0; /* length of address string */
8360 ulong bind_req_t_size; /* for debugging only */
8363 printf("TRACE: entering x25bind\n" );
8367 printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
8368 fd, addr, cud, line, bind_flags
8373 * Allocate and zero out space to hold the control portion of the
8374 * message passed to putmsg. This will contain the N_BIND_REQ
8375 * primitive and any additional info required for that.
8377 * Note: allocated space is the size of the union typedef
8378 * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
8380 bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
8381 if (bind_req == NULL) {
8382 perror("kermit: x25bind(): bind_req malloc failed");
8383 debug(F100, "x25bind bind_req malloc failed", "", 0);
8386 bzero((char *)bind_req, sizeof(N_npi_ctl_t));
8388 /* Build the Bind Request Primitive */
8389 bind_req->PRIM_type = (ulong) N_BIND_REQ;
8391 /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
8392 * the actual address in an N_BIND_REQ. The first byte contains the
8393 * line number being used with this address, and the second byte is the
8394 * X.121 address prefix, which must be zero.
8396 addr_len = strlen(addr);
8397 bind_req->ADDR_length = (ulong) (addr_len + 2);
8398 bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
8399 bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
8400 bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
8401 bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
8403 bind_req->PROTOID_offset = (ulong) 0;
8405 /* need to remember the trailing NULL in the address - not
8406 * counted in the address length
8408 bind_req->PROTOID_offset
8409 = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
8413 * Now fill in the additional information required with this primitive
8414 * (address and protocol information (Call User Data))
8416 addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
8418 * The bitwise "&" ensures that the line number is only one byte long
8420 *addtl_info++ = (char) line & 0xff;
8421 *addtl_info++ = (char) 0; /* X.121 format */
8422 bcopy( addr, addtl_info, addr_len ); /* include trailing null */
8423 addtl_info += addr_len;
8425 bcopy( cud, addtl_info, cud_len );
8427 * Call putmsg() to put the bind request message on the stream
8430 (N_npi_ctl_t*)bind_req,
8431 (N_npi_data_t *)NULL,
8435 printf( "kermit: x25bind(): x25putmsg failed\n" );
8440 * Allocate and zero out space for the N_BIND_ACK primitive
8442 bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
8443 if (bind_ack == NULL){
8444 perror("kermit: x25bind(): bind_ack malloc failed");
8447 bzero(bind_ack, sizeof(N_npi_ctl_t));
8449 * Initialize the control structure and flag variable sent to getmsg
8453 /* get the ACK for the bind */
8455 printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
8457 rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
8458 (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
8461 /* turn quantitive return code into a qualitative one */
8464 /* if all went well, get the token from the acknowledgement packet */
8465 if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
8466 rc = bind_ack->TOKEN_value;
8469 /* free up the memory we allocated earlier */
8474 printf( "TRACE: leaving x25bind\n" );
8480 /*****************************************************************************
8482 * Description: This routine builds and sends an N_CONN_REQ primitive, then
8483 * checks for an N_CONN_CON primitive in return.
8486 * fd - file descriptor of stream
8487 * caddr - called address (remote address)
8489 * Functions Referenced:
8497 * -1 if not successful
8498 *****************************************************************************/
8500 x25call(fd, remote_nua, cud)
8501 int fd; /* X25 device (opened) */
8502 char * remote_nua; /* remote address to call */
8503 char * cud; /* call user data */
8505 int rc; /* return code */
8506 int flags; /* Connection flags */
8507 int get_flags; /* priority flags for getmsg */
8508 ulong type; /* primitive type */
8509 N_conn_req_t *connreq_ctl; /* pointer to N_CONN_REQ primitive */
8510 N_npi_data_t *connreq_data; /* pointer to N_CONN_REQ data (CUD) */
8511 int connreq_data_len; /* length of filled data buffer */
8512 N_conn_con_t *conncon_ctl; /* pointer to N_CONN_CON primitive */
8513 N_npi_data_t *conncon_data; /* pointer to any data associated with
8514 * the N_CONN_CON primitive */
8515 char *addtl_info; /* pointer to additional info needed
8516 * for N_CONN_REQ primitive */
8517 int addr_len; /* length of address */
8520 printf( "TRACE: entering x25call\n" );
8524 printf( "x25call( %d, %s )\n", fd, remote_nua );
8525 printf( "connecting to %s on fd %d\n", remote_nua, fd );
8529 * Allocate and zero out space for the N_CONN_REQ primitive
8530 * use the size of the generic NPI primitive control buffer
8532 connreq_ctl = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
8533 if (connreq_ctl == NULL){
8534 perror("kermit: x25call(): connreq_ctl malloc failed");
8537 bzero(connreq_ctl,sizeof(N_npi_ctl_t));
8539 * Build the Connection Request Primitive
8542 connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
8544 /* Note that the address length is nchai+1 and not n+2. The line number
8545 * is only passed with the address for the bind. The first byte of
8546 * the address for the N_CONN primitives contains the X.121
8547 * address prefix, which must be zero. The remaining bytes are the
8550 addr_len = strlen( remote_nua );
8551 connreq_ctl->DEST_length = (ulong) (addr_len + 1);
8552 connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
8553 /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
8554 connreq_ctl->CONN_flags = (ulong) 0;
8555 connreq_ctl->QOS_length = (ulong) 0; /* unsupported in AIX 4.1 */
8556 connreq_ctl->QOS_offset = (ulong) 0; /* unsupported in AIX 4.1 */
8558 addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
8559 *addtl_info++ = (char) 0; /* X.121 format */
8560 bcopy( remote_nua, addtl_info, addr_len );
8563 * setup the data buffer for the connection request
8565 connreq_data = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
8566 if (connreq_data == NULL){
8567 perror("kermit: x25call(): connreq_data malloc failed");
8570 bzero(connreq_data,sizeof(N_npi_data_t));
8572 /* facility selection needs to be put in the front of connreq_data */
8573 connreq_data_len = 0;
8574 connreq_data_len += x25facilities( (char *)connreq_data );
8577 (char *)((char *)connreq_data + connreq_data_len),
8580 connreq_data_len += strlen( cud );
8584 * Call putmsg() to put the connection request message on the stream
8586 rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
8587 connreq_data_len, &flags );
8593 * Allocate and zero out space for the N_CONN_CON primitive
8595 if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8596 perror("kermit: x25call(): conncon_ctl malloc failed");
8599 bzero(conncon_ctl, sizeof(N_npi_ctl_t));
8602 * Allocate and zero out space for any data associated with N_CONN_CON
8604 if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
8605 perror("kermit: x25call(): conncon_data malloc failed");
8608 bzero(conncon_data, NPI_MAX_DATA);
8610 /* Initialize and build the structures for getmsg */
8613 rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
8614 conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
8616 /* turn quantitive return code into a qualitative one */
8619 /* Free the space that we no longer need */
8620 if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
8621 if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
8622 if (conncon_data) { free(conncon_data); conncon_data = NULL; }
8625 printf( "TRACE: leaving x25call\n" );
8631 /*****************************************************************************
8632 * Function: x25getcall
8634 * Description: This routine checks for an incomming call, verified
8635 * that it is a CONNIND (connection indication) message, and then
8636 * accepts the call and returns the file descriptor of the new stream
8639 * fd - file descriptor of listening stream
8642 * callfd - file descriptor of connected incomming call.
8643 * - set to -1 if an error occured
8645 *****************************************************************************/
8647 x25getcall(fd) int fd; {
8648 int x25callfd; /* fd of incomming call */
8649 N_conn_ind_t *connind_ctl; /* connind controll buffer */
8650 N_npi_data_t *connind_data; /* connind data buffer */
8651 int get_flags; /* flags for getmsg */
8652 ulong flags; /* connection flags */
8653 int rc; /* return code */
8655 extern x25addr_t remote_nua; /* remote X.25 addr global var */
8658 printf( "TRACE: entering x25getcall\n" );
8661 /* allocate space for connection indication buffers */
8662 if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
8663 perror("kermit: x25getcall(): connind_ctl malloc failed");
8666 bzero(connind_ctl, sizeof(N_npi_ctl_t));
8668 if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
8669 perror("kermit: x25getcall(): connind_data malloc failed");
8672 bzero(connind_data, NPI_MAX_DATA);
8674 /* initialise control structures */
8677 /* call getmsg to check for a connection indication */
8679 (N_npi_ctl_t*)connind_ctl,
8680 (int)sizeof(N_conn_ind_t),
8687 printf( "x25getcall(): errno is: %d\n", errno );
8689 perror ("x25getcall(): getmsg failed");
8693 /* a connection indication was received
8694 * - pull it to bits and answer the call
8696 x25seqno = connind_ctl->SEQ_number;
8697 flags = connind_ctl->CONN_flags;
8699 printf( "setting remote_nua to a new value due to incomming call\n" );
8702 * no guarantee that the address is null terminated, ensure that
8703 * after copying that it is (assumption: remote_nua is longer than
8706 bzero(remote_nua, sizeof(remote_nua));
8707 /* note: connind_ctl contains a x121 address, which has a null as
8708 * the FIRST character - strip it off!
8710 ckstrncpy(remote_nua,
8711 (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
8712 connind_ctl->SRC_length - 1
8715 printf( "remote_nua set to new value of %s\n", remote_nua );
8718 /* errors handled by callee */
8719 x25callfd = x25accept(x25seqno, flags);
8721 /* free the malloc'd buffers */
8722 if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
8723 if (connind_data) { free(connind_data); connind_data = NULL; }
8726 printf( "TRACE: leaving x25getcall\n" );
8729 /* return the file descriptor (or error if < 0) */
8730 return( x25callfd );
8733 /*****************************************************************************
8734 * Function: x25accept
8736 * Description: accept an incomming call
8737 * This essentially means opening a new STREAM and sending
8738 * an acknowledge back to the caller.
8741 * seqno - sequence number for acknowledgement
8742 * flags - flags passed to us by the caller
8745 * fd - file descriptor of new STREAM
8746 * set to -1 if an error occured
8748 *****************************************************************************/
8750 x25accept(seqno,flags)
8751 ulong seqno; /* connection sequence number */
8752 ulong flags; /* connection flags */
8754 int x25callfd; /* fd for incomming call */
8755 int get_flags; /* priority flags for getmsg */
8756 int put_flags = 0; /* flags for putmsg, always 0 */
8757 int addr_len; /* length of local address */
8758 ulong token; /* connection token */
8759 N_conn_res_t *conn_res; /* N_CONN_RES primitive */
8760 N_ok_ack_t *ok_ack; /* N_OK_ACK primitive */
8761 char *addtl_info; /* temp pointer */
8762 int rc; /* temporary return code */
8764 /* global variables from ckcmai.c */
8765 extern int revcall, closgr, cudata;
8766 extern char udata[];
8767 extern x25addr_t local_nua; /* local X.25 address */
8768 extern char x25name[]; /* x25 device name (sx25a0) */
8769 extern char x25dev[]; /* x25 device file /dev/x25pkt */
8770 extern int x25port; /* logical port to use */
8771 ulong bind_flags = 0; /* flags for binding the X25 stream */
8774 printf( "TRACE: entering x25accept\n" );
8777 /* open a new packet level stream */
8778 if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
8779 perror ("kermit: x25accept(): X.25 device open error");
8780 debug(F101,"x25accept() device open error","",errno);
8784 /* push the NPI onto the STREAM */
8785 if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
8786 perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
8787 debug(F101,"x25accept can't push npi on the X25 stream","",errno);
8791 /* bind kermit server to the local X25 address */
8792 /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
8793 bind_flags |= TOKEN_REQUEST;
8794 token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
8796 printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
8801 /* allocate connection response primitive */
8802 if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
8803 perror("kermit: x25accept(): conn_res malloc failed");
8806 bzero((char *)conn_res, NPI_MAX_CTL);
8808 /* setup connection response primitive */
8809 addr_len = strlen( local_nua );
8810 conn_res->PRIM_type = (ulong)N_CONN_RES;
8811 conn_res->TOKEN_value = token;
8812 /* note address length is n+1 to accomodate the X.121 address prefix */
8813 conn_res->RES_length = (ulong)(addr_len + 1);
8814 conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
8815 conn_res->SEQ_number = seqno;
8816 conn_res->CONN_flags = 0;
8817 conn_res->QOS_length = 0; /* unsupported - must be 0 (!?) */
8818 conn_res->QOS_offset = 0;
8820 addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
8821 *addtl_info++ = (char)0; /* X.121 address prefix */
8822 bcopy( local_nua, addtl_info, addr_len );
8825 * send off the connect response
8827 if (x25putmsg(x25callfd,
8828 (N_npi_ctl_t*)conn_res,
8829 (N_npi_data_t *)NULL,
8833 perror("kermit: x25accept(): putmsg connect response failed");
8838 * Allocate and zero out space for the OK_ACK primitive
8840 if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8841 perror("kermit: x25call(): ok_ack malloc failed");
8844 bzero(ok_ack, sizeof(N_npi_ctl_t));
8846 /* Initialize and build the structures for getmsg */
8849 rc = (int)x25getmsg(x25callfd,
8850 (N_npi_ctl_t*)ok_ack,
8851 (int)sizeof(N_ok_ack_t),
8852 (N_npi_data_t*)NULL,
8858 /* sequence number is only for disconnecting when not connected !? */
8862 /* free up malloc'ed buffer space */
8863 if (conn_res) { free(conn_res); conn_res = NULL; }
8864 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
8867 printf( "TRACE: leaving x25accept\n" );
8870 return( ( rc >= 0 ) ? x25callfd : -1 );
8873 /*****************************************************************************
8874 * Function: x25unbind
8876 * Description: This subroutine builds and sends an unbind request and gets
8877 * the acknowledgement for it.
8880 * fd - File descriptor of the stream
8882 * Functions Referenced:
8890 * -1 - if not successful
8891 *****************************************************************************/
8893 x25unbind(fd) int fd; { /* X25 device (opened) */
8894 int rc; /* return code */
8895 int flags; /* bind flags */
8896 int get_flags; /* priority flag for getmsg */
8897 ulong type; /* primitive type */
8898 N_unbind_req_t *unbind_req; /* pointer to N_UNBIND_REQ */
8899 N_ok_ack_t *ok_ack; /* pointer to N_OK_ACK */
8902 printf( "TRACE: entering x25unbind\n" );
8906 /* printf( "x25unbind( %d )\n", fd ); */
8908 debug(F101,"x25unbind closing x25 connection #","",fd);
8910 /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
8911 unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
8912 if (unbind_req == NULL) {
8913 perror("kermit: x25unbind(): unbind_req malloc failed");
8916 bzero(unbind_req, sizeof(N_npi_ctl_t));
8919 * Build the Unbind Request Primitive
8922 unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
8925 * Call putmsg() to put the bind request message on the stream
8928 (N_npi_ctl_t*)unbind_req,
8929 (N_npi_data_t *)NULL,
8933 perror ("kermit: x25unbind(): putmsg failed");
8937 /* Allocate and Zero out space for the N_OK_ACK primitive */
8938 ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
8939 if (ok_ack == NULL) {
8940 perror("kermit x25unbind(): ok_ack malloc failed\n");
8943 bzero(ok_ack, sizeof(N_npi_ctl_t));
8945 /* Initialize and build the control structure for getmsg */
8948 /* Call getmsg() to check for an acknowledgement */
8950 (N_npi_ctl_t*)ok_ack,
8951 (int)sizeof(N_ok_ack_t),
8952 (N_npi_data_t*)NULL,
8958 perror ("kermit: x25unbind: getmsg failed");
8962 /* Free up the space that we no longer need */
8963 if (unbind_req) { free(unbind_req); unbind_req = NULL; }
8964 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
8967 printf( "TRACE: leaving x25unbind\n" );
8973 /*****************************************************************************
8977 * Read n characters from X.25 circuit into buf (AIX only)
8980 * data_buf_len maximum size of data buffer
8981 * data_buf pointer to pre-allocated buffer space
8984 * the number of characters actually read
8987 x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
8988 struct strbuf getmsg_ctl; /* streams control structure */
8989 struct strbuf getmsg_data; /* streams data structure */
8990 int rc = 0; /* return code */
8991 int getmsg_flags; /* packet priority flags */
8992 char * ctl_buf; /* npi control buffer */
8993 N_npi_ctl_t * result; /* pointer to simplify switch() */
8996 printf( "TRACE: entering x25xin\n" );
8999 /* ensure that no maximum's are overridden */
9000 data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
9002 /* allocate space for packet control info */
9003 if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
9004 perror( "kermit: x25xin(): ctl_buf malloc" );
9008 /* riehm: need zeroed buffer for getmsg? */
9009 bzero( ctl_buf, NPI_MAX_CTL );
9010 /* clear data buffer */
9011 bzero( data_buf, data_buf_len );
9012 #endif /* COMMENT */
9014 getmsg_flags = 0; /* get the first packet available */
9016 rc = x25getmsg(ttyfd,
9027 printf( "kermit: x25xin(): got " );
9028 x25dump_data( data_buf, 0, rc );
9030 printf( "x25xin(): attempt to get data resulted in an error\n" );
9033 #endif /* COMMENT */
9036 if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
9039 printf( "TRACE: leaving x25xi\n" );
9045 /*****************************************************************************
9046 * Function: x25write
9049 * write a block of characters to the X25 STREAM (AIX)
9052 * fd file descriptor to write to
9053 * databuf buffer containing data to write
9054 * databufsize size of the buffer to write
9057 * size the number of bytes actually transmitted
9060 x25write(fd, databuf, databufsize)
9061 int fd; /* X25 STREAMS file descriptor (ttyfd) */
9062 char *databuf; /* buffer to write */
9063 int databufsize; /* buffer size */
9065 N_data_req_t *data_req_ctl;
9066 int rc; /* return code (size transmitted) */
9067 int write_flags = 0; /* always 0 !? */
9070 printf( "TRACE: entering x25write\n" );
9073 if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
9074 perror( "kermit: x25write(): data_req_ctl malloc" );
9077 data_req_ctl->PRIM_type = N_DATA_REQ;
9078 data_req_ctl->DATA_xfer_flags = 0;
9080 /* riehm: possible extension
9081 * possibly need to think about splitting up the data buffer
9082 * into multiple parts if databufsize > NPI_MAX_DATA
9087 printf( "kermit: x25write(): writing data to x25 stream\n" );
9088 printf( "\tdata:\t" );
9089 x25dump_data(databuf, 0, databufsize);
9091 #endif /* COMMENT */
9093 (N_npi_ctl_t*)data_req_ctl,
9094 (N_npi_data_t*)databuf,
9098 if (data_req) { free(data_req_ctl); data_req = NULL; }
9101 printf( "TRACE: leaving x25write\n" );
9107 /*****************************************************************************
9108 * Function: x25local_nua
9111 * This routine is only interesting for IBM computers. In order
9112 * to set up a connection (see x25bind()) you need to know the
9113 * local NUA (x25 address). Unfortunately, you need all this code
9114 * to find that out, I just hope this works for everyone else!
9117 * a pre-allocated character buffer, long enough to hold an X.25 address
9118 * and the tailing null.
9121 * the length of the address string.
9125 x25local_nua(char *buf) {
9126 struct CuAt *response; /* structure to fill with info from ODM */
9127 CLASS_SYMBOL retClass; /* ODM class */
9128 char query[64]; /* odm database query */
9129 int rc = 0; /* return value (length of local NUA) */
9130 extern char x25name[]; /* x25 device name (sx25a0) */
9133 printf( "TRACE: entering x25local_nua\n" );
9136 /* set up query string */
9137 if (x25name[0] == '\0') {
9139 printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
9141 strcpy( x25name, "sx25a0" );
9143 ckmakmsg(query, sizeof(query), "name like ",x25name,
9144 " and attribute like local_nua");
9146 /* initialise ODM database */
9148 if (odm_initialize() == -1) {
9149 printf( "x25local_nua(): can't initialize ODM database");
9151 case ODMI_INVALID_PATH:
9152 printf( "invalid path\n" );
9154 case ODMI_MALLOC_ERR:
9155 printf( "malloc failed\n" );
9158 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9163 /* open the CuAt class */
9164 retClass = odm_open_class(CuAt_CLASS);
9165 if (((int)retClass) == -1) {
9166 printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
9168 case ODMI_CLASS_DNE:
9169 printf( "CuAt class doesn't exist\n" );
9171 case ODMI_CLASS_PERMS:
9172 printf( "permission to CuAt class file denied\n" );
9174 case ODMI_MAGICNO_ERR:
9175 printf( "CuAt is an invalid ODM object class\n" );
9178 printf( "cannot open CuAt class - and don't know why!\n" );
9180 case ODMI_INVALID_PATH:
9181 printf( "invalid path\n" );
9183 case ODMI_TOOMANYCLASSES:
9184 printf( "too many object classes have been opened\n" );
9187 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9193 printf("retClass= %d\n", retClass);
9196 response = (struct CuAt *)odm_get_first( retClass, query, NULL );
9197 if (((int)response) == -1) {
9198 printf( "kermit: x25local_nua(): odm query failed " );
9200 case ODMI_BAD_CRIT: /* Programming error */
9201 printf( "bad search criteria\n" );
9203 case ODMI_CLASS_DNE:
9204 printf( "CuAt class doesn't exist\n" );
9206 case ODMI_CLASS_PERMS:
9207 printf( "permission to CuAt class file denied\n" );
9209 case ODMI_INTERNAL_ERR:
9210 printf("odm internal error\nPlease contact your administrator\n" );
9212 case ODMI_INVALID_CLXN:
9213 printf("CuAt is invalid or inconsistent odm class collection\n");
9215 case ODMI_INVALID_PATH:
9216 printf( "invalid path\n" );
9218 case ODMI_MAGICNO_ERR:
9219 printf( "CuAt is an invalid ODM object class\n" );
9221 case ODMI_MALLOC_ERR:
9222 printf( "malloc failed\n" );
9225 printf( "cannot open CuAt class - and don't know why!\n" );
9227 case ODMI_TOOMANYCLASSES:
9228 printf( "too many object classes have been opened\n" );
9231 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9236 /* check for a meaningfull response */
9237 if (response != NULL) {
9238 if (response->value != NULL) {
9239 strcpy(buf, response->value);
9243 printf( "attribute name is: %s\n", (char *)response->attribute );
9244 printf( "I think my address is %s\n", (char*)response->value );
9248 printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
9253 printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
9255 case ODMI_CLASS_DNE:
9256 printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
9258 case ODMI_CLASS_PERMS:
9259 printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
9261 case ODMI_INTERNAL_ERR:
9262 printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
9264 case ODMI_INVALID_CLXN:
9265 printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
9267 case ODMI_INVALID_PATH:
9268 printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
9270 case ODMI_MAGICNO_ERR:
9271 printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
9273 case ODMI_MALLOC_ERR:
9274 printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
9277 printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
9279 case ODMI_TOOMANYCLASSES:
9280 printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
9283 printf( "Unknown error!\n" );
9288 /* close the database again */
9289 odm_close_class( retClass );
9291 /* forget about ODM all together */
9295 printf( "TRACE: leaving x25local_nua\n" );
9298 debug(F110, "x25local_nua local address is ", buf, 0);
9302 /*****************************************************************************
9303 * Function: x25facilities
9306 * build up the facilities data packet for a connection request
9309 * a pre-allocated char buffer, normally NPI_MAX_DATA big.
9312 * the number of characters inserted into the buffer
9315 x25facilities(buffer) char *buffer; {
9318 char *p; /* temp pointer */
9319 char *start; /* temp pointer */
9322 printf( "TRACE: entering x25facilities\n" );
9329 printf( "kermit: x25facilities(): getting X25 facilities\n" );
9334 printf("reverse charge: %d\n", revcall );
9341 printf("closed user group: %d\n", closgr );
9349 printf( "no facilities\n" );
9353 /* set the size of the facilities buffer */
9354 *buffer = (char)( p - start ) & 0xff;
9357 printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer) );
9361 printf( "TRACE: leaving x25facilities\n" );
9364 /* return the size of the facilities with size byte */
9365 /* 1 == no facilities, 0 byte returned as facilities size */
9366 return( (int)(p - buffer) );
9370 * reset the connection
9373 x25reset(cause, diagn) char cause; char diagn; {
9374 /* not implemented */
9377 printf( "TRACE: entering x25reset\n" );
9381 printf( "TRACE: leaving x25reset\n" );
9388 * clear the x25 connection - ie: hang up
9392 int get_flags = 0; /* priority flag for getmsg */
9393 int put_flags = 0; /* send flags, always 0 */
9394 ulong type; /* primitive type */
9395 N_discon_req_t *discon_req; /* pointer to N_DISCON_REQ */
9396 N_discon_ind_t *discon_ind; /* pointer to N_DISCON_IND */
9397 N_npi_data_t *discon_data; /* pointer to N_DISCON_IND data */
9398 int rc = 0; /* return code */
9401 printf( "TRACE: entering x25clear\n" );
9405 /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
9409 * The following checks are used to ensure that we don't disconnect
9410 * or unbind twice - this seems to throw the NPI interface right out of
9413 switch(x25lastmsg) {
9421 /* printf("x25clear(): actively disconnecting\n"); */
9424 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
9425 if (discon_req == NULL) {
9426 perror("kermit x25clear(): discon_req malloc failed\n");
9427 /* fallthrough, try to unbind the NPI anyway */
9429 discon_req->PRIM_type = N_DISCON_REQ;
9430 discon_req->DISCON_reason = 0; /* not used by AIX */
9431 discon_req->RES_length = 0;
9432 discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
9433 discon_req->SEQ_number = x25seqno; /* global */
9435 if (x25putmsg(ttyfd,
9436 (N_npi_ctl_t*)discon_req,
9437 (N_npi_data_t*)NULL,
9441 perror("x25putmsg failed in x25clear()");
9443 discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
9444 discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
9445 if((discon_ind == NULL) || (discon_data == NULL)) {
9446 perror("x25clear(): discon_ind malloc failed\n");
9447 /* fallthrough, try to unbind the NPI anyway */
9450 (N_npi_ctl_t*)discon_ind,
9452 (N_npi_data_t*)discon_data,
9457 perror("x25getmsg failed in x25clear()");
9458 /* fallthrough, try to unbind the NPI anyway */
9466 if (x25lastmsg != N_UNBIND_REQ) {
9467 rc = x25unbind(ttyfd);
9471 printf( "TRACE: leaving x25clear\n" );
9479 * only for debugging
9481 * turn the internal representation of a datablock into something
9482 * half-way readable. Because the length is known, we can print
9483 * the string including null's etc (important, because the first(!)
9484 * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
9486 x25dump_data(char *addr, ulong offset, ulong length) {
9487 char *ptr = addr + offset;
9489 /* allocate enough memory for all unprintable chars */
9490 char *buf = (char *)malloc( length * 4 );
9491 char *bptr = buf; /* pointer to current place in the print buffer */
9494 if (isprint(*ptr)) {
9498 strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
9506 printf( "%s", buf );
9508 printf( " (%d+%d)\n", offset, length );
9510 if (buf) { free(buf); buf = NULL; }
9515 * only for debugging
9516 * print as much useful information about a packet as possible
9518 x25dump_prim(primitive) N_npi_ctl_t *primitive; {
9519 printf("Primitive");
9520 switch (primitive->PRIM_type) {
9522 printf( "\tN_BIND_ACK\n\taddress:\t" );
9523 x25dump_data( (char *)primitive,
9524 primitive->bind_ack.ADDR_offset,
9525 primitive->bind_ack.ADDR_length );
9526 printf( "\tproto id:\t" );
9527 x25dump_data( (char *)primitive,
9528 primitive->bind_ack.PROTOID_offset,
9529 primitive->bind_ack.PROTOID_length );
9530 printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
9531 primitive->bind_ack.CONIND_number,
9532 primitive->bind_ack.TOKEN_value );
9536 printf( "\tN_BIND_REQ\n\taddress:\t" );
9537 x25dump_data( (char *)primitive,
9538 primitive->bind_req.ADDR_offset,
9539 primitive->bind_req.ADDR_length );
9540 printf( "\tproto id:\t" );
9541 x25dump_data( (char *)primitive,
9542 primitive->bind_req.PROTOID_offset,
9543 primitive->bind_req.PROTOID_length );
9544 printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
9545 primitive->bind_req.CONIND_number,
9546 primitive->bind_req.BIND_flags );
9550 printf( "\tN_CONN_CON\n" );
9551 printf( "\tRES\t\t" );
9552 x25dump_data( (char *)primitive,
9553 primitive->conn_con.RES_offset,
9554 primitive->conn_con.RES_length );
9555 printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
9559 printf( "\tN_CONN_IND\n" );
9560 printf( "\tsource:\t\t" );
9561 x25dump_data( (char *)primitive,
9562 primitive->conn_ind.SRC_offset,
9563 primitive->conn_ind.SRC_length );
9564 printf( "\tdestination:\t" );
9565 x25dump_data( (char *)primitive,
9566 primitive->conn_ind.DEST_offset,
9567 primitive->conn_ind.DEST_length );
9568 printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
9569 printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
9573 printf( "\tN_CONN_REQ\n\tdestination:\t" );
9574 x25dump_data( (char *)primitive,
9575 primitive->conn_req.DEST_offset,
9576 primitive->conn_req.DEST_length );
9577 printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
9581 printf( "\tN_CONN_RES\n" );
9582 printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
9583 printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
9584 printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
9585 printf( "\tRES\t\t" );
9586 x25dump_data( (char *)primitive,
9587 primitive->conn_res.RES_offset,
9588 primitive->conn_res.RES_length );
9592 printf( "\tN_DATACK_IND\n" );
9596 printf( "\tN_DATACK_REQ\n" );
9597 printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
9601 printf( "\tN_DATA_IND\n" );
9602 printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
9606 printf( "\tN_DATA_REQ\n" );
9610 printf( "\tN_DISCON_IND\n" );
9611 printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
9612 printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
9613 printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
9614 printf( "\tRES:\t" );
9615 x25dump_data( (char *)primitive,
9616 primitive->discon_ind.RES_offset,
9617 primitive->discon_ind.RES_length );
9621 printf( "\tN_DISCON_REQ\n" );
9622 printf( "\tDISCON_reason:\t%d\n",
9623 primitive->discon_req.DISCON_reason );
9624 printf( "\tRES:\t" );
9625 x25dump_data( (char *)primitive,
9626 primitive->discon_req.RES_offset,
9627 primitive->discon_req.RES_length );
9628 printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
9632 printf( "\tN_ERROR_ACK\n" );
9633 printf( "\tCaused by:\t%s\n",
9634 x25prim( primitive->error_ack.ERROR_prim ) );
9635 printf( "\tNPI error:\t%s\n",
9636 x25err( primitive->error_ack.NPI_error ));
9637 errno = primitive->error_ack.UNIX_error;
9642 printf( "\tN_EXDATA_ACK\n" );
9646 printf( "\tN_EXDATA_REQ\n" );
9650 printf( "\tN_INFO_ACK\n" );
9651 printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
9652 printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
9653 printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
9654 printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
9655 printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
9656 printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
9660 printf( "\tN_INFO_REQ\n" );
9664 printf( "\tN_OK_ACK\n" );
9668 printf( "\tN_OPTMGMT_REQ\n" );
9672 printf( "\tN_RESET_CON\n" );
9676 printf( "\tN_RESET_IND\n" );
9677 printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
9678 printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
9682 printf( "\tN_RESET_REQ\n" );
9683 printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
9687 printf( "\tN_RESET_RES\n" );
9691 printf( "\tN_UDERROR_IND\n" );
9695 printf( "\tN_UNBIND_REQ\n" );
9698 case N_UNITDATA_REQ:
9699 printf( "\tN_UNITDATA_REQ\n" );
9702 case N_UNITDATA_IND:
9703 printf( "\tN_UNITDATA_IND\n" );
9707 (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
9713 /* it looks like signal handling is not needed with streams! */
9714 /* x25oobh() - handle SIGURG signals - take from isode ? */
9720 Which time.h files to include... See ckcdeb.h for defaults.
9721 Note that 0, 1, 2, or all 3 of these can be included according to
9722 the symbol definitions.
9728 #endif /* NOTIMEH */
9732 #include <sys/time.h>
9733 #endif /* SYSTIMEH */
9734 #endif /* NOSYSTIMEH */
9738 #include <sys/timeb.h>
9739 #endif /* SYSTIMEBH */
9740 #endif /* NOSYSTIMEBH */
9746 #include <sys/time.h>
9752 #include <sys/time.h>
9755 #include <sys/time.h>
9758 #include <posix/time.h>
9761 #include <sys/time.h>
9767 /* #include <utime.h> */
9771 #endif /* SYSTIMEH */
9780 #include <sys/utime.h>
9782 #define utimbuf _utimbuf
9784 #define utime _utime
9786 #ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
9787 #include <sys/utime.h> /* for extra fields required by */
9788 #else /* 88Open spec. */
9789 #ifdef UTIMEH /* or <utime.h> if requested */
9790 #include <utime.h> /* (SVR4, POSIX) */
9791 #define SYSUTIMEH /* Use this for both cases. */
9793 #endif /* SYSUTIMEH */
9796 #ifndef HTTP_VERSION
9797 #define HTTP_VERSION "HTTP/1.1"
9798 #endif /* HTTP_VERSION */
9803 http_date(char * date)
9805 http_date(date) char * date;
9806 #endif /* CK_ANSIC */
9808 /* HTTP dates are of the form: "Sun, 06 Oct 1997 20:11:47 GMT" */
9809 /* There are two older formats which we are required to parse
9810 * that we currently do not:
9812 * RFC 850: "Sunday, 06-Oct-97 20:11:47 GMT"
9813 * asctime(): "Sun Nov 6 20:11:47 1997"
9815 * However, it is required that all dates be sent in the form we
9816 * do accept. The other two formats are for compatibility with
9817 * really old servers.
9819 extern char cmdatebuf[18];
9825 j = ckindex(",",date,0,0,0);
9826 ckstrncpy(ldate,&date[j+1],25);
9829 cmcvtate() date changed to return a string pointer.
9833 dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
9836 t_tm = *cmdate2tm(dp,1);
9839 From Lucas Hart, 5 Dec 2001:
9840 "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
9841 setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
9842 the specified (GMT) time if the buffer size is 21, or the contemporaneous
9843 localtime if the buffer size is 25. Perhaps tm_isdst should be set in
9844 cmdate2tm(), rather than only in http_date."
9846 #ifndef NOTM_ISDST /* For platforms where */
9847 t_tm.tm_isdst = -1; /* tm_isdst doesn't exist. */
9848 #endif /* NOTM_ISDST */
9850 t = mktime(&t_tm); /* NOT PORTABLE */
9854 #endif /* XX_TIMEZONE */
9858 #endif /* CMDATE2TM */
9862 static char nowstr[32];
9865 time_t ltime; /* NOT PORTABLE */
9869 gmt = gmtime(<ime); /* PROBABLY NOT PORTABLE */
9870 strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
9871 /* not only is it not portable but it's locale-dependent */
9874 This is hopeless. First of all, it seems that HTTP wants Day and Month
9875 NAMES? In English? Whose idea was that? Even worse, the date/time must be
9876 expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
9877 nightmare. Every platform does it differently, if at all -- even if we
9878 restrict ourselves to UNIX. For example (quoting from recent C-Kermit edit
9879 history), "Fixed a longstanding bug in the BSDI version, in which incoming
9880 file dates were set in GMT rather than local time. It seems in 4.4BSD,
9881 localtime() does not return the local time, but rather Zero Meridian (Zulu)
9882 time (GMT), and must be adjusted by the tm_gmtoff value." Swell. For
9883 greater appreciation of the scope of the problem, just take a look at the
9884 time-related #ifdefs in ckutio.c. The only right way to do this is to add
9885 our own portable API for converting between local time and GMT/UTC/Zulu
9886 that shields us not only from UNIXisms like time_t and struct tm, but also
9887 the unbelievable amount of differences in time-related APIs -- e.g. is
9888 "timezone" an external variable or a function; which header file(s) do we
9889 include, etc etc etc. It's a major project.
9892 x = cmcvtdate("",1);
9894 Evidently this code is not used -- if it is, it must be fixed to use
9895 new (aug 2001) cmcvtdate() calling conventions.
9899 /* yyyymmdd hh:mm:ss */
9900 /* 01234567890123456 */
9901 nowstr[0] = 'X'; /* 1st letter of day */
9902 nowstr[1] = 'x'; /* 2nd letter of day */
9903 nowstr[2] = 'x'; /* 3rd letter of day */
9906 nowstr[5] = cmdate[6];
9907 nowstr[6] = cmdate[7];
9909 nowstr[8] = ' '; /* first letter of month */
9910 nowstr[9] = ' '; /* second letter of month */
9911 nowstr[10] = ' '; /* third letter of month */
9913 nowstr[12] = cmdate[0];
9914 nowstr[13] = cmdate[1];
9915 nowstr[14] = cmdate[2];
9916 nowstr[15] = cmdate[3];
9918 nowstr[17] = cmdate[9];
9919 nowstr[18] = cmdate[10];
9920 nowstr[19] = cmdate[11];
9921 nowstr[20] = cmdate[12];
9922 nowstr[21] = cmdate[13];
9923 nowstr[22] = cmdate[14];
9924 nowstr[23] = cmdate[15];
9925 nowstr[24] = cmdate[16];
9931 #endif /* CMDATE2TM */
9936 #ifndef CK_AUTHENTICATION
9937 /* from ckuusr.h, which this module normally doesn't include */
9938 _PROTOTYP( int dclarray, (char, int) );
9939 #endif /* CK_AUTHENTICATION */
9942 Assign http response pairs to given array.
9943 For best results, response pairs should contain no spaces.
9946 resp = pointer to response list.
9947 n = size of response list.
9948 array = array letter.
9951 >= 1, size of array, on success.
9955 http_mkarray(char ** resp, int n, char array)
9957 http_mkarray(resp, n, array) char ** resp; int n; char array;
9958 #endif /* CK_ANSIC */
9963 extern char ** a_ptr[];
9966 if (!array || n <= 0)
9968 if ((x = dclarray(array,n)) < 0) {
9969 printf("?Array declaration failure\n");
9972 /* Note: argument array is 0-based but Kermit array is 1-based */
9974 ap[0] = NULL; /* 0th element is empty */
9975 for (i = 1; i <= n; i++) {
9976 ap[i] = resp[i-1]; /* If resp elements were malloc'd */
9986 #define HTTPHEADCNT 64
9988 http_get_chunk_len()
9995 while ((ch = http_inc(0)) >= 0 && i < 24) {
9997 if ( buf[i] == ';' ) /* Find chunk-extension (if any) */
9999 if ( buf[i] == 10 ) { /* found end of line */
10000 if (i > 0 && buf[i-1] == 13)
10007 if ( i < 24 ) { /* buf now contains len in Hex */
10008 len = hextoulong(buf, j == -1 ? i : j-1);
10017 return(httpfd != -1);
10023 return(httpfd != -1 ? http_host_port : "");
10029 if ( httpfd == -1 )
10032 if (tls_http_active_flag) {
10033 SSL_CIPHER * cipher;
10034 const char *cipher_list;
10035 static char buf[128];
10037 cipher = SSL_get_current_cipher(tls_http_con);
10038 cipher_list = SSL_CIPHER_get_name(cipher);
10039 SSL_CIPHER_description(cipher,buf,sizeof(buf));
10042 #endif /* CK_SSL */
10050 char * s = NULL; /* strdup is not portable */
10051 if ( tcp_http_proxy ) {
10053 makestr(&s,(char *)http_host_port);
10055 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10056 if (*p == ':') { /* Have a colon */
10057 *p++ = '\0'; /* Get service name or number */
10061 rc = http_open(s,p,http_ssl,NULL,0,http_agent);
10063 makestr(&s,(char *)http_ip);
10064 rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
10073 http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
10074 int rdns_len, char * agent)
10075 #else /* CK_ANSIC */
10076 http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
10083 #endif /* CK_ANSIC */
10085 char namecopy[NAMECPYL];
10090 #ifdef SO_OOBINLINE
10092 #endif /* SO_OOBINLINE */
10093 struct servent *service=NULL;
10094 struct hostent *host=NULL;
10095 struct sockaddr_in r_addr;
10096 struct sockaddr_in sin;
10097 struct sockaddr_in l_addr;
10098 GSOCKNAME_T l_slen;
10100 struct sockaddr_in send_socket;
10101 #endif /* EXCELAN */
10104 /* inet_addr() is of type struct in_addr */
10106 extern struct in_addr inet_addr();
10109 extern struct in_addr inet_addr();
10110 #endif /* HPUX5WINTCP */
10111 #endif /* datageneral */
10112 struct in_addr iax;
10115 struct in_addr iax;
10116 #else /* INADDR_NONE */
10118 #endif /* INADDR_NONE */
10119 #endif /* INADDRX */
10121 if ( rdns_name == NULL || rdns_len < 0 )
10124 *http_ip = '\0'; /* Initialize IP address string */
10125 namecopy[0] = '\0';
10129 debug(F110,"http_open hostname",hostname,0);
10130 debug(F110,"http_open svcname",svcname,0);
10133 if (!hostname) hostname = "";
10134 if (!svcname) svcname = "";
10135 if (!*hostname || !*svcname) return(-1);
10138 service = ckgetservice(hostname,svcname,http_ip,20);
10140 if (service == NULL) {
10142 printf("?Invalid service: %s\r\n",svcname);
10146 /* For HTTP connections we must preserve the original hostname and */
10147 /* service requested so we can include them in the Host header. */
10148 ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
10149 ckuitoa(ntohs(service->s_port)),NULL);
10150 http_port = ntohs(service->s_port);
10151 http_ssl = use_ssl;
10152 debug(F111,"http_open",http_host_port,http_port);
10154 /* 'http_ip' contains the IP address to which we want to connect */
10155 /* 'svcnam' contains the service name */
10156 /* 'service->s_port' contains the port number in network byte order */
10158 /* If we are using an http proxy, we need to create a buffer containing */
10159 /* hostname:port-number */
10160 /* to pass to the http_connect() function. Then we need to replace */
10161 /* 'namecopy' with the name of the proxy server and the service->s_port */
10162 /* with the port number of the proxy (default port 80). */
10164 if ( tcp_http_proxy ) {
10166 ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
10167 ckuitoa(ntohs(service->s_port)),NULL);
10168 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10170 p = namecopy; /* Was a service requested? */
10171 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10172 if (*p == ':') { /* Have a colon */
10173 debug(F110,"http_open name has colon",namecopy,0);
10174 *p++ = '\0'; /* Get service name or number */
10176 strcpy(++p,"http");
10179 service = ckgetservice(namecopy,p,http_ip,20);
10181 fprintf(stderr, "Can't find port for service %s\n", p);
10183 debug(F101,"http_open can't get service for proxy","",socket_errno);
10185 debug(F101,"http_open can't get service for proxy","",errno);
10186 #endif /* TGVORWIN */
10187 errno = 0; /* (rather than mislead) */
10191 /* copy the proxyname and remove the service if any so we can use
10192 * it as the hostname
10194 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10195 p = namecopy; /* Was a service requested? */
10196 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10197 if (*p == ':') { /* Have a colon */
10198 *p = '\0'; /* terminate string */
10200 hostname = namecopy; /* use proxy as hostname */
10203 /* Set up socket structure and get host address */
10204 bzero((char *)&r_addr, sizeof(r_addr));
10205 debug(F100,"http_open bzero ok","",0);
10208 debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
10209 #else /* INADDR_NONE */
10210 debug(F100,"http_open INADDR_NONE not defined","",0);
10211 #endif /* INADDR_NONE */
10213 debug(F100,"http_open INADDRX defined","",0);
10214 #else /* INADDRX */
10215 debug(F100,"http_open INADDRX not defined","",0);
10216 #endif /* INADDRX */
10220 iax = inet_addr(http_ip[0]?http_ip:hostname);
10221 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10222 #else /* INADDRX */
10224 iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
10225 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10226 #else /* INADDR_NONE */
10227 #ifndef datageneral
10228 iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
10231 #endif /* datageneral */
10232 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
10233 #endif /* INADDR_NONE */
10234 #endif /* INADDRX */
10239 /* This might give warnings on 64-bit platforms but they should be harmless */
10240 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
10241 /* probably superfluous -- not sure why it's even there, maybe it should be */
10243 iax.s_addr == INADDR_NONE || iax.s_addr == (unsigned long) -1L
10244 #else /* INADDR_NONE */
10246 #endif /* INADDR_NONE */
10249 printf(" DNS Lookup... ");
10252 if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
10253 debug(F100,"http_open gethostbyname != NULL","",0);
10254 host = ck_copyhostent(host);
10255 dns = 1; /* Remember we performed dns lookup */
10256 r_addr.sin_family = host->h_addrtype;
10257 if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
10258 && (tcp_http_proxy == NULL)
10260 ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
10264 /* This is for trying multiple IP addresses - see <netdb.h> */
10265 if (!(host->h_addr_list))
10267 bcopy(host->h_addr_list[0],
10268 (caddr_t)&r_addr.sin_addr,
10272 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10273 #endif /* h_addr */
10274 #else /* HADDRLIST */
10275 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10276 #endif /* HADDRLIST */
10278 debug(F111,"BCOPY","host->h_addr",host->h_addr);
10279 #endif /* EXCELAN */
10280 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
10281 (caddr_t)&r_addr.sin_addr);
10282 debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
10283 r_addr.sin_addr.s_addr);
10284 debug(F111,"BCOPY","host->h_length",host->h_length);
10287 #endif /* NOMHHOST */
10291 /* inet_addr() is of type struct in_addr */
10292 struct in_addr ina;
10294 debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
10295 ina = inet_addr(http_ip[0]?http_ip:hostname);
10296 uu = *(unsigned int *)&ina;
10297 #else /* Not INADDRX */
10298 /* inet_addr() is unsigned long */
10300 debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
10301 uu = inet_addr(http_ip[0]?http_ip:hostname);
10302 #endif /* INADDRX */
10303 debug(F101,"http_open uu","",uu);
10306 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
10307 #else /* INADDR_NONE */
10308 uu != ((unsigned long)-1)
10309 #endif /* INADDR_NONE */
10311 r_addr.sin_addr.s_addr = uu;
10312 r_addr.sin_family = AF_INET;
10315 fprintf(stdout, "\r\n"); /* complete any previous message */
10317 fprintf(stderr, "Can't get address for %s\n",
10318 http_ip[0]?http_ip:hostname);
10320 debug(F101,"http_open can't get address","",socket_errno);
10322 debug(F101,"http_open can't get address","",errno);
10323 #endif /* TGVORWIN */
10324 errno = 0; /* Rather than mislead */
10329 /* Get a file descriptor for the connection. */
10331 r_addr.sin_port = service->s_port;
10332 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10333 debug(F110,"http_open trying",http_ip,0);
10334 if (!quiet && *http_ip) {
10335 printf(" Trying %s... ", http_ip);
10339 /* Loop to try additional IP addresses, if any. */
10343 send_socket.sin_family = AF_INET;
10344 send_socket.sin_addr.s_addr = 0;
10345 send_socket.sin_port = 0;
10346 if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
10347 &send_socket, SO_REUSEADDR)) < 0)
10348 #else /* EXCELAN */
10349 if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
10350 #endif /* EXCELAN */
10353 experror("TCP socket error");
10357 errno = socket_errno;
10358 #endif /* OLD_TWG */
10359 socket_perror("TCP socket error");
10360 debug(F101,"http_open socket error","",socket_errno);
10362 perror("TCP socket error");
10363 debug(F101,"http_open socket error","",errno);
10364 #endif /* TGVORWIN */
10365 #endif /* EXCELAN */
10370 /* If a specific TCP address on the local host is desired we */
10371 /* must bind it to the socket. */
10372 #ifndef datageneral
10376 debug(F110,"http_open binding socket to",tcp_address,0);
10377 bzero((char *)&sin,sizeof(sin));
10378 sin.sin_family = AF_INET;
10380 inaddrx = inet_addr(tcp_address);
10381 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
10383 sin.sin_addr.s_addr = inet_addr(tcp_address);
10384 #endif /* INADDRX */
10386 if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
10387 s_errno = socket_errno; /* Save error code */
10389 socket_close(httpfd);
10390 #else /* TCPIPLIB */
10392 #endif /* TCPIPLIB */
10394 errno = s_errno; /* and report this error */
10395 debug(F101,"http_open bind errno","",errno);
10399 #endif /* datageneral */
10401 /* Now connect to the socket on the other end. */
10404 if (connect(httpfd, &r_addr) < 0)
10407 WSASafeToCancel = 1;
10409 if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
10410 #endif /* EXCELAN */
10413 WSASafeToCancel = 0;
10421 i = errno; /* Save error code */
10422 #endif /* TGVORWIN */
10426 if (host && host->h_addr_list && host->h_addr_list[1]) {
10428 host->h_addr_list++;
10429 bcopy(host->h_addr_list[0],
10430 (caddr_t)&r_addr.sin_addr,
10433 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10434 debug(F110,"http_open h_addr_list",http_ip,0);
10435 if (!quiet && *http_ip) {
10436 printf(" Trying %s... ", http_ip);
10440 socket_close(httpfd); /* Close it. */
10443 #endif /* TCPIPLIB */
10446 #endif /* h_addr */
10447 #endif /* HADDRLIST */
10450 errno = i; /* And report this error */
10452 if (errno) experror("http_open connect");
10455 debug(F101,"http_open connect error","",socket_errno);
10456 /* if (errno) socket_perror("http_open connect"); */
10458 errno = socket_errno;
10459 #endif /* OLD_TWG */
10461 socket_perror("http_open connect");
10462 #else /* TGVORWIN */
10463 debug(F101,"http_open connect errno","",errno);
10466 perror("\r\nFailed");
10473 perror("http_open connect");
10474 #endif /* DEC_TCPIP */
10477 perror("http_open connect");
10478 #endif /* CMU_TCPIP */
10479 #endif /* TGVORWIN */
10480 #endif /* EXCELAN */
10484 WSASafeToCancel = 0;
10487 } while (!isconnect);
10489 #ifdef NON_BLOCK_IO
10491 x = socket_ioctl(httpfd,FIONBIO,&on);
10492 debug(F101,"http_open FIONBIO","",x);
10493 #endif /* NON_BLOCK_IO */
10495 /* We have succeeded in connecting to the HTTP PROXY. So now we */
10496 /* need to attempt to connect through the proxy to the actual host */
10497 /* If that is successful, we have to pretend that we made a direct */
10498 /* connection to the actual host. */
10500 if ( tcp_http_proxy ) {
10503 agent = "Kermit 95"; /* Default user agent */
10506 agent = "C-Kermit";
10509 if (http_connect(httpfd,
10510 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
10512 tcp_http_proxy_user,
10513 tcp_http_proxy_pwd,
10522 #ifdef SO_OOBINLINE
10523 /* See note on SO_OOBINLINE in netopen() */
10525 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10528 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10531 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10534 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10537 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10541 Maybe this applies to all SVR4 versions, but the other (else) way has been
10542 compiling and working fine on all the others, so best not to change it.
10544 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10547 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10552 rc = setsockopt(httpfd,
10558 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
10561 #ifdef VMS /* or, at least, VMS with gcc */
10562 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10565 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10567 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
10572 #endif /* SOLARIS */
10573 #endif /* MOTSV88R4 */
10577 #endif /* datageneral */
10578 #endif /* SO_OOBINLINE */
10581 #ifndef datageneral
10584 no_delay(ttyfd,tcp_nodelay);
10585 #endif /* TCP_NODELAY */
10586 #ifdef SO_KEEPALIVE
10587 keepalive(ttyfd,tcp_keepalive);
10588 #endif /* SO_KEEPALIVE */
10590 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
10591 #endif /* SO_LINGER */
10593 sendbuf(ttyfd,tcp_sendbuf);
10594 #endif /* SO_SNDBUF */
10596 recvbuf(ttyfd,tcp_recvbuf);
10597 #endif /* SO_RCVBUF */
10598 #endif /* SOL_SOCKET */
10599 #endif /* datageneral */
10600 #endif /* NOTCPOPTS */
10602 #ifndef datageneral
10603 /* Find out our own IP address. */
10604 /* We need the l_addr structure for [E]KLOGIN. */
10605 l_slen = sizeof(l_addr);
10606 bzero((char *)&l_addr, l_slen);
10608 if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
10609 char * s = (char *)inet_ntoa(l_addr.sin_addr);
10610 ckstrncpy(myipaddr, s, 20);
10611 debug(F110,"getsockname",myipaddr,0);
10613 #endif /* EXCELAN */
10614 #endif /* datageneral */
10616 /* See note in netopen() on Reverse DNS lookups */
10617 if (tcp_rdns == SET_ON) {
10623 printf(" Reverse DNS Lookup... ");
10626 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
10628 host = ck_copyhostent(host);
10629 debug(F100,"http_open gethostbyname != NULL","",0);
10635 if (!s) { /* This can happen... */
10636 debug(F100,"http_open host->h_name is NULL","",0);
10639 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
10640 /* The compiler says "Integral value implicitly converted to */
10641 /* pointer in assignment." The prototype is right there */
10642 /* in <arpa/inet.h> so what's the problem? */
10643 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
10644 if (!*s) { /* No name so substitute the address */
10645 debug(F100,"http_open host->h_name is empty","",0);
10646 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
10647 if (!s) /* Trust No 1 */
10649 if (*s) { /* If it worked, use this string */
10650 ckstrncpy(http_ip,s,20);
10652 s = http_ip; /* Otherwise stick with the IP */
10653 if (!*s) /* or failing that */
10654 s = http_host_port; /* the name we were called with. */
10656 if (*s) /* return the rdns name */
10657 ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
10664 printf(" %s connected on port %s\n",s,
10665 ckuitoa(ntohs(service->s_port)));
10667 /* This is simply for testing the DNS entries */
10668 if (host->h_aliases) {
10669 char ** a = host->h_aliases;
10671 printf(" alias => %s\n",*a);
10675 #endif /* BETADEBUG */
10678 if (!quiet) printf("Failed.\n");
10680 } else if (!quiet) printf("(OK)\n");
10681 if (!quiet) fflush(stdout);
10684 if ( tcp_http_proxy ) {
10685 /* Erase the IP address since we cannot reuse it */
10688 /* This should already have been done but just in case */
10689 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10691 makestr(&http_agent,agent);
10694 if (use_ssl && ck_ssleay_is_installed()) {
10695 if (!ssl_http_init(hostname)) {
10696 if (bio_err!=NULL) {
10697 BIO_printf(bio_err,"ssl_tn_init() failed\n");
10698 ERR_print_errors(bio_err);
10701 fprintf(stderr,"ssl_tn_init() failed\n");
10702 ERR_print_errors_fp(stderr);
10706 } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
10711 #endif /* CK_SSL */
10712 #endif /* TCPSOCKET */
10714 return(0); /* Done. */
10720 #else /* CK_ANSIC */
10722 #endif /* CK_ANSIC */
10725 debug(F101,"http_close","",httpfd);
10727 if (httpfd == -1) /* Was open? */
10728 return(0); /* Wasn't. */
10731 if (httpfd > -1) /* Was. */
10735 if (tls_http_active_flag) {
10736 if (ssl_debug_flag)
10737 BIO_printf(bio_err,"calling SSL_shutdown\n");
10738 SSL_shutdown(tls_http_con);
10739 tls_http_active_flag = 0;
10741 #endif /* CK_SSL */
10743 x = socket_close(httpfd); /* Close it. */
10748 #endif /* TCPIPLIB */
10750 httpfd = -1; /* Mark it as closed. */
10751 /* do not erase http_host_port, http_ip, http_port so they */
10752 /* can be used by http_reopen() */
10758 * Call with s = pointer to string, n = length.
10759 * Returns number of bytes actually written on success, or
10760 * -1 on i/o error, -2 if called improperly.
10764 http_tol(s,n) CHAR *s; int n; {
10769 if (httpfd == -1) {
10770 debug(F100,"http_tol socket is closed","",0);
10773 debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
10775 hexdump("http_tol",s,n);
10776 #endif /* COMMENT */
10779 if (tls_http_active_flag) {
10781 /* Write using SSL */
10783 r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
10784 switch (SSL_get_error(tls_http_con,r)) {
10785 case SSL_ERROR_NONE:
10786 debug(F111,"http_tol","SSL_write",r);
10792 case SSL_ERROR_WANT_WRITE:
10793 debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
10795 case SSL_ERROR_WANT_READ:
10796 debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
10798 case SSL_ERROR_SYSCALL:
10799 if ( r == 0 ) { /* EOF */
10805 int gle = GetLastError();
10806 debug(F111,"http_tol SSL_ERROR_SYSCALL",
10807 "GetLastError()",gle);
10808 rc = os2socketerror(gle);
10811 else if ( rc == -2 )
10816 case SSL_ERROR_WANT_X509_LOOKUP:
10817 debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
10820 case SSL_ERROR_SSL:
10821 debug(F100,"http_tol SSL_ERROR_SSL","",0);
10824 case SSL_ERROR_ZERO_RETURN:
10825 debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
10829 debug(F100,"http_tol SSL_ERROR_?????","",0);
10834 #endif /* CK_SSL */
10837 try++; /* Increase the try counter */
10844 debug(F101,"http_tol BSDSELECT","",0);
10848 WSASafeToCancel = 1;
10852 #endif /* STREAMING */
10854 FD_SET(httpfd, &wfds);
10855 if (select(FD_SETSIZE, NULL,
10859 #endif /* __DECC_VER */
10860 #endif /* __DECC */
10861 &wfds, NULL, &tv) < 0) {
10862 int s_errno = socket_errno;
10863 debug(F101,"http_tol select failed","",s_errno);
10865 printf("http_tol select failed: %d\n", s_errno);
10866 #endif /* BETADEBUG */
10868 WSASafeToCancel = 0;
10869 if (!win95selectbug)
10873 if (!FD_ISSET(httpfd, &wfds)) {
10877 #endif /* STREAMING */
10878 debug(F111,"http_tol","!FD_ISSET",ttyfd);
10880 WSASafeToCancel = 0;
10881 if (!win95selectbug)
10886 WSASafeToCancel = 0;
10888 #else /* BSDSELECT */
10892 debug(F101,"http_tol IBMSELECT","",0);
10893 while (select(&httpfd, 0, 1, 0, 1000) != 1) {
10895 if (tries++ >= 60) {
10896 /* if after 60 seconds we can't get permission to write */
10897 debug(F101,"http_tol select failed","",socket_errno);
10901 if ((count = http_tchk()) < 0) {
10902 debug(F111,"http_tol","http_tchk()",count);
10905 #endif /* COMMENT */
10908 #endif /* IBMSELECT */
10909 #endif /* BSDSELECT */
10911 if ((count = socket_write(httpfd,s,n)) < 0) {
10912 int s_errno = socket_errno; /* maybe a function */
10913 debug(F101,"http_tol socket_write error","",s_errno);
10915 if (os2socketerror(s_errno) < 0)
10918 return(-1); /* Call it an i/o error */
10920 #else /* TCPIPLIB */
10921 if ((count = write(httpfd,s,n)) < 0) {
10922 debug(F101,"http_tol socket_write error","",errno);
10923 return(-1); /* Call it an i/o error */
10925 #endif /* TCPIPLIB */
10927 debug(F111,"http_tol socket_write",s,count);
10929 /* don't try more than 25 times */
10930 debug(F100,"http_tol tried more than 25 times","",0);
10937 debug(F111,"http_tol retry",s,n);
10938 goto http_tol_retry;
10940 debug(F111,"http_tol socket_write",s,count);
10941 return(len); /* success - return total length */
10948 http_inc(timo) int timo; {
10949 int x=-1; unsigned char c; /* The locals. */
10951 if (httpfd == -1) {
10952 debug(F100,"http_inc socket is closed","",0);
10958 * In the case of OpenSSL, it is possible that there is still
10959 * data waiting in the SSL session buffers that has not yet
10960 * been read by Kermit. If this is the case we must process
10961 * it without calling select() because select() will not return
10962 * with an indication that there is data to be read from the
10963 * socket. If there is no data pending in the SSL session
10964 * buffers then fall through to the select() code and wait for
10965 * some data to arrive.
10967 if (tls_http_active_flag) {
10970 x = SSL_pending(tls_http_con);
10972 debug(F111,"http_inc","SSL_pending error",x);
10975 } else if ( x > 0 ) {
10977 x = SSL_read(tls_http_con, &c, 1);
10978 error = SSL_get_error(tls_http_con,x);
10980 case SSL_ERROR_NONE:
10981 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
10984 ReleaseTCPIPMutex();
10986 return(c); /* Return character. */
10987 } else if (x < 0) {
10989 ReleaseTCPIPMutex();
10995 ReleaseTCPIPMutex();
10999 case SSL_ERROR_WANT_WRITE:
11000 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11002 ReleaseTCPIPMutex();
11005 case SSL_ERROR_WANT_READ:
11006 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11008 ReleaseTCPIPMutex();
11011 case SSL_ERROR_SYSCALL:
11012 if ( x == 0 ) { /* EOF */
11015 ReleaseTCPIPMutex();
11021 int gle = GetLastError();
11022 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11023 "GetLastError()",gle);
11024 rc = os2socketerror(gle);
11027 else if ( rc == -2 )
11031 ReleaseTCPIPMutex();
11035 case SSL_ERROR_WANT_X509_LOOKUP:
11036 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11039 ReleaseTCPIPMutex();
11042 case SSL_ERROR_SSL:
11043 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11046 #endif /* COMMENT */
11048 ReleaseTCPIPMutex();
11051 case SSL_ERROR_ZERO_RETURN:
11052 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11055 ReleaseTCPIPMutex();
11059 debug(F100,"http_inc SSL_ERROR_?????","",0);
11062 ReleaseTCPIPMutex();
11068 #endif /* CK_SSL */
11073 int timeout = timo < 0 ? -timo : 1000 * timo;
11074 debug(F101,"http_inc BSDSELECT","",timo);
11076 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11078 debug(F111,"http_inc","timeout",timeout);
11079 /* Don't move select() initialization out of the loop. */
11081 FD_SET(httpfd, &rfds);
11082 tv.tv_sec = tv.tv_usec = 0L;
11084 tv.tv_usec = (long) 100000L;
11088 WSASafeToCancel = 1;
11090 rc = select(FD_SETSIZE,
11093 #endif /* __DECC */
11094 &rfds, NULL, NULL, &tv);
11096 int s_errno = socket_errno;
11097 debug(F111,"http_inc","select",rc);
11098 debug(F111,"http_inc","socket_errno",s_errno);
11102 debug(F111,"http_inc","select",rc);
11104 WSASafeToCancel = 0;
11106 if (FD_ISSET(httpfd, &rfds)) {
11110 /* If waiting forever we have no way of knowing if the */
11111 /* socket closed so try writing a 0-length TCP packet */
11112 /* which should force an error if the socket is closed */
11115 if ((rc = socket_write(httpfd,"",0)) < 0) {
11116 int s_errno = socket_errno;
11117 debug(F101,"http_inc socket_write error","",s_errno);
11119 if (os2socketerror(s_errno) < 0)
11122 return(-1); /* Call it an i/o error */
11124 #else /* TCPIPLIB */
11125 if ((rc = write(httpfd,"",0)) < 0) {
11126 debug(F101,"http_inc socket_write error","",errno);
11127 return(-1); /* Call it an i/o error */
11129 #endif /* TCPIPLIB */
11135 WSASafeToCancel = 0;
11137 #else /* !BSDSELECT */
11140 Was used by OS/2, currently not used, but might come in handy some day...
11141 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
11142 and timeval stuff since this is the only place where it is used.
11144 int socket = httpfd;
11145 int timeout = timo < 0 ? -timo : 1000 * timo;
11147 debug(F101,"http_inc IBMSELECT","",timo);
11148 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11149 if (select(&socket, 1, 0, 0, 100L) == 1) {
11154 #else /* !IBMSELECT */
11155 SELECT is required for this code
11156 #endif /* IBMSELECT */
11157 #endif /* BSDSELECT */
11160 if (timo && x < 0) { /* select() timed out */
11161 debug(F100,"http_inc select() timed out","",0);
11162 return(-1); /* Call it an i/o error */
11166 if ( tls_http_active_flag ) {
11169 x = SSL_read(tls_http_con, &c, 1);
11170 error = SSL_get_error(tls_http_con,x);
11172 case SSL_ERROR_NONE:
11173 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11176 ReleaseTCPIPMutex();
11178 return(c); /* Return character. */
11179 } else if (x < 0) {
11181 ReleaseTCPIPMutex();
11187 ReleaseTCPIPMutex();
11191 case SSL_ERROR_WANT_WRITE:
11192 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11194 ReleaseTCPIPMutex();
11197 case SSL_ERROR_WANT_READ:
11198 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11200 ReleaseTCPIPMutex();
11203 case SSL_ERROR_SYSCALL:
11204 if ( x == 0 ) { /* EOF */
11207 ReleaseTCPIPMutex();
11213 int gle = GetLastError();
11214 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11215 "GetLastError()",gle);
11216 rc = os2socketerror(gle);
11219 else if ( rc == -2 )
11223 ReleaseTCPIPMutex();
11227 case SSL_ERROR_WANT_X509_LOOKUP:
11228 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11231 ReleaseTCPIPMutex();
11234 case SSL_ERROR_SSL:
11235 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11238 #endif /* COMMENT */
11240 ReleaseTCPIPMutex();
11243 case SSL_ERROR_ZERO_RETURN:
11244 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11247 ReleaseTCPIPMutex();
11251 debug(F100,"http_inc SSL_ERROR_?????","",0);
11254 ReleaseTCPIPMutex();
11259 #endif /* CK_SSL */
11261 x = socket_read(httpfd,&c,1);
11263 x = read(httpfd,&c,1);
11267 int s_errno = socket_errno;
11268 debug(F101,"ttbufr socket_read","",x);
11269 debug(F101,"ttbufr socket_errno","",s_errno);
11271 if (x == 0 || os2socketerror(s_errno) < 0) {
11273 ReleaseTCPIPMutex();
11276 ReleaseTCPIPMutex();
11279 http_close(); /* *** *** */
11288 http_set_code_reply(char * msg)
11290 http_set_code_reply(msg)
11292 #endif /* CK_ANSIC */
11298 while ( *p != SP && *p != NUL ) {
11304 http_code = atoi(buf);
11309 ckstrncpy(http_reply_str,p,HTTPBUFLEN);
11314 http_get(char * agent, char ** hdrlist, char * user,
11315 char * pwd, char array, char * local, char * remote,
11318 http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
11319 char * agent; char ** hdrlist; char * user;
11320 char * pwd; char array; char * local; char * remote;
11322 #endif /* CK_ANSIC */
11324 char * request = NULL;
11325 int i, j, len = 0, hdcnt = 0, rc = 0;
11328 char buf[HTTPBUFLEN], *p;
11331 struct utimbuf u_t;
11334 struct utimbuf u_t;
11340 #endif /* SYSUTIMH */
11344 time_t local_t = 0;
11348 char * headers[HTTPHEADCNT];
11356 debug(F101,"http_get httpfd","",httpfd);
11357 debug(F110,"http_agent",agent,0);
11358 debug(F110,"http_user",user,0);
11359 debug(F110,"http_local",local,0);
11360 debug(F110,"http_remote",remote,0);
11363 if (!remote) remote = "";
11369 for (i = 0; i < HTTPHEADCNT; i++)
11373 len += strlen(HTTP_VERSION);
11374 len += strlen(remote);
11378 for (i = 0; hdrlist[i]; i++)
11379 len += strlen(hdrlist[i]) + 2;
11381 len += (int) strlen(http_host_port) + 8;
11384 len += 13 + strlen(agent);
11387 readpass("Password: ",passwd,64);
11390 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11391 j = b8tob64(b64in,strlen(b64in),b64out,256);
11392 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11399 len += 19; /* Connection: close */
11401 len += 3; /* blank line + null */
11403 request = malloc(len);
11407 sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION); /* safe */
11408 ckstrncat(request,"Host: ", len);
11409 ckstrncat(request,http_host_port, len);
11410 ckstrncat(request,"\r\n",len);
11412 ckstrncat(request,"User-agent: ",len);
11413 ckstrncat(request,agent,len);
11414 ckstrncat(request,"\r\n",len);
11417 ckstrncat(request,"Authorization: Basic ",len);
11418 ckstrncat(request,b64out,len);
11419 ckstrncat(request,"\r\n",len);
11422 for (i = 0; hdrlist[i]; i++) {
11423 ckstrncat(request,hdrlist[i],len);
11424 ckstrncat(request,"\r\n",len);
11428 ckstrncat(request,"Connection: close\r\n",len);
11430 ckstrncat(request,"\r\n",len);
11433 if (http_tol((CHAR *)request,strlen(request)) < 0)
11445 /* Process the headers */
11446 local_t = time(NULL);
11450 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11452 if ( buf[i] == 10 ) { /* found end of line */
11453 if (i > 0 && buf[i-1] == 13)
11458 if (array && !nullline && hdcnt < HTTPHEADCNT)
11459 makestr(&headers[hdcnt++],buf);
11460 if (!ckstrcmp(buf,"HTTP",4,0)) {
11462 j = ckindex(" ",buf,0,0,0);
11464 while ( isspace(*p) )
11467 case '1': /* Informational message */
11469 case '2': /* Success */
11471 case '3': /* Redirection */
11472 case '4': /* Client failure */
11473 case '5': /* Server failure */
11474 default: /* Unknown */
11476 printf("Failure: Server reports %s\n",p);
11480 http_set_code_reply(p);
11482 } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11483 mod_t = http_date(&buf[15]);
11484 } else if (!ckstrcmp(buf,"Date",4,0)) {
11485 srv_t = http_date(&buf[4]);
11486 #endif /* CMDATE2TM */
11487 } else if (!ckstrcmp(buf,"Connection:",11,0)) {
11488 if ( ckindex("close",buf,11,0,0) != 0 )
11490 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11491 len = atoi(&buf[16]);
11492 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11493 if ( ckindex("chunked",buf,18,0,0) != 0 )
11501 if (ch < 0 && first) {
11507 if (http_fnd == 0) {
11513 /* Now we have the contents of the file */
11514 if ( local && local[0] ) {
11515 if (zopeno(ZOFILE,local,NULL,NULL))
11522 while ((len = http_get_chunk_len()) > 0) {
11523 while (len && (ch = http_inc(0)) >= 0) {
11526 zchout(ZOFILE,(CHAR)ch);
11530 if ((ch = http_inc(0)) != CR)
11532 if ((ch = http_inc(0)) != LF)
11536 while (len && (ch = http_inc(0)) >= 0) {
11539 zchout(ZOFILE,(CHAR)ch);
11548 if ( chunked ) { /* Parse Trailing Headers */
11550 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11552 if ( buf[i] == 10 ) { /* found end of line */
11553 if (i > 0 && buf[i-1] == 13)
11558 if (array && !nullline && hdcnt < HTTPHEADCNT)
11559 makestr(&headers[hdcnt++],buf);
11561 if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11562 mod_t = http_date(&buf[15]);
11563 } else if (!ckstrcmp(buf,"Date",4,0)) {
11564 srv_t = http_date(&buf[4]);
11566 #endif /* CMDATE2TM */
11567 else if (!ckstrcmp(buf,"Connection:",11,0)) {
11568 if ( ckindex("close",buf,11,0,0) != 0 )
11578 if ( zfile ) { /* Set timestamp */
11581 u_t.actime = srv_t ? srv_t : local_t;
11582 u_t.modtime = mod_t ? mod_t : local_t;
11585 u_t.actime = srv_t ? srv_t : local_t;
11586 u_t.modtime = mod_t ? mod_t : local_t;
11589 u_t[0].tv_sec = srv_t ? srv_t : local_t;
11590 u_t[1].tv_sec = mod_t ? mod_t : local_t;
11592 u_t.mtime = srv_t ? srv_t : local_t;
11593 u_t.atime = mod_t ? mod_t : local_t;
11595 #endif /* SYSUTIMEH */
11598 #endif /* NOSETTIME */
11603 http_mkarray(headers,hdcnt,array);
11608 for (i = 0; i < hdcnt; i++) {
11617 http_head(char * agent, char ** hdrlist, char * user,
11618 char * pwd, char array, char * local, char * remote,
11621 http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
11622 char * agent; char ** hdrlist; char * user;
11623 char * pwd; char array; char * local; char * remote;
11625 #endif /* CK_ANSIC */
11627 char * request = NULL;
11628 int i, j, len = 0, hdcnt = 0, rc = 0;
11631 char buf[HTTPBUFLEN], *p;
11639 char * headers[HTTPHEADCNT];
11647 for (i = 0; i < HTTPHEADCNT; i++)
11650 len = 9; /* HEAD */
11651 len += strlen(HTTP_VERSION);
11652 len += strlen(remote);
11656 for (i = 0; hdrlist[i]; i++)
11657 len += strlen(hdrlist[i]) + 2;
11659 len += strlen(http_host_port) + 8;
11662 len += 13 + strlen(agent);
11665 readpass("Password: ",passwd,64);
11668 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11669 j = b8tob64(b64in,strlen(b64in),b64out,256);
11670 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11677 len += 19; /* Connection: close */
11679 len += 3; /* blank line + null */
11681 request = (char *)malloc(len);
11685 sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
11686 ckstrncat(request,"Host: ", len);
11687 ckstrncat(request,http_host_port, len);
11688 ckstrncat(request,"\r\n",len);
11690 ckstrncat(request,"User-agent: ",len);
11691 ckstrncat(request,agent,len);
11692 ckstrncat(request,"\r\n",len);
11695 ckstrncat(request,"Authorization: Basic ",len);
11696 ckstrncat(request,b64out,len);
11697 ckstrncat(request,"\r\n",len);
11700 for (i = 0; hdrlist[i]; i++) {
11701 ckstrncat(request,hdrlist[i],len);
11702 ckstrncat(request,"\r\n",len);
11706 ckstrncat(request,"Connection: close\r\n",len);
11708 ckstrncat(request,"\r\n",len);
11710 if ( local && local[0] ) {
11711 if (!zopeno(ZOFILE,local,NULL,NULL)) {
11718 if (http_tol((CHAR *)request,strlen(request)) < 0)
11730 /* Process the headers */
11732 local_t = time(NULL);
11735 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11737 if (buf[i] == 10) { /* found end of line */
11738 if (i > 0 && buf[i-1] == 13)
11743 if (array && !nullline && hdcnt < HTTPHEADCNT)
11744 makestr(&headers[hdcnt++],buf);
11745 if (!ckstrcmp(buf,"HTTP",4,0)) {
11747 j = ckindex(" ",buf,0,0,0);
11749 while (isspace(*p))
11752 case '1': /* Informational message */
11754 case '2': /* Success */
11756 case '3': /* Redirection */
11757 case '4': /* Client failure */
11758 case '5': /* Server failure */
11759 default: /* Unknown */
11761 printf("Failure: Server reports %s\n",p);
11764 http_set_code_reply(p);
11766 if (!ckstrcmp(buf,"Connection:",11,0)) {
11767 if ( ckindex("close",buf,11,0,0) != 0 )
11770 if ( local && local[0] ) {
11772 zsout(ZOFILE,"\r\n");
11775 printf("%s\r\n",buf);
11782 if (ch < 0 && first) {
11788 if ( http_fnd == 0 )
11792 http_mkarray(headers,hdcnt,array);
11795 if ( local && local[0] )
11800 for (i = 0; i < hdcnt; i++) {
11809 http_index(char * agent, char ** hdrlist, char * user, char * pwd,
11810 char array, char * local, char * remote, int stdio)
11812 http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
11813 char * agent; char ** hdrlist; char * user; char * pwd;
11814 char array; char * local; char * remote; int stdio;
11815 #endif /* CK_ANSIC */
11817 char * request = NULL;
11818 int i, j, len = 0, hdcnt = 0, rc = 0;
11821 char buf[HTTPBUFLEN], *p;
11829 char * headers[HTTPHEADCNT];
11839 for (i = 0; i < HTTPHEADCNT; i++)
11842 len = 10; /* INDEX */
11843 len += strlen(HTTP_VERSION);
11844 len += strlen(remote);
11848 for (i = 0; hdrlist[i]; i++)
11849 len += strlen(hdrlist[i]) + 2;
11851 len += strlen(http_host_port) + 8;
11854 len += 13 + strlen(agent);
11857 readpass("Password: ",passwd,64);
11860 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11861 j = b8tob64(b64in,strlen(b64in),b64out,256);
11862 memset(pwd,0,strlen(pwd));
11869 len += 19; /* Connection: close */
11871 len += 3; /* blank line + null */
11873 request = malloc(len);
11877 sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
11878 ckstrncat(request,"Host: ", len);
11879 ckstrncat(request,http_host_port, len);
11880 ckstrncat(request,"\r\n",len);
11882 ckstrncat(request,"User-agent: ",len);
11883 ckstrncat(request,agent,len);
11884 ckstrncat(request,"\r\n",len);
11887 ckstrncat(request,"Authorization: Basic ",len);
11888 ckstrncat(request,b64out,len);
11889 ckstrncat(request,"\r\n",len);
11892 for (i = 0; hdrlist[i]; i++) {
11893 ckstrncat(request,hdrlist[i],len);
11894 ckstrncat(request,"\r\n",len);
11898 ckstrncat(request,"Connection: close\r\n",len);
11900 ckstrncat(request,"\r\n",len);
11902 if (http_tol((CHAR *)request,strlen(request)) < 0)
11914 /* Process the headers */
11915 local_t = time(NULL);
11919 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11921 if (buf[i] == 10) { /* found end of line */
11922 if (i > 0 && buf[i-1] == 13)
11927 if (array && !nullline && hdcnt < HTTPHEADCNT)
11928 makestr(&headers[hdcnt++],buf);
11929 if (!ckstrcmp(buf,"HTTP",4,0)) {
11931 j = ckindex(" ",buf,0,0,0);
11933 while (isspace(*p))
11936 case '1': /* Informational message */
11938 case '2': /* Success */
11940 case '3': /* Redirection */
11941 case '4': /* Client failure */
11942 case '5': /* Server failure */
11943 default: /* Unknown */
11945 printf("Failure: Server reports %s\n",p);
11948 http_set_code_reply(p);
11949 } else if ( !nullline ) {
11950 if (!ckstrcmp(buf,"Connection:",11,0)) {
11951 if ( ckindex("close",buf,11,0,0) != 0 )
11953 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11954 len = atoi(&buf[16]);
11955 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11956 if ( ckindex("chunked",buf,18,0,0) != 0 )
11959 printf("%s\n",buf);
11967 if (ch < 0 && first) {
11973 if ( http_fnd == 0 ) {
11979 /* Now we have the contents of the file */
11980 if ( local && local[0] ) {
11981 if (zopeno(ZOFILE,local,NULL,NULL))
11988 while ((len = http_get_chunk_len()) > 0) {
11989 while (len && (ch = http_inc(0)) >= 0) {
11992 zchout(ZOFILE,(CHAR)ch);
11996 if ((ch = http_inc(0)) != CR)
11998 if ((ch = http_inc(0)) != LF)
12002 while (len && (ch = http_inc(0)) >= 0) {
12005 zchout(ZOFILE,(CHAR)ch);
12014 if ( chunked ) { /* Parse Trailing Headers */
12016 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12018 if ( buf[i] == 10 ) { /* found end of line */
12019 if (i > 0 && buf[i-1] == 13)
12024 if (array && !nullline && hdcnt < HTTPHEADCNT)
12025 makestr(&headers[hdcnt++],buf);
12026 if (!ckstrcmp(buf,"Connection:",11,0)) {
12027 if ( ckindex("close",buf,11,0,0) != 0 )
12040 http_mkarray(headers,hdcnt,array);
12045 for (i = 0; i < hdcnt; i++) {
12054 http_put(char * agent, char ** hdrlist, char * mime, char * user,
12055 char * pwd, char array, char * local, char * remote,
12056 char * dest, int stdio)
12058 http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
12059 char * agent; char ** hdrlist; char * mime; char * user;
12060 char * pwd; char array; char * local; char * remote; char * dest;
12062 #endif /* CK_ANSIC */
12064 char * request=NULL;
12065 int i, j, len = 0, hdcnt = 0, rc = 0;
12068 char buf[HTTPBUFLEN], *p;
12077 char * headers[HTTPHEADCNT];
12085 if (!mime) mime = "";
12086 if (!remote) remote = "";
12087 if (!local) local = "";
12088 if (!*local) return(-1);
12091 for (i = 0; i < HTTPHEADCNT; i++)
12094 filelen = zchki(local);
12098 /* Compute length of request header */
12100 len += strlen(HTTP_VERSION);
12101 len += strlen(remote);
12105 for (i = 0; hdrlist[i]; i++)
12106 len += strlen(hdrlist[i]) + 2;
12108 len += strlen(http_host_port) + 8;
12111 len += 13 + strlen(agent);
12114 readpass("Password: ",passwd,64);
12117 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12118 j = b8tob64(b64in,strlen(b64in),b64out,256);
12119 memset(pwd,0,strlen(pwd));
12125 len += 16 + strlen(mime); /* Content-type: */
12126 len += 32; /* Content-length: */
12127 len += 32; /* Date: */
12129 len += 19; /* Connection: close */
12131 len += 3; /* blank line + null */
12133 request = malloc(len);
12137 sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
12138 ckstrncat(request,"Date: ",len);
12140 ckstrncat(request,http_now(),len);
12142 strcat(request,...);
12143 #endif /* CMDATE2TM */
12144 ckstrncat(request,"\r\n",len);
12145 ckstrncat(request,"Host: ", len);
12146 ckstrncat(request,http_host_port, len);
12147 ckstrncat(request,"\r\n",len);
12149 ckstrncat(request,"User-agent: ",len);
12150 ckstrncat(request,agent,len);
12151 ckstrncat(request,"\r\n",len);
12154 ckstrncat(request,"Authorization: Basic ",len);
12155 ckstrncat(request,b64out,len);
12156 ckstrncat(request,"\r\n",len);
12159 for (i = 0; hdrlist[i]; i++) {
12160 ckstrncat(request,hdrlist[i],len);
12161 ckstrncat(request,"\r\n",len);
12164 ckstrncat(request,"Content-type: ",len);
12165 ckstrncat(request,mime,len);
12166 ckstrncat(request,"\r\n",len);
12167 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12168 ckstrncat(request,buf,len);
12170 ckstrncat(request,"Connection: close\r\n",len);
12172 ckstrncat(request,"\r\n",len);
12174 /* Now we have the contents of the file */
12175 if (zopeni(ZIFILE,local)) {
12177 putreq: /* Send request */
12178 if (http_tol((CHAR *)request,strlen(request)) <= 0) {
12189 /* Request headers have been sent */
12192 while (zchin(ZIFILE,&ch) == 0) {
12194 if (i == HTTPBUFLEN) {
12195 if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
12207 if (http_tol((CHAR *)buf,i) < 0) {
12218 /* Process the response headers */
12219 local_t = time(NULL);
12223 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12225 if (buf[i] == 10) { /* found end of line */
12226 if (i > 0 && buf[i-1] == 13)
12231 if (array && !nullline && hdcnt < HTTPHEADCNT)
12232 makestr(&headers[hdcnt++],buf);
12233 if (!ckstrcmp(buf,"HTTP",4,0)) {
12235 j = ckindex(" ",buf,0,0,0);
12237 while (isspace(*p))
12240 case '1': /* Informational message */
12242 case '2': /* Success */
12244 case '3': /* Redirection */
12245 case '4': /* Client failure */
12246 case '5': /* Server failure */
12247 default: /* Unknown */
12249 printf("Failure: Server reports %s\n",p);
12252 http_set_code_reply(p);
12254 if (!ckstrcmp(buf,"Connection:",11,0)) {
12255 if ( ckindex("close",buf,11,0,0) != 0 )
12257 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12258 len = atoi(&buf[16]);
12259 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12260 if ( ckindex("chunked",buf,18,0,0) != 0 )
12264 printf("%s\n",buf);
12271 if (ch < 0 && first) {
12277 if ( http_fnd == 0 ) {
12283 /* Any response data? */
12284 if ( dest && dest[0] ) {
12285 if (zopeno(ZOFILE,dest,NULL,NULL))
12292 while ((len = http_get_chunk_len()) > 0) {
12293 while (len && (ch = http_inc(0)) >= 0) {
12296 zchout(ZOFILE,(CHAR)ch);
12300 if ((ch = http_inc(0)) != CR)
12302 if ((ch = http_inc(0)) != LF)
12306 while (len && (ch = http_inc(0)) >= 0) {
12309 zchout(ZOFILE,(CHAR)ch);
12318 if ( chunked ) { /* Parse Trailing Headers */
12320 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12322 if ( buf[i] == 10 ) { /* found end of line */
12323 if (i > 0 && buf[i-1] == 13)
12328 if (array && !nullline && hdcnt < HTTPHEADCNT)
12329 makestr(&headers[hdcnt++],buf);
12330 if (!ckstrcmp(buf,"Connection:",11,0)) {
12331 if ( ckindex("close",buf,11,0,0) != 0 )
12346 http_mkarray(headers,hdcnt,array);
12351 for (i = 0; i < hdcnt; i++) {
12360 http_delete(char * agent, char ** hdrlist, char * user,
12361 char * pwd, char array, char * remote)
12363 http_delete(agent, hdrlist, user, pwd, array, remote)
12364 char * agent; char ** hdrlist; char * user;
12365 char * pwd; char array; char * remote;
12366 #endif /* CK_ANSIC */
12368 char * request=NULL;
12369 int i, j, len = 0, hdcnt = 0, rc = 0;
12372 char buf[HTTPBUFLEN], *p;
12380 char * headers[HTTPHEADCNT];
12389 for (i = 0; i < HTTPHEADCNT; i++)
12393 /* Compute length of request header */
12394 len = 11; /* DELETE */
12395 len += strlen(HTTP_VERSION);
12396 len += strlen(remote);
12400 for (i = 0; hdrlist[i]; i++)
12401 len += strlen(hdrlist[i]) + 2;
12403 len += strlen(http_host_port) + 8;
12406 len += 13 + strlen(agent);
12409 readpass("Password: ",passwd,64);
12412 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12413 j = b8tob64(b64in,strlen(b64in),b64out,256);
12414 memset(pwd,0,strlen(pwd));
12420 len += 32; /* Date: */
12422 len += 19; /* Connection: close */
12424 len += 3; /* blank line + null */
12426 request = malloc(len);
12430 sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
12431 ckstrncat(request,"Date: ",len);
12433 ckstrncat(request,http_now(),len);
12435 strcat(request,...);
12436 #endif /* CMDATE2TM */
12437 ckstrncat(request,"\r\n",len);
12438 ckstrncat(request,"Host: ", len);
12439 ckstrncat(request,http_host_port, len);
12440 ckstrncat(request,"\r\n",len);
12442 ckstrncat(request,"User-agent: ",len);
12443 ckstrncat(request,agent,len);
12444 ckstrncat(request,"\r\n",len);
12447 ckstrncat(request,"Authorization: Basic ",len);
12448 ckstrncat(request,b64out,len);
12449 ckstrncat(request,"\r\n",len);
12452 for (i = 0; hdrlist[i]; i++) {
12453 ckstrncat(request,hdrlist[i],len);
12454 ckstrncat(request,"\r\n",len);
12458 ckstrncat(request,"Connection: close\r\n",len);
12460 ckstrncat(request,"\r\n",len);
12462 if (http_tol((CHAR *)request,strlen(request)) < 0)
12474 /* Process the response headers */
12475 local_t = time(NULL);
12479 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12481 if (buf[i] == 10) { /* found end of line */
12482 if (i > 0 && buf[i-1] == 13)
12487 if (array && !nullline && hdcnt < HTTPHEADCNT)
12488 makestr(&headers[hdcnt++],buf);
12489 if (!ckstrcmp(buf,"HTTP",4,0)) {
12491 j = ckindex(" ",buf,0,0,0);
12493 while (isspace(*p))
12496 case '1': /* Informational message */
12498 case '2': /* Success */
12500 case '3': /* Redirection */
12501 case '4': /* Client failure */
12502 case '5': /* Server failure */
12503 default: /* Unknown */
12505 printf("Failure: Server reports %s\n",p);
12508 http_set_code_reply(p);
12510 if (!ckstrcmp(buf,"Connection:",11,0)) {
12511 if ( ckindex("close",buf,11,0,0) != 0 )
12513 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12514 len = atoi(&buf[16]);
12515 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12516 if ( ckindex("chunked",buf,18,0,0) != 0 )
12519 printf("%s\n",buf);
12526 if (ch < 0 && first) {
12532 if ( http_fnd == 0 ) {
12538 /* Any response data? */
12540 while ((len = http_get_chunk_len()) > 0) {
12541 while (len && (ch = http_inc(0)) >= 0) {
12545 if ((ch = http_inc(0)) != CR)
12547 if ((ch = http_inc(0)) != LF)
12551 while (len && (ch = http_inc(0)) >= 0) {
12557 if ( chunked ) { /* Parse Trailing Headers */
12559 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12561 if ( buf[i] == 10 ) { /* found end of line */
12562 if (i > 0 && buf[i-1] == 13)
12567 if (array && !nullline && hdcnt < HTTPHEADCNT)
12568 makestr(&headers[hdcnt++],buf);
12569 if (!ckstrcmp(buf,"Connection:",11,0)) {
12570 if ( ckindex("close",buf,11,0,0) != 0 )
12582 http_mkarray(headers,hdcnt,array);
12587 for (i = 0; i < hdcnt; i++) {
12596 http_post(char * agent, char ** hdrlist, char * mime, char * user,
12597 char * pwd, char array, char * local, char * remote,
12598 char * dest, int stdio)
12600 http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
12602 char * agent; char ** hdrlist; char * mime; char * user;
12603 char * pwd; char array; char * local; char * remote; char * dest;
12605 #endif /* CK_ANSIC */
12607 char * request=NULL;
12608 int i, j, len = 0, hdcnt = 0, rc = 0;
12611 char buf[HTTPBUFLEN], *p;
12620 char * headers[HTTPHEADCNT];
12630 for (i = 0; i < HTTPHEADCNT; i++)
12633 filelen = zchki(local);
12637 /* Compute length of request header */
12638 len = 9; /* POST */
12639 len += strlen(HTTP_VERSION);
12640 len += strlen(remote);
12644 for (i = 0; hdrlist[i]; i++)
12645 len += strlen(hdrlist[i]) + 2;
12647 len += strlen(http_host_port) + 8;
12650 len += 13 + strlen(agent);
12653 readpass("Password: ",passwd,64);
12656 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12657 j = b8tob64(b64in,strlen(b64in),b64out,256);
12658 memset(pwd,0,strlen(pwd));
12664 len += 16 + strlen(mime); /* Content-type: */
12665 len += 32; /* Content-length: */
12666 len += 32; /* Date: */
12668 len += 19; /* Connection: close */
12670 len += 3; /* blank line + null */
12672 request = malloc(len);
12676 sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
12677 ckstrncat(request,"Date: ",len);
12678 ckstrncat(request,http_now(),len);
12679 ckstrncat(request,"\r\n",len);
12680 ckstrncat(request,"Host: ", len);
12681 ckstrncat(request,http_host_port, len);
12682 ckstrncat(request,"\r\n",len);
12684 ckstrncat(request,"User-agent: ",len);
12685 ckstrncat(request,agent,len);
12686 ckstrncat(request,"\r\n",len);
12689 ckstrncat(request,"Authorization: Basic ",len);
12690 ckstrncat(request,b64out,len);
12691 ckstrncat(request,"\r\n",len);
12694 for (i = 0; hdrlist[i]; i++) {
12695 ckstrncat(request,hdrlist[i],len);
12696 ckstrncat(request,"\r\n",len);
12699 ckstrncat(request,"Content-type: ",len);
12700 ckstrncat(request,mime,len);
12701 ckstrncat(request,"\r\n",len);
12703 ckstrncat(request,"Connection: close\r\n",len);
12705 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12706 ckstrncat(request,buf,len);
12707 ckstrncat(request,"\r\n",len);
12708 ckstrncat(request,"\r\n",len);
12710 /* Now we have the contents of the file */
12712 if (zopeni(ZIFILE,local)) {
12714 if (http_tol((CHAR *)request,strlen(request)) < 0)
12728 while (zchin(ZIFILE,&ch) == 0) {
12730 if (i == HTTPBUFLEN) {
12731 http_tol((CHAR *)buf,HTTPBUFLEN);
12736 http_tol((CHAR *)buf,HTTPBUFLEN);
12739 /* Process the response headers */
12740 local_t = time(NULL);
12744 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12746 if (buf[i] == 10) { /* found end of line */
12747 if (i > 0 && buf[i-1] == 13)
12752 if (array && !nullline && hdcnt < HTTPHEADCNT)
12753 makestr(&headers[hdcnt++],buf);
12754 if (!ckstrcmp(buf,"HTTP",4,0)) {
12756 j = ckindex(" ",buf,0,0,0);
12758 while (isspace(*p))
12761 case '1': /* Informational message */
12763 case '2': /* Success */
12765 case '3': /* Redirection */
12766 case '4': /* Client failure */
12767 case '5': /* Server failure */
12768 default: /* Unknown */
12770 printf("Failure: Server reports %s\n",p);
12773 http_set_code_reply(p);
12775 if (!ckstrcmp(buf,"Connection:",11,0)) {
12776 if ( ckindex("close",buf,11,0,0) != 0 )
12778 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12779 len = atoi(&buf[16]);
12780 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12781 if ( ckindex("chunked",buf,18,0,0) != 0 )
12785 printf("%s\n",buf);
12792 if (ch < 0 && first) {
12798 if (http_fnd == 0) {
12804 /* Any response data? */
12805 if ( dest && dest[0] ) {
12806 if (zopeno(ZOFILE,dest,NULL,NULL))
12813 while ((len = http_get_chunk_len()) > 0) {
12814 while (len && (ch = http_inc(0)) >= 0) {
12817 zchout(ZOFILE,(CHAR)ch);
12821 if ((ch = http_inc(0)) != CR)
12823 if ((ch = http_inc(0)) != LF)
12827 while (len && (ch = http_inc(0)) >= 0) {
12830 zchout(ZOFILE,(CHAR)ch);
12839 if ( chunked ) { /* Parse Trailing Headers */
12841 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12843 if ( buf[i] == 10 ) { /* found end of line */
12844 if (i > 0 && buf[i-1] == 13)
12849 if (array && !nullline && hdcnt < HTTPHEADCNT)
12850 makestr(&headers[hdcnt++],buf);
12851 if (!ckstrcmp(buf,"Connection:",11,0)) {
12852 if ( ckindex("close",buf,11,0,0) != 0 )
12867 http_mkarray(headers,hdcnt,array);
12871 for (i = 0; i < hdcnt; i++) {
12880 http_connect(int socket, char * agent, char ** hdrlist, char * user,
12881 char * pwd, char array, char * host_port)
12883 http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
12885 char * agent; char ** hdrlist; char * user;
12886 char * pwd; char array; char * host_port;
12887 #endif /* CK_ANSIC */
12889 char * request=NULL;
12890 int i, j, len = 0, hdcnt = 0, rc = 0;
12892 char buf[HTTPBUFLEN], *p, ch;
12900 char * headers[HTTPHEADCNT];
12904 tcp_http_proxy_errno = 0;
12910 for (i = 0; i < HTTPHEADCNT; i++)
12914 /* Compute length of request header */
12915 len = 12; /* CONNECT */
12916 len += strlen(HTTP_VERSION);
12917 len += strlen(host_port);
12918 len += (int) strlen(http_host_port) + 8;
12920 len += strlen("Proxy-Connection: Keep-Alive\r\n");
12922 for (i = 0; hdrlist[i]; i++)
12923 len += strlen(hdrlist[i]) + 2;
12925 if (agent && agent[0])
12926 len += 13 + strlen(agent);
12927 if (user && user[0]) {
12929 readpass("Password: ",passwd,64);
12932 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12933 j = b8tob64(b64in,strlen(b64in),b64out,256);
12934 memset(pwd,0,strlen(pwd));
12940 len += 32; /* Date: */
12941 len += 3; /* blank line + null */
12943 request = malloc(len);
12947 sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
12948 ckstrncat(request,"Date: ",len);
12950 ckstrncat(request,http_now(),len);
12952 strcat(request,...);
12953 #endif /* CMDATE2TM */
12954 ckstrncat(request,"\r\n",len);
12955 ckstrncat(request,"Host: ", len);
12956 ckstrncat(request,http_host_port, len);
12957 ckstrncat(request,"\r\n",len);
12958 if (agent && agent[0]) {
12959 ckstrncat(request,"User-agent: ",len);
12960 ckstrncat(request,agent,len);
12961 ckstrncat(request,"\r\n",len);
12963 if (user && user[0]) {
12964 ckstrncat(request,"Proxy-authorization: Basic ",len);
12965 ckstrncat(request,b64out,len);
12966 ckstrncat(request,"\r\n",len);
12967 ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
12969 ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
12971 for (i = 0; hdrlist[i]; i++) {
12972 ckstrncat(request,hdrlist[i],len);
12973 ckstrncat(request,"\r\n",len);
12976 ckstrncat(request,"\r\n",len);
12977 len = strlen(request);
12981 if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
12986 if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
12990 #endif /* TCPIPLIB */
12992 /* Process the response headers */
12993 local_t = time(NULL);
12996 while (!nullline &&
12998 (socket_read(socket,&ch,1) == 1) &&
13000 (read(socket,&ch,1) == 1) &&
13001 #endif /* TCPIPLIB */
13004 if (buf[i] == 10) { /* found end of line */
13005 if (i > 0 && buf[i-1] == 13)
13011 if (array && !nullline && hdcnt < HTTPHEADCNT)
13012 makestr(&headers[hdcnt++],buf);
13013 if (!ckstrcmp(buf,"HTTP",4,0)) {
13015 j = ckindex(" ",buf,0,0,0);
13017 while (isspace(*p))
13019 tcp_http_proxy_errno = atoi(p);
13021 case '1': /* Informational message */
13023 case '2': /* Success */
13026 case '3': /* Redirection */
13027 case '4': /* Client failure */
13028 case '5': /* Server failure */
13029 default: /* Unknown */
13031 printf("Failure: Server reports %s\n",p);
13034 http_set_code_reply(p);
13036 printf("%s\n",buf);
13043 if ( http_fnd == 0 )
13047 http_mkarray(headers,hdcnt,array);
13050 if ( !connected ) {
13051 if ( socket == ttyfd ) {
13054 else if ( socket == httpfd ) {
13060 for (i = 0; i < hdcnt; i++) {
13066 #endif /* NOHTTP */
13070 #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
13071 #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
13072 #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
13074 #ifndef CKQUERYTYPE
13077 #define CKQUERYTYPE CHAR
13079 #endif /* UNIXWARE */
13080 #endif /* CKQUERYTYPE */
13082 #ifndef CKQUERYTYPE
13083 #define CKQUERYTYPE char
13084 #endif /* CKQUERYTYPE */
13086 /* 1 is success, 0 is failure */
13088 locate_srv_dns(host, service, protocol, addr_pp, naddrs)
13092 struct sockaddr **addr_pp;
13095 int nout, j, count;
13097 unsigned char bytes[2048];
13100 unsigned char *p=NULL;
13101 CKQUERYTYPE query[MAX_DNS_NAMELEN];
13106 #endif /* CK_ANSIC */
13107 struct sockaddr *addr = NULL;
13108 struct sockaddr_in *sin = NULL;
13109 struct hostent *hp = NULL;
13111 int priority, weight, size, len, numanswers, numqueries, rdlen;
13112 unsigned short port;
13115 #endif /* CK_ANSIC */
13116 int hdrsize = sizeof(HEADER);
13117 struct srv_dns_entry {
13118 struct srv_dns_entry *next;
13121 unsigned short port;
13124 struct srv_dns_entry *head = NULL;
13125 struct srv_dns_entry *srv = NULL, *entry = NULL;
13129 addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
13136 * First build a query of the form:
13138 * service.protocol.host
13140 * which will most likely be something like:
13142 * _telnet._tcp.host
13145 if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
13150 /* Realm names don't (normally) end with ".", but if the query
13151 doesn't end with "." and doesn't get an answer as is, the
13152 resolv code will try appending the local domain. Since the
13153 realm names are absolutes, let's stop that.
13155 But only if a name has been specified. If we are performing
13156 a search on the prefix alone then the intention is to allow
13157 the local domain or domain search lists to be expanded.
13159 h = host + strlen (host);
13160 ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
13161 ((h > host) && (h[-1] != '.')?".":NULL),
13162 NULL,NULL,NULL,NULL,NULL);
13164 size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
13166 if (size < hdrsize)
13169 /* We got a reply - See how many answers it contains. */
13173 numqueries = ntohs(answer.hdr.qdcount);
13174 numanswers = ntohs(answer.hdr.ancount);
13176 p += sizeof(HEADER);
13179 * We need to skip over all of the questions, so we have to iterate
13180 * over every query record. dn_expand() is able to tell us the size
13181 * of compressed DNS names, so we use it.
13183 while (numqueries--) {
13184 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13187 INCR_CHECK(p, len + 4);
13191 * We're now pointing at the answer records. Only process them if
13192 * they're actually T_SRV records (they might be CNAME records,
13195 * But in a DNS reply, if you get a CNAME you always get the associated
13196 * "real" RR for that CNAME. RFC 1034, 3.6.2:
13198 * CNAME RRs cause special action in DNS software. When a name server
13199 * fails to find a desired RR in the resource set associated with the
13200 * domain name, it checks to see if the resource set consists of a CNAME
13201 * record with a matching class. If so, the name server includes the CNAME
13202 * record in the response and restarts the query at the domain name
13203 * specified in the data field of the CNAME record. The one exception to
13204 * this rule is that queries which match the CNAME type are not restarted.
13206 * In other words, CNAMEs do not need to be expanded by the client.
13208 while (numanswers--) {
13210 /* First is the name; use dn_expand() to get the compressed size. */
13211 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13214 INCR_CHECK(p, len);
13216 CHECK(p,2); /* Query type */
13217 type = NTOHSP(p,2);
13219 CHECK(p, 6); /* Query class */
13220 class = NTOHSP(p,6); /* Also skip over 4-byte TTL */
13222 CHECK(p,2); /* Record data length */
13223 rdlen = NTOHSP(p,2);
13225 * If this is an SRV record, process it. Record format is:
13232 if (class == C_IN && type == T_SRV) {
13234 priority = NTOHSP(p,2);
13236 weight = NTOHSP(p,2);
13238 port = NTOHSP(p,2);
13239 len = dn_expand(answer.
13241 answer.bytes + size,
13248 INCR_CHECK(p, len);
13250 * We got everything. Insert it into our list, but make sure
13251 * it's in the right order. Right now we don't do anything
13252 * with the weight field
13254 srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
13258 srv->priority = priority;
13259 srv->weight = weight;
13261 makestr(&s,(char *)query); /* strdup() is not portable */
13264 if (head == NULL || head->priority > srv->priority) {
13269 * Confusing. Insert an entry into this spot only if:
13270 * . The next person has a higher priority (lower
13271 * priorities are preferred), or:
13272 * . There is no next entry (we're at the end)
13274 for (entry = head; entry != NULL; entry = entry->next)
13275 if ((entry->next &&
13276 entry->next->priority > srv->priority) ||
13277 entry->next == NULL) {
13278 srv->next = entry->next;
13283 INCR_CHECK(p, rdlen);
13287 * Now we've got a linked list of entries sorted by priority.
13288 * Start looking up A records and returning addresses.
13293 for (entry = head; entry != NULL; entry = entry->next) {
13294 hp = gethostbyname(entry->host);
13297 /* Watch out - memset() and memcpy() are not portable... */
13299 switch (hp->h_addrtype) {
13301 for (j = 0; hp->h_addr_list[j]; j++) {
13302 sin = (struct sockaddr_in *) &addr[nout++];
13303 memset ((char *) sin, 0, sizeof (struct sockaddr));
13304 sin->sin_family = hp->h_addrtype;
13305 sin->sin_port = htons(entry->port);
13306 memcpy((char *) &sin->sin_addr,
13307 (char *) hp->h_addr_list[j],
13308 sizeof(struct in_addr)); /* safe */
13309 if (nout + 1 >= count) {
13311 addr = (struct sockaddr *)
13312 realloc((char *) addr,
13313 sizeof(struct sockaddr) * count);
13324 for (entry = head; entry != NULL;) {
13326 entry->host = NULL;
13328 entry = entry->next;
13337 if (nout == 0) { /* No good servers */
13350 #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
13352 #define CHECK(x, y) if (x + y > size + answer.bytes) \
13354 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
13357 locate_txt_rr(prefix, name, retstr)
13358 char *prefix, *name;
13362 unsigned char bytes[2048];
13366 char host[MAX_DNS_NAMELEN], *h;
13368 int type, class, numanswers, numqueries, rdlen, len;
13371 * Form our query, and send it via DNS
13374 if (name == NULL || name[0] == '\0') {
13375 strcpy(host,prefix);
13377 if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
13380 /* Realm names don't (normally) end with ".", but if the query
13381 doesn't end with "." and doesn't get an answer as is, the
13382 resolv code will try appending the local domain. Since the
13383 realm names are absolutes, let's stop that.
13385 But only if a name has been specified. If we are performing
13386 a search on the prefix alone then the intention is to allow
13387 the local domain or domain search lists to be expanded.
13389 h = host + strlen (host);
13390 ckmakmsg(host,sizeof(host),prefix, ".", name,
13391 ((h > host) && (h[-1] != '.'))?".":NULL);
13394 size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
13401 numqueries = ntohs(answer.hdr.qdcount);
13402 numanswers = ntohs(answer.hdr.ancount);
13404 p += sizeof(HEADER);
13407 * We need to skip over the questions before we can get to the answers,
13408 * which means we have to iterate over every query record. We use
13409 * dn_expand to tell us how long each compressed name is.
13412 while (numqueries--) {
13413 len = dn_expand(answer.bytes, answer.bytes + size, p, host,
13417 INCR_CHECK(p, len + 4); /* Name plus type plus class */
13421 * We're now pointing at the answer records. Process the first
13422 * TXT record we find.
13425 while (numanswers--) {
13427 /* First the name; use dn_expand to get the compressed size */
13428 len = dn_expand(answer.bytes, answer.bytes + size, p,
13429 host, sizeof(host));
13432 INCR_CHECK(p, len);
13434 /* Next is the query type */
13436 type = NTOHSP(p,2);
13438 /* Next is the query class; also skip over 4 byte TTL */
13440 class = NTOHSP(p,6);
13442 /* Record data length - make sure we aren't truncated */
13445 rdlen = NTOHSP(p,2);
13447 if (p + rdlen > answer.bytes + size)
13451 * If this is a TXT record, return the string. Note that the
13452 * string has a 1-byte length in the front
13454 /* XXX What about flagging multiple TXT records as an error? */
13456 if (class == C_IN && type == T_TXT) {
13458 if (p + len > answer.bytes + size)
13460 *retstr = malloc(len + 1);
13461 if (*retstr == NULL)
13463 strncpy(*retstr, (char *) p, len);
13464 (*retstr)[len] = '\0';
13465 /* Avoid a common error. */
13466 if ( (*retstr)[len-1] == '.' )
13467 (*retstr)[len-1] = '\0';
13477 #endif /* CK_DNS_SRV */
13480 #ifdef CK_FORWARD_X
13482 #include <sys/un.h>
13483 #define FWDX_UNIX_SOCK
13485 #define AF_LOCAL AF_UNIX
13488 #define PF_LOCAL PF_UNIX
13491 /* Evaluate to actual length of the `sockaddr_un' structure. */
13492 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
13493 + strlen ((ptr)->sun_path))
13497 fwdx_create_listen_socket(screen) int screen; {
13500 #else /* NOPUTENV */
13501 struct sockaddr_in saddr;
13502 int display, port, sock=-1, i;
13503 static char env[512];
13506 * X Windows Servers support multiple displays by listening on
13507 * one socket per display. Display 0 is port 6000; Display 1 is
13510 * We start by trying to open port 6001 so that display 0 is
13511 * reserved for the local X Windows Server.
13514 for ( display=1; display < 1000 ; display++ ) {
13516 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13517 debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
13521 port = 6000 + display;
13522 bzero((char *)&saddr, sizeof(saddr));
13523 saddr.sin_family = AF_INET;
13524 saddr.sin_addr.s_addr = inet_addr(myipaddr);
13525 saddr.sin_port = htons(port);
13527 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13528 i = errno; /* Save error code */
13530 socket_close(sock);
13531 #else /* TCPIPLIB */
13533 #endif /* TCPIPLIB */
13535 debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
13539 debug(F100,"fdwx_create_listen_socket() bind OK","",0);
13543 if ( display > 1000 ) {
13544 debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
13548 if (listen(sock, 5) < 0) {
13549 i = errno; /* Save error code */
13551 socket_close(sock);
13552 #else /* TCPIPLIB */
13554 #endif /* TCPIPLIB */
13555 debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
13558 debug(F100,"fwdx_create_listen_socket() listen OK","",0);
13560 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
13564 ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
13565 ckuitoa(display),":",ckuitoa(screen),
13566 NULL,NULL,NULL,NULL,NULL,NULL);
13568 ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
13572 #endif /* NOPUTENV */
13577 fwdx_open_client_channel(channel) int channel; {
13579 struct sockaddr_in saddr;
13580 #ifdef FWDX_UNIX_SOCK
13581 struct sockaddr_un saddr_un = { AF_LOCAL };
13582 #endif /* FWDX_UNIX_SOCK */
13583 int colon, dot, display, port, sock, i, screen;
13585 char buf[256], * host=NULL, * rest=NULL;
13588 #endif /* TCP_NODELAY */
13590 debug(F111,"fwdx_create_client_channel()","channel",channel);
13592 for ( i=0; i<MAXFWDX ; i++ ) {
13593 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
13595 debug(F110,"fwdx_create_client_channel()","already open",0);
13600 env = getenv("DISPLAY");
13602 env = tn_get_display();
13604 ckstrncpy(buf,env,256);
13606 ckstrncpy(buf,"127.0.0.1:0.0",256);
13608 bzero((char *)&saddr,sizeof(saddr));
13609 saddr.sin_family = AF_INET;
13611 if (!fwdx_parse_displayname(buf,
13619 if ( host ) free(host);
13620 if ( rest ) free(rest);
13623 if (rest) free(rest);
13625 #ifndef FWDX_UNIX_SOCK
13626 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13627 * we change things to use inet sockets on the ip loopback interface instead,
13628 * and hope that it works.
13630 if (family == FamilyLocal) {
13631 debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
13632 family = FamilyInternet;
13633 if (host) free(host);
13634 if (host = malloc(strlen("localhost") + 1))
13635 strcpy(host, "localhost");
13640 #else /* FWDX_UNIX_SOCK */
13641 if (family == FamilyLocal) {
13642 if (host) free(host);
13643 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13647 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13648 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13649 if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
13652 #endif /* FWDX_UNIX_SOCK */
13654 /* Otherwise, we are assuming FamilyInternet */
13656 ckstrncpy(buf,host,sizeof(buf));
13659 ckstrncpy(buf,myipaddr,sizeof(buf));
13661 debug(F111,"fwdx_create_client_channel()","display",display);
13663 port = 6000 + display;
13664 saddr.sin_port = htons(port);
13666 debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
13667 saddr.sin_addr.s_addr = inet_addr(buf);
13668 if ( saddr.sin_addr.s_addr == (unsigned long) -1
13670 || saddr.sin_addr.s_addr == INADDR_NONE
13671 #endif /* INADDR_NONE */
13674 struct hostent *host;
13675 host = gethostbyname(buf);
13676 if ( host == NULL )
13678 host = ck_copyhostent(host);
13681 /* This is for trying multiple IP addresses - see <netdb.h> */
13682 if (!(host->h_addr_list))
13684 bcopy(host->h_addr_list[0],
13685 (caddr_t)&saddr.sin_addr,
13689 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13690 #endif /* h_addr */
13691 #else /* HADDRLIST */
13692 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13693 #endif /* HADDRLIST */
13696 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13697 debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
13701 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13702 debug(F110,"fwdx_create_client_channel()","connect() failed",0);
13704 socket_close(sock);
13705 #else /* TCPIPLIB */
13707 #endif /* TCPIPLIB */
13712 setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13713 #endif /* TCP_NODELAY */
13716 for (i = 0; i < MAXFWDX; i++) {
13717 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
13718 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
13719 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
13720 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
13721 debug(F111,"fwdx_create_client_channel()","socket",sock);
13729 fwdx_server_avail() {
13731 struct sockaddr_in saddr;
13732 #ifdef FWDX_UNIX_SOCK
13733 struct sockaddr_un saddr_un = { AF_LOCAL };
13734 #endif /* FWDX_UNIX_SOCK */
13735 int colon, dot, display, port, sock, i, screen;
13736 char buf[256], *host=NULL, *rest=NULL;
13739 #endif /* TCP_NODELAY */
13742 env = getenv("DISPLAY");
13744 env = tn_get_display();
13746 ckstrncpy(buf,env,256);
13748 ckstrncpy(buf,"127.0.0.1:0.0",256);
13750 bzero((char *)&saddr,sizeof(saddr));
13751 saddr.sin_family = AF_INET;
13753 if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
13754 if ( host ) free(host);
13755 if ( rest ) free(rest);
13758 if (rest) free(rest);
13760 #ifndef FWDX_UNIX_SOCK
13761 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13762 * we change things to use inet sockets on the ip loopback interface instead,
13763 * and hope that it works.
13765 if (family == FamilyLocal) {
13766 family = FamilyInternet;
13767 if (host) free(host);
13768 if (host = malloc(strlen("localhost") + 1))
13769 strcpy(host, "localhost");
13774 #else /* FWDX_UNIX_SOCK */
13775 if (family == FamilyLocal) {
13776 debug(F100,"fwdx_server_avail() FamilyLocal","",0);
13777 if (host) free(host);
13778 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13782 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13783 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13784 if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
13789 #endif /* FWDX_UNIX_SOCK */
13791 /* Otherwise, we are assuming FamilyInternet */
13793 ckstrncpy(buf,host,sizeof(buf));
13796 ckstrncpy(buf,myipaddr,sizeof(buf));
13798 debug(F111,"fwdx_server_avail()","display",display);
13800 port = 6000 + display;
13801 saddr.sin_port = htons(port);
13803 debug(F110,"fwdx_server_avail() ip-address",buf,0);
13804 saddr.sin_addr.s_addr = inet_addr(buf);
13805 if ( saddr.sin_addr.s_addr == (unsigned long) -1
13807 || saddr.sin_addr.s_addr == INADDR_NONE
13808 #endif /* INADDR_NONE */
13811 struct hostent *host;
13812 host = gethostbyname(buf);
13813 if ( host == NULL ) {
13814 debug(F110,"fwdx_server_avail() gethostbyname() failed",
13818 host = ck_copyhostent(host);
13821 /* This is for trying multiple IP addresses - see <netdb.h> */
13822 if (!(host->h_addr_list))
13824 bcopy(host->h_addr_list[0],
13825 (caddr_t)&saddr.sin_addr,
13829 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13830 #endif /* h_addr */
13831 #else /* HADDRLIST */
13832 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13833 #endif /* HADDRLIST */
13836 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13837 debug(F111,"fwdx_server_avail()","socket() < 0",sock);
13841 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13842 debug(F110,"fwdx_server_avail()","connect() failed",0);
13844 socket_close(sock);
13845 #else /* TCPIPLIB */
13847 #endif /* TCPIPLIB */
13852 socket_close(sock);
13853 #else /* TCPIPLIB */
13855 #endif /* TCPIPLIB */
13860 fwdx_open_server_channel() {
13861 int sock, ready_to_accept, sock2,channel,i;
13864 #endif /* TCP_NODELAY */
13866 static u_int saddrlen;
13868 static SOCKOPT_T saddrlen;
13870 struct sockaddr_in saddr;
13872 extern char tn_msg[];
13885 #endif /* BELLSELECT */
13886 #endif /* BSDSELECT */
13887 unsigned short nchannel;
13890 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
13895 tv.tv_sec = tv.tv_usec = 0L;
13898 FD_SET(sock, &rfds);
13900 ((select(FD_SETSIZE,
13907 #endif /* HPUX1010 */
13911 #endif /* __DECC */
13913 &rfds, NULL, NULL, &tv) > 0) &&
13914 FD_ISSET(sock, &rfds));
13915 #else /* BSDSELECT */
13917 ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
13921 FD_SET(sock, rfds);
13923 ((select(128, rfds, NULL, NULL, 50) > 0) &&
13924 FD_ISSET(sock, rfds));
13926 /* Try this - what's the worst that can happen... */
13928 tv.tv_sec = tv.tv_usec = 0L;
13931 FD_SET(sock, &rfds);
13933 ((select(FD_SETSIZE,
13934 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
13935 FD_ISSET(sock, &rfds));
13936 #endif /* BELLSELECT */
13937 #endif /* IBMSELECT */
13938 #endif /* BSDSELECT */
13940 if ( !ready_to_accept )
13943 if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
13944 int i = errno; /* save error code */
13945 debug(F101,"tcpsrv_open accept errno","",i);
13950 * Now we have the open socket. We must now find a channel to store
13951 * it in, and then notify the client.
13954 for ( channel=0;channel<MAXFWDX;channel++ ) {
13955 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
13959 if ( channel == MAXFWDX ) {
13961 socket_close(sock2);
13962 #else /* TCPIPLIB */
13964 #endif /* TCPIPLIB */
13968 if ( fwdx_send_open(channel) < 0 ) {
13970 socket_close(sock2);
13971 #else /* TCPIPLIB */
13973 #endif /* TCPIPLIB */
13977 setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13978 #endif /* TCP_NODELAY */
13980 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
13981 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
13984 return(0); /* never reached */
13988 fwdx_close_channel(channel) int channel; {
13991 for ( i=0; i<MAXFWDX ; i++ ) {
13992 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
13995 if ( i == MAXFWDX )
13998 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
13999 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
14000 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
14001 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
14005 #else /* TCPIPLIB */
14007 #endif /* TCPIPLIB */
14015 debug(F111,"fwdx_close_all()",
14016 "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
14017 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14019 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
14021 socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14022 #else /* TCPIPLIB */
14023 close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14024 #endif /* TCPIPLIB */
14025 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
14028 for (x = 0; x < MAXFWDX; x++) {
14029 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14030 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14031 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
14032 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
14033 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
14034 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
14037 #else /* TCPIPLIB */
14039 #endif /* TCPIPLIB */
14045 /* The following definitions are for Unix */
14046 #ifndef socket_write
14047 #define socket_write(f,s,n) write(f,s,n)
14048 #endif /* socket_write */
14049 #ifndef socket_read
14050 #define socket_read(f,s,n) read(f,s,n)
14051 #endif /* socket_read */
14054 fwdx_write_data_to_channel(channel, data, len)
14055 int channel; char * data; int len;
14057 int sock, count, try=0, length = len, i;
14062 for ( i=0; i<MAXFWDX ; i++ ) {
14063 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14066 if ( i == MAXFWDX ) {
14067 debug(F110,"fwdx_write_data_to_channel",
14068 "attempting to write to closed channel",0);
14072 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14073 debug(F111,"fwdx_write_data_to_channel","socket",sock);
14074 hexdump("fwdx_write_data_to_channel",data,len);
14076 fwdx_write_data_to_channel_retry:
14078 if ((count = socket_write(sock,data,len)) < 0) {
14079 int s_errno = socket_errno; /* maybe a function */
14080 debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
14082 printf("fwdx_write_data_to_channel error\r\n");
14083 #endif /* BETATEST */
14085 if (os2socketerror(s_errno) < 0)
14088 return(-1); /* Call it an i/o error */
14091 debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
14096 debug(F111,"fwdx_write_data_to_channel retry",data,len);
14098 goto fwdx_write_data_to_channel_retry;
14101 debug(F111,"fwdx_write_data_to_channel complete",data,length);
14102 return(length); /* success - return total length */
14106 fwdx_check_sockets(fd_set *ibits)
14108 int x, sock, channel, bytes;
14109 static char buffer[32000];
14111 debug(F100,"fwdx_check_sockets()","",0);
14112 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14113 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14114 debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
14118 for (x = 0; x < MAXFWDX; x++) {
14119 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
14120 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
14123 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14124 if (FD_ISSET(sock, ibits))
14126 channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
14127 debug(F111,"fwdx_check_sockets()","channel set",channel);
14129 bytes = socket_read(sock, buffer, sizeof(buffer));
14131 fwdx_send_data_from_channel(channel, buffer, bytes);
14132 else if (bytes == 0) {
14133 fwdx_close_channel(channel);
14134 fwdx_send_close(channel);
14141 fwdx_init_fd_set(fd_set *ibits)
14145 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14146 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14147 debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
14151 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
14153 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
14155 for (x = 0; x < MAXFWDX; x++) {
14156 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14158 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
14161 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
14164 if (set + cnt == 0) {
14173 fwdx_thread( VOID * dummy )
14177 extern int priority;
14181 SetThreadPrty(priority,isWin95() ? 3 : 11);
14183 while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
14184 sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
14187 n = fwdx_init_fd_set(&ifds);
14191 if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
14192 fwdx_check_sockets(&ifds);
14194 } else if (n < 0) {
14195 TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
14203 #endif /* CK_FORWARD_X */
14204 #endif /* TNCODE */
14205 #endif /* NETCONN */