1 char *cknetv = "Network support, 9.0.296, 16 Mar 2010";
3 /* C K C N E T -- Network support */
6 Copyright (C) 1985, 2010,
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 */
77 #include <net/gen/resolv.h>
78 #include <net/gen/nameser.h>
80 #include <arpa/nameser.h>
101 /* for old Unixes and friends ... */
102 #ifndef MAXHOSTNAMELEN
103 #define MAXHOSTNAMELEN 64
104 #endif /* MAXHOSTNAMELEN */
106 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
107 #endif /* CK_DNS_SRV */
112 #endif /* TCPIPLIB */
121 #endif /* HPUX5WINTCP */
122 #endif /* datageneral */
123 #endif /* NOMHHOST */
126 struct in_addr inaddrx;
129 int ttnet = NET_NONE; /* Network type */
130 int ttnproto = NP_DEFAULT; /* Network virtual terminal protocol */
132 /* 0 = don't lowercase username for Rlogin/Telnet protocol */
133 /* nonzero = do lowercase it. Add a SET command if necessary... */
140 extern int /* External variables */
141 duplex, debses, seslog, sessft, wasclosed,
142 ttyfd, quiet, msgflg, what, nettype, ttmdm;
147 char myipaddr[20] = { '\0' }; /* Global copy of my IP address */
148 char hostipaddr[64] = { '\0' }; /* Global copy of remote IP address */
151 /* Don't need any of this if there is no network support. */
154 /* Current fd-swapping hack is not thread-safe */
155 #define HTTP_BUFFERING
158 #ifdef HTTP_BUFFERING
159 #define HTTP_INBUFLEN 8192
160 static char http_inbuf[HTTP_INBUFLEN];
161 static int http_bufp = 0, http_count;
162 #endif /* HTTP_BUFFERING */
165 NETLEBUF is (must be) defined for those platforms that call this
166 module to do network i/o (e.g. netinc(), nettchk(), etc) rather
167 than doing it themselves (ttinc(), ttchk(), etc). In this case
168 the Telnet local-echo buffers and routines are defined and referenced
169 here, rather than in the ck?tio.c module.
172 #define LEBUFSIZ 4096
173 int ttpush = -1, le_data = 0; /* These are seen from outside */
174 static CHAR le_buf[LEBUFSIZ]; /* These are used internally */
175 static int le_start = 0, le_end = 0;
176 int tt_push_inited = 0;
177 #endif /* NETLEBUF */
179 #ifdef CK_SOCKS /* SOCKS Internet relay package */
180 #ifdef CK_SOCKS5 /* SOCKS 5 */
181 #define accept SOCKSaccept
182 #define bind SOCKSbind
183 #define connect SOCKSconnect
184 #define getsockname SOCKSgetsockname
185 #define listen SOCKSlisten
186 #else /* Not SOCKS 5 */
187 #define accept Raccept
189 #define connect Rconnect
190 #define getsockname Rgetsockname
191 #define listen Rlisten
192 #endif /* CK_SOCKS5 */
193 #endif /* CK_SOCKS */
198 #endif /* DEC_TCPIP */
200 /* Also see ckcnet.h -- hmmm, why don't we always include inet.h? */
203 #ifndef HPUX7 /* HPUX 7.00 doesn't have it */
204 #ifndef HPUX6 /* HPUX 6.00 doesn't have it */
205 #include <arpa/inet.h> /* For inet_ntoa() prototype */
212 #endif /* CMU_TCPIP */
215 #ifdef DCLTIMEVAL /* UnixWare 7 */
216 struct timeval { /* And define these ourselves. */
217 long tv_sec; /* (see comments in ckutio.c) */
224 #endif /* DCLTIMEVAL */
225 #endif /* NODCLTIMEVAL */
231 #include <sys/time.h>
233 The WIN/TCP code path is the same as that for MultiNet.
234 Only the routine names have changed ...
236 #define socket_read netread
237 #define socket_ioctl ioctl
238 #define socket_write netwrite
239 #define socket_close netclose
241 #ifdef OLD_TWG /* some routines have evolved */
242 extern int vmserrno, uerrno;
243 #define socket_errno uerrno
244 #define socket_perror perror /* which uses errno, not uerrno! */
246 #define socket_errno errno
247 #define socket_perror win$perror
250 #else /* Not WINTCP */
256 #endif /* _NO_PROTO */
257 #endif /* CK_ANSIC */
261 #include <errno.h> /* Already included above */
264 #include <signal.h> /* Everybody needs this */
266 #ifdef ZILOG /* Zilog has different name for this */
274 #ifdef datageneral /* Data General AOS/VS */
275 #include <:usr:include:vs_tcp_errno.h>
276 #include <:usr:include:sys:vs_tcp_types.h>
279 NOTE: This can be compiled and linked OK with SELECT defined
280 but it doesn't work at all. Anybody who cares and knows how
281 to fix it, feel free.
283 #include <:usr:include:sys:vs_tcp_time.h>
285 #include <:usr:include:sys:socket.h>
286 #include <:usr:include:netinet:in.h>
287 #include <:usr:include:netdb.h>
288 #endif /* datageneral */
291 #define socket_errno errno
292 #endif /* socket_errno */
298 int tcp_rdns = /* Reverse DNS lookup */
300 SET_OFF /* Doesn't seem to work in UCX */
303 #endif /* DEC_TCPIP */
306 int tcp_dns_srv = SET_OFF;
307 #endif /* CK_DNS_SRV */
309 _PROTOTYP( char * cmcvtdate, (char *, int) );
312 _PROTOTYP( int rlog_ctrl, (CHAR *, int) );
313 _PROTOTYP( static int rlog_oob, (CHAR *, int) );
315 _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
316 #endif /* TCPIPLIB */
317 _PROTOTYP( static int rlog_ini, (CHAR *, int,
318 struct sockaddr_in *,
319 struct sockaddr_in *) );
320 int rlog_mode = RL_COOKED;
321 int rlog_stopped = 0;
323 #endif /* RLOGCODE */
326 extern int doconx; /* CONNECT-class command active */
330 /* This variable should probably be generalised for true client/server
331 * support - ie: the fd of the listening server, accepted calls should
332 * be forked or at least handled via a second fd (for IBM's X.25 -
333 * ttyfd always holds the active fd - ie the server becomes inactive
334 * as long as a client is connected, and becomes active again when the
335 * connection is closed)
337 int x25serverfd = 0; /* extern in ckcnet.h */
338 int x25seqno = 0; /* Connection sequence number */
339 int x25lastmsg = -1; /* A cheapskate's state table */
341 #define X25_CLOSED 0 /* Default state: no connection, no STREAM */
342 #define X25_SETUP 1 /* X.25 has been set up (no connection) */
343 #define X25_CONNECTED 2 /* X.25 connection has been established */
344 int x25_state = X25_CLOSED; /* Default state */
351 #ifdef CK_NAWS /* Negotiate About Window Size */
353 _PROTOTYP( int rlog_naws, (void) );
354 #endif /* RLOGCODE */
357 #ifdef OS2 /* For terminal type name string */
364 extern int tt_type, max_tt;
365 extern struct tt_info_rec tt_info[];
366 extern char ttname[];
368 #ifdef CK_AUTHENTICATION
370 #endif /* CK_AUTHENTICATION */
374 extern int winsock_version;
377 #ifdef CK_AUTHENTICATION
379 #endif /* CK_AUTHENTICATION */
383 #ifndef OS2 /* For timeout longjumps */
384 static ckjmpbuf njbuf;
387 #define NAMECPYL 1024 /* Local copy of hostname */
388 char namecopy[NAMECPYL]; /* Referenced by ckctel.c */
389 char namecopy2[NAMECPYL]; /* Referenced by ckctel.c */
391 char http_host_port[NAMECPYL]; /* orig host/port necessary for http */
392 char http_ip[20] = { '\0' }; /* ip address of host */
395 char * http_agent = 0;
396 int httpfd = -1; /* socket for http connections */
398 #define HTTPBUFLEN 1024
399 char http_reply_str[HTTPBUFLEN] = "";
402 char ipaddr[20] = { '\0' }; /* Global copy of IP address */
403 unsigned long myxipaddr = 0L; /* Ditto as a number */
406 char *tcp_address = NULL; /* Preferred IP Address */
407 extern char uidbuf[]; /* User ID buffer */
408 extern char pwbuf[]; /* Password buffer */
411 char * tcp_http_proxy = NULL; /* Name[:port] of http proxy server */
412 int tcp_http_proxy_errno = 0;
413 char * tcp_http_proxy_user = NULL;
414 char * tcp_http_proxy_pwd = NULL;
415 char * tcp_http_proxy_agent = NULL;
416 #define HTTPCPYL 1024
417 static char proxycopy[HTTPCPYL];
421 extern int tt_rows[], tt_cols[];
422 extern int tt_status[VNUM];
424 extern int tt_rows, tt_cols; /* Everybody has this */
427 extern int cmd_cols, cmd_rows;
429 #ifdef STREAMING /* Use blocking writes for streaming */
430 extern int streaming;
431 #endif /* STREAMING */
434 extern int WSASafeToCancel;
435 int win95selectbug = 0; /* For TCP/IP stacks whose select() */
436 /* always fails on write requests such as Cisco and Quarterdeck */
437 #define stricmp _stricmp
442 /* Skip all this if NOTCPOPTS specified. */
447 int tcp_nodelay = 0; /* Nagle algorithm TCP_NODELAY */
448 #endif /* TCP_NODELAY */
451 int tcp_dontroute = 0;
452 #endif /* SO_DONTROUTE */
455 int tcp_linger = 0; /* SO_LINGER */
456 int tcp_linger_tmo = 0; /* SO_LINGER timeout */
457 #endif /* SO_LINGER */
459 #ifdef HPUX /* But the data structures */
460 #ifndef HPUX8 /* needed for linger are not */
461 #ifndef HPUX9 /* defined in HP-UX versions */
462 #ifndef HPUX10 /* prior to 8.00. */
465 #endif /* SO_LINGER */
471 #ifndef SO_OOBINLINE /* Hopefully only HP-UX 7.0 */
472 #define SO_OOBINLINE 0x0100
473 #endif /* SO_OOBINLINE */
478 #define TCPSNDBUFSIZ 16384
481 #endif /* TCPSNDBUFSIZ */
484 #define TCPSNDBUFSIZ -1
485 #endif /* TCPSNDBUFSIZ */
488 int tcp_sendbuf = TCPSNDBUFSIZ;
489 #endif /* SO_SNDBUF */
492 int tcp_recvbuf = -1;
493 #endif /* SO_RCVBUF */
496 int tcp_keepalive = 1;
497 #endif /* SO_KEEPALIVE */
499 #endif /* SOL_SOCKET */
500 #endif /* NOTCPOPTS */
504 Network support not defined.
505 Dummy functions here in case #ifdef's forgotten elsewhere.
507 int /* Open network connection */
508 netopen(name, lcl, nett) char *name; int *lcl, nett; {
511 int /* Close network connection */
515 int /* Check network input buffer */
519 int /* Flush network input buffer */
523 int /* Send network BREAK */
527 int /* Input character from network */
528 netinc(timo) int timo; {
531 int /* Output character to network */
536 #endif /* CK_ANSIC */
541 nettol(s,n) CHAR *s; int n; {
545 #else /* NETCONN is defined (much of this module...) */
549 le_init() { /* LocalEchoInit() */
551 for (i = 0; i < LEBUFSIZ; i++)
560 le_clean() { /* LocalEchoCleanup() */
568 if (le_start != le_end) {
571 LEBUFSIZ) % LEBUFSIZ;
580 le_putchar(ch) CHAR ch;
581 #endif /* CK_ANSIC */
583 if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
584 debug(F110,"le_putchar","buffer is full",0);
587 le_buf[le_end++] = ch;
588 if (le_end == LEBUFSIZ)
596 le_puts(CHAR * s, int n)
598 le_puts(s,n) CHAR * s; int n;
599 #endif /* CK_ANSIC */
603 CHAR * p = (CHAR *)"le_puts";
605 for (i = 0; i < n; i++)
606 rc = le_putchar((char)s[i]);
607 debug(F101,"le_puts","",rc);
615 le_putstr(s) CHAR * s;
616 #endif /* CK_ANSIC */
620 p = (CHAR *)"le_putstr";
621 ckhexdump(p,s,(int)strlen((char *)s));
622 for (p = s; *p && !rc; p++)
629 le_getchar(CHAR * pch)
631 le_getchar(pch) CHAR * pch;
632 #endif /* CK_ANSIC */
635 if (le_start != le_end) {
636 *pch = le_buf[le_start];
637 le_buf[le_start] = 0;
640 if (le_start == LEBUFSIZ)
643 if (le_start == le_end) {
652 #endif /* NETLEBUF */
656 In edit 190, we moved tn_ini() to be called from within netopen().
657 But tn_ini() calls ttol(), and ttol() checks to see if it's a net
658 connection, but the flag for that isn't set until after netopen()
659 is finished. Since, in this module, we are always doing network
660 output anyway, we just call nettol() directly, instead of going thru
661 ttol(). Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
662 net connections just like regular connections in ttol(), and OS/2
663 has a special routine for this.
672 char * krb5_d_principal = NULL; /* Default principal */
673 char * krb5_d_instance = NULL; /* Default instance */
674 char * krb5_d_realm = NULL; /* Default realm */
675 char * krb5_d_cc = NULL; /* Default credentials cache */
676 char * krb5_d_srv = NULL; /* Default Service */
677 int krb5_d_lifetime = 600; /* Default lifetime (10 hours) */
678 int krb5_d_forwardable = 0; /* creds not forwardable */
679 int krb5_d_proxiable = 0; /* creds not proxiable */
680 int krb5_d_renewable = 0; /* creds not renewable (0 min) */
681 int krb5_autoget = 1; /* Autoget TGTs */
682 int krb5_autodel = 0; /* Auto delete TGTs */
683 int krb5_d_getk4 = 0; /* K5 Kinit gets K4 TGTs */
684 int krb5_checkaddrs = 1; /* Check TGT Addrs */
685 int krb5_d_no_addresses = 0; /* Do not include IP Addresses */
686 char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
687 int krb5_errno = 0; /* Last K5 errno */
688 char * krb5_errmsg = NULL; /* Last K5 errmsg */
689 char * k5_keytab = NULL;
691 char * krb4_d_principal = NULL; /* Default principal */
692 char * krb4_d_realm = NULL; /* Default realm */
693 char * krb4_d_srv = NULL; /* Default Service */
694 int krb4_d_lifetime = 600; /* Default lifetime (10 hours) */
695 int krb4_d_preauth = 1; /* Use preauth requests */
696 char * krb4_d_instance = NULL; /* Default instance */
697 int krb4_autoget = 1; /* Autoget TGTs */
698 int krb4_autodel = 0; /* Auto delete TGTs */
699 int krb4_checkaddrs = 1; /* Check TGT Addrs */
700 char * k4_keytab = NULL;
702 int krb4_errno = 0; /* Last K4 errno */
703 char * krb4_errmsg = NULL; /* Last K4 errmsg */
705 struct krb_op_data krb_op = { /* Operational data structure */
706 0, NULL /* (version, cachefile) */
709 struct krb4_init_data krb4_init = { /* Kerberos 4 INIT data structure */
710 0, NULL, NULL, NULL, NULL
713 struct krb5_init_data krb5_init = { /* Kerberos 5 INIT data structure */
714 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
715 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
716 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
720 struct krb5_list_cred_data krb5_lc = { /* List Credentials data structure */
724 int krb_action = -1; /* Kerberos action to perform */
726 #ifndef CK_AUTHENTICATION
732 ck_krb5_getrealm(cc) char * cc; {
736 ck_krb4_getprincipal() {
740 ck_krb5_getprincipal(cc) char * cc; {
743 #endif /* CK_AUTHENTICATION */
745 /* I N I _ K E R B -- Initialize Kerberos data */
751 krb_action = -1; /* No action specified */
753 krb_op.version = 0; /* Kerberos version (none) */
754 krb_op.cache = NULL; /* Cache file (none) */
758 krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
759 krb5_init.proxiable = krb5_d_proxiable;
760 krb5_init.lifetime = krb5_d_lifetime;
762 krb5_init.renewable = krb5_d_renewable;
763 krb5_init.validate = 0;
764 krb5_init.no_addresses = krb5_d_no_addresses;
765 krb5_init.getk4 = krb5_d_getk4;
766 if (krb5_init.postdate) {
767 free(krb5_init.postdate);
768 krb5_init.postdate = NULL;
770 if (krb5_init.service) {
771 free(krb5_init.service);
772 krb5_init.service = NULL;
774 if (!krb5_d_cc || !krb5_d_cc[0]) { /* Set default cache */
776 p = ck_krb5_get_cc_name();
777 makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
779 if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
781 p = ck_krb5_getrealm(krb5_d_cc);
782 makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
784 makestr(&krb5_init.instance,krb5_d_instance);
785 makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
786 if (krb5_init.password) {
787 memset(krb5_init.password,0xFF,strlen(krb5_init.password));
788 free(krb5_init.password);
789 krb5_init.password = NULL;
791 if (!krb5_d_principal) { /* Default principal */
792 /* a Null principal indicates the user should be prompted */
793 char * p = ck_krb5_getprincipal(krb5_d_cc);
795 p = (char *)uidbuf; /* Principal = user */
796 makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
798 makestr(&krb5_init.principal,krb5_d_principal);
799 for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
800 if (krb5_init.addrs[i])
801 free(krb5_init.addrs[i]);
802 krb5_init.addrs[i] = NULL;
804 for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
805 makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
810 krb4_init.lifetime = krb4_d_lifetime;
811 krb4_init.preauth = krb4_d_preauth;
812 makestr(&krb4_init.instance,krb4_d_instance);
813 if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
815 p = ck_krb4_getrealm();
816 makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
818 makestr(&krb4_init.realm,krb4_d_realm);
819 if (krb4_init.password) {
820 memset(krb4_init.password,0xFF,strlen(krb4_init.password));
821 free(krb4_init.password);
822 krb4_init.password = NULL;
824 if (!krb4_d_principal) { /* Default principal */
825 /* a Null principal indicates the user should be prompted */
826 char * p = ck_krb4_getprincipal();
828 p = (char *)uidbuf; /* Principal = user */
829 makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
831 makestr(&(krb4_init.principal),krb4_d_principal);
834 /* D O A U T H -- AUTHENTICATE action routine */
837 doauth(cx) int cx; { /* AUTHENTICATE action routine */
838 int rc = 0; /* Return code */
840 #ifdef CK_AUTHENTICATION
842 if (!ck_security_loaddll()) /* Load various DLLs */
845 if (krb_op.version == 4) { /* Version = 4 */
847 sho_auth(AUTHTYPE_KERBEROS_V4);
849 if (!ck_krb4_is_installed()) {
850 printf("?Kerberos 4 is not installed\n");
853 switch (krb_action) { /* Perform V4 functions */
854 case KRB_A_IN: /* INIT */
855 rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
857 case KRB_A_DE: /* DESTROY */
858 rc |= !(ck_krb4_destroy(&krb_op) < 0);
860 case KRB_A_LC: /* LIST-CREDENTIALS */
861 rc |= !(ck_krb4_list_creds(&krb_op) < 0);
865 if (krb_op.version == 5) { /* V5 functions */
867 sho_auth(AUTHTYPE_KERBEROS_V5);
869 if (!ck_krb5_is_installed()) {
870 printf("?Kerberos 5 is not installed\n");
873 switch (krb_action) {
874 case KRB_A_IN: /* INIT */
875 rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
876 krb5_init.getk4 ? &krb4_init : 0) < 0);
878 case KRB_A_DE: /* DESTROY */
879 rc |= !(ck_krb5_destroy(&krb_op) < 0);
881 case KRB_A_LC: /* LIST-CREDENTIALS */
882 if (krb_op.version == 0)
884 rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
891 rc = sho_auth(0); /* Show all */
894 #endif /* CK_AUTHENTICATION */
897 #endif /* CK_KERBEROS */
901 #ifndef NOLISTEN /* For incoming connections */
905 #endif /* INADDR_ANY */
907 _PROTOTYP( int ttbufr, ( VOID ) );
908 _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
910 static unsigned short tcpsrv_port = 0;
912 #endif /* NOLISTEN */
915 static char svcbuf[80]; /* TCP service string */
916 static int svcnum = 0; /* TCP port number */
918 #endif /* TCPSOCKET */
921 TCPIPLIB means use separate socket calls for i/o, while on UNIX the
922 normal file system calls are used for TCP/IP sockets too.
923 Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
928 /* For buffered network reads... */
930 If the buffering code is written right, it shouldn't matter
931 how long this buffer is.
935 #define TTIBUFL 64240 /* 44 * 1460 (MSS) */
937 #define TTIBUFL 32120 /* 22 * 1460 (MSS) */
940 #define TTIBUFL 8191 /* Let's use 8K. */
943 CHAR ttibuf[TTIBUFL+1];
946 select() is used in preference to alarm()/signal(), but different systems
947 use different forms of select()...
949 #ifndef NOSELECT /* Option to override BSDSELECT */
952 Note: Although BELLV10 does have TCP/IP support, and does use the unique
953 form of select() that is evident in this module (and in ckutio.c), it does
954 not have a sockets library and so we can't build Kermit TCP/IP support for
955 it. For this, somebody would have to write TCP/IP streams code.
959 #define FD_SETSIZE 128
960 #endif /* FD_SETSIZE */
962 #ifdef WINTCP /* VMS with Wollongong WIN/TCP */
963 #ifndef OLD_TWG /* TWG 3.2 has only select(read) */
967 #ifdef CMU_TCPIP /* LIBCMU can do select */
973 #ifdef OS2 /* OS/2 with TCP/IP */
980 #endif /* DEC_TCPIP */
981 #endif /* CMU_TCPIP */
984 #endif /* NOSELECT */
986 Others (TGV, TCPware, ...) use alarm()/signal(). The BSDSELECT case does not
987 compile at all; the IBMSELECT case compiles and links but crashes at runtime.
988 NOTE: If any of these can be converted to select(), they should be for two
989 reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
990 their socket_read() calls to be interrupted; subsequent socket_read()'s tend
991 to fail with EBUSY. This happened in the UCX case before it was converted
996 static /* These are used in CKVTIO.C */
997 #endif /* VMS */ /* And in CKONET.C */
1003 Read bytes from network into internal buffer ttibuf[].
1004 To be called when input buffer is empty, i.e. when ttibn == 0.
1006 Other network reading routines, like ttinc, ttinl, ttxin, should check the
1007 internal buffer first, and call this routine for a refill if necessary.
1009 Returns -1 on error, 0 if nothing happens. When data is read successfully,
1010 returns number of bytes read, and sets global ttibn to that number and
1011 ttibp (the buffer pointer) to zero.
1013 _PROTOTYP( int ttbufr, ( VOID ) );
1015 ttbufr() { /* TT Buffer Read */
1018 if (ttnet != NET_TCPB) /* First make sure current net is */
1019 return(-1); /* TCP/IP; if not, do nothing. */
1022 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1025 if (ttibn > 0) { /* Our internal buffer is not empty, */
1027 ReleaseTCPIPMutex();
1029 return(ttibn); /* so keep using it. */
1032 if (ttyfd == -1) { /* No connection, error */
1034 ReleaseTCPIPMutex();
1039 ttibp = 0; /* Else reset pointer to beginning */
1042 count = 512; /* This works for WIN/TCP */
1045 count = 512; /* UCX */
1049 #else /* Multinet, etc. */
1050 count = ttchk(); /* Check network input buffer, */
1051 if (ttibn > 0) { /* which can put a char there! */
1052 debug(F111,"ttbufr","ttchk() returns",count);
1054 ReleaseTCPIPMutex();
1058 if (count < 0) { /* Read error - connection closed */
1060 ReleaseTCPIPMutex();
1064 else if (count > TTIBUFL) /* Too many to read */
1066 else if (count == 0) /* None, so force blocking read */
1069 #endif /* DEC_TCPIP */
1071 debug(F101,"ttbufr count 1","",count);
1074 if (ssl_active_flag || tls_active_flag) {
1077 if (ssl_active_flag)
1078 count = SSL_read(ssl_con, ttibuf, count);
1080 count = SSL_read(tls_con, ttibuf, count);
1081 error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
1083 case SSL_ERROR_NONE:
1084 debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
1086 ttibp = 0; /* Reset buffer pointer. */
1089 ReleaseTCPIPMutex();
1091 return(ttibn); /* Return buffer count. */
1092 } else if (count < 0) {
1094 ReleaseTCPIPMutex();
1100 ReleaseTCPIPMutex();
1104 case SSL_ERROR_WANT_WRITE:
1105 debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
1107 ReleaseTCPIPMutex();
1110 case SSL_ERROR_WANT_READ:
1111 debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
1113 ReleaseTCPIPMutex();
1116 case SSL_ERROR_SYSCALL:
1117 if ( count == 0 ) { /* EOF */
1120 ReleaseTCPIPMutex();
1126 int gle = GetLastError();
1127 debug(F111,"ttbufr SSL_ERROR_SYSCALL",
1128 "GetLastError()",gle);
1129 rc = os2socketerror(gle);
1132 else if ( rc == -2 )
1136 ReleaseTCPIPMutex();
1140 case SSL_ERROR_WANT_X509_LOOKUP:
1141 debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
1144 ReleaseTCPIPMutex();
1148 if (bio_err!=NULL) {
1150 extern char ssl_err[];
1151 BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
1152 ERR_print_errors(bio_err);
1153 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
1154 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
1155 debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
1158 } else if (ssl_debug_flag) {
1159 debug(F100,"ttbufr SSL_ERROR_SSL","",0);
1161 fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
1162 ERR_print_errors_fp(stderr);
1166 #endif /* COMMENT */
1168 ReleaseTCPIPMutex();
1171 case SSL_ERROR_ZERO_RETURN:
1172 debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
1175 ReleaseTCPIPMutex();
1179 debug(F100,"ttbufr SSL_ERROR_?????","",0);
1182 ReleaseTCPIPMutex();
1191 This is for nonblocking reads, which we don't do any more. This code didn't
1192 work anyway, in the sense that a broken connection was never sensed.
1194 if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
1195 if (count == -1 && socket_errno == EWOULDBLOCK) {
1196 debug(F100,"ttbufr finds nothing","",0);
1198 ReleaseTCPIPMutex();
1202 debug(F101,"ttbufr socket_read error","",socket_errno);
1204 ReleaseTCPIPMutex();
1209 } else if (count == 0) {
1210 debug(F100,"ttbufr socket eof","",0);
1212 ReleaseTCPIPMutex();
1218 /* This is for blocking reads */
1225 if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
1232 FD_SET(ttyfd, &efds);
1233 tv.tv_sec = tv.tv_usec = 0L;
1234 debug(F100,"Out-of-Band BSDSELECT","",0);
1236 WSASafeToCancel = 1;
1238 if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
1239 FD_ISSET(ttyfd, &efds))
1242 WSASafeToCancel = 0;
1244 #else /* !BSDSELECT */
1246 /* Is used by OS/2 ... */
1247 /* ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set */
1248 /* and timeval stuff since this is the only place where it is used. */
1250 debug(F100,"Out-of-Band IBMSELECT","",0);
1251 if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
1253 #else /* !IBMSELECT */
1255 If we can't use select(), then we use the regular alarm()/signal()
1258 debug(F101,"Out-of-Band data not supported","",0);
1261 #endif /* IBMSELECT */
1262 #endif /* BSDSELECT */
1263 #endif /* BELLSELECT */
1265 /* Get the Urgent Data */
1266 /* if OOBINLINE is disabled this should be only a single byte */
1267 /* MS Winsock has a bug in Windows 95. Extra bytes are delivered */
1268 /* That were never sent. */
1270 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1272 count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
1274 ReleaseTCPIPMutex();
1277 int s_errno = socket_errno;
1278 debug(F101, "ttbufr socket_recv MSG_OOB","",count);
1279 debug(F101, "ttbufr socket_errno","",s_errno);
1281 if (count < 0 && (s_errno == 0 || s_errno == 23)) {
1282 /* These appear in OS/2 - don't know why */
1283 /* ignore it and read as normal data */
1284 /* and break, then we will attempt to read */
1285 /* the port using normal read() techniques */
1286 debug(F100,"ttbufr handing as in-band data","",0);
1289 netclos(); /* *** *** */
1291 ReleaseTCPIPMutex();
1296 netclos(); /* *** *** */
1298 ReleaseTCPIPMutex();
1301 #endif /* OS2ONLY */
1302 } else { /* we got out-of-band data */
1303 ckhexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
1306 #endif /* BETADEBUG */
1307 #ifdef RLOGCODE /* blah */
1308 if (ttnproto == NP_RLOGIN ||
1309 ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
1310 ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) &&
1315 When urgent data is read with MSG_OOB and not OOBINLINE
1316 then urgent data and normal data are not mixed. So
1317 treat the entire buffer as urgent data.
1319 rlog_oob(&ttibuf[ttibp+ttibn], count);
1321 ReleaseTCPIPMutex();
1325 #endif /* RLOGCODE */ /* blah */
1328 I haven't written this yet, nor do I know what it should do
1330 if (ttnproto == NP_TELNET) {
1333 ReleaseTCPIPMutex();
1337 #endif /* COMMENT */
1339 /* For any protocols we don't have a special out-of-band */
1340 /* handler for, just put the bytes in the normal buffer */
1343 ttibp += 0; /* Reset buffer pointer. */
1346 /* Got some bytes. */
1347 debug(F101,"ttbufr count 2","",count);
1349 ttibuf[ttibp+ttibn] = '\0';
1350 debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
1353 ReleaseTCPIPMutex();
1355 return(ttibn); /* Return buffer count. */
1360 #endif /* SO_OOBINLINE */
1363 count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
1365 int s_errno = socket_errno;
1366 debug(F101,"ttbufr socket_read","",count);
1367 debug(F101,"ttbufr socket_errno","",s_errno);
1369 if (count == 0 || os2socketerror(s_errno) < 0) {
1371 ReleaseTCPIPMutex();
1374 ReleaseTCPIPMutex();
1377 netclos(); /* *** *** */
1381 #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
1383 ttibp = 0; /* Reset buffer pointer. */
1386 debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
1388 ttibuf[ttibp+ttibn] = '\0';
1389 debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
1393 ReleaseTCPIPMutex();
1395 return(ttibn); /* Return buffer count. */
1398 #endif /* TCPIPLIB */
1402 #ifndef BSDSELECT /* Non-TCPIPLIB case */
1406 #endif /* BSDSELECT */
1407 #endif /* BELLSELECT */
1408 #endif /* IBMSELECT */
1410 #define TELNET_PORT 23 /* Should do lookup, but it won't change */
1411 #define RLOGIN_PORT 513
1412 #define KERMIT_PORT 1649
1413 #define KLOGIN_PORT 543
1414 #define EKLOGIN_PORT 2105
1418 C-Kermit network open/close functions for BSD-sockets.
1419 Much of this code shared by SunLink X.25, which also uses the socket library.
1422 /* N E T O P N -- Open a network connection. */
1425 name of host (or host:service),
1426 lcl - local-mode flag to be set if this function succeeds,
1427 network type - value defined in ckunet.h.
1432 ck_copyhostent(struct hostent * h)
1433 #else /* CK_ANSIC */
1434 ck_copyhostent(h) struct hostent * h;
1435 #endif /* CK_ANSIC */
1438 * The hostent structure is dynamic in nature.
1441 * char * * h_aliases;
1444 * char * * h_addr_list;
1445 * #define h_addr h_addr_list[0]
1447 #define HOSTENTCNT 5
1448 static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
1449 {NULL,NULL,0,0,NULL},
1450 {NULL,NULL,0,0,NULL},
1451 {NULL,NULL,0,0,NULL},
1452 {NULL,NULL,0,0,NULL}};
1453 static int next = 0;
1460 if (next == HOSTENTCNT)
1463 if ( hosts[next].h_name ) {
1464 free(hosts[next].h_name);
1465 hosts[next].h_name = NULL;
1467 if ( hosts[next].h_aliases ) {
1468 pp = hosts[next].h_aliases;
1473 free(hosts[next].h_aliases);
1476 if ( hosts[next].h_addr_list ) {
1477 pp = hosts[next].h_addr_list;
1482 free(hosts[next].h_addr_list);
1484 #endif /* HADDRLIST */
1486 makestr(&hosts[next].h_name,h->h_name);
1488 for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
1489 /* The following can give warnings in non-ANSI builds */
1490 hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
1491 for ( i=0; i<cnt; i++) {
1492 hosts[next].h_aliases[i] = NULL;
1493 makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
1495 hosts[next].h_aliases[i] = NULL;
1497 hosts[next].h_aliases = NULL;
1499 hosts[next].h_addrtype = h->h_addrtype;
1500 hosts[next].h_length = h->h_length;
1504 if (h->h_addr_list) {
1505 for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
1506 /* The following can give warnings non-ANSI builds */
1507 hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
1508 for ( i=0; i<cnt; i++) {
1509 hosts[next].h_addr_list[i] = malloc(h->h_length);
1510 bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
1512 hosts[next].h_addr_list[i] = NULL;
1514 hosts[next].h_addr_list = NULL;
1516 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1518 #else /* HADDRLIST */
1519 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1520 #endif /* HADDRLIST */
1522 return(&hosts[next++]);
1527 Most other BSD sockets implementations define these in header files
1531 unsigned short s_port;
1536 struct in_addr h_addr;
1541 getservbyname(service, connection) char *service,*connection; {
1542 static struct servent servrec;
1546 if (strcmp(service, "telnet") == 0) port = 23;
1547 else if (strcmp(service, "smtp") == 0) port = 25;
1548 else port = atoi(service);
1550 debug(F101,"getservbyname return port ","",port);
1553 servrec.s_port = htons(port);
1556 return((struct servent *) NULL);
1560 gethostbyname(hostname) char *hostname; {
1561 return((struct hostent *) NULL);
1565 inet_addr(name) char *name; {
1568 addr = rhost(&name);
1569 debug(F111,"inet_addr ",name,(int)addr);
1574 inet_ntoa(in) struct in_addr in; {
1575 static char name[80];
1576 ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
1577 ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
1581 #ifdef DEC_TCPIP /* UCX */
1583 int ucx_port_bug = 0; /* Explained below */
1585 #ifdef OLDIP /* Very old VAXC or GCC */
1587 Note that my oldest VAX C (V3.1-051) does not need (or want) OLDIP,
1588 hence the "Very old" in the comment - SMS, 2010/03/15.
1590 #define getservbyname my_getservbyname
1593 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1594 extern void C$$TRANSLATE();
1595 extern void C$$SOCK_TRANSLATE();
1597 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1598 extern VOID C$$TRANSLATE();
1599 extern VOID C$$SOCK_TRANSLATE();
1600 #endif /* CK_ANSIC */
1603 my_getservbyname (service, proto) char *service, *proto; {
1604 static struct servent sent;
1607 unsigned long status;
1608 unsigned short st[2];
1610 unsigned long spare;
1618 char sbuf[30], pbuf[30];
1621 debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
1624 ckstrncpy(p, service, 29);
1625 while (*p = toupper(*p), *p++) {}
1627 ckstrncpy(p, proto, 29);
1628 while (*p = toupper(*p), *p++) {}
1634 /* reset file pointer or something like that!?!? */
1635 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1637 par.prot = pbuf; /* that is don't care */
1638 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1641 if ((e & 1) == 0L) {
1645 if ((s.sb.st[0] & 1) == 0) {
1646 C$$SOCK_TRANSLATE(&s.sb.st[0]);
1650 sent.s_port is supposed to be returned by UCX in network byte order.
1651 However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
1652 But there is no way of knowing which UCX version, so we have a user-settable
1653 runtime variable. Note: UCX 2.0 was only for the VAX.
1655 debug(F101,"UCX getservbyname port","",sent.s_port);
1656 debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
1658 sent.s_port = htons(sent.s_port);
1659 debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
1660 debug(F101,"UCX swapped port","",sent.s_port);
1661 debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
1665 #endif /* def OLDIP */
1666 #endif /* DEC_TCPIP */
1667 #endif /* EXCELAN */
1674 #endif /* TCPSOCKET */
1679 ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
1681 The following, from William Bader, turns off the socket linger parameter,
1682 which makes a close() block until all data is sent. "I don't think that
1683 disabling linger can ever cause kermit to lose data, but you telnet to a
1684 flaky server (or to our modem server when the modem is in use), disabling
1685 linger prevents kermit from hanging on the close if you try to exit."
1687 Modified by Jeff Altman to be generally useful.
1691 struct linger set_linger_opt;
1692 struct linger get_linger_opt;
1699 nettype != NET_TCPA && nettype != NET_TCPB &&
1700 nettype != NET_SSH || ttmdm >= 0) {
1702 tcp_linger_tmo = timo;
1705 x = sizeof(get_linger_opt);
1706 if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
1707 (char *)&get_linger_opt, &x)) {
1708 debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1709 } else if (x != sizeof(get_linger_opt)) {
1714 } get_linger_opt16, set_linger_opt16;
1715 if ( x == sizeof(get_linger_opt16) ) {
1716 debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
1717 if (getsockopt(sock,
1718 SOL_SOCKET, SO_LINGER,
1719 (char *)&get_linger_opt16, &x)
1722 "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1723 } else if (get_linger_opt16.s_onoff != onoff ||
1724 get_linger_opt16.s_linger != timo)
1726 set_linger_opt16.s_onoff = onoff;
1727 set_linger_opt16.s_linger = timo;
1728 if (setsockopt(sock,
1731 (char *)&set_linger_opt16,
1732 sizeof(set_linger_opt16))
1735 "TCP ck_linger can't set SO_LINGER",
1739 tcp_linger = get_linger_opt16.s_onoff;
1740 tcp_linger_tmo = get_linger_opt16.s_linger;
1743 "TCP ck_linger new SO_LINGER","",
1744 set_linger_opt16.s_onoff);
1745 tcp_linger = set_linger_opt16.s_onoff;
1746 tcp_linger_tmo = set_linger_opt16.s_linger;
1750 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1751 get_linger_opt16.s_onoff);
1752 tcp_linger = get_linger_opt16.s_onoff;
1753 tcp_linger_tmo = get_linger_opt16.s_linger;
1759 debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
1760 debug(F111,"TCP ck_linger SO_LINGER",
1761 "expected len",sizeof(get_linger_opt));
1762 debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
1763 get_linger_opt.l_onoff);
1764 debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
1765 get_linger_opt.l_linger);
1766 } else if (get_linger_opt.l_onoff != onoff ||
1767 get_linger_opt.l_linger != timo) {
1768 set_linger_opt.l_onoff = onoff;
1769 set_linger_opt.l_linger = timo;
1770 if (setsockopt(sock,
1773 (char *)&set_linger_opt,
1774 sizeof(set_linger_opt))) {
1775 debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
1776 tcp_linger = get_linger_opt.l_onoff;
1777 tcp_linger_tmo = get_linger_opt.l_linger;
1780 "TCP ck_linger new SO_LINGER",
1782 set_linger_opt.l_onoff
1784 tcp_linger = set_linger_opt.l_onoff;
1785 tcp_linger_tmo = set_linger_opt.l_linger;
1789 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1790 get_linger_opt.l_onoff);
1791 tcp_linger = get_linger_opt.l_onoff;
1792 tcp_linger_tmo = get_linger_opt.l_linger;
1796 debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
1797 #endif /* SO_LINGER */
1799 debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
1800 #endif /* SOL_SOCKET */
1805 sendbuf(sock,size) int sock; int size; {
1807 The following, from William Bader, allows changing of socket buffer sizes,
1808 in case that might affect performance.
1810 Modified by Jeff Altman to be generally useful.
1821 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1827 if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1828 debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
1829 } else if (x != sizeof(i)) {
1832 if (x == sizeof(i16)) {
1833 debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
1834 if (getsockopt(sock,
1835 SOL_SOCKET, SO_SNDBUF,
1838 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
1840 } else if (size <= 0) {
1842 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
1844 } else if (i16 != size) {
1846 if (setsockopt(sock,
1852 debug(F111,"TCP sendbuf can't set SO_SNDBUF",
1855 debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
1856 debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
1861 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
1868 debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
1869 debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
1870 debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
1871 } else if (size <= 0) {
1873 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
1875 } else if (i != size) {
1877 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
1878 debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
1881 debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
1882 debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
1887 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
1892 debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
1893 #endif /* SO_SNDBUF */
1895 debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
1896 #endif /* SOL_SOCKET */
1901 recvbuf(sock,size) int sock; int size; {
1903 The following, from William Bader, allows changing of socket buffer sizes,
1904 in case that might affect performance.
1906 Modified by Jeff Altman to be generally useful.
1917 nettype != NET_TCPA && nettype != NET_TCPB &&
1918 nettype != NET_SSH || ttmdm >= 0) {
1923 if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1924 debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
1925 } else if (x != sizeof(i)) {
1928 if ( x == sizeof(i16) ) {
1929 debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
1930 if (getsockopt(sock,
1931 SOL_SOCKET, SO_RCVBUF,
1934 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
1936 } else if (size <= 0) {
1938 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
1940 } else if (i16 != size) {
1942 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
1944 debug(F111,"TCP recvbuf can' set SO_RCVBUF",
1947 debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
1948 debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
1953 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
1960 debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
1961 debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
1962 debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
1963 } else if (size <= 0) {
1965 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
1967 } else if (i != size) {
1969 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
1970 debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
1973 debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
1974 debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
1979 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
1984 debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
1985 #endif /* SO_RCVBUF */
1987 debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
1988 #endif /* SOL_SOCKET */
1993 keepalive(sock,onoff) int sock; int onoff; {
1996 int get_keepalive_opt;
1997 int set_keepalive_opt;
2000 debug(F111,"TCP keepalive","sock",sock);
2001 debug(F111,"TCP keepalive","nettype",nettype);
2002 debug(F111,"TCP keepalive","ttmdm",ttmdm);
2008 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2010 tcp_keepalive = onoff;
2013 x = sizeof(get_keepalive_opt);
2014 if (getsockopt(sock,
2015 SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
2016 debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
2017 } else if (x != sizeof(get_keepalive_opt)) {
2019 short get_keepalive_opt16;
2020 short set_keepalive_opt16;
2021 if (x == sizeof(get_keepalive_opt16)) {
2022 debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
2024 if (getsockopt(sock,
2025 SOL_SOCKET, SO_KEEPALIVE,
2026 (char *)&get_keepalive_opt16, &x)
2029 "TCP keepalive can't get SO_KEEPALIVE",
2033 } else if (get_keepalive_opt16 != onoff) {
2034 set_keepalive_opt16 = onoff;
2035 if (setsockopt(sock,
2038 (char *)&set_keepalive_opt16,
2039 sizeof(set_keepalive_opt16))
2042 "TCP keepalive can't clear SO_KEEPALIVE",
2046 tcp_keepalive = get_keepalive_opt16;
2049 "TCP keepalive new SO_KEEPALIVE","",
2050 set_keepalive_opt16);
2051 tcp_keepalive = set_keepalive_opt16;
2055 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
2056 get_keepalive_opt16);
2057 tcp_keepalive = onoff;
2063 debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
2065 "TCP keepalive SO_KEEPALIVE",
2067 sizeof(get_keepalive_opt)
2070 "TCP keepalive SO_KEEPALIVE",
2074 } else if (get_keepalive_opt != onoff) {
2075 set_keepalive_opt = onoff;
2076 if (setsockopt(sock,
2079 (char *)&set_keepalive_opt,
2080 sizeof(set_keepalive_opt))
2083 "TCP keepalive can't clear SO_KEEPALIVE",
2087 tcp_keepalive = get_keepalive_opt;
2090 "TCP keepalive new SO_KEEPALIVE",
2094 tcp_keepalive = onoff;
2098 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
2102 tcp_keepalive = onoff;
2106 debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
2107 #endif /* SO_KEEPALIVE */
2109 debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
2110 #endif /* SOL_SOCKET */
2115 dontroute(sock,onoff) int sock; int onoff; {
2118 int get_dontroute_opt;
2119 int set_dontroute_opt;
2126 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2128 tcp_dontroute = onoff;
2131 x = sizeof(get_dontroute_opt);
2132 if (getsockopt(sock,
2133 SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
2134 debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
2135 } else if (x != sizeof(get_dontroute_opt)) {
2137 short get_dontroute_opt16;
2138 short set_dontroute_opt16;
2139 if (x == sizeof(get_dontroute_opt16)) {
2140 debug(F111,"TCP dontroute warning: SO_DONTROUTE",
2142 if (getsockopt(sock,
2143 SOL_SOCKET, SO_DONTROUTE,
2144 (char *)&get_dontroute_opt16, &x)
2147 "TCP dontroute can't get SO_DONTROUTE",
2151 } else if (get_dontroute_opt16 != onoff) {
2152 set_dontroute_opt16 = onoff;
2153 if (setsockopt(sock,
2156 (char *)&set_dontroute_opt16,
2157 sizeof(set_dontroute_opt16))
2160 "TCP dontroute can't clear SO_DONTROUTE",
2164 tcp_dontroute = get_dontroute_opt16;
2167 "TCP dontroute new SO_DONTROUTE","",
2168 set_dontroute_opt16);
2169 tcp_dontroute = set_dontroute_opt16;
2173 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
2174 get_dontroute_opt16);
2175 tcp_dontroute = onoff;
2181 debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
2183 "TCP dontroute SO_DONTROUTE",
2185 sizeof(get_dontroute_opt)
2188 "TCP dontroute SO_DONTROUTE",
2192 } else if (get_dontroute_opt != onoff) {
2193 set_dontroute_opt = onoff;
2194 if (setsockopt(sock,
2197 (char *)&set_dontroute_opt,
2198 sizeof(set_dontroute_opt))
2201 "TCP dontroute can't clear SO_DONTROUTE",
2205 tcp_dontroute = get_dontroute_opt;
2208 "TCP dontroute new SO_DONTROUTE",
2212 tcp_dontroute = onoff;
2216 debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
2220 tcp_dontroute = onoff;
2224 debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
2225 #endif /* SO_DONTROUTE */
2227 debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
2228 #endif /* SOL_SOCKET */
2233 no_delay(sock,onoff) int sock; int onoff; {
2236 int get_nodelay_opt;
2237 int set_nodelay_opt;
2244 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2246 tcp_nodelay = onoff;
2249 x = sizeof(get_nodelay_opt);
2250 if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
2251 (char *)&get_nodelay_opt,&x)) {
2253 "TCP no_delay can't get TCP_NODELAY",
2256 } else if (x != sizeof(get_nodelay_opt)) {
2258 short get_nodelay_opt16;
2259 short set_nodelay_opt16;
2260 if (x == sizeof(get_nodelay_opt16)) {
2261 debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
2262 if (getsockopt(sock,
2263 IPPROTO_TCP, TCP_NODELAY,
2264 (char *)&get_nodelay_opt16, &x)
2267 "TCP no_delay can't get TCP_NODELAY",
2270 } else if (get_nodelay_opt16 != onoff) {
2271 set_nodelay_opt16 = onoff;
2272 if (setsockopt(sock,
2275 (char *)&set_nodelay_opt16,
2276 sizeof(set_nodelay_opt16))
2279 "TCP no_delay can't clear TCP_NODELAY",
2282 tcp_nodelay = get_nodelay_opt16;
2285 "TCP no_delay new TCP_NODELAY",
2288 tcp_nodelay = onoff;
2292 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
2294 tcp_nodelay = onoff;
2300 debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
2301 debug(F111,"TCP no_delay TCP_NODELAY","expected len",
2302 sizeof(get_nodelay_opt));
2303 debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
2304 } else if (get_nodelay_opt != onoff) {
2305 set_nodelay_opt = onoff;
2306 if (setsockopt(sock,
2309 (char *)&set_nodelay_opt,
2310 sizeof(set_nodelay_opt))) {
2312 "TCP no_delay can't clear TCP_NODELAY",
2316 tcp_nodelay = get_nodelay_opt;
2318 debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
2319 tcp_nodelay = onoff;
2323 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
2324 tcp_nodelay = onoff;
2328 debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
2329 #endif /* TCP_NODELAY */
2331 debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
2332 #endif /* SOL_SOCKET */
2335 #endif /* datageneral */
2336 #endif /* NOTCPOPTS */
2339 #ifndef X25_WR_FACILITY
2340 /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
2342 bzero(s,n) char *s; int n; {
2345 #endif /* X25_WR_FACILITY */
2356 #ifdef hp9000s500 /* HP-9000/500 HP-U 5.21 */
2360 /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
2361 * ------------------------------------------------------
2363 * Due to OS9's Lack of a select() call, the following seems to be
2364 * enough to fool the rest of the code into compiling. The only
2365 * effect that I can see is using control L to refresh the status
2366 * display gets qued up until some network packets arrive.
2368 * This solution is by no means elegant but works enough to be
2371 * Also with the defines I had specified in my makefile I had to
2372 * have an #endif right at the end of the file when compiling.
2373 * I did not bother speding time to find out why.
2375 * COPTS = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
2376 * -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
2377 * -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
2378 * -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
2379 * -l=termlib.l -l=math.l -l=sys_clib.l
2381 * stever@ozemail.com.au
2385 #define BSDSELECT /* switch on BSD select code */
2386 #define FD_SETSIZE 32 /* Max # of paths in OS9 */
2387 #define FD_ZERO(p) ((*p)=0)
2388 #define FD_SET(n,b) ((*b)|=(1<<(n)))
2389 #define FD_ISSET(n,b) 1 /* always say data is ready */
2390 #define select(a,b,c,d,e) 1 /* always say 1 path has data */
2391 typedef int fd_set; /* keep BSD Code Happy */
2392 struct timeval {int tv_sec,tv_usec;}; /* keep BSD Code Happy */
2394 /****** END OF OS9 MODS FROM STEVE RANCE **************************/
2397 #include <sys/time.h>
2398 #endif /* hp9000s500 */
2399 #endif /* datageneral */
2400 #endif /* BELLV10 */
2403 #include <sys/select.h>
2404 #endif /* SELECT_H */
2405 #endif /* BSDSELECT */
2409 #include <sys/select.h>
2410 #endif /* CK_SCOV5 */
2414 /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
2417 tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
2419 static struct servent *service, servrec;
2420 static struct hostent *host;
2421 static struct sockaddr_in saddr;
2440 #endif /* BELLSELECT */
2441 #endif /* BSDSELECT */
2443 debug(F101,"tcpsocket_open nett","",nett);
2446 if (nett != NET_TCPB)
2447 return(-1); /* BSD socket support */
2449 netclos(); /* Close any previous connection. */
2450 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2452 /* Jeff's version from 30 Dec 2005 doesn't inhibit Telnet */
2453 if (ttnproto != NP_TCPRAW &&
2454 ttnproto != NP_SSL_RAW &&
2455 ttnproto != NP_TLS_RAW)
2456 ttnproto = NP_NONE; /* No protocol selected yet. */
2458 /* fdc's version from 4 Dec 2005 works ok */
2459 if (ttnproto != NP_TCPRAW)
2460 ttnproto = NP_NONE; /* No protocol selected yet. */
2461 #endif /* COMMENT */
2462 debug(F110,"tcpsocket_open namecopy",namecopy,0);
2464 /* Assign the socket number to ttyfd and then fill in tcp structures */
2465 ttyfd = atoi(&name[1]);
2466 debug(F111,"tcpsocket_open","ttyfd",ttyfd);
2470 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2474 no_delay(ttyfd,tcp_nodelay);
2475 #endif /* TCP_NODELAY */
2477 keepalive(ttyfd,tcp_keepalive);
2478 #endif /* SO_KEEPALIVE */
2480 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2481 #endif /* SO_LINGER */
2483 sendbuf(ttyfd,tcp_sendbuf);
2484 #endif /* SO_SNDBUF */
2486 recvbuf(ttyfd,tcp_recvbuf);
2487 #endif /* SO_RCVBUF */
2488 #endif /* datageneral */
2489 #endif /* SOL_SOCKET */
2490 #endif /* NOTCPOPTS */
2492 #ifdef NT_TCP_OVERLAPPED
2493 OverlappedWriteInit();
2494 OverlappedReadInit();
2495 #endif /* NT_TCP_OVERLAPPED */
2498 /* Get the name of the host we are connected to */
2500 saddrlen = sizeof(saddr);
2501 getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
2503 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2505 if (tcp_rdns == SET_ON
2507 || tcp_rdns == SET_AUTO &&
2508 (ck_krb5_is_installed() || ck_krb4_is_installed())
2509 #endif /* CK_KERBEROS */
2511 && (tcp_http_proxy == NULL)
2514 && !(ssl_only_flag || tls_only_flag)
2516 ) { /* Reverse DNS */
2518 printf(" Reverse DNS Lookup... ");
2521 host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
2522 debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
2524 host = ck_copyhostent(host);
2525 debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
2530 ckstrncpy(name, host->h_name, 80);
2531 ckstrncat(name, ":", 80);
2532 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
2538 printf("%s connected on port %d\n",
2540 ntohs(saddr.sin_port)
2547 if (tcp_rdns != SET_ON || !host) {
2548 ckstrncpy(name,ipaddr,80);
2549 ckstrncat(name,":",80);
2550 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2556 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2558 if (!quiet) fflush(stdout);
2559 ttnet = nett; /* TCP/IP (sockets) network */
2562 if (ntohs(saddr.sin_port) == 513)
2563 ttnproto = NP_LOGIN;
2565 #endif /* RLOGCODE */
2566 /* Assume the service is TELNET. */
2568 /* Jeff's code from 2005/12/30 */
2569 if (ttnproto != NP_TCP_RAW &&
2570 ttnproto != NP_SSL_RAW &&
2571 ttnproto != NP_TLS_RAW)
2573 /* fdc's code from 2005/12/04 */
2574 if (ttnproto != NP_TCPRAW)
2575 #endif /* COMMENT */
2576 ttnproto = NP_TELNET; /* Yes, set global flag. */
2578 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2579 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2580 host->h_name : ipaddr,
2585 #endif /* CK_SECURITY */
2586 if (tn_ini() < 0) /* Start/Reset TELNET negotiations */
2587 if (ttchk() < 0) /* Did it fail due to connect loss? */
2590 if (*lcl < 0) *lcl = 1; /* Local mode. */
2592 return(0); /* Done. */
2594 #endif /* NOTUSED */
2596 /* T C P S R V _ O P E N -- Open a TCP/IP Server connection */
2598 Calling conventions same as ttopen(), except third argument is network
2599 type rather than modem type.
2602 tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
2606 int ready_to_accept = 0;
2607 static struct servent *service, *service2, servrec;
2608 static struct hostent *host;
2609 static struct sockaddr_in saddr;
2610 struct sockaddr_in l_addr;
2613 static u_int saddrlen;
2615 static SOCKOPT_T saddrlen;
2630 #endif /* BELLSELECT */
2631 #endif /* BSDSELECT */
2636 debug(F101,"tcpsrv_open nett","",nett);
2639 if (nett != NET_TCPB)
2640 return(-1); /* BSD socket support */
2642 netclos(); /* Close any previous connection. */
2643 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2644 /* Don't do this. */
2647 if (ttnproto != NP_TCPRAW)
2648 ttnproto = NP_NONE; /* No protocol selected yet. */
2649 #endif /* COMMENT */
2652 if (ttnproto != NP_TCP_RAW &&
2653 ttnproto != NP_SSL_RAW &&
2654 ttnproto != NP_TLS_RAW)
2655 ttnproto = NP_NONE; /* No protocol selected yet. */
2656 #endif /* COMMENT */
2657 debug(F110,"tcpsrv_open namecopy",namecopy,0);
2659 p = namecopy; /* Was a service requested? */
2660 while (*p != '\0' && *p != ':')
2661 p++; /* Look for colon */
2662 if (*p == ':') { /* Have a colon */
2663 *p++ = '\0'; /* Get service name or number */
2664 } else { /* Otherwise use kermit */
2667 debug(F110,"tcpsrv_open service requested",p,0);
2668 if (isdigit(*p)) { /* Use socket number without lookup */
2670 service->s_port = htons((unsigned short)atoi(p));
2671 } else { /* Otherwise lookup the service name */
2672 service = getservbyname(p, "tcp");
2674 if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
2676 service->s_port = htons(1649);
2679 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
2681 " Warning: login service on port %d instead of port 513\n",
2682 ntohs(service->s_port));
2683 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
2684 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
2686 #endif /* RLOGCODE */
2688 fprintf(stderr, "Cannot find port for service: %s\n", p);
2689 debug(F111,"tcpsrv_open can't get service",p,errno);
2690 errno = 0; /* rather than mislead */
2694 /* If we currently have a listen active but port has changed then close */
2696 debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
2697 debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
2698 if (tcpsrfd != -1 &&
2699 tcpsrv_port != ntohs((unsigned short)service->s_port)) {
2700 debug(F100,"tcpsrv_open closing previous connection","",0);
2702 socket_close(tcpsrfd);
2705 #endif /* TCPIPLIB */
2708 debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
2709 if (tcpsrfd == -1) {
2711 /* Set up socket structure and get host address */
2713 bzero((char *)&saddr, sizeof(saddr));
2714 debug(F100,"tcpsrv_open bzero ok","",0);
2715 saddr.sin_family = AF_INET;
2718 inaddrx = inet_addr(tcp_address);
2719 saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
2721 saddr.sin_addr.s_addr = inet_addr(tcp_address);
2722 #endif /* INADDRX */
2724 saddr.sin_addr.s_addr = INADDR_ANY;
2726 /* Get a file descriptor for the connection. */
2728 saddr.sin_port = service->s_port;
2731 debug(F100,"tcpsrv_open calling socket","",0);
2732 if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2733 perror("TCP socket error");
2734 debug(F101,"tcpsrv_open socket error","",errno);
2739 /* Specify the Port may be reused */
2741 debug(F100,"tcpsrv_open calling setsockopt","",0);
2742 x = setsockopt(tcpsrfd,
2743 SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
2744 debug(F101,"tcpsrv_open setsockopt","",x);
2746 /* Now bind to the socket */
2747 printf("\nBinding socket to port %d ...\n",
2748 ntohs((unsigned short)service->s_port));
2749 if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
2750 i = errno; /* Save error code */
2752 socket_close(tcpsrfd);
2753 #else /* TCPIPLIB */
2755 #endif /* TCPIPLIB */
2760 errno = i; /* and report this error */
2761 debug(F101,"tcpsrv_open bind errno","",errno);
2762 printf("?Unable to bind to socket (errno = %d)\n",errno);
2765 debug(F100,"tcpsrv_open bind OK","",0);
2766 printf("Listening ...\n");
2767 if (listen(tcpsrfd, 15) < 0) {
2768 i = errno; /* Save error code */
2770 socket_close(tcpsrfd);
2771 #else /* TCPIPLIB */
2773 #endif /* TCPIPLIB */
2778 errno = i; /* And report this error */
2779 debug(F101,"tcpsrv_open listen errno","",errno);
2782 debug(F100,"tcpsrv_open listen OK","",0);
2783 tcpsrv_port = ntohs((unsigned short)service->s_port);
2787 if (ck_ssleay_is_installed()) {
2788 if (!ssl_tn_init(SSL_SERVER)) {
2790 if (bio_err!=NULL) {
2791 BIO_printf(bio_err,"do_ssleay_init() failed\n");
2792 ERR_print_errors(bio_err);
2795 fprintf(stderr,"do_ssleay_init() failed\n");
2796 ERR_print_errors_fp(stderr);
2798 if (tls_only_flag || ssl_only_flag) {
2800 socket_close(ttyfd);
2801 socket_close(tcpsrfd);
2802 #else /* TCPIPLIB */
2805 #endif /* TCPIPLIB */
2812 /* we will continue to accept the connection */
2813 /* without SSL or TLS support unless required. */
2814 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2815 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2816 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2817 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2818 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2819 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2820 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2821 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2826 printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
2827 ntohs((unsigned short)service->s_port));
2828 saddrlen = sizeof(saddr);
2831 tv.tv_sec = tv.tv_usec = 0L;
2833 tv.tv_usec = (long) -timo * 10000L;
2836 debug(F101,"tcpsrv_open BSDSELECT","",timo);
2838 debug(F101,"tcpsrv_open not BSDSELECT","",timo);
2839 #endif /* BSDSELECT */
2842 while (!ready_to_accept) {
2845 FD_SET(tcpsrfd, &rfds);
2847 ((select(FD_SETSIZE,
2854 #endif /* HPUX1010 */
2859 #else /* def INTSELECT */
2861 #endif /* def INTSELECT [else] */
2864 &rfds, NULL, NULL, &tv) > 0) &&
2865 FD_ISSET(tcpsrfd, &rfds));
2866 #else /* BSDSELECT */
2868 #define ck_sleepint 250
2870 (select(&tcpsrfd, 1, 0, 0,
2872 (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
2877 FD_SET(tcpsrfd, rfds);
2879 ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
2880 (timo > 0 ? timo * 1000L)) > 0) &&
2881 FD_ISSET(tcpsrfd, rfds));
2883 /* Try this - what's the worst that can happen... */
2886 FD_SET(tcpsrfd, &rfds);
2888 ((select(FD_SETSIZE,
2889 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
2890 FD_ISSET(tcpsrfd, &rfds));
2892 #endif /* BELLSELECT */
2893 #endif /* IBMSELECT */
2894 #endif /* BSDSELECT */
2897 if (ready_to_accept || timo == 0) {
2898 if ((ttyfd = accept(tcpsrfd,
2899 (struct sockaddr *)&saddr,&saddrlen)) < 0) {
2900 i = errno; /* save error code */
2902 socket_close(tcpsrfd);
2903 #else /* TCPIPLIB */
2905 #endif /* TCPIPLIB */
2910 errno = i; /* and report this error */
2911 debug(F101,"tcpsrv_open accept errno","",errno);
2914 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2920 no_delay(ttyfd,tcp_nodelay);
2921 debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
2922 #endif /* TCP_NODELAY */
2924 keepalive(ttyfd,tcp_keepalive);
2925 debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
2926 #endif /* SO_KEEPALIVE */
2928 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2929 debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
2930 #endif /* SO_LINGER */
2932 sendbuf(ttyfd,tcp_sendbuf);
2933 #endif /* SO_SNDBUF */
2935 recvbuf(ttyfd,tcp_recvbuf);
2936 #endif /* SO_RCVBUF */
2937 #endif /* SOL_SOCKET */
2938 #endif /* datageneral */
2939 #endif /* NOTCPOPTS */
2941 ttnet = nett; /* TCP/IP (sockets) network */
2942 tcp_incoming = 1; /* This is an incoming connection */
2943 sstelnet = 1; /* Do server-side Telnet protocol */
2945 /* See if the service is TELNET. */
2946 x = (unsigned short)service->s_port;
2947 service2 = getservbyname("telnet", "tcp");
2948 if (service2 && x == service2->s_port) {
2950 /* Jeff 2005/12/30 */
2951 if (ttnproto != NP_TCPRAW && /* Yes... */
2952 ttnproto != NP_SSL_RAW &&
2953 ttnproto != NP_TLS_RAW) /* and if raw port not requested */
2955 /* fdc 2005/12/04 */
2956 if (ttnproto != NP_TCPRAW) /* Yes and if raw port not requested */
2958 ttnproto = NP_TELNET; /* set protocol to TELNET. */
2960 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2963 printf(" Reverse DNS Lookup... ");
2966 if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
2967 host = ck_copyhostent(host);
2968 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
2974 ckstrncpy(&name[1],host->h_name,78);
2975 ckstrncat(name,":",80-strlen(name));
2976 ckstrncat(name,p,80-strlen(name));
2982 printf("%s connected on port %s\n",host->h_name,p);
2984 if (!quiet) printf("Failed.\n");
2986 } else if (!quiet) printf("(OK)\n");
2988 if (!tcp_rdns || !host) {
2989 ckstrncpy(name,ipaddr,80);
2990 ckstrncat(name,":",80);
2991 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2997 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2999 if (!quiet) fflush(stdout);
3002 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
3003 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
3004 (char *)host->h_name : ipaddr,
3009 #endif /* CK_SECURITY */
3012 if (ck_ssleay_is_installed() && !ssl_failed) {
3013 if (ck_ssl_incoming(ttyfd) < 0) {
3015 socket_close(ttyfd);
3016 socket_close(tcpsrfd);
3017 #else /* TCPIPLIB */
3020 #endif /* TCPIPLIB */
3031 /* Find out our own IP address. */
3032 l_slen = sizeof(l_addr);
3033 bzero((char *)&l_addr, l_slen);
3035 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
3036 char * s = (char *)inet_ntoa(l_addr.sin_addr);
3037 ckstrncpy(myipaddr, s,20);
3038 debug(F110,"getsockname",myipaddr,0);
3040 #endif /* EXCELAN */
3041 #endif /* datageneral */
3043 if (tn_ini() < 0) /* Start TELNET negotiations. */
3044 if (ttchk() < 0) { /* Disconnected? */
3045 i = errno; /* save error code */
3047 socket_close(tcpsrfd);
3048 #else /* TCPIPLIB */
3050 #endif /* TCPIPLIB */
3055 errno = i; /* and report this error */
3056 debug(F101,"tcpsrv_open accept errno","",errno);
3059 debug(F101,"tcpsrv_open service","",x);
3060 if (*lcl < 0) /* Set local mode. */
3065 if ( ttnproto == NP_K5U2U ) {
3066 if (k5_user_to_user_server_auth() != 0) {
3067 i = errno; /* save error code */
3069 socket_close(tcpsrfd);
3070 #else /* TCPIPLIB */
3072 #endif /* TCPIPLIB */
3077 errno = i; /* and report this error */
3078 debug(F101,"tcpsrv_open accept errno","",errno);
3082 #endif /* KRB5_U2U */
3083 #endif /* CK_KERBEROS */
3084 return(0); /* Done. */
3086 i = errno; /* save error code */
3088 socket_close(tcpsrfd);
3089 #else /* TCPIPLIB */
3091 #endif /* TCPIPLIB */
3096 errno = i; /* and report this error */
3097 debug(F101,"tcpsrv_open accept errno","",errno);
3101 #endif /* NOLISTEN */
3103 #endif /* TCPSOCKET */
3108 ckname2addr(name) char * name;
3113 struct hostent *host;
3115 if (name == NULL || *name == '\0')
3118 host = gethostbyname(name);
3120 host = ck_copyhostent(host);
3121 return(inet_ntoa(*((struct in_addr *) host->h_addr)));
3128 ckaddr2name(addr) char * addr;
3133 struct hostent *host;
3134 struct in_addr sin_addr;
3136 if (addr == NULL || *addr == '\0')
3139 sin_addr.s_addr = inet_addr(addr);
3140 host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
3142 host = ck_copyhostent(host);
3143 return((char *)host->h_name);
3148 #endif /* TCPSOCKET */
3150 unsigned long peerxipaddr = 0L;
3155 static char namebuf[256];
3156 static struct hostent *host;
3157 static struct sockaddr_in saddr;
3159 static GPEERNAME_T saddrlen;
3162 static size_t saddrlen;
3165 /* It's size_t in 4.2 but int in 4.1 and earlier. */
3166 /* Note: the 4.2 man page lies; believe socket.h. */
3167 static size_t saddrlen;
3170 static size_t saddrlen;
3171 #else /* UNIXWARE */
3174 * Coincidentally, the condition for integer arguments in select(),
3175 * which is actually "defined( _DECC_V4_SOURCE)", works for an integer
3176 * argument in getpeername(). Sadly, due to a lack of foresight,
3177 * "defined( _DECC_V4_SOURCE)" doesn't work with DEC C V4.0, so the
3178 * user-specified INTSELECT is used instead. Most likely, "size_t"
3179 * should be used instead of "unsigned int", but I'm a coward.
3182 static int saddrlen;
3183 #else /* def INTSELECT */
3184 static unsigned int saddrlen;
3185 #endif /* def INTSELECT [else] */
3188 static unsigned int saddrlen;
3191 static socklen_t saddrlen;
3193 static int saddrlen;
3194 #endif /* CK_64BIT */
3195 #endif /* MACOSX10 */
3196 #endif /* DEC_TCPIP */
3197 #endif /* UNIXWARE */
3200 #endif /* GPEERNAME_T */
3201 saddrlen = sizeof(saddr);
3202 if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
3203 debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
3206 host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
3208 host = ck_copyhostent(host);
3209 ckstrncpy(namebuf,(char *)host->h_name,80);
3211 ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
3213 peerxipaddr = ntohl(saddr.sin_addr.s_addr);
3214 debug(F111,"ckgetpeer",namebuf,peerxipaddr);
3218 #endif /* TCPSOCKET */
3221 /* Get fully qualified IP hostname */
3226 ckgetfqhostname(char * name)
3228 ckgetfqhostname(name) char * name;
3229 #endif /* CK_ANSIC */
3231 #ifdef NOCKGETFQHOST
3235 #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
3237 static char namebuf[256];
3238 struct hostent *host=NULL;
3239 struct sockaddr_in r_addr;
3242 debug(F110,"ckgetfqhn()",name,0);
3244 ckstrncpy(namebuf,name,256);
3245 namebuf[255] = '\0';
3246 i = ckindex(":",namebuf,0,0,0);
3248 namebuf[i-1] = '\0';
3250 bzero((char *)&r_addr, sizeof(r_addr));
3252 host = gethostbyname(namebuf);
3254 host = ck_copyhostent(host);
3255 debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
3256 r_addr.sin_family = host->h_addrtype;
3259 /* This is for trying multiple IP addresses - see <netdb.h> */
3260 if (!(host->h_addr_list))
3262 bcopy(host->h_addr_list[0],
3263 (caddr_t)&r_addr.sin_addr,
3267 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3269 #else /* HADDRLIST */
3270 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3271 #endif /* HADDRLIST */
3274 debug(F111,"BCOPY","host->h_addr",host->h_addr);
3275 #endif /* EXCELAN */
3276 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
3277 (caddr_t)&r_addr.sin_addr);
3278 #endif /* COMMENT */
3279 debug(F111,"BCOPY","host->h_length",host->h_length);
3282 /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
3283 /* provided DNS functions. Otherwise, the TTL of the DNS response */
3288 host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
3290 host = ck_copyhostent(host);
3291 debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
3292 ckstrncpy(namebuf, host->h_name, 256);
3300 #endif /* HADDRLIST */
3303 ckstrncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
3304 debug(F110,"ckgetfqhn()",namebuf,0);
3306 #endif /* NOCKGETFQHOST */
3313 setnproto(p) char * p;
3314 #endif /* CK_ANSIC */
3317 if (!strcmp("kermit",p))
3318 ttnproto = NP_KERMIT;
3319 else if (!strcmp("telnet",p))
3320 ttnproto = NP_TELNET;
3321 else if (!strcmp("http",p))
3322 ttnproto = NP_TCPRAW;
3324 else if (!strcmp("login",p))
3325 ttnproto = NP_RLOGIN;
3326 #endif /* RLOGCODE */
3328 /* Commonly used SSL ports (might not be in services file) */
3329 else if (!strcmp("https",p)) {
3330 ttnproto = NP_SSL_RAW;
3332 } else if (!strcmp("ssl-telnet",p)) {
3333 ttnproto = NP_TELNET;
3335 } else if (!strcmp("telnets",p)) {
3336 ttnproto = NP_TELNET;
3342 else if (!strcmp("klogin",p)) {
3343 if (ck_krb5_is_installed())
3344 ttnproto = NP_K5LOGIN;
3345 else if (ck_krb4_is_installed())
3346 ttnproto = NP_K4LOGIN;
3348 ttnproto = NP_RLOGIN;
3349 } else if (!strcmp("eklogin",p)) {
3350 if (ck_krb5_is_installed())
3351 ttnproto = NP_EK5LOGIN;
3352 else if (ck_krb4_is_installed())
3353 ttnproto = NP_EK4LOGIN;
3355 ttnproto = NP_RLOGIN;
3357 #endif /* RLOGCODE */
3358 #endif /* CK_KERBEROS */
3363 case 23: /* Telnet */
3364 ttnproto = NP_TELNET;
3367 ttnproto = NP_RLOGIN;
3370 ttnproto = NP_KERMIT;
3375 /* Jeff 2005/12/30 */
3376 ttnproto = NP_SSL_RAW;
3378 /* fdc 2005/12/04 */
3380 #endif /* COMMENT */
3385 ttnproto = NP_TELNET;
3391 if (ck_krb5_is_installed())
3392 ttnproto = NP_K5LOGIN;
3393 else if (ck_krb4_is_installed())
3394 ttnproto = NP_K4LOGIN;
3396 ttnproto = NP_RLOGIN;
3399 if (ck_krb5_is_installed())
3400 ttnproto = NP_EK5LOGIN;
3401 else if (ck_krb4_is_installed())
3402 ttnproto = NP_EK4LOGIN;
3404 ttnproto = NP_RLOGIN;
3406 #endif /* CK_KERBEROS */
3408 ttnproto = NP_TCPRAW;
3417 /* ckgetservice() is used to determine the port number for a given */
3418 /* service taking into account the use of DNS SRV records. */
3420 static struct servent servrec;
3421 static struct servent *
3422 ckgetservice(hostname, servicename, ip, iplen)
3423 char *hostname; char * servicename; char * ip; int iplen;
3425 struct servent * service = NULL;
3427 struct sockaddr * dns_addrs = NULL;
3429 #endif /* CK_DNS_SRV */
3431 if (isdigit(*servicename)) { /* Use socket number without lookup */
3433 service->s_port = htons((unsigned short)atoi(servicename));
3434 } else { /* Otherwise lookup the service name */
3436 if (tcp_dns_srv && !quiet) {
3437 printf(" DNS SRV Lookup... ");
3441 locate_srv_dns(hostname,
3448 /* Use the first one. Eventually we should cycle through all */
3449 /* the returned IP addresses and port numbers. */
3450 struct sockaddr_in *sin = NULL;
3454 for ( i=0;i<dns_naddrs;i++ ) {
3455 sin = (struct sockaddr_in *) &dns_addrs[i];
3456 printf("dns_addrs[%d] = %s %d\r\n", i,
3457 (char *)inet_ntoa(sin->sin_addr),
3458 ntohs(sin->sin_port));
3460 #endif /* BETADEBUG */
3461 sin = (struct sockaddr_in *) &dns_addrs[0];
3462 if ( ip && iplen > 0 )
3463 ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
3465 service->s_port = sin->sin_port;
3471 #endif /* CK_DNS_SRV */
3472 service = getservbyname(servicename, "tcp");
3475 if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
3477 service->s_port = htons(1649);
3478 } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
3480 service->s_port = htons(23);
3481 } else if (!ckstrcmp("http",servicename,-1,0)) {
3483 service->s_port = htons(80);
3486 else if (!ckstrcmp("login",servicename,-1,0)) {
3488 service->s_port = htons(513);
3490 #endif /* RLOGCODE */
3492 /* Commonly used SSL ports (might not be in services file) */
3493 else if (!ckstrcmp("https",servicename,-1,0)) {
3495 service->s_port = htons(443);
3496 } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
3498 service->s_port = htons(151);
3499 } else if (!ckstrcmp("telnets",servicename,-1,0)) {
3501 service->s_port = htons(992);
3506 else if (!ckstrcmp("klogin",servicename,-1,0)) {
3508 service->s_port = htons(543);
3509 } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
3511 service->s_port = htons(2105);
3513 #endif /* RLOGCODE */
3514 #endif /* CK_KERBEROS */
3519 /* N E T O P E N -- Open a network connection */
3521 Calling conventions same as ttopen(), except third argument is network
3522 type rather than modem type. Designed to be called from within ttopen.
3525 #define XXNAMELEN 256
3526 static char xxname[XXNAMELEN];
3529 netopen(name, lcl, nett) char *name; int *lcl, nett; {
3531 int i, x, rc_inet_addr = 0, dns = 0;
3536 #endif /* SO_OOBINLINE */
3537 struct servent *service=NULL;
3538 struct hostent *host=NULL;
3539 struct sockaddr_in r_addr;
3540 struct sockaddr_in sin;
3541 struct sockaddr_in l_addr;
3544 struct sockaddr_in send_socket;
3545 #endif /* EXCELAN */
3548 /* inet_addr() is of type struct in_addr */
3550 extern struct in_addr inet_addr();
3553 extern struct in_addr inet_addr();
3554 #endif /* HPUX5WINTCP */
3555 #endif /* datageneral */
3560 #else /* INADDR_NONE */
3562 #endif /* INADDR_NONE */
3563 #endif /* INADDRX */
3564 #endif /* TCPSOCKET */
3567 /* This causes big trouble */
3569 #define INADDR_NONE 0xffffffff
3570 #endif /* INADDR_NONE */
3571 #endif /* COMMENT */
3573 #ifdef SUNX25 /* Code for SunLink X.25 support */
3574 #define X29PID 1 /* X.29 Protocol ID */
3575 _PROTOTYP(SIGTYP x25oobh, (int) );
3577 #ifndef X25_WR_FACILITY
3580 FACILITY_DB x25facil;
3581 #endif /* X25_WR_FACILITY */
3582 static int needh = 1;
3584 extern int linkid, lcn, x25ver;
3587 extern int revcall, closgr, cudata;
3588 extern char udata[];
3591 #ifdef IBMX25 /* Variables for IBM X25 */
3592 extern int x25port; /* Logical port to use */
3593 extern x25addr_t local_nua; /* Local X.25 address */
3594 extern x25addr_t remote_nua; /* Remote X.25 address */
3595 extern char x25name[]; /* X25 device name (sx25a0) */
3596 extern char x25dev[]; /* X25 device file /dev/x25pkt */
3597 ulong bind_flags = 0; /* Flags for binding the X25 stream */
3598 ulong token = 0; /* Temporary return code */
3601 debug(F101,"netopen nett","",nett);
3602 *ipaddr = '\0'; /* Initialize IP address string */
3605 if (nett == NET_SX25) { /* If network type is X.25 */
3606 netclos(); /* Close any previous net connection */
3607 ttnproto = NP_NONE; /* No protocol selected yet */
3609 /* Set up host structure */
3610 bzero((char *)&x25host,sizeof(x25host));
3611 if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
3612 fprintf (stderr,"Invalid X.121 host address %s\n",name);
3616 x25host.datalen = X29PIDLEN;
3617 x25host.data[0] = X29PID;
3619 /* Set call user data if specified */
3621 ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
3622 x25host.datalen += (int)strlen(udata);
3625 /* Open SunLink X.25 socket */
3626 if (!quiet && *name) {
3627 printf(" Trying %s... ", name);
3630 if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
3631 debug(F101,"netopen socket error","",errno);
3632 perror ("X.25 socket error");
3636 /* Setting X.25 out-of-band data handler */
3638 if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
3639 perror("X.25 set process group id error");
3642 (VOID) signal(SIGURG,x25oobh);
3644 /* Set reverse charge call and closed user group if requested */
3645 bzero ((char *)&x25facil,sizeof(x25facil));
3647 #ifndef X25_WR_FACILITY
3648 /* New SunLink (7.0 or 8.0, not sure which)... */
3649 x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
3650 x25facil.f_reverse_charge = revcall ? 1 : 0;
3651 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3652 perror ("Setting X.25 reverse charge");
3655 if (closgr > -1) { /* Closed User Group (Outgoing) */
3656 bzero ((char *)&x25facil,sizeof(x25facil));
3657 x25facil.type = T_CUG;
3658 x25facil.f_cug_req = CUG_REQ_ACS;
3659 x25facil.f_cug_index = closgr;
3660 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3661 perror ("Setting X.25 closed user group");
3666 /* Old SunLink 6.0 (or 7.0?)... */
3667 if (revcall) x25facil.reverse_charge = revcall;
3669 x25facil.cug_req = 1;
3670 x25facil.cug_index = closgr;
3672 if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
3673 perror ("Setting X.25 facilities");
3676 #endif /* X25_WR_FACILITY */
3678 /* Need X.25 header with bits Q and M */
3679 if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
3680 perror ("Setting X.25 header");
3684 /* Connects to remote host via SunLink X.25 */
3685 if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
3687 debug(F101,"netopen connect errno","",i);
3689 perror("netopen x25 connect");
3700 /* Get X.25 link identification used for the connection */
3701 if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
3702 perror ("Getting X.25 link id");
3706 /* Get X.25 logical channel number used for the connection */
3707 if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
3708 perror ("Getting X.25 lcn");
3712 /* Get SunLink X.25 version */
3713 if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
3714 perror ("Getting SunLink X.25 version");
3717 ttnet = nett; /* Sunlink X.25 network */
3718 ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */
3719 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3721 } else /* Note that SUNX25 support can coexist with TCP/IP support. */
3726 if (nett == NET_IX25) { /* IBM AIX X.25 */
3727 netclos(); /* Close any previous net connection */
3728 ttnproto = NP_NONE; /* No protocol selected yet */
3730 /* find out who we are - this is not so easy on AIX */
3731 /* riehm: need to write the code that finds this out
3732 * automatically, or at least allow it to be configured
3735 if (!local_nua[0] && !x25local_nua(local_nua)) {
3739 /* Initialise the X25 API (once per process? once per connection?) */
3741 debug(F110, "Opening ", x25dev, 0 );
3742 /* set O_NDELAY to allow polling? */
3743 if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
3744 perror ("X.25 device open error");
3745 debug(F101,"netopen: device open error","",errno);
3749 /* push the NPI onto the STREAM */
3750 if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
3754 perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
3755 debug(F101,"netopen: can't push npi on the X25 stream","",errno);
3759 /* set up server mode - bind the x25 port and wait for
3760 * incoming connections
3762 if (name[0] == '*') { /* Server */
3763 /* set up a server - see the warning in x25bind() */
3764 bind_flags |= TOKEN_REQUEST;
3766 /* bind kermit to the local X25 address */
3767 token = x25bind(ttyfd,
3770 (int)strlen( udata ),
3776 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3780 /* Currently not connected to a remote host */
3782 remote_nua[0] = '\0';
3784 /* store the fd so that incoming calls can have their own fd
3785 * This is almost support for a true server (ie: a'la ftpd)
3786 * but we're not quite there yet.
3789 x25serverfd = ttyfd;
3791 * wait for an incoming call
3792 * this should happen in the "server" command and not in
3793 * the "set host *" command.
3795 if ((ttyfd = x25getcall(ttyfd)) < 0) {
3799 } else { /* Client */
3800 /* Bind kermit to the local X25 address */
3811 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3815 /* riehm: this should be done via the CONNECT command, not HOST! */
3818 /* call the remote host */
3819 /* name == address of remote host as char* */
3820 if (x25call(ttyfd, name, udata) < 0 ) {
3822 "netopen: couldn't connect to remote X25 address",
3827 strcpy(remote_nua, name);
3830 ttnet = nett; /* AIX X.25 network */
3831 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3834 } else /* Note that IBMX25 support can coexist with TCP/IP support. */
3837 /* Add support for other networks here. */
3839 if (nett != NET_TCPB) return(-1); /* BSD socket support */
3842 netclos(); /* Close any previous connection. */
3843 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
3844 debug(F110,"netopen namecopy",namecopy,0);
3848 return(tcpsrv_open(name, lcl, nett, 0));
3849 #endif /* NOLISTEN */
3851 p = namecopy; /* Was a service requested? */
3852 while (*p != '\0' && *p != ':') p++; /* Look for colon */
3853 if (*p == ':') { /* Have a colon */
3854 debug(F110,"netopen name has colon",namecopy,0);
3855 *p++ = '\0'; /* Get service name or number */
3858 Here we have to check for various popular syntaxes:
3859 host:port (our original syntax)
3860 URL such as telnet:host or telnet://host/
3861 Or even telnet://user:password@host:port/path/
3862 Or a malformed URL such as generated by Netscape 4.0 like:
3863 telnet:telnet or telnet::host.
3867 * REPLACE THIS CODE WITH urlparse() but not on the day of the
3868 * C-Kermit 8.0 RELEASE.
3871 if (*p == ':') /* a second colon */
3872 *p++ = '\0'; /* get rid of that one too */
3873 while (*p == '/') *p++ = '\0'; /* and slashes */
3874 x = strlen(p); /* Length of remainder */
3875 if (p[x-1] == '/') /* If there is a trailing slash */
3876 p[x-1] = '\0'; /* remove it. */
3877 debug(F110,"netopen namecopy after stripping",namecopy,0);
3878 debug(F110,"netopen p after stripping",p,0);
3879 service = getservbyname(namecopy,"tcp");
3882 !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
3883 #endif /* RLOGCODE */
3885 !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
3887 !ckstrcmp("iksd",namecopy,NAMECPYL,0)
3889 char temphost[256], tempservice[80], temppath[256];
3890 char * q = p, *r = p, *w = p;
3892 extern char pwbuf[];
3893 extern int pwflg, pwcrypt;
3895 if (ttnproto == NP_DEFAULT)
3896 setnproto(namecopy);
3898 /* Check for userid and possibly password */
3899 while (*p != '\0' && *p != '@')
3900 p++; /* look for @ */
3902 /* found username and perhaps password */
3903 debug(F110,"netopen namecopy found @","",0);
3906 while (*w != '\0' && *w != ':')
3910 /* r now points to username, save it and the password */
3911 debug(F110,"netopen namecopy username",r,0);
3912 debug(F110,"netopen namecopy password",w,0);
3914 if ( strcmp(uidbuf,r) || *w )
3915 ckstrncpy(pwbuf,w,PWBUFL+1);
3916 ckstrncpy(uidbuf,r,UIDBUFLEN);
3919 q = p; /* Host after user and pwd */
3921 p = q; /* No username or password */
3923 /* Now we must look for the optional port. */
3924 debug(F110,"netopen x p",p,0);
3925 debug(F110,"netopen x q",q,0);
3927 /* Look for the port/service or a file/directory path */
3928 while (*p != '\0' && *p != ':' && *p != '/')
3931 debug(F110,"netopen found port",q,0);
3932 *p++ = '\0'; /* Found a port name or number */
3935 /* Look for the end of port/service or a file/directory path */
3936 while (*p != '\0' && *p != '/')
3941 debug(F110,"netopen port",r,0);
3942 ckstrncpy(tempservice,r,80);
3943 ckstrncpy(temphost,q,256);
3944 ckstrncpy(temppath,p,256);
3945 ckstrncpy(namecopy,temphost,NAMECPYL);
3946 debug(F110,"netopen tempservice",tempservice,0);
3947 debug(F110,"netopen temphost",temphost,0);
3948 debug(F110,"netopen temppath",temppath,0);
3950 /* move port/service to a buffer that won't go away */
3951 x = strlen(namecopy);
3952 p = namecopy + x + 1;
3953 ckstrncpy(p, tempservice, NAMECPYL - x);
3955 /* Handle a path if we found one */
3958 ckstrncpy(temppath,p,256);
3960 /* We didn't find another port, but if q is a service */
3961 /* then assume that namecopy is actually a host. */
3962 if (getservbyname(q,"tcp")) {
3966 /* rlogin is not a valid service */
3967 if (!ckstrcmp("rlogin",namecopy,6,0)) {
3968 ckstrncpy(namecopy,"login",NAMECPYL);
3970 #endif /* RLOGCODE */
3971 /* iksd is not a valid service */
3972 if (!ckstrcmp("iksd",namecopy,6,0)) {
3973 ckstrncpy(namecopy,"kermit",NAMECPYL);
3975 /* Reconstruct namecopy */
3976 ckstrncpy(tempservice,namecopy,80);
3977 ckstrncpy(temphost,q,256);
3978 ckstrncpy(namecopy,temphost,NAMECPYL);
3979 debug(F110,"netopen tempservice",tempservice,0);
3980 debug(F110,"netopen temphost",temphost,0);
3981 debug(F110,"netopen temppath",temppath,0);
3983 /* move port/service to a buffer that won't go away */
3984 x = strlen(namecopy);
3985 p = namecopy + x + 1;
3986 ckstrncpy(p, tempservice, NAMECPYL - x - 1);
3989 debug(F110,"netopen URL result: host",namecopy,0);
3990 debug(F110,"netopen URL result: service",p,0);
3991 debug(F110,"netopen URL result: path",temppath,0);
3994 /* If we have set a path specified, we need to try to GET it */
3995 /* But we have another problem, we have to login first. How */
3996 /* do we specify that a login must be done before the GET? */
3997 /* The user's name if specified is in 'userid' and the */
3998 /* password if any is in 'pwbuf'. */
3999 if ( temppath[0] ) {
4001 extern char * cmarg;
4004 /* If no userid was specified as part of the URL but
4005 * a path was specified, then we
4006 * set the user name to anonymous and the password
4007 * to the current userid.
4009 ckstrncpy(pwbuf,uidbuf,PWBUFL);
4010 ckstrncat(pwbuf,"@",PWBUFL);
4013 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
4017 * If a file path was specified we perform the GET
4018 * operation and then terminate the connection.
4020 * If a directory was given instead of a file, then
4021 * we should REMOTE CD to the directory and list its
4022 * contents. But how do we tell the difference?
4024 makestr(&cmarg,temppath);
4027 #endif /* IKS_GET */
4030 } else { /* Otherwise use telnet */
4034 By the time we get here, namecopy[] should hold the null-terminated
4035 hostname or address, and p should point to the service name or number.
4037 debug(F110,"netopen host",namecopy,0);
4038 debug(F110,"netopen service requested",p,0);
4040 /* Use the service port to set the default protocol type if necessary */
4041 if (ttnproto == NP_DEFAULT)
4044 ckstrncpy(namecopy2,namecopy,NAMECPYL);
4045 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4047 fprintf(stderr, "Can't find port for service %s\n", p);
4049 debug(F101,"netopen can't get service","",socket_errno);
4051 debug(F101,"netopen can't get service","",errno);
4052 #endif /* TGVORWIN */
4053 errno = 0; /* (rather than mislead) */
4056 if (!ckstrcmp(namecopy,namecopy2,-1,0))
4057 namecopy2[0] = '\0';
4058 ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
4059 debug(F110,"netopen service ok",svcbuf,0);
4063 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
4065 " Warning: login service on port %d instead of port 513\n",
4066 ntohs(service->s_port)
4068 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
4069 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
4071 #endif /* RLOGCODE */
4074 /* For HTTP connections we must preserve the original hostname and */
4075 /* service requested so we can include them in the Host header. */
4076 ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
4077 ckitoa(ntohs(service->s_port)),NULL);
4079 /* 'namecopy' contains the name of the host to which we want to connect */
4080 /* 'svcbuf' contains the service name */
4081 /* 'service->s_port' contains the port number in network byte order */
4083 /* If we are using an http proxy, we need to create a buffer containing */
4084 /* hostname:port-number */
4085 /* to pass to the http_connect() function. Then we need to replace */
4086 /* 'namecopy' with the name of the proxy server and the service->s_port */
4087 /* with the port number of the proxy (default port 80). */
4089 if ( tcp_http_proxy ) {
4090 ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
4091 ckuitoa(ntohs(service->s_port)),NULL);
4092 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
4094 p = namecopy; /* Was a service requested? */
4095 while (*p != '\0' && *p != ':') p++; /* Look for colon */
4096 if (*p == ':') { /* Have a colon */
4097 debug(F110,"netopen name has colon",namecopy,0);
4098 *p++ = '\0'; /* Get service name or number */
4103 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4105 fprintf(stderr, "Can't find port for service %s\n", p);
4107 debug(F101,"netopen can't get service for proxy","",socket_errno);
4109 debug(F101,"netopen can't get service for proxy","",errno);
4110 #endif /* TGVORWIN */
4111 errno = 0; /* (rather than mislead) */
4114 ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
4119 /* Set up socket structure and get host address */
4121 bzero((char *)&r_addr, sizeof(r_addr));
4122 debug(F100,"netopen bzero ok","",0);
4124 NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
4125 all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
4126 address without going through the multihomed host sequence and winding up
4127 at a different place than the one requested.
4130 debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
4131 #else /* INADDR_NONE */
4132 debug(F100,"netopen INADDR_NONE not defined","",0);
4133 #endif /* INADDR_NONE */
4135 debug(F100,"netopen INADDRX defined","",0);
4137 debug(F100,"netopen INADDRX not defined","",0);
4138 #endif /* INADDRX */
4142 iax = inet_addr(namecopy);
4143 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4146 iax.s_addr = inet_addr(namecopy);
4147 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4148 #else /* INADDR_NONE */
4150 /* In Solaris inet_addr() is of type in_addr_t which is uint32_t */
4151 /* (unsigned) yet it returns -1 (signed) on failure. */
4152 /* It makes a difference in 64-bit builds. */
4153 rc_inet_addr = inet_addr(namecopy); /* Assign return code to an int */
4154 iax = (unsigned) rc_inet_addr; /* and from there to whatever.. */
4157 iax = (unsigned int) inet_addr(namecopy);
4160 #endif /* datageneral */
4161 #endif /* SOLARIS */
4162 debug(F111,"netopen rc_inet_addr",namecopy,rc_inet_addr);
4163 debug(F111,"netopen inet_addr",namecopy,iax);
4164 #endif /* INADDR_NONE */
4165 #endif /* INADDRX */
4169 /* This might give warnings on 64-bit platforms but they should be harmless */
4170 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
4171 /* probably superfluous -- not sure why it's even there, maybe it should be */
4177 iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
4178 #else /* INADDR_NONE */
4180 #endif /* INADDR_NONE */
4181 #endif /* SOLARIS */
4184 printf(" DNS Lookup... ");
4187 if ((host = gethostbyname(namecopy)) != NULL) {
4188 debug(F110,"netopen gethostbyname != NULL",namecopy,0);
4189 host = ck_copyhostent(host);
4190 dns = 1; /* Remember we performed dns lookup */
4191 r_addr.sin_family = host->h_addrtype;
4192 if (tcp_rdns && host->h_name && host->h_name[0]
4194 && (tcp_http_proxy == NULL)
4198 ckstrncpy(xxname,host->h_name,XXNAMELEN);
4199 debug(F110,"netopen xxname[1]",xxname,0);
4200 if ((XXNAMELEN - (int)strlen(name)) > ((int)strlen(svcbuf)+1)){
4201 ckstrncat(xxname,":",XXNAMELEN - (int)strlen(xxname));
4202 ckstrncat(xxname,svcbuf,XXNAMELEN - (int)strlen(xxname));
4203 debug(F110,"netopen xxname[2]",xxname,0);
4205 name = (char *)xxname;
4207 ckstrncpy(name,host->h_name,80); /* Bad Bad Bad */
4208 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4209 ckstrncat(name,":",80-strlen(name));
4210 ckstrncat(name,svcbuf,80-strlen(name));
4212 #endif /* COMMENT */
4214 debug(F110,"netopen name after lookup",name,0);
4218 /* This is for trying multiple IP addresses - see <netdb.h> */
4219 if (!(host->h_addr_list))
4221 bcopy(host->h_addr_list[0],
4222 (caddr_t)&r_addr.sin_addr,
4226 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4228 #else /* HADDRLIST */
4230 r_addr.sin_addr.s_addr = (u_long)host->h_addr;
4232 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4234 #endif /* HADDRLIST */
4237 debug(F111,"BCOPY","host->h_length",host->h_length);
4241 #endif /* NOMHHOST */
4243 debug(F101,"netopen dns","",dns);
4247 /* inet_addr() is of type struct in_addr */
4250 debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
4251 ina = inet_addr(namecopy);
4252 uu = *(unsigned int *)&ina;
4253 #else /* Not INADDRX */
4254 /* inet_addr() is unsigned long */
4256 debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
4257 uu = inet_addr(namecopy);
4258 #endif /* INADDRX */
4259 debug(F101,"netopen uu","",uu);
4262 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
4263 #else /* INADDR_NONE */
4264 uu != ((unsigned long)-1)
4265 #endif /* INADDR_NONE */
4267 r_addr.sin_addr.s_addr = uu;
4268 r_addr.sin_family = AF_INET;
4271 fprintf(stdout, "\r\n"); /* complete any previous message */
4273 fprintf(stderr, "Can't get address for %s\n", namecopy);
4275 debug(F101,"netopen can't get address","",socket_errno);
4277 debug(F101,"netopen can't get address","",errno);
4278 #endif /* TGVORWIN */
4279 errno = 0; /* Rather than mislead */
4284 /* Get a file descriptor for the connection. */
4286 r_addr.sin_port = service->s_port;
4287 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4288 debug(F110,"netopen trying",ipaddr,0);
4289 if (!quiet && *ipaddr) {
4290 printf(" Trying %s... ", ipaddr);
4294 /* Loop to try additional IP addresses, if any. */
4298 send_socket.sin_family = AF_INET;
4299 send_socket.sin_addr.s_addr = 0;
4300 send_socket.sin_port = 0;
4301 if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
4302 &send_socket, SO_REUSEADDR)) < 0)
4307 Must make sure that all sockets are opened in
4308 Non-overlapped mode since we use the standard
4309 C RTL functions to read and write data.
4310 But it doesn't seem to work as planned.
4313 int optionValue = SO_SYNCHRONOUS_NONALERT;
4314 if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
4315 (char *) &optionValue, sizeof(optionValue))
4319 #endif /* COMMENT */
4322 if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
4323 #endif /* EXCELAN */
4326 experror("TCP socket error");
4329 fprintf(stdout, "\r\n"); /* complete any previous stdout */
4333 errno = socket_errno;
4334 #endif /* OLD_TWG */
4335 socket_perror("TCP socket error");
4336 debug(F101,"netopen socket error","",socket_errno);
4338 perror("TCP socket error");
4339 debug(F101,"netopen socket error","",errno);
4340 #endif /* TGVORWIN */
4341 #endif /* EXCELAN */
4347 /* Not part of the RLOGIN RFC, but the BSD implementation */
4348 /* requires that the client port be a priviliged port (<1024) */
4349 /* on a Unix system this would require SuperUser permissions */
4350 /* thereby saying that the root of the Unix system has given */
4351 /* permission for this connection to be created */
4352 if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
4353 static unsigned short lport = 1024; /* max reserved port */
4358 lport--; /* Make sure we do not reuse a port */
4362 sin.sin_family = AF_INET;
4365 inaddrx = inet_addr(tcp_address);
4366 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4368 sin.sin_addr.s_addr = inet_addr(tcp_address);
4369 #endif /* INADDRX */
4371 sin.sin_addr.s_addr = INADDR_ANY;
4373 sin.sin_port = htons(lport);
4374 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
4377 s_errno = socket_errno;
4378 if (s_errno && /* OS2 bind fails with 0, if already in use */
4380 s_errno != WSAEADDRINUSE
4382 s_errno != SOCEADDRINUSE &&
4383 s_errno != (SOCEADDRINUSE - SOCBASEERR)
4388 if (socket_errno != EADDRINUSE)
4390 if (errno != EADDRINUSE)
4391 #endif /* TGVORWIN */
4395 printf("\nBind failed with errno %d for port %d.\n",
4403 #endif /* TGVORWIN */
4408 debug(F101,"rlogin bind failed","",s_errno);
4411 debug(F101,"rlogin bind failed","",socket_errno);
4413 errno = socket_errno;
4414 #endif /* OLD_TWG */
4415 socket_perror("rlogin bind");
4417 debug(F101,"rlogin bind failed","",errno);
4418 perror("rlogin bind");
4419 #endif /* TGVORWIN */
4423 debug(F101,"rlogin bind s_errno","",s_errno);
4424 perror("rlogin bind");
4427 printf("\r\n"); /* complete any previous message */
4430 debug(F101,"rlogin bind socket_errno","",socket_errno);
4432 errno = socket_errno;
4433 #endif /* OLD_TWG */
4434 socket_perror("rlogin bind");
4436 debug(F101,"rlogin bind errno","",errno);
4437 perror("rlogin bind");
4438 #endif /* TGVORWIN */
4440 debug(F101,"rlogin local port","",lport);
4441 #endif /* COMMENT */
4446 if (lport == 512 /* lowest reserved port to use */ ) {
4447 printf("\nNo reserved ports available.\n");
4452 debug(F101,"rlogin lport","",lport);
4453 ttnproto = NP_RLOGIN;
4455 #endif /* RLOGCODE */
4457 /* If a specific TCP address on the local host is desired we */
4458 /* must bind it to the socket. */
4463 debug(F110,"netopen binding socket to",tcp_address,0);
4464 bzero((char *)&sin,sizeof(sin));
4465 sin.sin_family = AF_INET;
4467 inaddrx = inet_addr(tcp_address);
4468 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4470 sin.sin_addr.s_addr = inet_addr(tcp_address);
4471 #endif /* INADDRX */
4473 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
4474 s_errno = socket_errno; /* Save error code */
4476 socket_close(ttyfd);
4477 #else /* TCPIPLIB */
4479 #endif /* TCPIPLIB */
4482 errno = s_errno; /* and report this error */
4483 debug(F101,"netopen bind errno","",errno);
4487 #endif /* datageneral */
4489 /* Now connect to the socket on the other end. */
4492 if (connect(ttyfd, &r_addr) < 0)
4495 WSASafeToCancel = 1;
4497 if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
4498 #endif /* EXCELAN */
4501 WSASafeToCancel = 0;
4509 i = errno; /* Save error code */
4510 #endif /* TGVORWIN */
4515 i && /* OS2 bind fails with 0, if already in use */
4519 (i == SOCEADDRINUSE ||
4520 i == (SOCEADDRINUSE - SOCBASEERR))
4524 socket_errno == EADDRINUSE
4527 #endif /* TGVORWIN */
4529 && ttnproto == NP_RLOGIN) {
4531 socket_close(ttyfd); /* Close it. */
4534 #endif /* TCPIPLIB */
4535 continue; /* Try a different lport */
4537 #endif /* RLOGCODE */
4540 if (host && host->h_addr_list && host->h_addr_list[1]) {
4542 host->h_addr_list++;
4543 bcopy(host->h_addr_list[0],
4544 (caddr_t)&r_addr.sin_addr,
4547 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4548 debug(F110,"netopen h_addr_list",ipaddr,0);
4549 if (!quiet && *ipaddr) {
4550 printf(" Trying %s... ", ipaddr);
4554 socket_close(ttyfd); /* Close it. */
4557 #endif /* TCPIPLIB */
4561 #endif /* HADDRLIST */
4566 errno = i; /* And report this error */
4568 if (errno) experror("netopen connect");
4571 debug(F101,"netopen connect error","",socket_errno);
4572 /* if (errno) socket_perror("netopen connect"); */
4574 errno = socket_errno;
4575 #endif /* OLD_TWG */
4577 socket_perror("netopen connect");
4578 #else /* TGVORWIN */
4579 debug(F101,"netopen connect errno","",errno);
4582 perror("\r\nFailed");
4589 perror("netopen connect");
4590 #endif /* DEC_TCPIP */
4593 perror("netopen connect");
4594 #endif /* CMU_TCPIP */
4595 #endif /* TGVORWIN */
4596 #endif /* EXCELAN */
4600 WSASafeToCancel = 0;
4603 } while (!isconnect);
4607 x = socket_ioctl(ttyfd,FIONBIO,&on);
4608 debug(F101,"netopen FIONBIO","",x);
4609 #endif /* NON_BLOCK_IO */
4611 #ifdef NT_TCP_OVERLAPPED
4612 OverlappedWriteInit();
4613 OverlappedReadInit();
4614 #endif /* NT_TCP_OVERLAPPED */
4616 ttnet = nett; /* TCP/IP (sockets) network */
4619 /* We have succeeded in connecting to the HTTP PROXY. So now we */
4620 /* need to attempt to connect through the proxy to the actual host */
4621 /* If that is successful, we have to pretend that we made a direct */
4622 /* connection to the actual host. */
4624 if ( tcp_http_proxy ) {
4626 char * agent = "Kermit 95"; /* Default user agent */
4628 char * agent = "C-Kermit";
4631 if (http_connect(ttyfd,
4632 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
4634 tcp_http_proxy_user,
4643 ckstrncpy(namecopy,proxycopy,NAMECPYL);
4644 p = namecopy; /* Was a service requested? */
4645 while (*p != '\0' && *p != ':') p++; /* Look for colon */
4650 /* Jeff - Does this next block of code that set's the protocol */
4651 /* need to be here anymore? 5/10/2000 */
4653 /* There are certain magic port numbers that when used require */
4654 /* the use of specific protocols. Check this now before we */
4655 /* set the SO_OOBINLINE state or we might get it wrong. */
4656 x = ntohs((unsigned short)service->s_port);
4658 /* See if the service is TELNET. */
4659 if (x == TELNET_PORT) {
4660 /* Yes, so if raw port not requested */
4662 /* Jeff 2005/12/30 */
4663 if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW &&
4664 ttnproto != NP_TLS_RAW && ttnproto != NP_NONE)
4666 /* fdc 2005/12/04 */
4667 if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
4668 #endif /* COMMENT */
4669 ttnproto = NP_TELNET; /* Select TELNET protocol. */
4672 else if (x == RLOGIN_PORT) {
4673 ttnproto = NP_RLOGIN;
4676 /* There is no good way to do this. If the user didn't tell */
4677 /* which one to use up front. We may guess wrong if the user */
4678 /* has both Kerberos versions installed and valid TGTs for each */
4679 else if (x == KLOGIN_PORT &&
4680 ttnproto != NP_K4LOGIN &&
4681 ttnproto != NP_K5LOGIN) {
4682 if (ck_krb5_is_installed() &&
4683 ck_krb5_is_tgt_valid())
4684 ttnproto = NP_K5LOGIN;
4685 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4686 ttnproto = NP_K4LOGIN;
4688 ttnproto = NP_K4LOGIN;
4689 } else if (x == EKLOGIN_PORT &&
4690 ttnproto != NP_EK4LOGIN &&
4691 ttnproto != NP_EK5LOGIN) {
4692 if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
4693 ttnproto = NP_EK5LOGIN;
4694 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4695 ttnproto = NP_EK4LOGIN;
4697 ttnproto = NP_EK4LOGIN;
4699 #endif /* CK_KERBEROS */
4700 #endif /* RLOGCODE */
4702 else if (x == KERMIT_PORT) { /* IKS uses Telnet protocol */
4703 if (ttnproto == NP_NONE)
4704 ttnproto = NP_KERMIT;
4706 #endif /* IKS_OPTION */
4710 The symbol SO_OOBINLINE is not known to Ultrix 2.0.
4711 It means "leave out of band data inline". The normal value is 0x0100,
4712 but don't try this on systems where the symbol is undefined.
4715 Note from Jeff Altman: 12/13/95
4716 In implementing rlogin protocol I have come to the conclusion that it is
4717 a really bad idea to read out-of-band data inline.
4718 At least Windows and OS/2 does not handle this well.
4719 And if you need to know that data is out-of-band, then it becomes
4720 absolutely pointless.
4722 Therefore, at least on OS2 and Windows (NT) I have changed the value of
4723 on to 0, so that out-of-band data stays out-of-band.
4726 Actually, OOB data should be read inline when possible. Especially with
4727 protocols that don't care about the Urgent flag. This is true with Telnet.
4728 With Rlogin, you need to be able to catch OOB data. However, the best
4729 way to do this is to set a signal handler on SIGURG. This isn't possible
4730 on OS/2 and Windows. But it is in UNIX. We will also need OOB data for
4731 FTP so better create a general mechanism.
4733 The reason for making OOB data be inline is that the standard ttinc/ttoc
4734 calls can be used for reading that data on UNIX systems. If we didn't
4735 have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
4740 if (ttnproto == NP_RLOGIN
4742 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4743 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4744 #endif /* CK_KERBEROS */
4747 #else /* TCPIPLIB */
4748 if (ttnproto == NP_RLOGIN
4750 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4751 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4752 #endif /* CK_KERBEROS */
4754 debug(F100,"Installing rlogoobh on SIGURG","",0);
4755 signal(SIGURG, rlogoobh);
4758 debug(F100,"Ignoring SIGURG","",0);
4759 signal(SIGURG, SIG_DFL);
4761 #endif /* TCPIPLIB */
4762 #endif /* RLOGCODE */
4765 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4768 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4771 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4774 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4777 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4781 Maybe this applies to all SVR4 versions, but the other (else) way has been
4782 compiling and working fine on all the others, so best not to change it.
4784 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4787 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4792 rc = setsockopt(ttyfd,
4798 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
4801 #ifdef VMS /* or, at least, VMS with gcc */
4802 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4805 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4807 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
4812 #endif /* SOLARIS */
4813 #endif /* MOTSV88R4 */
4817 #endif /* datageneral */
4818 #endif /* SO_OOBINLINE */
4824 no_delay(ttyfd,tcp_nodelay);
4825 #endif /* TCP_NODELAY */
4827 keepalive(ttyfd,tcp_keepalive);
4828 #endif /* SO_KEEPALIVE */
4830 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
4831 #endif /* SO_LINGER */
4833 sendbuf(ttyfd,tcp_sendbuf);
4834 #endif /* SO_SNDBUF */
4836 recvbuf(ttyfd,tcp_recvbuf);
4837 #endif /* SO_RCVBUF */
4838 #endif /* SOL_SOCKET */
4839 #endif /* datageneral */
4840 #endif /* NOTCPOPTS */
4843 /* Find out our own IP address. */
4844 /* We need the l_addr structure for [E]KLOGIN. */
4845 l_slen = sizeof(l_addr);
4846 bzero((char *)&l_addr, l_slen);
4848 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
4849 char * s = (char *)inet_ntoa(l_addr.sin_addr);
4850 ckstrncpy(myipaddr, s, 20);
4851 debug(F110,"getsockname",myipaddr,0);
4853 #endif /* EXCELAN */
4854 #endif /* datageneral */
4857 This is really only needed for Kerberos IV but is useful information in any
4858 case. If we connect to a name that is really a pool, we need to get the
4859 name of the machine we are actually connecting to for K4 to authenticate
4860 properly. This way we also update the names properly.
4862 However, it is a security hole when used with insecure DNS.
4864 Note: This does not work on Windows 95 or Windows NT 3.5x. This is because
4865 of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
4866 and Winsock 2.0 on those platforms. Their algorithm is:
4868 1. Check the HOSTENT cache.
4869 2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
4870 3. Do a DNS query if the DNS server is configured for name resolution.
4871 4. Do an additional NetBIOS remote adapter status to an IP address for its
4872 NetBIOS name table. This step is specific only to the Windows NT version
4873 3.51 implementation.
4875 The problem is the use of the HOSTENT cache. It means that gethostbyaddr()
4876 can not be used to resolve the real name of machine if it was originally
4877 accessed by an alias used to represent a cluster.
4879 if ((tcp_rdns && dns || tcp_rdns == SET_ON
4881 || tcp_rdns == SET_AUTO &&
4882 (ck_krb5_is_installed() || ck_krb4_is_installed())
4883 #endif /* CK_KERBEROS */
4886 && (tcp_http_proxy == NULL)
4889 && !(ssl_only_flag || tls_only_flag)
4897 printf(" Reverse DNS Lookup... ");
4900 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
4902 host = ck_copyhostent(host);
4903 debug(F100,"netopen gethostbyname != NULL","",0);
4909 if (!s) { /* This can happen... */
4910 debug(F100,"netopen host->h_name is NULL","",0);
4913 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
4914 /* The compiler says "Integral value implicitly converted to */
4915 /* pointer in assignment." The prototype is right there */
4916 /* in <arpa/inet.h> so what's the problem? */
4917 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
4918 if (!*s) { /* No name so substitute the address */
4919 debug(F100,"netopen host->h_name is empty","",0);
4920 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
4921 if (!s) /* Trust No 1 */
4923 if (*s) { /* If it worked, use this string */
4924 ckstrncpy(ipaddr,s,20);
4926 s = ipaddr; /* Otherwise stick with the IP */
4927 if (!*s) /* or failing that */
4928 s = namecopy; /* the name we were called with. */
4930 if (*s) { /* Copying into our argument? */
4931 ckstrncpy(name,s,80); /* Bad Bad Bad */
4932 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4933 ckstrncat(name,":",80-strlen(name));
4934 ckstrncat(name,svcbuf,80-strlen(name));
4942 printf(" %s connected on port %s\n",s,p);
4944 /* This is simply for testing the DNS entries */
4945 if (host->h_aliases) {
4946 char ** a = host->h_aliases;
4948 printf(" alias => %s\n",*a);
4952 #endif /* BETADEBUG */
4955 if (!quiet) printf("Failed.\n");
4957 } else if (!quiet) printf("(OK)\n");
4958 if (!quiet) fflush(stdout);
4960 /* This should already have been done but just in case */
4961 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4965 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
4967 if (tcp_http_proxy) {
4968 for (i=strlen(proxycopy); i >= 0 ; i--)
4969 if ( proxycopy[i] == ':' )
4970 proxycopy[i] = '\0';
4975 tcp_http_proxy ? proxycopy :
4977 (tcp_rdns && host && host->h_name && host->h_name[0]) ?
4978 (char *)host->h_name : (namecopy2[0] ? namecopy2 :
4979 (namecopy[0] ? namecopy : ipaddr)),
4984 #endif /* CK_SECURITY */
4986 if (ck_ssleay_is_installed()) {
4987 if (!ssl_tn_init(SSL_CLIENT)) {
4988 debug(F100,"netopen ssl_tn_init() failed","",0);
4989 if (bio_err!=NULL) {
4990 BIO_printf(bio_err,"ssl_tn_init() failed\n");
4991 ERR_print_errors(bio_err);
4994 fprintf(stderr,"ssl_tn_init() failed\n");
4995 ERR_print_errors_fp(stderr);
4997 if (tls_only_flag || ssl_only_flag) {
4998 debug(F100,"netopen ssl/tls required","",0);
5003 /* we will continue to accept the connection */
5004 /* without SSL or TLS support unless required. */
5005 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5006 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5007 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5008 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5009 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5010 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5011 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5012 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5013 } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
5014 debug(F100,"ck_ssl_outgoing() failed","",0);
5022 if (ttnproto == NP_RLOGIN
5024 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
5025 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
5026 #endif /* CK_KERBEROS */
5027 ) { /* Similar deal for rlogin */
5028 if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
5029 (CHAR *)host->h_name : (CHAR *)ipaddr),
5033 debug(F100,"rlogin initialization failed","",0);
5038 #endif /* RLOGCODE */
5039 if (tn_ini() < 0) { /* Start Telnet negotiations. */
5041 return(-1); /* Gone, so open failed. */
5049 if ( ttnproto == NP_K5U2U ) {
5050 if (k5_user_to_user_client_auth()) {
5055 #endif /* KRB5_U2U */
5056 #endif /* CK_KERBEROS */
5058 debug(F101,"netopen service","",svcnum);
5059 debug(F110,"netopen name",name,0);
5060 debug(F110,"netopen ipaddr",ipaddr,0);
5061 ckstrncpy(hostipaddr,ipaddr,63);
5063 if (lcl) if (*lcl < 0) /* Local mode. */
5065 #endif /* TCPSOCKET */
5066 return(0); /* Done. */
5069 /* N E T C L O S -- Close current network connection. */
5072 _PROTOTYP(VOID slrestor,(VOID));
5074 int tls_norestore = 0;
5076 #endif /* NOLOCAL */
5080 static int close_in_progress = 0;
5082 debug(F101,"netclos","",ttyfd);
5085 if (!tt_push_inited)
5087 #endif /* NETLEBUF */
5089 if (ttyfd == -1) /* Was open? */
5090 return(0); /* Wasn't. */
5092 if (close_in_progress)
5094 close_in_progress = 1; /* Remember */
5097 /* This function call should not be here since this is a direct call */
5098 /* from an I/O routine to a user interface level function. However, */
5099 /* the reality is that we do not have pure interfaces. If we ever */
5100 /* decide to clean this up the UI level should assign this function */
5101 /* via a pointer assignment. - Jeff 9/10/1999 */
5106 #endif /* NOLOCAL */
5108 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5110 if (ttyfd > -1) /* Was. */
5114 y = 1; /* Turn on nonblocking reads */
5115 z = socket_ioctl(ttyfd,FIONBIO,&y);
5116 debug(F111,"netclos FIONBIO","on",z);
5119 if (ttnproto == NP_TELNET) {
5120 if (!TELOPT_ME(TELOPT_LOGOUT)
5122 /* Jeff 2005/12/30 */
5124 && !ssl_raw_flag && !tls_raw_flag
5126 #endif /* COMMENT */
5128 /* Send LOGOUT option before close */
5129 if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
5130 TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
5131 /* It would be nice to call tn_wait but we can't */
5134 tn_push(); /* Place any waiting data into input*/
5138 if (ssl_active_flag) {
5140 BIO_printf(bio_err,"calling SSL_shutdown\n");
5141 SSL_shutdown(ssl_con);
5142 ssl_active_flag = 0;
5144 if (tls_active_flag) {
5146 BIO_printf(bio_err,"calling SSL_shutdown\n");
5147 SSL_shutdown(tls_con);
5148 tls_active_flag = 0;
5152 ck_cancio(); /* Cancel any outstanding reads. */
5155 x = socket_close(ttyfd); /* Close it. */
5159 if (ttnet == NET_IX25) {
5160 /* riehm: should send a disc_req - but only if link is still OK */
5164 /* we were the passive client of a server, now we
5165 * go back to being the normal client.
5166 * I hope that kermit can cope with the logic that
5167 * there can still be a connection after netclos
5170 ttyfd = x25serverfd;
5173 * need to close the server connection too - because
5174 * all file descriptors connected to the NPI have the
5177 * The problem is that any waiting connections get
5178 * lost, the client doesn't realise, and hangs.
5182 x25_state = X25_CLOSED; /* riehm: dead code? */
5187 #endif /* TCPIPLIB */
5189 ttyfd = -1; /* Mark it as closed. */
5192 ReleaseTCPIPMutex();
5196 fwdx_close_all(); /* Shut down any Forward X sockets */
5197 #endif /* CK_FORWARD_X */
5198 tn_reset(); /* The Reset Telnet Option table. */
5199 debug(F100,"netclose setting tn_init = 0","",0);
5200 tn_init = 0; /* Remember about telnet protocol... */
5201 sstelnet = 0; /* Client-side Telnet */
5203 *ipaddr = '\0'; /* Zero the IP address string */
5204 tcp_incoming = 0; /* No longer incoming */
5205 /* Don't reset ttnproto so that we can remember which protocol is in use */
5209 Empty the internal buffers so they won't be used as invalid input on
5210 the next connect attempt (rlogin).
5214 #endif /* TCPIPLIB */
5216 /* If we are automatically destroying Kerberos credentials on Close */
5219 if (krb4_autodel == KRB_DEL_CL) {
5220 extern struct krb_op_data krb_op;
5222 krb_op.cache = NULL;
5223 ck_krb4_destroy(&krb_op);
5227 if (krb5_autodel == KRB_DEL_CL) {
5228 extern struct krb_op_data krb_op;
5229 extern char * krb5_d_cc;
5231 krb_op.cache = krb5_d_cc;
5232 ck_krb5_destroy(&krb_op);
5235 #endif /* CK_KERBEROS */
5236 close_in_progress = 0; /* Remember we are done. */
5242 os2socketerror( int s_errno ) {
5244 if (s_errno > 0 && s_errno <= SOCBASEERR) {
5245 /* in OS/2, there is a problem with threading in that
5246 * the value of errno is not thread safe. It can be
5247 * set to a value from a previous library call and if
5248 * it was not cleared it will appear here. Only treat
5249 * valid socket error codes as errors in this function.
5251 debug(F100,"os2socketerror errno.h","",0);
5255 #endif /* OS2ONLY */
5258 case 0: /* NO ERROR */
5259 debug(F100,"os2socketerror NOERROR","",0);
5265 case SOCECONNRESET - SOCBASEERR:
5267 debug(F100,"os2socketerror ECONRESET","",0);
5268 tn_debug("ECONRESET");
5269 netclos(); /* *** *** */
5270 return(-1); /* Connection is broken. */
5272 case WSAECONNABORTED:
5274 case SOCECONNABORTED:
5275 case SOCECONNABORTED - SOCBASEERR:
5277 debug(F100,"os2socketerror ECONNABORTED","",0);
5278 tn_debug("ECONNABORTED");
5279 netclos(); /* *** *** */
5280 return(-1); /* Connection is broken. */
5285 case SOCENETRESET - SOCBASEERR:
5287 debug(F100,"os2socketerror ENETRESET","",0);
5288 tn_debug("ENETRESET");
5289 netclos(); /* *** *** */
5290 return(-1); /* Connection is broken. */
5295 case SOCENOTCONN - SOCBASEERR:
5297 debug(F100,"os2socketerror ENOTCONN","",0);
5298 tn_debug("ENOTCONN");
5299 netclos(); /* *** *** */
5300 return(-1); /* Connection is broken. */
5303 debug(F100,"os2socketerror ESHUTDOWN","",0);
5304 tn_debug("ESHUTDOWN");
5305 netclos(); /* *** *** */
5306 return(-1); /* Connection is broken. */
5309 case WSAEWOULDBLOCK:
5311 case SOCEWOULDBLOCK:
5312 case SOCEWOULDBLOCK - SOCBASEERR:
5314 debug(F100,"os2socketerror EWOULDBLOCK","",0);
5317 case ERROR_IO_INCOMPLETE:
5318 case ERROR_IO_PENDING:
5319 case ERROR_OPERATION_ABORTED:
5329 /* N E T T C H K -- Check if network up, and how many bytes can be read */
5331 Returns number of bytes waiting, or -1 if connection has been dropped.
5333 int /* Check how many bytes are ready */
5334 nettchk() { /* for reading from network */
5342 extern int ionoblock; /* For Overlapped I/O */
5345 debug(F101,"nettchk entry ttibn","",ttibn);
5346 debug(F101,"nettchk entry ttibp","",ttibp);
5357 #endif /* NETLEBUF */
5361 socket_errno = 0; /* This is a function call in NT, and BeOS */
5366 debug(F100,"nettchk socket is closed","",0);
5370 Note: this socket_ioctl() call does NOT return an error if the
5371 connection has been broken. (At least not in MultiNet.)
5374 /* Another trick that can be tried here is something like this: */
5376 if (ttnet == NET_TCPB) {
5378 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5379 if (x < 0) { /* "Connection reset by peer" */
5380 perror("TCP/IP"); /* or somesuch... */
5381 ttclos(0); /* Close our end too. */
5385 #endif /* COMMENT */
5389 if (ssl_active_flag) {
5392 if ( IsConnectMode() ) {
5393 debug(F101,"nettchk (ssl_active_flag) returns","",count);
5397 #endif /* IKSDONLY */
5398 count = SSL_pending(ssl_con);
5400 debug(F111,"nettchk","SSL_pending error",count);
5405 return(count); /* Don't perform a read */
5406 } else if (tls_active_flag) {
5409 if ( IsConnectMode() ) {
5410 debug(F101,"nettchk (tls_active_flag) returns","",count);
5414 #endif /* IKSDONLY */
5415 count = SSL_pending(tls_con);
5417 debug(F111,"nettchk","TLS_pending error",count);
5422 return(count); /* Don't perform a read */
5426 if (socket_ioctl(ttyfd,FIONREAD,
5428 /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
5430 /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
5431 /* Cast needed for DECC 4.1 & later? */
5432 /* Maybe, but __DECC_VER only exists in 5.0 and later */
5435 #endif /* COMMENT */
5438 debug(F101,"nettchk socket_ioctl error","",socket_errno);
5439 /* If the connection is gone, the connection is gone. */
5441 #ifdef NT_TCP_OVERLAPPED
5442 /* Is there anything in the overlapped I/O buffers? */
5443 count += OverlappedDataWaiting();
5444 #endif /* NT_TCP_OVERLAPPED */
5446 return(count>0?count:-1);
5448 debug(F101,"nettchk count","",count);
5449 #ifdef NT_TCP_OVERLAPPED
5450 /* Is there anything in the overlapped I/O buffers? */
5451 count += OverlappedDataWaiting();
5452 debug(F101,"nettchk count w/overlapped","",count);
5453 #endif /* NT_TCP_OVERLAPPED */
5457 if ( IsConnectMode() ) {
5458 debug(F101,"nettchk (FIONREAD) returns","",count);
5461 #endif /* IKSDONLY */
5464 /* For the sake of efficiency, if there is still data in the ttibuf */
5465 /* do not go to the bother of checking to see of the connection is */
5466 /* still valid. The handle is still good, so just return the count */
5467 /* of the bytes that we already have left to process. */
5469 if ( count > 0 || ttibn > 0 ) {
5471 debug(F101,"nettchk (count+ttibn > 0) returns","",count);
5474 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5476 ttibp = 0; /* reset for next read */
5479 if ( count > 0 || ttibn > 0 ) {
5480 debug(F101,"nettchk returns","",count+ttibn);
5481 return(count+ttibn);
5487 The following code works well in most settings, but messes things up in
5488 others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
5489 make it impossible to ever make a new connection to the same host again with
5490 CONNECT, once it has been logged out from the first time. Not even if you
5491 HANGUP first, or SET HOST<CR>, or SET LINE<CR>. Reportedly, however, it
5492 does work OK in later releases of UCX. But there is no way we can
5493 accommodate both old and new -- we might have static linking or dynamic
5494 linking, etc etc. If we have static, I only have access to 2.0, where this
5495 doesn't work, etc etc blah blah.
5497 In the following lines, we define a symbol NOCOUNT for builds where we want
5498 to omit this code. By default, it is omitted for CMU/Tek. You can force
5499 omission of it for other combinations by defining NOCOUNT in CFLAGS. You
5500 can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
5506 #endif /* NOCOUNT */
5511 #endif /* CMU_TCPIP */
5512 #endif /* NOCOUNT */
5513 #endif /* NONOCOUNT */
5516 /* From this point forward we have a possible race condition in K95
5517 * due to its use of multiple threads. Therefore, we must ensure
5518 * that only one thread attempt to read/write from the socket at a
5519 * time. Otherwise, it is possible for a buffer to be overwritten.
5521 /* we know now that count >= 0 and that ttibn == 0 */
5526 && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
5527 #endif /* CK_KERBEROS */
5528 #endif /* RLOGCODE */
5533 Here we need to tell the difference between a 0 count on an active
5534 connection, and a 0 count because the remote end of the socket broke the
5535 connection. There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
5536 the status of the connection, so we have to do a read. -1 means there was
5537 no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
5538 down. But if, by chance, we actually get a character, we have to put it
5539 where it won't be lost.
5541 #ifndef NON_BLOCK_IO
5544 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5547 y = 1; /* Turn on nonblocking reads */
5548 z = socket_ioctl(ttyfd,FIONBIO,&y);
5549 debug(F111,"nettchk FIONBIO","on",z);
5555 #endif /* NON_BLOCK_IO */
5556 #ifdef NT_TCP_OVERLAPPED
5557 ionoblock = 1; /* For Overlapped I/O */
5558 #endif /* NT_TCP_OVERLAPPED */
5560 if ( ssl_active_flag || tls_active_flag ) {
5563 x = SSL_read( ssl_active_flag?ssl_con:tls_con,
5564 &ttibuf[ttibp+ttibn],
5565 TTIBUFL-ttibp-ttibn );
5566 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
5567 case SSL_ERROR_NONE:
5568 debug(F111,"nettchk SSL_ERROR_NONE","x",x);
5570 case SSL_ERROR_WANT_WRITE:
5571 debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
5574 case SSL_ERROR_WANT_READ:
5575 debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
5578 case SSL_ERROR_SYSCALL:
5579 if ( x == 0 ) { /* EOF */
5582 goto nettchk_return;
5585 int gle = GetLastError();
5587 #ifndef NON_BLOCK_IO
5590 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5593 y = 0; /* Turn off nonblocking reads */
5594 z = socket_ioctl(ttyfd,FIONBIO,&y);
5595 debug(F111,"nettchk FIONBIO","off",z);
5601 #endif /* NON_BLOCK_IO */
5602 #ifdef NT_TCP_OVERLAPPED
5603 ionoblock = 0; /* For Overlapped I/O */
5604 #endif /* NT_TCP_OVERLAPPED */
5606 debug(F111,"nettchk SSL_ERROR_SYSCALL",
5607 "GetLastError()",gle);
5608 rc = os2socketerror(gle);
5611 else if ( rc == -2 )
5613 goto nettchk_return;
5617 case SSL_ERROR_WANT_X509_LOOKUP:
5618 debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
5621 if (bio_err!=NULL) {
5623 extern char ssl_err[];
5624 BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
5625 ERR_print_errors(bio_err);
5626 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
5627 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
5628 debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
5631 } else if (ssl_debug_flag) {
5632 debug(F100,"nettchk SSL_ERROR_SSL","",0);
5634 fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
5635 ERR_print_errors_fp(stderr);
5640 goto nettchk_return;
5645 case SSL_ERROR_ZERO_RETURN:
5646 debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
5649 goto nettchk_return;
5651 debug(F100,"nettchk SSL_ERROR_?????","",0);
5654 goto nettchk_return;
5664 x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
5665 TTIBUFL-ttibp-ttibn); /* Returns -1 if no data */
5667 x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */
5670 s_errno = socket_errno; /* socket_errno may be a function */
5671 debug(F101,"nettchk socket_read","",x);
5673 #ifndef NON_BLOCK_IO
5676 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5679 y = 0; /* Turn off nonblocking reads */
5680 z = socket_ioctl(ttyfd,FIONBIO,&y);
5681 debug(F111,"nettchk FIONBIO","off",z);
5687 #endif /* NON_BLOCK_IO */
5688 #ifdef NT_TCP_OVERLAPPED
5689 ionoblock = 0; /* For Overlapped I/O */
5690 #endif /* NT_TCP_OVERLAPPED */
5693 debug(F101,"nettchk socket_read errno","",s_errno);
5695 if (os2socketerror(s_errno) < 0) {
5697 goto nettchk_return;
5700 } else if (x == 0) {
5701 debug(F100,"nettchk connection closed","",0);
5702 netclos(); /* *** *** */
5704 goto nettchk_return;
5706 if (x >= 1) { /* Oops, actually got a byte? */
5708 /* In OS/2 we read directly into ttibuf[] */
5709 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5713 if ( ssl_active_flag || tls_active_flag ) {
5714 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5719 debug(F101,"nettchk socket_read char","",c);
5720 debug(F101,"nettchk ttibp","",ttibp);
5721 debug(F101,"nettchk ttibn","",ttibn);
5723 In the case of Overlapped I/O the character would have come from
5724 the beginning of the buffer, so put it back.
5731 ttibuf[ttibp+ttibn] = c;
5738 if (ttnet == NET_TCPB) {
5740 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5741 if (x < 0) { /* "Connection reset by peer" */
5742 perror("TCP/IP"); /* or somesuch... */
5743 ttclos(0); /* Close our end too. */
5745 goto nettchk_return;
5748 #endif /* NOCOUNT */
5753 if (ttnproto == NP_EK4LOGIN)
5754 count += krb4_des_avail(ttyfd);
5755 #endif /* RLOGCODE */
5759 if (ttnproto == NP_EK5LOGIN)
5760 count += krb5_des_avail(ttyfd);
5761 #endif /* RLOGCODE */
5763 if (ttnproto == NP_K5U2U)
5764 count += krb5_u2u_avail(ttyfd);
5765 #endif /* KRB5_U2U */
5767 #endif /* CK_KERBEROS */
5769 debug(F101,"nettchk returns","",count+ttibn);
5774 ReleaseTCPIPMutex();
5778 #else /* Not TCPIPLIB */
5780 UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
5784 #endif /* TCPIPLIB */
5786 But what about X.25?
5792 nettout(i) int i; { /* Catch the alarm interrupts */
5793 debug(F100,"nettout caught timeout","",0);
5795 cklongjmp(njbuf, -1);
5803 donetinc(void * threadinfo)
5804 #else /* CK_ANSIC */
5805 donetinc(threadinfo) VOID * threadinfo;
5806 #endif /* CK_ANSIC */
5809 extern int TlsIndex;
5811 if (threadinfo) { /* Thread local storage... */
5812 TlsSetValue(TlsIndex,threadinfo);
5822 #endif /* CK_LOGIN */
5824 if (ttbufr() < 0) /* Keep trying to refill it. */
5825 break; /* Till we get an error. */
5826 if (ttibn > 0) /* Or we get a character. */
5830 #endif /* TCPIPLIB */
5834 failnetinc(void * threadinfo)
5835 #else /* CK_ANSIC */
5836 failnetinc(threadinfo) VOID * threadinfo;
5837 #endif /* CK_ANSIC */
5839 ; /* Nothing to do on an error */
5842 /* N E T X I N -- Input block of characters from network */
5845 netxin(n,buf) int n; CHAR * buf; {
5849 #endif /* TCPIPLIB */
5852 debug(F100,"netxin socket is closed","",0);
5858 if (ttnproto == NP_EK4LOGIN) {
5859 if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
5864 #endif /* RLOGCODE */
5868 if (ttnproto == NP_EK5LOGIN) {
5869 if ((len = krb5_des_read(ttyfd,(char *)buf,n,0)) < 0)
5874 #endif /* RLOGCODE */
5876 if (ttnproto == NP_K5U2U) {
5877 if ((len = krb5_u2u_read(ttyfd,(char *)buf,n)) < 0)
5882 #endif /* KRB5_U2U */
5884 #endif /* CK_KERBEROS */
5888 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5891 if ((rc = ttbufr()) <= 0) {
5893 ReleaseTCPIPMutex();
5900 memcpy(buf,&ttibuf[ttibp],len); /* safe */
5904 memcpy(buf,&ttibuf[ttibp],n); /* safe */
5910 ReleaseTCPIPMutex();
5912 #else /* TCPIPLIB */
5913 for (i = 0; i < n; i++) {
5914 if ((j = netinc(0)) < 0) {
5923 #endif /* TCPIPLIB */
5926 #ifdef CK_ENCRYPTION
5927 /* This would be great if it worked. But what if the buffer we read */
5928 /* contains a telnet negotiation that changes the state of the */
5929 /* encryption. If so, we would be either decrypting unencrypted text */
5930 /* or not decrypting encrypted text. So we must move this call to */
5931 /* all functions that call ttxin(). In OS2 that means os2_netxin() */
5932 /* where the Telnet Negotiations are handled. */
5934 ck_tn_decrypt(buf,len);
5935 #endif /* CK_ENCRYPTION */
5936 #endif /* COMMENT */
5941 /* N E T I N C -- Input character from network */
5945 #endif /* NETLEBUF */
5948 #endif /* TTLEBUF */
5956 netinc(timo) int timo; {
5958 int x; unsigned char c; /* The locals. */
5962 debug(F111,"netinc","ttpush",ttpush);
5968 if (le_getchar((CHAR *)&c) > 0) {
5969 debug(F111,"netinc le_getchar","c",c);
5973 #endif /* NETLEBUF */
5976 debug(F100,"netinc socket is closed","",0);
5983 if (ttnproto == NP_EK4LOGIN) {
5984 if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
5991 #endif /* RLOGCODE */
5995 if (ttnproto == NP_EK5LOGIN) {
5996 if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
6003 #endif /* RLOGCODE */
6005 if (ttnproto == NP_K5U2U) {
6006 if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
6013 #endif /* KRB5_U2U */
6015 #endif /* CK_KERBEROS */
6018 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6020 if (ttibn > 0) { /* Something in internal buffer? */
6022 debug(F100,"netinc char in buf","",0); /* Yes. */
6023 #endif /* COMMENT */
6024 x = 0; /* Success. */
6025 } else { /* Else must read from network. */
6026 x = -1; /* Assume failure. */
6028 debug(F101,"netinc goes to net, timo","",timo);
6032 * In the case of OpenSSL, it is possible that there is still
6033 * data waiting in the SSL session buffers that has not yet
6034 * been read by Kermit. If this is the case we must process
6035 * it without calling select() because select() will not return
6036 * with an indication that there is data to be read from the
6037 * socket. If there is no data pending in the SSL session
6038 * buffers then fall through to the select() code and wait for
6039 * some data to arrive.
6041 if (ssl_active_flag) {
6042 x = SSL_pending(ssl_con);
6044 debug(F111,"netinc","SSL_pending error",x);
6047 ReleaseTCPIPMutex();
6050 } else if ( x > 0 ) {
6051 if ( ttbufr() >= 0 ) {
6054 ReleaseTCPIPMutex();
6060 } else if (tls_active_flag) {
6061 x = SSL_pending(tls_con);
6063 debug(F111,"netinc","TLS_pending error",x);
6066 ReleaseTCPIPMutex();
6069 } else if ( x > 0 ) {
6070 if ( ttbufr() >= 0 ) {
6073 ReleaseTCPIPMutex();
6082 if (timo == 0) { /* Untimed case. */
6083 while (1) { /* Wait forever if necessary. */
6084 if (ttbufr() < 0) /* Refill buffer. */
6085 break; /* Error, fail. */
6086 if (ttibn > 0) { /* Success. */
6091 } else /* Timed case... */
6094 #ifdef NT_TCP_OVERLAPPED
6095 /* This code is for use on NT when we are using */
6096 /* Overlapped I/O to handle reads. In the case */
6097 /* of outstanding reads select() doesn't work */
6099 if (WaitForOverlappedReadData(timo)) {
6101 if (ttbufr() < 0) /* Keep trying to refill it. */
6102 break; /* Till we get an error. */
6103 if (ttibn > 0) { /* Or we get a character. */
6109 #else /* NT_TCP_OVERLAPPED */
6113 int timeout = timo < 0 ? -timo : 1000 * timo;
6114 debug(F101,"netinc BSDSELECT","",timo);
6116 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6118 debug(F111,"netinc","timeout",timeout);
6119 /* Don't move select() initialization out of the loop. */
6121 FD_SET(ttyfd, &rfds);
6122 tv.tv_sec = tv.tv_usec = 0L;
6124 tv.tv_usec = (long) 100000L;
6128 WSASafeToCancel = 1;
6130 rc = select(FD_SETSIZE,
6134 #else /* def INTSELECT */
6136 #endif /* def INTSELECT [else] */
6137 #else /* def __DECC */
6139 #endif /* def __DECC [else] */
6140 &rfds, NULL, NULL, &tv);
6142 int s_errno = socket_errno;
6143 debug(F111,"netinc","select",rc);
6144 debug(F111,"netinc","socket_errno",s_errno);
6147 ReleaseTCPIPMutex();
6152 debug(F111,"netinc","select",rc);
6154 WSASafeToCancel = 0;
6156 if (!FD_ISSET(ttyfd, &rfds)) {
6158 if (le_inbuf() > 0) {
6163 /* If waiting forever we have no way of knowing if the */
6164 /* socket closed so try writing a 0-length TCP packet */
6165 /* which should force an error if the socket is closed */
6167 if ((rc = socket_write(ttyfd,"",0)) < 0) {
6168 int s_errno = socket_errno;
6169 debug(F101,"netinc socket_write error","",s_errno);
6171 if (os2socketerror(s_errno) < 0) {
6172 ReleaseTCPIPMutex();
6175 ReleaseTCPIPMutex();
6177 return(-1); /* Call it an i/o error */
6183 if (ttbufr() < 0) { /* Keep trying to refill it. */
6185 break; /* Till we get an error. */
6187 if (ttibn > 0) { /* Or we get a character. */
6195 WSASafeToCancel = 0;
6197 #else /* !BSDSELECT */
6200 Was used by OS/2, currently not used, but might come in handy some day...
6201 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
6202 and timeval stuff since this is the only place where it is used.
6205 int timeout = timo < 0 ? -timo : 1000 * timo;
6207 debug(F101,"netinc IBMSELECT","",timo);
6208 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6209 if (select(&socket, 1, 0, 0, 100L) == 1) {
6211 if (ttbufr() < 0) { /* Keep trying to refill it. */
6213 break; /* Till we get an error. */
6215 if (ttibn > 0) { /* Or we get a character. */
6223 else if (le_inbuf() > 0) {
6229 #else /* !IBMSELECT */
6231 /* Actually, under WinSock we have a better mechanism than select() */
6232 /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
6233 SOCKET socket = ttyfd;
6234 debug(F101,"netinc NTSELECT","",timo);
6235 if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
6236 sizeof(timo)) == NO_ERROR)
6238 if (ttbufr() < 0) /* Keep trying to refill it. */
6239 break; /* Till we get an error. */
6240 if (ttibn > 0) { /* Or we get a character. */
6247 If we can't use select(), then we use the regular alarm()/signal()
6250 debug(F101,"netinc alarm","",timo);
6251 x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
6252 ttimoff(); /* Timer off. */
6253 #endif /* WINSOCK */
6254 #endif /* IBMSELECT */
6255 #endif /* BSDSELECT */
6256 #endif /* NT_TCP_OVERLAPPED */
6261 if (le_inbuf() > 0) { /* If data was inserted into the */
6262 if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the */
6263 #ifdef OS2 /* was taking place do not mix */
6264 ReleaseTCPIPMutex(); /* the le data with the net data */
6270 if (x < 0) { /* Return -1 if we failed. */
6271 debug(F100,"netinc timed out","",0);
6273 ReleaseTCPIPMutex();
6276 } else { /* Otherwise */
6277 c = ttibuf[ttibp]; /* Return the first char in ttibuf[] */
6280 debug(F101,"netinc returning","",c);
6281 #endif /* COMMENT */
6283 debug(F101,"netinc 0 ttibn","",ttibn);
6284 debug(F101,"netinc 0 ttibp","",ttibp);
6288 extern int tt_type_mode;
6289 if ( !ISVTNT(tt_type_mode) )
6291 ckhexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
6293 #endif /* BETADEBUG */
6299 ReleaseTCPIPMutex();
6301 #ifdef CK_ENCRYPTION
6302 if (TELOPT_U(TELOPT_ENCRYPTION))
6303 ck_tn_decrypt(&c,1);
6304 #endif /* CK_ENCRYPTION */
6307 #else /* Not using TCPIPLIB */
6309 #endif /* TCPIPLIB */
6312 /* N E T T O L -- Output a string of bytes to the network */
6314 Call with s = pointer to string, n = length.
6315 Returns number of bytes actually written on success, or
6316 -1 on i/o error, -2 if called improperly.
6320 nettol(s,n) CHAR *s; int n; {
6327 debug(F100,"nettol socket is closed","",0);
6330 debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
6332 ckhexdump("nettol",s,n);
6333 #endif /* COMMENT */
6338 if (ttnproto == NP_EK4LOGIN) {
6339 return(krb4_des_write(ttyfd,s,n));
6341 #endif /* RLOGCODE */
6345 if (ttnproto == NP_EK5LOGIN) {
6346 return(krb5_des_write(ttyfd,s,n,0));
6348 #endif /* RLOGCODE */
6350 if (ttnproto == NP_K5U2U) {
6351 return(krb5_u2u_write(ttyfd,s,n));
6353 #endif /* KRB5_U2U */
6355 #endif /* CK_KERBEROS */
6357 #ifdef CK_ENCRYPTION
6358 if (TELOPT_ME(TELOPT_ENCRYPTION))
6360 #endif /* CK_ENCRYPTION */
6363 if (ssl_active_flag || tls_active_flag) {
6365 /* Write using SSL */
6367 if (ssl_active_flag)
6368 r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
6370 r = SSL_write(tls_con, s, len /* >1024?1024:len */);
6371 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
6372 case SSL_ERROR_NONE:
6373 debug(F111,"nettol","SSL_write",r);
6379 case SSL_ERROR_WANT_WRITE:
6380 debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
6382 case SSL_ERROR_WANT_READ:
6383 debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
6385 case SSL_ERROR_SYSCALL:
6386 if ( r == 0 ) { /* EOF */
6392 int gle = GetLastError();
6393 debug(F111,"nettol SSL_ERROR_SYSCALL",
6394 "GetLastError()",gle);
6395 rc = os2socketerror(gle);
6398 else if ( rc == -2 )
6403 case SSL_ERROR_WANT_X509_LOOKUP:
6404 debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
6408 debug(F100,"nettol SSL_ERROR_SSL","",0);
6409 if (bio_err!=NULL) {
6411 extern char ssl_err[];
6412 BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
6413 ERR_print_errors(bio_err);
6414 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6415 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6416 debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
6419 } else if (ssl_debug_flag) {
6420 debug(F100,"nettol SSL_ERROR_SSL","",0);
6422 fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
6423 ERR_print_errors_fp(stderr);
6431 case SSL_ERROR_ZERO_RETURN:
6432 debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
6436 debug(F100,"nettol SSL_ERROR_?????","",0);
6444 try++; /* Increase the try counter */
6446 if (ttnet == NET_TCPB) {
6451 debug(F101,"nettol BSDSELECT","",0);
6455 WSASafeToCancel = 1;
6459 #endif /* STREAMING */
6461 FD_SET(ttyfd, &wfds);
6462 if (select(FD_SETSIZE, NULL,
6466 #endif /* __DECC_VER */
6468 &wfds, NULL, &tv) < 0) {
6469 int s_errno = socket_errno;
6470 debug(F101,"nettol select failed","",s_errno);
6472 printf("nettol select failed: %d\n", s_errno);
6473 #endif /* BETADEBUG */
6475 WSASafeToCancel = 0;
6476 if (!win95selectbug)
6480 if (!FD_ISSET(ttyfd, &wfds)) {
6484 #endif /* STREAMING */
6485 debug(F111,"nettol","!FD_ISSET",ttyfd);
6487 WSASafeToCancel = 0;
6488 if (!win95selectbug)
6493 WSASafeToCancel = 0;
6495 #else /* BSDSELECT */
6499 debug(F101,"nettol IBMSELECT","",0);
6500 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6502 if (tries++ >= 60) {
6503 /* if after 60 seconds we can't get permission to write */
6504 debug(F101,"nettol select failed","",socket_errno);
6507 if ((count = nettchk()) < 0) {
6508 debug(F111,"nettol","nettchk()",count);
6513 #endif /* IBMSELECT */
6514 #endif /* BSDSELECT */
6515 if ((count = socket_write(ttyfd,s,n)) < 0) {
6516 int s_errno = socket_errno; /* maybe a function */
6517 debug(F101,"nettol socket_write error","",s_errno);
6519 if (os2socketerror(s_errno) < 0)
6522 return(-1); /* Call it an i/o error */
6525 debug(F111,"nettol socket_write",s,count);
6527 /* don't try more than 25 times */
6528 debug(F100,"nettol tried more than 25 times","",0);
6535 debug(F111,"nettol retry",s,n);
6538 debug(F111,"nettol socket_write",s,count);
6539 return(len); /* success - return total length */
6544 debug(F100,"nettol TCPIPLIB not defined","",0);
6546 #endif /* TCPIPLIB */
6549 /* N E T T O C -- Output character to network */
6551 Call with character to be transmitted.
6552 Returns 0 if transmission was successful, or
6553 -1 upon i/o error, or -2 if called improperly.
6560 #endif /* CK_ANSIC */
6568 debug(F100,"nettoc socket is closed","",0);
6572 debug(F101,"nettoc cc","",cc);
6577 if (ttnproto == NP_EK4LOGIN) {
6578 return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
6580 #endif /* RLOGCODE */
6584 if (ttnproto == NP_EK5LOGIN) {
6585 return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
6587 #endif /* RLOGCODE */
6589 if (ttnproto == NP_K5U2U) {
6590 return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
6592 #endif /* KRB5_U2U */
6594 #endif /* CK_KERBEROS */
6596 #ifdef CK_ENCRYPTION
6597 if ( TELOPT_ME(TELOPT_ENCRYPTION) )
6598 ck_tn_encrypt(&cc,1);
6599 #endif /* CK_ENCRYPTION */
6601 if (ssl_active_flag || tls_active_flag) {
6603 /* Write using SSL */
6605 if (ssl_active_flag)
6606 len = SSL_write(ssl_con, &cc, 1);
6608 len = SSL_write(tls_con, &cc, 1);
6609 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
6610 case SSL_ERROR_NONE:
6611 debug(F111,"nettoc","SSL_write",len);
6612 return(len == 1 ? 0 : -1);
6613 case SSL_ERROR_WANT_WRITE:
6614 case SSL_ERROR_WANT_READ:
6616 case SSL_ERROR_SYSCALL:
6617 if ( len == 0 ) { /* EOF */
6623 int gle = GetLastError();
6624 debug(F111,"nettoc SSL_ERROR_SYSCALL",
6625 "GetLastError()",gle);
6626 rc = os2socketerror(gle);
6629 else if ( rc == -2 )
6635 if (bio_err!=NULL) {
6637 extern char ssl_err[];
6638 BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
6639 ERR_print_errors(bio_err);
6640 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6641 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6642 debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
6645 } else if (ssl_debug_flag) {
6646 debug(F100,"nettoc SSL_ERROR_SSL","",0);
6648 fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
6649 ERR_print_errors_fp(stderr);
6653 case SSL_ERROR_WANT_X509_LOOKUP:
6654 case SSL_ERROR_ZERO_RETURN:
6661 if (ttnet == NET_TCPB) {
6666 debug(F101,"nettoc BSDSELECT","",0);
6672 #endif /* STREAMING */
6675 FD_SET(ttyfd, &wfds);
6676 if (select(FD_SETSIZE, NULL,
6680 #endif /* __DECC_VER */
6682 &wfds, NULL, &tv) < 0) {
6683 int s_errno = socket_errno;
6684 debug(F101,"nettoc select failed","",s_errno);
6686 printf("nettoc select failed: %d\n", s_errno);
6687 #endif /* BETADEBUG */
6689 WSASafeToCancel = 0;
6690 if (!win95selectbug)
6694 if (!FD_ISSET(ttyfd, &wfds)) {
6698 #endif /* STREAMING */
6699 debug(F111,"nettoc","!FD_ISSET",ttyfd);
6701 WSASafeToCancel = 0;
6702 if (!win95selectbug)
6707 WSASafeToCancel = 0;
6709 #else /* BSDSELECT */
6713 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6715 if (tries++ >= 60) {
6716 /* if after 60 seconds we can't get permission to write */
6717 debug(F101,"nettoc select failed","",socket_errno);
6720 if ((count = nettchk()) < 0) {
6721 debug(F111,"nettoc","nettchk()",count);
6726 #endif /* IBMSELECT */
6727 #endif /* BSDSELECT */
6728 if (socket_write(ttyfd,&cc,1) < 1) {
6729 int s_errno = socket_errno; /* maybe a function */
6730 debug(F101,"nettoc socket_write error","",s_errno);
6732 if (os2socketerror(s_errno) < 0)
6737 debug(F101,"nettoc socket_write","", cc);
6742 #endif /* TCPIPLIB */
6746 /* N E T F L U I -- Flush network input buffer */
6751 netgetc(int timo) /* Input function to point to... */
6752 #else /* CK_ANSIC */
6753 netgetc(timo) int timo;
6754 #endif /* CK_ANSIC */
6755 { /* ...in the tn_doop() call */
6757 return netinc(timo);
6758 #else /* TCPIPLIB */
6760 #endif /* TCPIPLIB */
6769 ttpush = -1; /* Clear the peek-ahead char */
6770 while (le_data && (le_inbuf() > 0)) {
6772 if (le_getchar(&ch) > 0) {
6773 debug(F101,"ttflui le_inbuf ch","",ch);
6776 #endif /* NETLEBUF */
6780 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6783 if (ttnproto == NP_TELNET) {
6784 /* Netflui must process Telnet negotiations or get out of sync */
6785 if ((n = nettchk()) <= 0)
6790 extern int duplex; /* this really shouldn't be here but ... */
6791 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6792 if (tx == 1) duplex = 1;
6793 else if (tx == 2) duplex = 0;
6800 ttibuf[ttibp+ttibn] = '\0';
6801 debug(F111,"netflui 1",ttibuf,ttibn);
6802 #ifdef CK_ENCRYPTION
6803 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6804 ck_tn_decrypt(&ttibuf[ttibp],ttibn);
6806 #endif /* CK_ENCRYPTION */
6807 ttibn = ttibp = 0; /* Flush internal buffer *FIRST* */
6810 if ((n = nettchk()) > 0) { /* Now see what's waiting on the net */
6811 if (n > TTIBUFL) n = TTIBUFL; /* and sponge it up */
6812 debug(F101,"netflui 2","",n); /* ... */
6813 n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
6814 if (n >= 0) ttibuf[n] = '\0';
6815 debug(F111,"netflui 3",ttibuf,n);
6816 #ifdef CK_ENCRYPTION
6817 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6818 ck_tn_decrypt(&ttibuf[ttibp],n);
6820 #endif /* CK_ENCRYPTION */
6824 #else /* !TCPIPLIB */
6828 if (ttnproto == NP_TELNET) {
6829 if ((n = ttchk()) <= 0)
6832 /* Netflui must process Telnet negotiations or get out of sync */
6835 extern int duplex; /* this really shouldn't be here but ... */
6836 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6837 if (tx == 1) duplex = 1;
6838 else if (tx == 2) duplex = 0;
6844 if ((n = ttchk()) > 0) {
6845 debug(F101,"netflui non-TCPIPLIB","",n);
6846 while ((n--) && ttinc(1) > -1) /* Don't worry, ttinc() is buffered */
6847 ; /* and it handles the decryption... */
6849 #endif /* TCPIPLIB */
6852 ReleaseTCPIPMutex();
6858 /* The following two functions are required for encrypted rlogin */
6859 /* They are called with nettoc() or nettol() are transmitting */
6860 /* encrypted data. They call a function to encrypt the data */
6861 /* and that function needs to be able to write to/read from the */
6862 /* network in an unimpeded manner. Hence, these two simple fns. */
6864 net_write(fd, buf, len)
6866 register const char *buf;
6870 register int wrlen = len;
6873 cc = socket_write(fd, buf, wrlen);
6875 cc = write(fd,buf,wrlen);
6876 #endif /* TCPIPLIB */
6878 int s_errno = socket_errno;
6879 debug(F101,"net_write error","",s_errno);
6881 if (os2socketerror(s_errno) < 0)
6895 } while (wrlen > 0);
6899 net_read(fd, buf, len)
6908 cc = socket_read(fd, buf, len);
6910 cc = read(fd,buf,len);
6913 int s_errno = socket_errno;
6914 debug(F101,"net_read error","",s_errno);
6916 if (os2socketerror(s_errno) < 0)
6919 return(cc); /* errno is already set */
6932 #endif /* CK_KERBEROS */
6935 /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
6936 * If the host is multi-homed it returns only one address.
6938 * Two techniques are used.
6939 * (1) get the local host name and perform a DNS lookup, then take
6941 * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
6942 * no data is sent), then retrieve the local address from the socket.
6943 * Note: the second technique won't work on Microsoft systems. See
6944 * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
6947 /* Technique number one cannot work reliably if the machine is a laptop
6948 * and the hostname is associated with a physical adapter which is not
6949 * installed and a PPP connection is being used instead. This is because
6950 * the hostname DNS lookup will succeed for the physical adapter even though
6951 * it would be impossible to use it. In NT4 SP4, the gethostbyname()
6952 * when given the result of gethostname() returns not the real DNS entries
6953 * for that name+domain. Instead it returns all of the static and dynamic
6954 * IP addresses assigned to any physical or virtual adapter defined in the
6955 * system regardless of whether or not it is installed. The order of the
6956 * addresses is fixed according to the binding order in the NT registry.
6960 * It appears that calling gethostbyname(NULL) is more reliable than
6961 * calling gethostbyname(gethostname()) on Windows. So on Windows we will
6962 * only call gethostbyname(NULL).
6968 struct sockaddr_in l_sa;
6969 struct sockaddr_in r_sa;
6970 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6973 struct in_addr laddr;
6975 /* if still not resolved, then try second strategy */
6976 /* This second strategy does not work on Windows */
6978 debug(F100,"getlocalipaddr","",0);
6979 memset(&l_sa,0,slen);
6980 memset(&r_sa,0,slen);
6982 /* get a UDP socket */
6983 sock = socket(AF_INET, SOCK_DGRAM, 0);
6985 /* connect to arbirary port and address (NOT loopback) */
6986 r_sa.sin_family = AF_INET;
6987 r_sa.sin_port = htons(IPPORT_ECHO);
6989 /* The following is an "illegal conversion" in AOS/VS */
6990 /* (and who knows where else) */
6993 inaddrx = inet_addr("128.127.50.1");
6994 r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
6996 r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
6997 #endif /* INADDRX */
6998 rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
6999 if (!rc) { /* get local address */
7000 getsockname(sock,(struct sockaddr *)&l_sa,&slen);
7002 socket_close(sock); /* We're done with the socket */
7005 #endif /* TCPIPLIB */
7006 if (l_sa.sin_addr.s_addr != INADDR_ANY) {
7007 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
7008 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
7009 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
7014 return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
7015 #else /* datageneral */
7017 #endif /* datageneral */
7021 getlocalipaddrs(buf,bufsz,index)
7025 /* getlocalipaddrs */ {
7027 char localhost[256];
7028 struct hostent * host=NULL;
7029 struct sockaddr_in l_sa;
7030 struct sockaddr_in r_sa;
7031 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
7035 char messageBuf[60];
7036 struct in_addr laddr;
7037 #endif /* COMMENT */
7039 debug(F100,"getlocalipaddrs","",0);
7040 memset(&l_sa,0,slen);
7041 memset(&r_sa,0,slen);
7043 /* init local address (to zero) */
7044 l_sa.sin_addr.s_addr = INADDR_ANY;
7047 rc = gethostname(localhost, 256);
7048 debug(F110,"getlocalipaddrs localhost",localhost,0);
7050 /* This doesn't work on some platforms, e.g. Solaris */
7052 localhost[0] = '\0';
7054 if ( winsock_version < 20 ) {
7055 rc = gethostname(localhost, 256);
7056 debug(F110,"getlocalipaddrs localhost",localhost,0);
7059 #endif /* CKGHNLHOST */
7061 /* resolve host name for local address */
7062 debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
7063 host = gethostbyname(localhost);
7064 /* debug(F111,"getlocalipaddrs","gethostbyname() returned",host); */
7067 host = ck_copyhostent(host);
7068 if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
7072 l_sa.sin_addr.s_addr =
7073 *((unsigned long *) (host->h_addr_list[index]));
7074 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
7075 debug(F110,"getlocalipaddrs setting buf to",buf,0);
7078 /* This is for reporting multiple IP Address */
7079 while (host->h_addr_list && host->h_addr_list[0]) {
7080 l_sa.sin_addr.s_addr =
7081 *((unsigned long *) (host->h_addr_list[0]));
7082 ckstrncpy(messageBuf,
7083 (char *)inet_ntoa(l_sa.sin_addr),60);
7085 if (!strcmp(messageBuf,tcp_address))
7086 ckstrncpy(myipaddr,tcp_address,20);
7088 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
7089 host->h_addr_list++;
7091 #endif /* COMMENT */
7092 #else /* HADDRLIST */
7097 l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
7098 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
7099 debug(F110,"getlocalipaddrs setting buf to",buf,0);
7100 #endif /* HADDRLIST */
7103 "getlocalipaddrs: gethostbyname() failed",
7108 #endif /* datageneral */
7112 #ifdef RLOGCODE /* TCP/IP RLOGIN protocol support code */
7116 unsigned char id[4];
7117 unsigned short rows, cols, ypix, xpix;
7120 if (ttnet != NET_TCPB)
7122 if (ttnproto != NP_RLOGIN
7124 && ttnproto != NP_K4LOGIN
7125 && ttnproto != NP_EK4LOGIN
7126 && ttnproto != NP_K5LOGIN
7127 && ttnproto != NP_EK5LOGIN
7128 #endif /* CK_KERBEROS */
7131 if (!TELOPT_ME(TELOPT_NAWS))
7134 debug(F100,"rlogin Window Size sent","",0);
7136 nawsbuf.id[0] = nawsbuf.id[1] = 0377;
7137 nawsbuf.id[2] = nawsbuf.id[3] = 's';
7139 nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
7140 -(tt_status[VTERM]?1:0)));
7141 nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
7143 nawsbuf.rows = htons((unsigned short) tt_rows);
7144 nawsbuf.cols = htons((unsigned short) tt_cols);
7146 nawsbuf.ypix = htons(0); /* y pixels */
7148 nawsbuf.xpix = htons(0); /* x pixels */
7149 if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
7159 rlog_ini(CHAR * hostname, int port,
7160 struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
7161 #else /* CK_ANSIC */
7162 rlog_ini(hostname, port, l_addr, r_addr)
7165 struct sockaddr_in * l_addr;
7166 struct sockaddr_in * r_addr;
7167 #endif /* CK_ANSIC */
7173 #endif /* RLOGOUTBUF */
7176 #define CONSPDLEN 16
7177 CHAR localuser[UIDBUFLEN+1];
7178 CHAR remoteuser[UIDBUFLEN+1];
7180 CHAR term_speed[TERMLEN+CONSPDLEN+1];
7183 #endif /* CONGSPD */
7185 extern int tt_type, max_tt;
7186 extern struct tt_info_rec tt_info[];
7191 tn_reset(); /* This call will reset all of the Telnet */
7192 /* options and then quit. We need to do */
7193 /* this since we use the Telnet options */
7194 /* to hold various state information */
7195 duplex = 0; /* Rlogin is always remote echo */
7200 But compute the values anyway before the first read since the out-
7201 of-band NAWS request would arrive before the first data byte (NULL).
7204 /* Console terminal screen rows and columns */
7205 debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
7206 -(tt_status[VTERM]?1:0));
7207 debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
7209 if (VscrnGetWidth(VTERM) < 0 ||
7210 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
7211 ttgwsiz(); /* Try to get screen dimensions */
7214 "rlog_ini tt_rows 2",
7216 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
7218 debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
7220 debug(F101,"rlog_ini tt_rows 1","",tt_rows);
7221 debug(F101,"rlog_ini tt_cols 1","",tt_cols);
7222 if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */
7223 ttgwsiz(); /* Try to find out */
7225 debug(F101,"rlog_ini tt_rows 2","",tt_rows);
7226 debug(F101,"rlog_ini tt_cols 2","",tt_cols);
7228 #endif /* CK_TTGWSIZ */
7230 ttflui(); /* Start by flushing the buffers */
7232 rlog_mode = RL_COOKED;
7234 /* Determine the user's local username ... */
7236 localuser[0] = '\0';
7239 char localuid[UIDBUFLEN+1];
7240 ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
7243 if ( !localuser[0] )
7246 char * user = getenv("USER");
7249 userlen = strlen(user);
7250 debug(F111,"rlogin getenv(USER)",user,userlen);
7251 ckstrncpy((char *)localuser,user,UIDBUFLEN);
7252 debug(F110,"rlog_ini localuser 1",localuser,0);
7254 if ( !localuser[0] )
7255 strcpy((char *)localuser,"unknown");
7256 else if (ck_lcname) {
7257 cklower((char *)localuser);
7258 debug(F110,"rlog_ini localuser 2",localuser,0);
7261 /* And the username to login with */
7263 ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
7264 debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
7265 } else if (localuser[0]) {
7266 ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
7267 debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
7269 remoteuser[0] = '\0';
7270 debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
7273 cklower((char *)remoteuser);
7274 debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
7276 /* The command to issue is the terminal type and speed */
7277 term_speed[0] = '\0';
7278 if (tn_term) { /* SET TELNET TERMINAL-TYPE value */
7279 if (*tn_term) { /* (if any) takes precedence. */
7280 ckstrncpy((char *)term_speed, tn_term, TERMLEN);
7283 } else { /* Otherwise the local terminal type */
7285 /* In terminal-emulating versions, it's the SET TERM TYPE value */
7286 ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
7287 tt_info[tt_type].x_name : "network", TERMLEN);
7289 /* In the others, we just look at the TERM environment variable */
7291 char *p = getenv("TERM");
7293 ckstrncpy((char *)term_speed,p,TERMLEN);
7295 term_speed[0] = '\0';
7297 for (p = (char *) term_speed; *p; p++) {
7298 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
7300 else if (isupper(*p))
7308 n = strlen((char *)term_speed);
7309 if (n > 0) { /* We have a terminal type */
7310 if (!flag) { /* If not user-specified */
7311 for (i = 0; i < n; i++) /* then lowercase it. */
7312 if (isupper(term_speed[i]))
7313 term_speed[i] = tolower(term_speed[i]);
7315 debug(F110,"rlog_ini term_speed 1",term_speed,0);
7318 /* conspd() is not yet defined in all ck*tio.c modules */
7321 ckstrncat((char *)term_speed,"/",sizeof(term_speed));
7322 ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
7324 #endif /* CONGSPD */
7325 ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
7326 debug(F110,"rlog_ini term_speed 2",term_speed,0);
7328 term_speed[0] = '\0';
7329 debug(F110,"rlog_ini term_speed 3",term_speed,0);
7333 if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
7334 ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
7335 int kver, encrypt, rc;
7357 rc = ck_krb_rlogin(hostname, port,
7358 localuser, remoteuser, term_speed,
7359 l_addr, r_addr, kver, encrypt);
7360 if (!rc) { /* success */
7361 TELOPT_ME(TELOPT_NAWS) = 1;
7366 #endif /* CK_KERBEROS */
7367 if (ttnproto == NP_RLOGIN) {
7370 * The rcmds start the connection with a series of init data:
7372 * a port number upon which client is listening for stderr data
7373 * the user's name on the client machine
7374 * the user's name on the server machine
7375 * the terminal_type/speed or command to execute
7377 outbuf[outbytes++] = 0;
7378 strcpy((char *)outbuf+outbytes,(char *)localuser);
7379 outbytes += strlen((char *)localuser) + 1;
7380 strcpy((char *)outbuf+outbytes,(char *)remoteuser);
7381 outbytes += strlen((char *)remoteuser) + 1;
7382 strcpy((char *)outbuf+outbytes,(char *)term_speed);
7383 outbytes += strlen((char *)term_speed) + 1;
7384 rc = ttol((CHAR *)outbuf,outbytes);
7385 #else /* RLOGOUTBUF */
7386 ttoc(0); /* Send an initial NUL as wake-up */
7387 /* Send each variable with the trailing NUL */
7388 rc = ttol(localuser,strlen((char *)localuser)+1);
7390 rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
7392 rc = ttol(term_speed,strlen((char *)term_speed)+1);
7393 #endif /* RLOGOUTBUF */
7395 /* Now we are supposed to get back a single NUL as confirmation */
7398 debug(F101,"rlogin first ttinc","",rc);
7400 debug(F101,"rlogin ttinc 1","",rc);
7402 "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
7404 } else if (rc < 0) {
7405 debug(F101,"rlogin ttinc errno","",errno);
7406 /* printf("Network error: %d\n", errno); */
7413 /* two control messages are defined:
7415 a double flag byte of 'o' indicates a one-byte message which is
7416 identical to what was once carried out of band.
7418 a double flag byte of 'q' indicates a zero-byte message. This
7419 message is interpreted as two \377 data bytes. This is just a
7420 quote rule so that binary data from the server does not confuse the
7428 if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
7429 if (rlog_oob(&cp[4],1))
7432 } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
7433 /* this is somewhat of a hack */
7442 rlog_oob(oobdata, count) CHAR * oobdata; int count; {
7446 debug(F111,"rlogin out_of_band","count",count);
7448 for (i = 0; i<count; i++) {
7449 debug(F101,"rlogin out_of_band","",oobdata[i]);
7450 if (oobdata[i] & 0x01)
7453 if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
7454 debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
7456 /* Only flush the data if in fact we are in a mode that won't */
7457 /* get out of sync. Ie, not when we are in protocol mode. */
7469 if (oobdata[i] & 0x10) { /* Switch to RAW mode */
7470 debug(F101,"rlogin Raw Mode command","",oobdata[i]);
7474 if (oobdata[i] & 0x20) { /* Switch to COOKED mode */
7475 debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
7476 rlog_mode = RL_COOKED;
7478 if (oobdata[i] & 0x80)
7479 { /* Send Window Size Info */
7480 debug(F101,"rlogin Window Size command","",oobdata[i]);
7481 /* Remember to send WS Info when Window Size changes */
7482 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7483 TELOPT_ME(TELOPT_NAWS) = 1;
7492 rlogoobh(sig) int sig; {
7494 char /* Or should it be char for all? */
7497 #endif /* SOLARIS */
7500 /* int count = 0; */ /* (not used) */
7502 while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
7504 * We need to do some special processing here.
7505 * Just in case the socket is blocked for input
7515 debug(F101,"rlogin out_of_band","",oobdata);
7516 if (oobdata == 0x02) { /* Flush Buffered Data not yet displayed */
7517 debug(F101,"rlogin Flush Buffered Data command","",oobdata);
7520 if (oobdata & 0x10) { /* Switch to raw mode */
7521 debug(F101,"rlogin Raw Mode command","",oobdata);
7524 if (oobdata & 0x20) { /* Switch to cooked mode */
7525 debug(F101,"rlogin Cooked Mode command","",oobdata);
7526 rlog_mode = RL_COOKED;
7528 if (oobdata & 0x80) { /* Send Window Size Info */
7529 debug(F101,"rlogin Window Size command","",oobdata);
7530 /* Remember to send WS Info when Window Size changes */
7531 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7532 TELOPT_ME(TELOPT_NAWS) = 1;
7537 #endif /* TCPIPLIB */
7538 #endif /* RLOGCODE */
7540 /* Send network BREAK */
7542 Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
7547 if (ttnet == NET_TCPB) {
7548 if (ttnproto == NP_TELNET) {
7550 buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
7553 nettol((char *) buf, 2)
7559 if (tn_deb || debses || deblog) {
7560 extern char tn_msg[];
7561 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
7563 debug(F101,tn_msg,"",BREAK);
7564 if (debses || tn_deb) tn_debug(tn_msg);
7568 debug(F100,"netbreak no TNCODE","",0);
7572 /* Insert other TCP/IP protocols here */
7574 /* Insert other networks here */
7577 #endif /* NETCONN */
7583 SunLink X.25 support by Marcello Frutig, Catholic University,
7584 Rio de Janeiro, Brazil, 1990.
7587 /* PAD X.3, X.28 and X.29 support */
7589 static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
7591 /* Initialize PAD */
7593 extern CHAR padparms[];
7597 padparms[PAD_BREAK_CHARACTER] = 0; /* Break character */
7598 padparms[PAD_ESCAPE] = 1; /* Escape permitted */
7599 padparms[PAD_ECHO] = 1; /* Kermit PAD does echo */
7600 padparms[PAD_DATA_FORWARD_CHAR] = 2; /* forward character CR */
7601 padparms[PAD_DATA_FORWARD_TIMEOUT] = 0; /* no timeout forward condition */
7602 padparms[PAD_FLOW_CONTROL_BY_PAD] = 0; /* not used */
7603 padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1; /* allow PAD service signals */
7604 padparms[PAD_BREAK_ACTION] = 21; /* brk action: INT pk + brk ind*/
7605 padparms[PAD_SUPPRESSION_OF_DATA] = 0; /* no supression of user data */
7606 padparms[PAD_PADDING_AFTER_CR] = 0; /* no padding after CR */
7607 padparms[PAD_LINE_FOLDING] = 0; /* no line fold */
7608 padparms[PAD_LINE_SPEED] = 0; /* line speed - don't care */
7609 padparms[PAD_FLOW_CONTROL_BY_USER] = 0; /* flow cont of PAD - not used */
7610 padparms[PAD_LF_AFTER_CR] = 0; /* no LF insertion after CR */
7611 padparms[PAD_PADDING_AFTER_LF] = 0; /* no padding after LF */
7612 padparms[PAD_EDITING] = 1; /* can edit */
7613 padparms[PAD_CHAR_DELETE_CHAR] = 8; /* character delete character */
7614 padparms[PAD_BUFFER_DELETE_CHAR] = 21; /* buffer delete character */
7615 padparms[PAD_BUFFER_DISPLAY_CHAR] = 18; /* buffer display character */
7618 /* Set PAD parameters */
7621 setpad(s,n) CHAR *s; int n; {
7628 for (i = 0; i < n; i++) {
7629 if (*ps > MAXPADPARMS)
7632 padparms[*ps] = *(ps+1);
7638 /* Read PAD parameters */
7641 readpad(s,n,r) CHAR *s; int n; CHAR *r; {
7646 *pr++ = X29_PARAMETER_INDICATION;
7648 for (i = 0; i < n; i++, ps++) {
7649 if (*ps > MAXPADPARMS) {
7650 x29err[i+2] = *ps++;
7653 *pr++ = padparms[*ps++];
7657 for (i = 1; i < MAXPADPARMS; i++) {
7659 *pr++ = padparms[i];
7665 qbitpkt(s,n) CHAR *s; int n; {
7669 CHAR x29resp[(MAXPADPARMS*2)+1];
7675 if ((int)strlen((char *)x29err) > 2) {
7676 ttol(x29err,(int)strlen((char *)x29err));
7680 case X29_READ_PARMS:
7681 readpad (ps+1,n/2,x29resp);
7683 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7684 if ((int)strlen((char *)x29err) > 2) {
7685 ttol(x29err,(int)strlen((char *)x29err));
7690 case X29_SET_AND_READ_PARMS:
7692 readpad (ps+1,n/2,x29resp);
7694 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7695 if ((int)strlen((char *)x29err) > 2) {
7696 ttol (x29err,(int)strlen((char *)x29err));
7701 case X29_INVITATION_TO_CLEAR:
7704 case X29_INDICATION_OF_BREAK:
7710 /* PAD break action processor */
7714 extern char x25obuf[MAXOX25];
7717 extern unsigned char tosend;
7718 static CHAR indbrk[3] = {
7719 X29_INDICATION_OF_BREAK,
7720 PAD_SUPPRESSION_OF_DATA,
7723 CHAR intudat, cause, diag;
7725 if (x25stat() < 0) return; /* Ignore if no virtual call established */
7727 if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
7728 if (ttol((CHAR *)x25obuf,obufl) < 0) {
7729 perror ("\r\nCan't send characters");
7732 bzero (x25obuf,sizeof(x25obuf));
7737 switch (padparms[PAD_BREAK_ACTION]) {
7739 case 0 : break; /* do nothing */
7740 case 1 : /* send interrupt packet with interrupt user data field = 1 */
7744 case 2 : /* send reset packet with cause and diag = 0 */
7746 x25reset (cause,diag);
7748 case 5 : /* send interrupt packet with interrupt user data field = 0 */
7752 /* send indication of break without a parameter field */
7753 ttoc(X29_INDICATION_OF_BREAK);
7756 case 8 : active = 0; /* leave data transfer */
7759 case 21: /* send interrupt packet with interrupt user data field = 0 */
7762 setpad (indbrk+1,2); /* set pad to discard input */
7764 /* send indication of break with parameter field */
7765 ttol (indbrk,sizeof(indbrk));
7771 /* X.25 support functions */
7773 X25_CAUSE_DIAG diag;
7776 Convert a null-terminated string representing an X.121 address
7777 to a packed BCD form.
7780 pkx121(str,bcd) char *str; CHAR *bcd; {
7786 if (i >= 15 || str [i] < '0' || str [i] > '9')
7798 /* Reads and prints X.25 diagnostic */
7804 bzero ((char *)&diag,sizeof(diag));
7805 if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
7806 perror ("Reading X.25 diagnostic");
7809 if (diag.datalen > 0) {
7810 printf ("X.25 Diagnostic :");
7811 for (i = 0; i < (int)diag.datalen; i++)
7812 printf(" %02h",diag.data[i])+
7818 /* X.25 Out-of-Band Signal Handler */
7821 x25oobh(foo) int foo; {
7826 (VOID) signal(SIGURG,x25oobh);
7828 if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
7829 perror ("Getting signal type");
7834 if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
7835 perror ("Receiving X.25 interrupt data");
7839 printf ("\r\nInterrupt received, data = %d\r\n", t);
7842 printf ("\r\nVirtual circuit reset\r\n");
7846 printf ("\r\nReset timeout\r\n");
7849 printf ("\r\nClear timeout\r\n");
7852 printf ("\r\nMessage discarded, too long\r\n");
7855 if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
7861 /* Send a X.25 interrupt packet */
7867 x25intr(intr) char intr;
7868 #endif /* CK_ANSIC */
7870 if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
7871 debug(F100,"X.25 intr","",0);
7875 /* Reset X.25 virtual circuit */
7878 x25reset(char cause, char diagn)
7880 x25reset(cause, diagn) char cause; char diagn;
7881 #endif /* CK_ANSIC */
7883 bzero ((char *)&diag,sizeof(diag));
7886 diag.data[0] = cause;
7887 diag.data[1] = diagn;
7888 if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
7890 debug(F100,"X.25 reset","",0);
7894 /* Clear X.25 virtual circuit */
7898 debug(F100,"X.25 clear","",0);
7899 bzero ((char *)&diag,sizeof(diag));
7900 diag.flags = (1 << DIAG_TYPE);
7904 ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
7905 return(ttclos(0)); /* Close socket */
7911 if (ttyfd == -1) return (-1);
7918 static int qbiton = 1 << Q_BIT;
7919 ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
7925 static int qbitoff = 0;
7926 ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
7929 /* Read n characters from X.25 circuit into buf */
7932 x25xin(n,buf) int n; CHAR *buf; {
7937 x = read(ttyfd,buf,n);
7938 if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
7939 /* If return -1 : invitation to clear; -2 : PAD changes */
7940 if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
7945 #ifdef COMMENT /* Disabled by Stephen Riehm 19.12.97 */
7947 * if buf[] is full, then this null lands in nirvana!
7948 * I was unable to find any code which needs a trailing null in buf[]
7950 if (x > 0) buf[x] = '\0';
7951 #endif /* COMMENT */
7953 debug(F101,"x25xin x","",x);
7958 #ifdef COMMENT /* NO LONGER NEEDED! */
7959 /* X.25 read a line */
7964 x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
7966 x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
7967 #endif /* CK_ANSIC */
7968 #else /* not PARSENSE */
7970 x25inl(CHAR *dest, int max,int timo, CHAR eol)
7972 x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
7973 #endif /* __SDTC__ */
7974 #endif /*PARSENSE */
7977 int pktype, goteol, rest, n;
7979 extern int ttprty, ttpflg;
7982 ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask */
7984 debug(F101,"x25inl max","",max);
7985 debug(F101,"x25inl eol","",eol);
7990 n = read(ttyfd,pdest,rest);
7992 pktype = *pdest & 0x7f;
7995 if (qbitpkt(pdest+1,--n) < 0) return(-2);
7998 if (flag == 0) { /* if not in packet, search start */
7999 for (i = 1; (i < n) &&
8000 !(flag = ((dest[i] & 0x7f) == start));
8002 if (flag == 0) { /* not found, discard junk */
8003 debug(F101,"x25inl skipping","",n);
8005 } else { /* found, discard junk before start */
8008 for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
8011 for (i = 0; (i < n) && /* search for eol */
8012 !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
8017 } while ((rest > 0) && (!goteol));
8021 debug (F111,"x25inl X.25 got",(char *) dest,n);
8022 if (timo) ttimoff();
8023 if (ttpflg++ == 0 && ttprty == 0) {
8024 if ((ttprty = parchk(dest,start,n)) > 0) {
8026 debug(F101,"x25inl senses parity","",ttprty);
8027 debug(F110,"x25inl packet before",(char *)dest,0);
8029 for (j = 0; j < n; j++)
8030 dest[j] &= 0x7f; /* Strip parity from packet */
8031 debug(F110,"x25inl packet after ",dest,0);
8033 debug(F101,"parchk","",ttprty);
8034 if (ttprty < 0) { ttprty = 0; n = -1; }
8043 #endif /* COMMENT */
8048 * IBM X25 support - using the NPI streams interface
8049 * written by Stephen Riehm, pc-plus, Munich Germany
8052 /* riehm: missing functions / TODO list */
8055 x25intr() - Send an interrupt packet
8058 /* return an error message depending on packet type */
8061 static char buf[30];
8063 case NBADADDR: return "invalid address";
8064 case NBADOPT: return "invalid options";
8065 case NACCESS: return "no permission";
8066 case NNOADDR: return "unable to allocate address";
8067 case NOUTSTATE: return "invalid state";
8068 case NBADSEQ: return "invalid sequence number";
8069 case NSYSERR: return "system error";
8070 case NBADDATA: return "invalid data size";
8071 case NBADFLAG: return "invalid flag";
8072 case NNOTSUPPORT: return "unsupported primitive";
8073 case NBOUND: return "address in use";
8074 case NBADQOSPARAM: return "bad QOS parameters";
8075 case NBADQOSTYPE: return "bad QOS type";
8076 case NBADTOKEN: return "bad token value";
8077 case NNOPROTOID: return "protocol id could not be allocated";
8078 case NODDCUD: return "odd length call user data";
8080 ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
8085 /* turn a meaningless primitive number into a meaningful primitive name */
8088 static char buf[30];
8090 case N_BIND_ACK: return "N_BIND_ACK";
8091 case N_BIND_REQ: return "N_BIND_REQ";
8092 case N_CONN_CON: return "N_CONN_CON";
8093 case N_CONN_IND: return "N_CONN_IND";
8094 case N_CONN_REQ: return "N_CONN_REQ";
8095 case N_CONN_RES: return "N_CONN_RES";
8096 case N_DATACK_IND: return "N_DATAACK_IND";
8097 case N_DATACK_REQ: return "N_DATAACK_REQ";
8098 case N_DATA_IND: return "N_DATA_IND";
8099 case N_DATA_REQ: return "N_DATA_REQ";
8100 case N_DISCON_IND: return "N_DISCON_IND";
8101 case N_DISCON_REQ: return "N_DISCON_REQ";
8102 case N_ERROR_ACK: return "N_ERROR_ACK";
8103 case N_EXDATA_IND: return "N_EXDATA_IND";
8104 case N_EXDATA_REQ: return "N_EXDATA_REQ";
8105 case N_INFO_ACK: return "N_INFO_ACK";
8106 case N_INFO_REQ: return "N_INFO_REQ";
8107 case N_OK_ACK: return "N_OK_ACK";
8108 case N_OPTMGMT_REQ: return "N_OPTMGMT_REQ";
8109 case N_RESET_CON: return "N_RESET_CON";
8110 case N_RESET_IND: return "N_RESET_IND";
8111 case N_RESET_REQ: return "N_RESET_REQ";
8112 case N_RESET_RES: return "N_RESET_RES";
8113 case N_UDERROR_IND: return "N_UDERROR_IND";
8114 case N_UNBIND_REQ: return "N_UNBIND_REQ";
8115 case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
8116 case N_UNITDATA_IND: return "N_UNITDATA_IND";
8118 ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
8123 /*****************************************************************************
8124 * Function: x25getmsg()
8125 * Description: get a STREAMS message, and check it for errors
8128 * fd - file descriptor to x25 device (opened)
8129 * control - control buffer (pre-allocated)
8130 * ctl_size - size of control buffer
8131 * data - data buffer (pre-allocated)
8132 * data_size - size of data buffer
8133 * flags - flags for getmsg()
8134 * expected - expected Primitive type
8137 * >= 0 OK (size of data returned)
8142 x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
8143 int fd; /* X25 device (opened) */
8144 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
8145 int ctl_size; /* size of control buffer */
8146 N_npi_data_t *data; /* data buffer (pre-allocated) */
8147 int data_size; /* size of data buffer */
8148 int *get_flags; /* getmsg() flags */
8149 int expected; /* expected primitive type */
8151 int rc = 0; /* return code */
8152 struct strbuf *get_ctl=NULL; /* getmsg control */
8153 struct strbuf *get_data=NULL; /* getmsg data */
8154 int more = 0; /* flag for more data etc */
8155 int file_status = -1; /* file async status */
8156 N_npi_ctl_t * result; /* pointer to simplify switch() */
8157 int packet_type = -1; /* unknown packet thus far */
8160 printf( "TRACE: entering x25getmsg\n" );
8163 debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
8164 /* prepare the control structures for getmsg */
8166 if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8168 perror("kermit x25getmsg(): get_ctl malloc failed\n");
8169 debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
8172 /* allow getmsg to return an unexpected packet type (which may be
8173 * larger than the expected one)
8175 get_ctl->maxlen = NPI_MAX_CTL;
8177 get_ctl->buf = (char *)control;
8180 "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
8182 debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
8186 if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8188 perror("kermit x25getmsg(): get_data malloc failed\n");
8189 debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
8192 get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
8196 get_data->buf = (char *)data;
8199 /* get an X.25 packet -
8200 * it may be any kind of packet, so check for special cases
8201 * it may be split into multiple parts - so loop if necessary
8205 printf( "kermit: x25getmsg(): getting a message\n" );
8208 if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
8210 printf( "kermit: x25getmsg(): getmsg returned an error\n" );
8211 perror( "getmsg error was" );
8213 debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
8214 if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
8215 /* was in non-blocking mode, nothing to get, but we're
8216 * already waiting for the rest of the packet -
8217 * switch to blocking mode for the next read.
8218 * file_status used to reset file status before returning
8220 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
8221 || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
8223 perror("x25getmsg(): couldn't change x25 blocking mode");
8225 "x25getmsg fcntl returned an error\n", "", errno);
8230 /* loop again into a blocking getmsg() */
8234 /* no data to get in non-blocking mode - return empty handed */
8235 perror( "x25getmsg(): getmsg failed" );
8236 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
8240 } else if (more & MORECTL) {
8241 /* panic - the control information was larger than the
8242 * maximum control buffer size!
8244 /* riehm: close connection? */
8246 printf("x25getmsg(): received partial control packet - panic\n");
8248 debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
8253 if (result = (N_npi_ctl_t *)control) {
8254 packet_type = result->bind_ack.PRIM_type;
8255 if (packet_type != N_OK_ACK) {
8256 x25lastmsg = packet_type;
8260 /* printf( "kermit: x25getmsg(): getting " ); */
8261 if (get_ctl->len > 0) {
8262 x25dump_prim(result);
8265 "x25getmsg got packet ",
8266 x25prim( result->bind_ack.PRIM_type ),
8271 if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
8272 /* not as pretty as a switch(), but switch can't handle
8273 * runtime variable values :-(
8275 if (packet_type == expected ) {
8276 /* got what we wanted, special case for DATA_IND
8278 /* riehm: check Q-bit ? */
8280 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
8282 if (packet_type == N_DATA_IND ) {
8283 /* data received. May be incomplete, even though
8284 * getmsg returned OK
8286 if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
8288 if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
8289 printf( "x25getmsg(): data packet wants ack\n" );
8291 } else if( packet_type == N_DISCON_IND) {
8292 printf( "X25 diconnected\n" );
8293 /* riehm: need to acknowledge a disconnection? */
8295 /* x25unbind( ttyfd ); */
8297 } else if( packet_type == N_ERROR_ACK) {
8298 errno = result->error_ack.UNIX_error;
8299 perror( "X25 error received" );
8302 printf("x25getmsg(): failed %s\n", x25err(packet_type));
8308 /* Panic - no control data */
8309 printf( "kermit: x25getmsg(): no control data with packet\n" );
8312 #endif /* COMMENT */
8314 if (get_data && (get_data->len >= 0)) {
8315 get_data->buf += get_data->len;
8316 get_data->maxlen -= get_data->len;
8319 && (get_data && (get_data->maxlen > 0))
8320 && (more & MOREDATA)
8323 /* return the file status to its original value, unless its still
8324 * set to -1, or one of the fcntl's failed */
8325 if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
8329 * Verify that we received an expected primitive
8330 * there is apparantly an error case where the primitive is set
8331 * correctly, but there is not enough data in the control structure
8333 if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
8335 "x25getmsg(): %s NOT received. Primitive received was %s\n",
8336 x25prim( expected ), x25prim( packet_type ));
8337 debug(F110, "x25getmsg got an unexpected packet ",
8338 x25prim(packet_type),
8345 if (get_data && ( get_data->len >= 0)) {
8350 if (get_ctl) { free(get_ctl); get_ctl = NULL; }
8351 if (get_data) { free(get_data); get_data = NULL; }
8355 printf( "kermit x25getmsg(): returning %d\n", rc );
8357 #endif /* COMMENT */
8358 debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
8361 printf( "TRACE: leaving x25getmsg\n" );
8366 /*****************************************************************************
8367 * Function: x25putmsg()
8370 * send a message to a X25 STREAM
8373 * fd - file descriptor to x25 device (opened)
8374 * control - control buffer (pre-allocated)
8375 * data - data buffer (pre-allocated)
8376 * data_len - length of data to be transmitted
8377 * put_flags - flags for putmsg()
8380 * >= 0 number of bytes transmitted
8384 x25putmsg(fd, control, data, data_len, put_flags)
8385 int fd; /* X25 device (opened) */
8386 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
8387 N_npi_data_t *data; /* data buffer (pre-allocated) */
8388 int data_len; /* length of data (not the size of
8390 int *put_flags; /* putmsg() flags */
8392 int rc = 0; /* return code */
8393 ulong type; /* primitive type */
8394 struct strbuf *put_ctl = NULL; /* putmsg control */
8395 struct strbuf *put_data = NULL; /* putmsg data */
8398 printf( "TRACE: entering x25putmsg\n" );
8402 printf( "kermit: x25putmsg(): putting " );
8403 x25dump_prim( control );
8404 printf( "\tdata:\t\t" );
8405 x25dump_data( data, 0, data_len );
8406 debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
8410 put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8411 if (put_ctl == NULL) {
8412 perror("kermit x25putmsg(): put_ctl malloc failed\n");
8415 put_ctl->maxlen = 0; /* unused by putmsg */
8416 put_ctl->len = NPI_MAX_CTL;
8417 put_ctl->buf = (char *)control;
8419 if (data && ( data_len > 0)) {
8420 put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8421 if( put_data == NULL) {
8422 perror("kermit x25putmsg(): put_data malloc failed\n");
8425 put_data->maxlen = 0; /* unused by putmsg */
8426 put_data->len = data_len;
8427 put_data->buf = (char *)data;
8431 rc = putmsg (fd, put_ctl, put_data, 0);
8433 printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
8434 perror("kermit: x25putmsg(): putmsg failed");
8438 /* riehm: this should perhaps be discounted! */
8439 x25lastmsg = control->PRIM_type;
8443 printf( "kermit debug: x25putmsg() returning %d\n", data_len );
8445 #endif /* COMMENT */
8446 debug( F101, "x25putmsg block size put ", "", data_len);
8449 printf( "TRACE: leaving x25putmsg\n" );
8455 /*****************************************************************************
8457 * Description: The bind submitted to NPI provides the information required
8458 * by the packet layer for it to listen for suitable incoming
8463 * This routine needs to be called in a completely different manner for
8464 * the client and server side. When starting a client, the
8465 * num_waiting_calls and CUD information should all be set to 0! The
8466 * client's CUD must be inserted in the CONN_REQ data block.
8467 * When starting a server, the CUD must be set to a CUD pattern, and
8468 * the number of waiting calls should be set to a number other than 0.
8469 * (num waiting calls is the number of incomming calls which are to be
8470 * put on hold while the server is servicing another client.)
8472 * Who invented this crap?
8475 * fd - X25 device (opened)
8476 * addr - local address
8477 * cud - User Data (null terminated)
8478 * cud_len - User Data length
8479 * num_waiting_calls - number of outstanding calls allowed on this stream
8480 * line - logical port number (1)
8481 * flags - 0, DEFAULT_LISTENER or TOKEN_REQUEST
8484 * if binding is successful, 0 is returned for a client, and a token is
8485 * returned for a server
8487 * Return code: 0 if successful
8488 * -1 if unsuccessful
8489 *****************************************************************************/
8492 x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
8493 int fd; /* X25 device (opened) */
8494 char * addr; /* local address */
8495 char * cud; /* Call User Data (null terminated) */
8496 int cud_len; /* User Data length */
8497 int num_waiting_calls; /* Outstanding calls allowed */
8498 int line; /* logical port number */
8499 ulong bind_flags; /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
8501 ulong rc; /* return code */
8502 int get_flags; /* priority flag passed to getmsg */
8503 int put_flags = 0; /* output flags for putmsg, always 0 */
8504 ulong type; /* primitive type */
8505 N_bind_req_t *bind_req; /* pointer to N_BIND_REQ primitive */
8506 N_bind_ack_t *bind_ack; /* pointer to N_BIND_ACK primitive */
8507 char *addtl_info; /* pointer to info in addition to
8508 * the N_BIND_REQ primitive that is
8509 * passed in the control structure
8511 int addr_len = 0; /* length of address string */
8512 ulong bind_req_t_size; /* for debugging only */
8515 printf("TRACE: entering x25bind\n" );
8519 printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
8520 fd, addr, cud, line, bind_flags
8525 * Allocate and zero out space to hold the control portion of the
8526 * message passed to putmsg. This will contain the N_BIND_REQ
8527 * primitive and any additional info required for that.
8529 * Note: allocated space is the size of the union typedef
8530 * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
8532 bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
8533 if (bind_req == NULL) {
8534 perror("kermit: x25bind(): bind_req malloc failed");
8535 debug(F100, "x25bind bind_req malloc failed", "", 0);
8538 bzero((char *)bind_req, sizeof(N_npi_ctl_t));
8540 /* Build the Bind Request Primitive */
8541 bind_req->PRIM_type = (ulong) N_BIND_REQ;
8543 /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
8544 * the actual address in an N_BIND_REQ. The first byte contains the
8545 * line number being used with this address, and the second byte is the
8546 * X.121 address prefix, which must be zero.
8548 addr_len = strlen(addr);
8549 bind_req->ADDR_length = (ulong) (addr_len + 2);
8550 bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
8551 bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
8552 bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
8553 bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
8555 bind_req->PROTOID_offset = (ulong) 0;
8557 /* need to remember the trailing NULL in the address - not
8558 * counted in the address length
8560 bind_req->PROTOID_offset
8561 = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
8565 * Now fill in the additional information required with this primitive
8566 * (address and protocol information (Call User Data))
8568 addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
8570 * The bitwise "&" ensures that the line number is only one byte long
8572 *addtl_info++ = (char) line & 0xff;
8573 *addtl_info++ = (char) 0; /* X.121 format */
8574 bcopy( addr, addtl_info, addr_len ); /* include trailing null */
8575 addtl_info += addr_len;
8577 bcopy( cud, addtl_info, cud_len );
8579 * Call putmsg() to put the bind request message on the stream
8582 (N_npi_ctl_t*)bind_req,
8583 (N_npi_data_t *)NULL,
8587 printf( "kermit: x25bind(): x25putmsg failed\n" );
8592 * Allocate and zero out space for the N_BIND_ACK primitive
8594 bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
8595 if (bind_ack == NULL){
8596 perror("kermit: x25bind(): bind_ack malloc failed");
8599 bzero(bind_ack, sizeof(N_npi_ctl_t));
8601 * Initialize the control structure and flag variable sent to getmsg
8605 /* get the ACK for the bind */
8607 printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
8609 rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
8610 (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
8613 /* turn quantitive return code into a qualitative one */
8616 /* if all went well, get the token from the acknowledgement packet */
8617 if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
8618 rc = bind_ack->TOKEN_value;
8621 /* free up the memory we allocated earlier */
8626 printf( "TRACE: leaving x25bind\n" );
8632 /*****************************************************************************
8634 * Description: This routine builds and sends an N_CONN_REQ primitive, then
8635 * checks for an N_CONN_CON primitive in return.
8638 * fd - file descriptor of stream
8639 * caddr - called address (remote address)
8641 * Functions Referenced:
8649 * -1 if not successful
8650 *****************************************************************************/
8652 x25call(fd, remote_nua, cud)
8653 int fd; /* X25 device (opened) */
8654 char * remote_nua; /* remote address to call */
8655 char * cud; /* call user data */
8657 int rc; /* return code */
8658 int flags; /* Connection flags */
8659 int get_flags; /* priority flags for getmsg */
8660 ulong type; /* primitive type */
8661 N_conn_req_t *connreq_ctl; /* pointer to N_CONN_REQ primitive */
8662 N_npi_data_t *connreq_data; /* pointer to N_CONN_REQ data (CUD) */
8663 int connreq_data_len; /* length of filled data buffer */
8664 N_conn_con_t *conncon_ctl; /* pointer to N_CONN_CON primitive */
8665 N_npi_data_t *conncon_data; /* pointer to any data associated with
8666 * the N_CONN_CON primitive */
8667 char *addtl_info; /* pointer to additional info needed
8668 * for N_CONN_REQ primitive */
8669 int addr_len; /* length of address */
8672 printf( "TRACE: entering x25call\n" );
8676 printf( "x25call( %d, %s )\n", fd, remote_nua );
8677 printf( "connecting to %s on fd %d\n", remote_nua, fd );
8681 * Allocate and zero out space for the N_CONN_REQ primitive
8682 * use the size of the generic NPI primitive control buffer
8684 connreq_ctl = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
8685 if (connreq_ctl == NULL){
8686 perror("kermit: x25call(): connreq_ctl malloc failed");
8689 bzero(connreq_ctl,sizeof(N_npi_ctl_t));
8691 * Build the Connection Request Primitive
8694 connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
8696 /* Note that the address length is nchai+1 and not n+2. The line number
8697 * is only passed with the address for the bind. The first byte of
8698 * the address for the N_CONN primitives contains the X.121
8699 * address prefix, which must be zero. The remaining bytes are the
8702 addr_len = strlen( remote_nua );
8703 connreq_ctl->DEST_length = (ulong) (addr_len + 1);
8704 connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
8705 /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
8706 connreq_ctl->CONN_flags = (ulong) 0;
8707 connreq_ctl->QOS_length = (ulong) 0; /* unsupported in AIX 4.1 */
8708 connreq_ctl->QOS_offset = (ulong) 0; /* unsupported in AIX 4.1 */
8710 addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
8711 *addtl_info++ = (char) 0; /* X.121 format */
8712 bcopy( remote_nua, addtl_info, addr_len );
8715 * setup the data buffer for the connection request
8717 connreq_data = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
8718 if (connreq_data == NULL){
8719 perror("kermit: x25call(): connreq_data malloc failed");
8722 bzero(connreq_data,sizeof(N_npi_data_t));
8724 /* facility selection needs to be put in the front of connreq_data */
8725 connreq_data_len = 0;
8726 connreq_data_len += x25facilities( (char *)connreq_data );
8729 (char *)((char *)connreq_data + connreq_data_len),
8732 connreq_data_len += strlen( cud );
8736 * Call putmsg() to put the connection request message on the stream
8738 rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
8739 connreq_data_len, &flags );
8745 * Allocate and zero out space for the N_CONN_CON primitive
8747 if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8748 perror("kermit: x25call(): conncon_ctl malloc failed");
8751 bzero(conncon_ctl, sizeof(N_npi_ctl_t));
8754 * Allocate and zero out space for any data associated with N_CONN_CON
8756 if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
8757 perror("kermit: x25call(): conncon_data malloc failed");
8760 bzero(conncon_data, NPI_MAX_DATA);
8762 /* Initialize and build the structures for getmsg */
8765 rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
8766 conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
8768 /* turn quantitive return code into a qualitative one */
8771 /* Free the space that we no longer need */
8772 if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
8773 if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
8774 if (conncon_data) { free(conncon_data); conncon_data = NULL; }
8777 printf( "TRACE: leaving x25call\n" );
8783 /*****************************************************************************
8784 * Function: x25getcall
8786 * Description: This routine checks for an incomming call, verified
8787 * that it is a CONNIND (connection indication) message, and then
8788 * accepts the call and returns the file descriptor of the new stream
8791 * fd - file descriptor of listening stream
8794 * callfd - file descriptor of connected incomming call.
8795 * - set to -1 if an error occured
8797 *****************************************************************************/
8799 x25getcall(fd) int fd; {
8800 int x25callfd; /* fd of incomming call */
8801 N_conn_ind_t *connind_ctl; /* connind controll buffer */
8802 N_npi_data_t *connind_data; /* connind data buffer */
8803 int get_flags; /* flags for getmsg */
8804 ulong flags; /* connection flags */
8805 int rc; /* return code */
8807 extern x25addr_t remote_nua; /* remote X.25 addr global var */
8810 printf( "TRACE: entering x25getcall\n" );
8813 /* allocate space for connection indication buffers */
8814 if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
8815 perror("kermit: x25getcall(): connind_ctl malloc failed");
8818 bzero(connind_ctl, sizeof(N_npi_ctl_t));
8820 if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
8821 perror("kermit: x25getcall(): connind_data malloc failed");
8824 bzero(connind_data, NPI_MAX_DATA);
8826 /* initialise control structures */
8829 /* call getmsg to check for a connection indication */
8831 (N_npi_ctl_t*)connind_ctl,
8832 (int)sizeof(N_conn_ind_t),
8839 printf( "x25getcall(): errno is: %d\n", errno );
8841 perror ("x25getcall(): getmsg failed");
8845 /* a connection indication was received
8846 * - pull it to bits and answer the call
8848 x25seqno = connind_ctl->SEQ_number;
8849 flags = connind_ctl->CONN_flags;
8851 printf( "setting remote_nua to a new value due to incomming call\n" );
8854 * no guarantee that the address is null terminated, ensure that
8855 * after copying that it is (assumption: remote_nua is longer than
8858 bzero(remote_nua, sizeof(remote_nua));
8859 /* note: connind_ctl contains a x121 address, which has a null as
8860 * the FIRST character - strip it off!
8862 ckstrncpy(remote_nua,
8863 (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
8864 connind_ctl->SRC_length - 1
8867 printf( "remote_nua set to new value of %s\n", remote_nua );
8870 /* errors handled by callee */
8871 x25callfd = x25accept(x25seqno, flags);
8873 /* free the malloc'd buffers */
8874 if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
8875 if (connind_data) { free(connind_data); connind_data = NULL; }
8878 printf( "TRACE: leaving x25getcall\n" );
8881 /* return the file descriptor (or error if < 0) */
8882 return( x25callfd );
8885 /*****************************************************************************
8886 * Function: x25accept
8888 * Description: accept an incomming call
8889 * This essentially means opening a new STREAM and sending
8890 * an acknowledge back to the caller.
8893 * seqno - sequence number for acknowledgement
8894 * flags - flags passed to us by the caller
8897 * fd - file descriptor of new STREAM
8898 * set to -1 if an error occured
8900 *****************************************************************************/
8902 x25accept(seqno,flags)
8903 ulong seqno; /* connection sequence number */
8904 ulong flags; /* connection flags */
8906 int x25callfd; /* fd for incomming call */
8907 int get_flags; /* priority flags for getmsg */
8908 int put_flags = 0; /* flags for putmsg, always 0 */
8909 int addr_len; /* length of local address */
8910 ulong token; /* connection token */
8911 N_conn_res_t *conn_res; /* N_CONN_RES primitive */
8912 N_ok_ack_t *ok_ack; /* N_OK_ACK primitive */
8913 char *addtl_info; /* temp pointer */
8914 int rc; /* temporary return code */
8916 /* global variables from ckcmai.c */
8917 extern int revcall, closgr, cudata;
8918 extern char udata[];
8919 extern x25addr_t local_nua; /* local X.25 address */
8920 extern char x25name[]; /* x25 device name (sx25a0) */
8921 extern char x25dev[]; /* x25 device file /dev/x25pkt */
8922 extern int x25port; /* logical port to use */
8923 ulong bind_flags = 0; /* flags for binding the X25 stream */
8926 printf( "TRACE: entering x25accept\n" );
8929 /* open a new packet level stream */
8930 if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
8931 perror ("kermit: x25accept(): X.25 device open error");
8932 debug(F101,"x25accept() device open error","",errno);
8936 /* push the NPI onto the STREAM */
8937 if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
8938 perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
8939 debug(F101,"x25accept can't push npi on the X25 stream","",errno);
8943 /* bind kermit server to the local X25 address */
8944 /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
8945 bind_flags |= TOKEN_REQUEST;
8946 token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
8948 printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
8953 /* allocate connection response primitive */
8954 if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
8955 perror("kermit: x25accept(): conn_res malloc failed");
8958 bzero((char *)conn_res, NPI_MAX_CTL);
8960 /* setup connection response primitive */
8961 addr_len = strlen( local_nua );
8962 conn_res->PRIM_type = (ulong)N_CONN_RES;
8963 conn_res->TOKEN_value = token;
8964 /* note address length is n+1 to accomodate the X.121 address prefix */
8965 conn_res->RES_length = (ulong)(addr_len + 1);
8966 conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
8967 conn_res->SEQ_number = seqno;
8968 conn_res->CONN_flags = 0;
8969 conn_res->QOS_length = 0; /* unsupported - must be 0 (!?) */
8970 conn_res->QOS_offset = 0;
8972 addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
8973 *addtl_info++ = (char)0; /* X.121 address prefix */
8974 bcopy( local_nua, addtl_info, addr_len );
8977 * send off the connect response
8979 if (x25putmsg(x25callfd,
8980 (N_npi_ctl_t*)conn_res,
8981 (N_npi_data_t *)NULL,
8985 perror("kermit: x25accept(): putmsg connect response failed");
8990 * Allocate and zero out space for the OK_ACK primitive
8992 if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8993 perror("kermit: x25call(): ok_ack malloc failed");
8996 bzero(ok_ack, sizeof(N_npi_ctl_t));
8998 /* Initialize and build the structures for getmsg */
9001 rc = (int)x25getmsg(x25callfd,
9002 (N_npi_ctl_t*)ok_ack,
9003 (int)sizeof(N_ok_ack_t),
9004 (N_npi_data_t*)NULL,
9010 /* sequence number is only for disconnecting when not connected !? */
9014 /* free up malloc'ed buffer space */
9015 if (conn_res) { free(conn_res); conn_res = NULL; }
9016 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9019 printf( "TRACE: leaving x25accept\n" );
9022 return( ( rc >= 0 ) ? x25callfd : -1 );
9025 /*****************************************************************************
9026 * Function: x25unbind
9028 * Description: This subroutine builds and sends an unbind request and gets
9029 * the acknowledgement for it.
9032 * fd - File descriptor of the stream
9034 * Functions Referenced:
9042 * -1 - if not successful
9043 *****************************************************************************/
9045 x25unbind(fd) int fd; { /* X25 device (opened) */
9046 int rc; /* return code */
9047 int flags; /* bind flags */
9048 int get_flags; /* priority flag for getmsg */
9049 ulong type; /* primitive type */
9050 N_unbind_req_t *unbind_req; /* pointer to N_UNBIND_REQ */
9051 N_ok_ack_t *ok_ack; /* pointer to N_OK_ACK */
9054 printf( "TRACE: entering x25unbind\n" );
9058 /* printf( "x25unbind( %d )\n", fd ); */
9060 debug(F101,"x25unbind closing x25 connection #","",fd);
9062 /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
9063 unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
9064 if (unbind_req == NULL) {
9065 perror("kermit: x25unbind(): unbind_req malloc failed");
9068 bzero(unbind_req, sizeof(N_npi_ctl_t));
9071 * Build the Unbind Request Primitive
9074 unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
9077 * Call putmsg() to put the bind request message on the stream
9080 (N_npi_ctl_t*)unbind_req,
9081 (N_npi_data_t *)NULL,
9085 perror ("kermit: x25unbind(): putmsg failed");
9089 /* Allocate and Zero out space for the N_OK_ACK primitive */
9090 ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
9091 if (ok_ack == NULL) {
9092 perror("kermit x25unbind(): ok_ack malloc failed\n");
9095 bzero(ok_ack, sizeof(N_npi_ctl_t));
9097 /* Initialize and build the control structure for getmsg */
9100 /* Call getmsg() to check for an acknowledgement */
9102 (N_npi_ctl_t*)ok_ack,
9103 (int)sizeof(N_ok_ack_t),
9104 (N_npi_data_t*)NULL,
9110 perror ("kermit: x25unbind: getmsg failed");
9114 /* Free up the space that we no longer need */
9115 if (unbind_req) { free(unbind_req); unbind_req = NULL; }
9116 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9119 printf( "TRACE: leaving x25unbind\n" );
9125 /*****************************************************************************
9129 * Read n characters from X.25 circuit into buf (AIX only)
9132 * data_buf_len maximum size of data buffer
9133 * data_buf pointer to pre-allocated buffer space
9136 * the number of characters actually read
9139 x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
9140 struct strbuf getmsg_ctl; /* streams control structure */
9141 struct strbuf getmsg_data; /* streams data structure */
9142 int rc = 0; /* return code */
9143 int getmsg_flags; /* packet priority flags */
9144 char * ctl_buf; /* npi control buffer */
9145 N_npi_ctl_t * result; /* pointer to simplify switch() */
9148 printf( "TRACE: entering x25xin\n" );
9151 /* ensure that no maximum's are overridden */
9152 data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
9154 /* allocate space for packet control info */
9155 if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
9156 perror( "kermit: x25xin(): ctl_buf malloc" );
9160 /* riehm: need zeroed buffer for getmsg? */
9161 bzero( ctl_buf, NPI_MAX_CTL );
9162 /* clear data buffer */
9163 bzero( data_buf, data_buf_len );
9164 #endif /* COMMENT */
9166 getmsg_flags = 0; /* get the first packet available */
9168 rc = x25getmsg(ttyfd,
9179 printf( "kermit: x25xin(): got " );
9180 x25dump_data( data_buf, 0, rc );
9182 printf( "x25xin(): attempt to get data resulted in an error\n" );
9185 #endif /* COMMENT */
9188 if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
9191 printf( "TRACE: leaving x25xi\n" );
9197 /*****************************************************************************
9198 * Function: x25write
9201 * write a block of characters to the X25 STREAM (AIX)
9204 * fd file descriptor to write to
9205 * databuf buffer containing data to write
9206 * databufsize size of the buffer to write
9209 * size the number of bytes actually transmitted
9212 x25write(fd, databuf, databufsize)
9213 int fd; /* X25 STREAMS file descriptor (ttyfd) */
9214 char *databuf; /* buffer to write */
9215 int databufsize; /* buffer size */
9217 N_data_req_t *data_req_ctl;
9218 int rc; /* return code (size transmitted) */
9219 int write_flags = 0; /* always 0 !? */
9222 printf( "TRACE: entering x25write\n" );
9225 if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
9226 perror( "kermit: x25write(): data_req_ctl malloc" );
9229 data_req_ctl->PRIM_type = N_DATA_REQ;
9230 data_req_ctl->DATA_xfer_flags = 0;
9232 /* riehm: possible extension
9233 * possibly need to think about splitting up the data buffer
9234 * into multiple parts if databufsize > NPI_MAX_DATA
9239 printf( "kermit: x25write(): writing data to x25 stream\n" );
9240 printf( "\tdata:\t" );
9241 x25dump_data(databuf, 0, databufsize);
9243 #endif /* COMMENT */
9245 (N_npi_ctl_t*)data_req_ctl,
9246 (N_npi_data_t*)databuf,
9250 if (data_req) { free(data_req_ctl); data_req = NULL; }
9253 printf( "TRACE: leaving x25write\n" );
9259 /*****************************************************************************
9260 * Function: x25local_nua
9263 * This routine is only interesting for IBM computers. In order
9264 * to set up a connection (see x25bind()) you need to know the
9265 * local NUA (x25 address). Unfortunately, you need all this code
9266 * to find that out, I just hope this works for everyone else!
9269 * a pre-allocated character buffer, long enough to hold an X.25 address
9270 * and the tailing null.
9273 * the length of the address string.
9277 x25local_nua(char *buf) {
9278 struct CuAt *response; /* structure to fill with info from ODM */
9279 CLASS_SYMBOL retClass; /* ODM class */
9280 char query[64]; /* odm database query */
9281 int rc = 0; /* return value (length of local NUA) */
9282 extern char x25name[]; /* x25 device name (sx25a0) */
9285 printf( "TRACE: entering x25local_nua\n" );
9288 /* set up query string */
9289 if (x25name[0] == '\0') {
9291 printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
9293 strcpy( x25name, "sx25a0" );
9295 ckmakmsg(query, sizeof(query), "name like ",x25name,
9296 " and attribute like local_nua");
9298 /* initialise ODM database */
9300 if (odm_initialize() == -1) {
9301 printf( "x25local_nua(): can't initialize ODM database");
9303 case ODMI_INVALID_PATH:
9304 printf( "invalid path\n" );
9306 case ODMI_MALLOC_ERR:
9307 printf( "malloc failed\n" );
9310 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9315 /* open the CuAt class */
9316 retClass = odm_open_class(CuAt_CLASS);
9317 if (((int)retClass) == -1) {
9318 printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
9320 case ODMI_CLASS_DNE:
9321 printf( "CuAt class doesn't exist\n" );
9323 case ODMI_CLASS_PERMS:
9324 printf( "permission to CuAt class file denied\n" );
9326 case ODMI_MAGICNO_ERR:
9327 printf( "CuAt is an invalid ODM object class\n" );
9330 printf( "cannot open CuAt class - and don't know why!\n" );
9332 case ODMI_INVALID_PATH:
9333 printf( "invalid path\n" );
9335 case ODMI_TOOMANYCLASSES:
9336 printf( "too many object classes have been opened\n" );
9339 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9345 printf("retClass= %d\n", retClass);
9348 response = (struct CuAt *)odm_get_first( retClass, query, NULL );
9349 if (((int)response) == -1) {
9350 printf( "kermit: x25local_nua(): odm query failed " );
9352 case ODMI_BAD_CRIT: /* Programming error */
9353 printf( "bad search criteria\n" );
9355 case ODMI_CLASS_DNE:
9356 printf( "CuAt class doesn't exist\n" );
9358 case ODMI_CLASS_PERMS:
9359 printf( "permission to CuAt class file denied\n" );
9361 case ODMI_INTERNAL_ERR:
9362 printf("odm internal error\nPlease contact your administrator\n" );
9364 case ODMI_INVALID_CLXN:
9365 printf("CuAt is invalid or inconsistent odm class collection\n");
9367 case ODMI_INVALID_PATH:
9368 printf( "invalid path\n" );
9370 case ODMI_MAGICNO_ERR:
9371 printf( "CuAt is an invalid ODM object class\n" );
9373 case ODMI_MALLOC_ERR:
9374 printf( "malloc failed\n" );
9377 printf( "cannot open CuAt class - and don't know why!\n" );
9379 case ODMI_TOOMANYCLASSES:
9380 printf( "too many object classes have been opened\n" );
9383 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9388 /* check for a meaningfull response */
9389 if (response != NULL) {
9390 if (response->value != NULL) {
9391 strcpy(buf, response->value);
9395 printf( "attribute name is: %s\n", (char *)response->attribute );
9396 printf( "I think my address is %s\n", (char*)response->value );
9400 printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
9405 printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
9407 case ODMI_CLASS_DNE:
9408 printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
9410 case ODMI_CLASS_PERMS:
9411 printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
9413 case ODMI_INTERNAL_ERR:
9414 printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
9416 case ODMI_INVALID_CLXN:
9417 printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
9419 case ODMI_INVALID_PATH:
9420 printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
9422 case ODMI_MAGICNO_ERR:
9423 printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
9425 case ODMI_MALLOC_ERR:
9426 printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
9429 printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
9431 case ODMI_TOOMANYCLASSES:
9432 printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
9435 printf( "Unknown error!\n" );
9440 /* close the database again */
9441 odm_close_class( retClass );
9443 /* forget about ODM all together */
9447 printf( "TRACE: leaving x25local_nua\n" );
9450 debug(F110, "x25local_nua local address is ", buf, 0);
9454 /*****************************************************************************
9455 * Function: x25facilities
9458 * build up the facilities data packet for a connection request
9461 * a pre-allocated char buffer, normally NPI_MAX_DATA big.
9464 * the number of characters inserted into the buffer
9467 x25facilities(buffer) char *buffer; {
9470 char *p; /* temp pointer */
9471 char *start; /* temp pointer */
9474 printf( "TRACE: entering x25facilities\n" );
9481 printf( "kermit: x25facilities(): getting X25 facilities\n" );
9486 printf("reverse charge: %d\n", revcall );
9493 printf("closed user group: %d\n", closgr );
9501 printf( "no facilities\n" );
9505 /* set the size of the facilities buffer */
9506 *buffer = (char)( p - start ) & 0xff;
9509 printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer) );
9513 printf( "TRACE: leaving x25facilities\n" );
9516 /* return the size of the facilities with size byte */
9517 /* 1 == no facilities, 0 byte returned as facilities size */
9518 return( (int)(p - buffer) );
9522 * reset the connection
9525 x25reset(cause, diagn) char cause; char diagn; {
9526 /* not implemented */
9529 printf( "TRACE: entering x25reset\n" );
9533 printf( "TRACE: leaving x25reset\n" );
9540 * clear the x25 connection - ie: hang up
9544 int get_flags = 0; /* priority flag for getmsg */
9545 int put_flags = 0; /* send flags, always 0 */
9546 ulong type; /* primitive type */
9547 N_discon_req_t *discon_req; /* pointer to N_DISCON_REQ */
9548 N_discon_ind_t *discon_ind; /* pointer to N_DISCON_IND */
9549 N_npi_data_t *discon_data; /* pointer to N_DISCON_IND data */
9550 int rc = 0; /* return code */
9553 printf( "TRACE: entering x25clear\n" );
9557 /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
9561 * The following checks are used to ensure that we don't disconnect
9562 * or unbind twice - this seems to throw the NPI interface right out of
9565 switch(x25lastmsg) {
9573 /* printf("x25clear(): actively disconnecting\n"); */
9576 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
9577 if (discon_req == NULL) {
9578 perror("kermit x25clear(): discon_req malloc failed\n");
9579 /* fallthrough, try to unbind the NPI anyway */
9581 discon_req->PRIM_type = N_DISCON_REQ;
9582 discon_req->DISCON_reason = 0; /* not used by AIX */
9583 discon_req->RES_length = 0;
9584 discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
9585 discon_req->SEQ_number = x25seqno; /* global */
9587 if (x25putmsg(ttyfd,
9588 (N_npi_ctl_t*)discon_req,
9589 (N_npi_data_t*)NULL,
9593 perror("x25putmsg failed in x25clear()");
9595 discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
9596 discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
9597 if((discon_ind == NULL) || (discon_data == NULL)) {
9598 perror("x25clear(): discon_ind malloc failed\n");
9599 /* fallthrough, try to unbind the NPI anyway */
9602 (N_npi_ctl_t*)discon_ind,
9604 (N_npi_data_t*)discon_data,
9609 perror("x25getmsg failed in x25clear()");
9610 /* fallthrough, try to unbind the NPI anyway */
9618 if (x25lastmsg != N_UNBIND_REQ) {
9619 rc = x25unbind(ttyfd);
9623 printf( "TRACE: leaving x25clear\n" );
9631 * only for debugging
9633 * turn the internal representation of a datablock into something
9634 * half-way readable. Because the length is known, we can print
9635 * the string including null's etc (important, because the first(!)
9636 * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
9638 x25dump_data(char *addr, ulong offset, ulong length) {
9639 char *ptr = addr + offset;
9641 /* allocate enough memory for all unprintable chars */
9642 char *buf = (char *)malloc( length * 4 );
9643 char *bptr = buf; /* pointer to current place in the print buffer */
9646 if (isprint(*ptr)) {
9650 strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
9658 printf( "%s", buf );
9660 printf( " (%d+%d)\n", offset, length );
9662 if (buf) { free(buf); buf = NULL; }
9667 * only for debugging
9668 * print as much useful information about a packet as possible
9670 x25dump_prim(primitive) N_npi_ctl_t *primitive; {
9671 printf("Primitive");
9672 switch (primitive->PRIM_type) {
9674 printf( "\tN_BIND_ACK\n\taddress:\t" );
9675 x25dump_data( (char *)primitive,
9676 primitive->bind_ack.ADDR_offset,
9677 primitive->bind_ack.ADDR_length );
9678 printf( "\tproto id:\t" );
9679 x25dump_data( (char *)primitive,
9680 primitive->bind_ack.PROTOID_offset,
9681 primitive->bind_ack.PROTOID_length );
9682 printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
9683 primitive->bind_ack.CONIND_number,
9684 primitive->bind_ack.TOKEN_value );
9688 printf( "\tN_BIND_REQ\n\taddress:\t" );
9689 x25dump_data( (char *)primitive,
9690 primitive->bind_req.ADDR_offset,
9691 primitive->bind_req.ADDR_length );
9692 printf( "\tproto id:\t" );
9693 x25dump_data( (char *)primitive,
9694 primitive->bind_req.PROTOID_offset,
9695 primitive->bind_req.PROTOID_length );
9696 printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
9697 primitive->bind_req.CONIND_number,
9698 primitive->bind_req.BIND_flags );
9702 printf( "\tN_CONN_CON\n" );
9703 printf( "\tRES\t\t" );
9704 x25dump_data( (char *)primitive,
9705 primitive->conn_con.RES_offset,
9706 primitive->conn_con.RES_length );
9707 printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
9711 printf( "\tN_CONN_IND\n" );
9712 printf( "\tsource:\t\t" );
9713 x25dump_data( (char *)primitive,
9714 primitive->conn_ind.SRC_offset,
9715 primitive->conn_ind.SRC_length );
9716 printf( "\tdestination:\t" );
9717 x25dump_data( (char *)primitive,
9718 primitive->conn_ind.DEST_offset,
9719 primitive->conn_ind.DEST_length );
9720 printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
9721 printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
9725 printf( "\tN_CONN_REQ\n\tdestination:\t" );
9726 x25dump_data( (char *)primitive,
9727 primitive->conn_req.DEST_offset,
9728 primitive->conn_req.DEST_length );
9729 printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
9733 printf( "\tN_CONN_RES\n" );
9734 printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
9735 printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
9736 printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
9737 printf( "\tRES\t\t" );
9738 x25dump_data( (char *)primitive,
9739 primitive->conn_res.RES_offset,
9740 primitive->conn_res.RES_length );
9744 printf( "\tN_DATACK_IND\n" );
9748 printf( "\tN_DATACK_REQ\n" );
9749 printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
9753 printf( "\tN_DATA_IND\n" );
9754 printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
9758 printf( "\tN_DATA_REQ\n" );
9762 printf( "\tN_DISCON_IND\n" );
9763 printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
9764 printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
9765 printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
9766 printf( "\tRES:\t" );
9767 x25dump_data( (char *)primitive,
9768 primitive->discon_ind.RES_offset,
9769 primitive->discon_ind.RES_length );
9773 printf( "\tN_DISCON_REQ\n" );
9774 printf( "\tDISCON_reason:\t%d\n",
9775 primitive->discon_req.DISCON_reason );
9776 printf( "\tRES:\t" );
9777 x25dump_data( (char *)primitive,
9778 primitive->discon_req.RES_offset,
9779 primitive->discon_req.RES_length );
9780 printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
9784 printf( "\tN_ERROR_ACK\n" );
9785 printf( "\tCaused by:\t%s\n",
9786 x25prim( primitive->error_ack.ERROR_prim ) );
9787 printf( "\tNPI error:\t%s\n",
9788 x25err( primitive->error_ack.NPI_error ));
9789 errno = primitive->error_ack.UNIX_error;
9794 printf( "\tN_EXDATA_ACK\n" );
9798 printf( "\tN_EXDATA_REQ\n" );
9802 printf( "\tN_INFO_ACK\n" );
9803 printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
9804 printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
9805 printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
9806 printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
9807 printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
9808 printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
9812 printf( "\tN_INFO_REQ\n" );
9816 printf( "\tN_OK_ACK\n" );
9820 printf( "\tN_OPTMGMT_REQ\n" );
9824 printf( "\tN_RESET_CON\n" );
9828 printf( "\tN_RESET_IND\n" );
9829 printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
9830 printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
9834 printf( "\tN_RESET_REQ\n" );
9835 printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
9839 printf( "\tN_RESET_RES\n" );
9843 printf( "\tN_UDERROR_IND\n" );
9847 printf( "\tN_UNBIND_REQ\n" );
9850 case N_UNITDATA_REQ:
9851 printf( "\tN_UNITDATA_REQ\n" );
9854 case N_UNITDATA_IND:
9855 printf( "\tN_UNITDATA_IND\n" );
9859 (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
9865 /* it looks like signal handling is not needed with streams! */
9866 /* x25oobh() - handle SIGURG signals - take from isode ? */
9872 Which time.h files to include... See ckcdeb.h for defaults.
9873 Note that 0, 1, 2, or all 3 of these can be included according to
9874 the symbol definitions.
9880 #endif /* NOTIMEH */
9884 #include <sys/time.h>
9885 #endif /* SYSTIMEH */
9886 #endif /* NOSYSTIMEH */
9890 #include <sys/timeb.h>
9891 #endif /* SYSTIMEBH */
9892 #endif /* NOSYSTIMEBH */
9898 #include <sys/time.h>
9904 #include <sys/time.h>
9907 #include <sys/time.h>
9910 #include <posix/time.h>
9913 #include <sys/time.h>
9919 /* #include <utime.h> */
9923 #endif /* SYSTIMEH */
9932 #include <sys/utime.h>
9934 #define utimbuf _utimbuf
9936 #define utime _utime
9938 #ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
9939 #include <sys/utime.h> /* for extra fields required by */
9940 #else /* 88Open spec. */
9941 #ifdef UTIMEH /* or <utime.h> if requested */
9942 #include <utime.h> /* (SVR4, POSIX) */
9943 #define SYSUTIMEH /* Use this for both cases. */
9945 #endif /* SYSUTIMEH */
9948 #ifdef VMS /* SMS 2007/02/15 */
9950 #endif /* def VMS */
9952 #ifndef HTTP_VERSION
9953 #define HTTP_VERSION "HTTP/1.1"
9954 #endif /* HTTP_VERSION */
9959 http_date(char * date)
9961 http_date(date) char * date;
9962 #endif /* CK_ANSIC */
9964 /* HTTP dates are of the form: "Sun, 06 Oct 1997 20:11:47 GMT" */
9965 /* There are two older formats which we are required to parse
9966 * that we currently do not:
9968 * RFC 850: "Sunday, 06-Oct-97 20:11:47 GMT"
9969 * asctime(): "Sun Nov 6 20:11:47 1997"
9971 * However, it is required that all dates be sent in the form we
9972 * do accept. The other two formats are for compatibility with
9973 * really old servers.
9975 extern char cmdatebuf[18];
9981 j = ckindex(",",date,0,0,0);
9982 ckstrncpy(ldate,&date[j+1],25);
9985 cmcvtate() date changed to return a string pointer.
9989 dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
9992 t_tm = *cmdate2tm(dp,1);
9995 From Lucas Hart, 5 Dec 2001:
9996 "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
9997 setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
9998 the specified (GMT) time if the buffer size is 21, or the contemporaneous
9999 localtime if the buffer size is 25. Perhaps tm_isdst should be set in
10000 cmdate2tm(), rather than only in http_date."
10002 #ifndef NOTM_ISDST /* For platforms where */
10003 t_tm.tm_isdst = -1; /* tm_isdst doesn't exist. */
10004 #endif /* NOTM_ISDST */
10006 t = mktime(&t_tm); /* NOT PORTABLE */
10010 #endif /* XX_TIMEZONE */
10014 #endif /* CMDATE2TM */
10018 static char nowstr[32];
10021 time_t ltime; /* NOT PORTABLE */
10025 gmt = gmtime(<ime); /* PROBABLY NOT PORTABLE */
10026 strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
10027 /* not only is it not portable but it's locale-dependent */
10030 This is hopeless. First of all, it seems that HTTP wants Day and Month
10031 NAMES? In English? Whose idea was that? Even worse, the date/time must be
10032 expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
10033 nightmare. Every platform does it differently, if at all -- even if we
10034 restrict ourselves to UNIX. For example (quoting from recent C-Kermit edit
10035 history), "Fixed a longstanding bug in the BSDI version, in which incoming
10036 file dates were set in GMT rather than local time. It seems in 4.4BSD,
10037 localtime() does not return the local time, but rather Zero Meridian (Zulu)
10038 time (GMT), and must be adjusted by the tm_gmtoff value." Swell. For
10039 greater appreciation of the scope of the problem, just take a look at the
10040 time-related #ifdefs in ckutio.c. The only right way to do this is to add
10041 our own portable API for converting between local time and GMT/UTC/Zulu
10042 that shields us not only from UNIXisms like time_t and struct tm, but also
10043 the unbelievable amount of differences in time-related APIs -- e.g. is
10044 "timezone" an external variable or a function; which header file(s) do we
10045 include, etc etc etc. It's a major project.
10048 x = cmcvtdate("",1);
10050 Evidently this code is not used -- if it is, it must be fixed to use
10051 new (aug 2001) cmcvtdate() calling conventions.
10055 /* yyyymmdd hh:mm:ss */
10056 /* 01234567890123456 */
10057 nowstr[0] = 'X'; /* 1st letter of day */
10058 nowstr[1] = 'x'; /* 2nd letter of day */
10059 nowstr[2] = 'x'; /* 3rd letter of day */
10062 nowstr[5] = cmdate[6];
10063 nowstr[6] = cmdate[7];
10065 nowstr[8] = ' '; /* first letter of month */
10066 nowstr[9] = ' '; /* second letter of month */
10067 nowstr[10] = ' '; /* third letter of month */
10069 nowstr[12] = cmdate[0];
10070 nowstr[13] = cmdate[1];
10071 nowstr[14] = cmdate[2];
10072 nowstr[15] = cmdate[3];
10074 nowstr[17] = cmdate[9];
10075 nowstr[18] = cmdate[10];
10076 nowstr[19] = cmdate[11];
10077 nowstr[20] = cmdate[12];
10078 nowstr[21] = cmdate[13];
10079 nowstr[22] = cmdate[14];
10080 nowstr[23] = cmdate[15];
10081 nowstr[24] = cmdate[16];
10087 #endif /* CMDATE2TM */
10092 #ifndef CK_AUTHENTICATION
10093 /* from ckuusr.h, which this module normally doesn't include */
10094 _PROTOTYP( int dclarray, (char, int) );
10095 #endif /* CK_AUTHENTICATION */
10098 Assign http response pairs to given array.
10099 For best results, response pairs should contain no spaces.
10102 resp = pointer to response list.
10103 n = size of response list.
10104 array = array letter.
10107 >= 1, size of array, on success.
10111 http_mkarray(char ** resp, int n, char array)
10113 http_mkarray(resp, n, array) char ** resp; int n; char array;
10114 #endif /* CK_ANSIC */
10119 extern char ** a_ptr[];
10120 extern int a_dim[];
10122 if (!array || n <= 0)
10124 if ((x = dclarray(array,n)) < 0) {
10125 printf("?Array declaration failure\n");
10128 /* Note: argument array is 0-based but Kermit array is 1-based */
10130 ap[0] = NULL; /* 0th element is empty */
10131 for (i = 1; i <= n; i++) {
10132 ap[i] = resp[i-1]; /* If resp elements were malloc'd */
10142 #define HTTPHEADCNT 64
10144 http_get_chunk_len()
10151 while ((ch = http_inc(0)) >= 0 && i < 24) {
10153 if ( buf[i] == ';' ) /* Find chunk-extension (if any) */
10155 if ( buf[i] == 10 ) { /* found end of line */
10156 if (i > 0 && buf[i-1] == 13)
10163 if ( i < 24 ) { /* buf now contains len in Hex */
10164 len = hextoulong(buf, j == -1 ? i : j-1);
10173 return(httpfd != -1);
10179 return(httpfd != -1 ? http_host_port : "");
10185 if ( httpfd == -1 )
10188 if (tls_http_active_flag) {
10189 SSL_CIPHER * cipher;
10190 const char *cipher_list;
10191 static char buf[128];
10193 cipher = SSL_get_current_cipher(tls_http_con);
10194 cipher_list = SSL_CIPHER_get_name(cipher);
10195 SSL_CIPHER_description(cipher,buf,sizeof(buf));
10198 #endif /* CK_SSL */
10206 char * s = NULL; /* strdup is not portable */
10207 if ( tcp_http_proxy ) {
10209 makestr(&s,(char *)http_host_port);
10211 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10212 if (*p == ':') { /* Have a colon */
10213 *p++ = '\0'; /* Get service name or number */
10217 rc = http_open(s,p,http_ssl,NULL,0,http_agent);
10219 makestr(&s,(char *)http_ip);
10220 rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
10229 http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
10230 int rdns_len, char * agent)
10231 #else /* CK_ANSIC */
10232 http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
10239 #endif /* CK_ANSIC */
10241 char namecopy[NAMECPYL];
10246 #ifdef SO_OOBINLINE
10248 #endif /* SO_OOBINLINE */
10249 struct servent *service=NULL;
10250 struct hostent *host=NULL;
10251 struct sockaddr_in r_addr;
10252 struct sockaddr_in sin;
10253 struct sockaddr_in l_addr;
10254 GSOCKNAME_T l_slen;
10256 struct sockaddr_in send_socket;
10257 #endif /* EXCELAN */
10260 /* inet_addr() is of type struct in_addr */
10262 extern struct in_addr inet_addr();
10265 extern struct in_addr inet_addr();
10266 #endif /* HPUX5WINTCP */
10267 #endif /* datageneral */
10268 struct in_addr iax;
10271 struct in_addr iax;
10272 #else /* INADDR_NONE */
10274 #endif /* INADDR_NONE */
10275 #endif /* INADDRX */
10277 if ( rdns_name == NULL || rdns_len < 0 )
10280 *http_ip = '\0'; /* Initialize IP address string */
10281 namecopy[0] = '\0';
10285 debug(F110,"http_open hostname",hostname,0);
10286 debug(F110,"http_open svcname",svcname,0);
10289 if (!hostname) hostname = "";
10290 if (!svcname) svcname = "";
10291 if (!*hostname || !*svcname) return(-1);
10294 service = ckgetservice(hostname,svcname,http_ip,20);
10296 if (service == NULL) {
10298 printf("?Invalid service: %s\r\n",svcname);
10302 /* For HTTP connections we must preserve the original hostname and */
10303 /* service requested so we can include them in the Host header. */
10304 ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
10305 ckuitoa(ntohs(service->s_port)),NULL);
10306 http_port = ntohs(service->s_port);
10307 http_ssl = use_ssl;
10308 debug(F111,"http_open",http_host_port,http_port);
10310 /* 'http_ip' contains the IP address to which we want to connect */
10311 /* 'svcnam' contains the service name */
10312 /* 'service->s_port' contains the port number in network byte order */
10314 /* If we are using an http proxy, we need to create a buffer containing */
10315 /* hostname:port-number */
10316 /* to pass to the http_connect() function. Then we need to replace */
10317 /* 'namecopy' with the name of the proxy server and the service->s_port */
10318 /* with the port number of the proxy (default port 80). */
10320 if ( tcp_http_proxy ) {
10322 ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
10323 ckuitoa(ntohs(service->s_port)),NULL);
10324 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10326 p = namecopy; /* Was a service requested? */
10327 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10328 if (*p == ':') { /* Have a colon */
10329 debug(F110,"http_open name has colon",namecopy,0);
10330 *p++ = '\0'; /* Get service name or number */
10332 strcpy(++p,"http");
10335 service = ckgetservice(namecopy,p,http_ip,20);
10337 fprintf(stderr, "Can't find port for service %s\n", p);
10339 debug(F101,"http_open can't get service for proxy","",socket_errno);
10341 debug(F101,"http_open can't get service for proxy","",errno);
10342 #endif /* TGVORWIN */
10343 errno = 0; /* (rather than mislead) */
10347 /* copy the proxyname and remove the service if any so we can use
10348 * it as the hostname
10350 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10351 p = namecopy; /* Was a service requested? */
10352 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10353 if (*p == ':') { /* Have a colon */
10354 *p = '\0'; /* terminate string */
10356 hostname = namecopy; /* use proxy as hostname */
10359 /* Set up socket structure and get host address */
10360 bzero((char *)&r_addr, sizeof(r_addr));
10361 debug(F100,"http_open bzero ok","",0);
10364 debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
10365 #else /* INADDR_NONE */
10366 debug(F100,"http_open INADDR_NONE not defined","",0);
10367 #endif /* INADDR_NONE */
10369 debug(F100,"http_open INADDRX defined","",0);
10370 #else /* INADDRX */
10371 debug(F100,"http_open INADDRX not defined","",0);
10372 #endif /* INADDRX */
10376 iax = inet_addr(http_ip[0]?http_ip:hostname);
10377 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10378 #else /* INADDRX */
10380 iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
10381 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10382 #else /* INADDR_NONE */
10383 #ifndef datageneral
10384 iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
10387 #endif /* datageneral */
10388 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
10389 #endif /* INADDR_NONE */
10390 #endif /* INADDRX */
10395 /* This might give warnings on 64-bit platforms but they should be harmless */
10396 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
10397 /* probably superfluous -- not sure why it's even there, maybe it should be */
10399 iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
10400 #else /* INADDR_NONE */
10402 #endif /* INADDR_NONE */
10405 printf(" DNS Lookup... ");
10408 if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
10409 debug(F100,"http_open gethostbyname != NULL","",0);
10410 host = ck_copyhostent(host);
10411 dns = 1; /* Remember we performed dns lookup */
10412 r_addr.sin_family = host->h_addrtype;
10413 if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
10414 && (tcp_http_proxy == NULL)
10416 ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
10420 /* This is for trying multiple IP addresses - see <netdb.h> */
10421 if (!(host->h_addr_list))
10423 bcopy(host->h_addr_list[0],
10424 (caddr_t)&r_addr.sin_addr,
10428 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10429 #endif /* h_addr */
10430 #else /* HADDRLIST */
10431 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10432 #endif /* HADDRLIST */
10435 debug(F111,"BCOPY","host->h_addr",host->h_addr);
10436 #endif /* EXCELAN */
10437 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
10438 (caddr_t)&r_addr.sin_addr);
10439 debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
10440 r_addr.sin_addr.s_addr);
10441 #endif /* COMMENT */
10442 debug(F111,"BCOPY","host->h_length",host->h_length);
10445 #endif /* NOMHHOST */
10449 /* inet_addr() is of type struct in_addr */
10450 struct in_addr ina;
10452 debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
10453 ina = inet_addr(http_ip[0]?http_ip:hostname);
10454 uu = *(unsigned int *)&ina;
10455 #else /* Not INADDRX */
10456 /* inet_addr() is unsigned long */
10458 debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
10459 uu = inet_addr(http_ip[0]?http_ip:hostname);
10460 #endif /* INADDRX */
10461 debug(F101,"http_open uu","",uu);
10464 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
10465 #else /* INADDR_NONE */
10466 uu != ((unsigned long)-1)
10467 #endif /* INADDR_NONE */
10469 r_addr.sin_addr.s_addr = uu;
10470 r_addr.sin_family = AF_INET;
10473 fprintf(stdout, "\r\n"); /* complete any previous message */
10475 fprintf(stderr, "Can't get address for %s\n",
10476 http_ip[0]?http_ip:hostname);
10478 debug(F101,"http_open can't get address","",socket_errno);
10480 debug(F101,"http_open can't get address","",errno);
10481 #endif /* TGVORWIN */
10482 errno = 0; /* Rather than mislead */
10487 /* Get a file descriptor for the connection. */
10489 r_addr.sin_port = service->s_port;
10490 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10491 debug(F110,"http_open trying",http_ip,0);
10492 if (!quiet && *http_ip) {
10493 printf(" Trying %s... ", http_ip);
10497 /* Loop to try additional IP addresses, if any. */
10501 send_socket.sin_family = AF_INET;
10502 send_socket.sin_addr.s_addr = 0;
10503 send_socket.sin_port = 0;
10504 if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
10505 &send_socket, SO_REUSEADDR)) < 0)
10506 #else /* EXCELAN */
10507 if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
10508 #endif /* EXCELAN */
10511 experror("TCP socket error");
10515 errno = socket_errno;
10516 #endif /* OLD_TWG */
10517 socket_perror("TCP socket error");
10518 debug(F101,"http_open socket error","",socket_errno);
10520 perror("TCP socket error");
10521 debug(F101,"http_open socket error","",errno);
10522 #endif /* TGVORWIN */
10523 #endif /* EXCELAN */
10528 /* If a specific TCP address on the local host is desired we */
10529 /* must bind it to the socket. */
10530 #ifndef datageneral
10534 debug(F110,"http_open binding socket to",tcp_address,0);
10535 bzero((char *)&sin,sizeof(sin));
10536 sin.sin_family = AF_INET;
10538 inaddrx = inet_addr(tcp_address);
10539 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
10541 sin.sin_addr.s_addr = inet_addr(tcp_address);
10542 #endif /* INADDRX */
10544 if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
10545 s_errno = socket_errno; /* Save error code */
10547 socket_close(httpfd);
10548 #else /* TCPIPLIB */
10550 #endif /* TCPIPLIB */
10552 errno = s_errno; /* and report this error */
10553 debug(F101,"http_open bind errno","",errno);
10557 #endif /* datageneral */
10559 /* Now connect to the socket on the other end. */
10562 if (connect(httpfd, &r_addr) < 0)
10565 WSASafeToCancel = 1;
10567 if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
10568 #endif /* EXCELAN */
10571 WSASafeToCancel = 0;
10579 i = errno; /* Save error code */
10580 #endif /* TGVORWIN */
10584 if (host && host->h_addr_list && host->h_addr_list[1]) {
10586 host->h_addr_list++;
10587 bcopy(host->h_addr_list[0],
10588 (caddr_t)&r_addr.sin_addr,
10591 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10592 debug(F110,"http_open h_addr_list",http_ip,0);
10593 if (!quiet && *http_ip) {
10594 printf(" Trying %s... ", http_ip);
10598 socket_close(httpfd); /* Close it. */
10601 #endif /* TCPIPLIB */
10604 #endif /* h_addr */
10605 #endif /* HADDRLIST */
10608 errno = i; /* And report this error */
10610 if (errno) experror("http_open connect");
10613 debug(F101,"http_open connect error","",socket_errno);
10614 /* if (errno) socket_perror("http_open connect"); */
10616 errno = socket_errno;
10617 #endif /* OLD_TWG */
10619 socket_perror("http_open connect");
10620 #else /* TGVORWIN */
10621 debug(F101,"http_open connect errno","",errno);
10624 perror("\r\nFailed");
10631 perror("http_open connect");
10632 #endif /* DEC_TCPIP */
10635 perror("http_open connect");
10636 #endif /* CMU_TCPIP */
10637 #endif /* TGVORWIN */
10638 #endif /* EXCELAN */
10642 WSASafeToCancel = 0;
10645 } while (!isconnect);
10647 #ifdef NON_BLOCK_IO
10649 x = socket_ioctl(httpfd,FIONBIO,&on);
10650 debug(F101,"http_open FIONBIO","",x);
10651 #endif /* NON_BLOCK_IO */
10653 /* We have succeeded in connecting to the HTTP PROXY. So now we */
10654 /* need to attempt to connect through the proxy to the actual host */
10655 /* If that is successful, we have to pretend that we made a direct */
10656 /* connection to the actual host. */
10658 if ( tcp_http_proxy ) {
10661 agent = "Kermit 95"; /* Default user agent */
10664 agent = "C-Kermit";
10667 if (http_connect(httpfd,
10668 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
10670 tcp_http_proxy_user,
10671 tcp_http_proxy_pwd,
10680 #ifdef SO_OOBINLINE
10681 /* See note on SO_OOBINLINE in netopen() */
10683 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10686 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10689 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10692 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10695 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10699 Maybe this applies to all SVR4 versions, but the other (else) way has been
10700 compiling and working fine on all the others, so best not to change it.
10702 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10705 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10710 rc = setsockopt(httpfd,
10716 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
10719 #ifdef VMS /* or, at least, VMS with gcc */
10720 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10723 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10725 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
10730 #endif /* SOLARIS */
10731 #endif /* MOTSV88R4 */
10735 #endif /* datageneral */
10736 #endif /* SO_OOBINLINE */
10739 #ifndef datageneral
10742 no_delay(ttyfd,tcp_nodelay);
10743 #endif /* TCP_NODELAY */
10744 #ifdef SO_KEEPALIVE
10745 keepalive(ttyfd,tcp_keepalive);
10746 #endif /* SO_KEEPALIVE */
10748 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
10749 #endif /* SO_LINGER */
10751 sendbuf(ttyfd,tcp_sendbuf);
10752 #endif /* SO_SNDBUF */
10754 recvbuf(ttyfd,tcp_recvbuf);
10755 #endif /* SO_RCVBUF */
10756 #endif /* SOL_SOCKET */
10757 #endif /* datageneral */
10758 #endif /* NOTCPOPTS */
10760 #ifndef datageneral
10761 /* Find out our own IP address. */
10762 /* We need the l_addr structure for [E]KLOGIN. */
10763 l_slen = sizeof(l_addr);
10764 bzero((char *)&l_addr, l_slen);
10766 if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
10767 char * s = (char *)inet_ntoa(l_addr.sin_addr);
10768 ckstrncpy(myipaddr, s, 20);
10769 debug(F110,"getsockname",myipaddr,0);
10771 #endif /* EXCELAN */
10772 #endif /* datageneral */
10774 /* See note in netopen() on Reverse DNS lookups */
10775 if (tcp_rdns == SET_ON) {
10781 printf(" Reverse DNS Lookup... ");
10784 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
10786 host = ck_copyhostent(host);
10787 debug(F100,"http_open gethostbyname != NULL","",0);
10793 if (!s) { /* This can happen... */
10794 debug(F100,"http_open host->h_name is NULL","",0);
10797 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
10798 /* The compiler says "Integral value implicitly converted to */
10799 /* pointer in assignment." The prototype is right there */
10800 /* in <arpa/inet.h> so what's the problem? */
10801 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
10802 if (!*s) { /* No name so substitute the address */
10803 debug(F100,"http_open host->h_name is empty","",0);
10804 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
10805 if (!s) /* Trust No 1 */
10807 if (*s) { /* If it worked, use this string */
10808 ckstrncpy(http_ip,s,20);
10810 s = http_ip; /* Otherwise stick with the IP */
10811 if (!*s) /* or failing that */
10812 s = http_host_port; /* the name we were called with. */
10814 if (*s) /* return the rdns name */
10815 ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
10822 printf(" %s connected on port %s\n",s,
10823 ckuitoa(ntohs(service->s_port)));
10825 /* This is simply for testing the DNS entries */
10826 if (host->h_aliases) {
10827 char ** a = host->h_aliases;
10829 printf(" alias => %s\n",*a);
10833 #endif /* BETADEBUG */
10836 if (!quiet) printf("Failed.\n");
10838 } else if (!quiet) printf("(OK)\n");
10839 if (!quiet) fflush(stdout);
10842 if ( tcp_http_proxy ) {
10843 /* Erase the IP address since we cannot reuse it */
10846 /* This should already have been done but just in case */
10847 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10849 makestr(&http_agent,agent);
10852 if (use_ssl && ck_ssleay_is_installed()) {
10853 if (!ssl_http_init(hostname)) {
10854 if (bio_err!=NULL) {
10855 BIO_printf(bio_err,"ssl_tn_init() failed\n");
10856 ERR_print_errors(bio_err);
10859 fprintf(stderr,"ssl_tn_init() failed\n");
10860 ERR_print_errors_fp(stderr);
10864 } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
10869 #endif /* CK_SSL */
10870 #endif /* TCPSOCKET */
10872 return(0); /* Done. */
10878 #else /* CK_ANSIC */
10880 #endif /* CK_ANSIC */
10883 debug(F101,"http_close","",httpfd);
10885 #ifdef HTTP_BUFFERING
10888 #endif /* HTTP_BUFFERING */
10890 if (httpfd == -1) /* Was open? */
10891 return(0); /* Wasn't. */
10894 if (httpfd > -1) /* Was. */
10898 if (tls_http_active_flag) {
10899 if (ssl_debug_flag)
10900 BIO_printf(bio_err,"calling SSL_shutdown\n");
10901 SSL_shutdown(tls_http_con);
10902 tls_http_active_flag = 0;
10904 #endif /* CK_SSL */
10906 x = socket_close(httpfd); /* Close it. */
10911 #endif /* TCPIPLIB */
10913 httpfd = -1; /* Mark it as closed. */
10914 /* do not erase http_host_port, http_ip, http_port so they */
10915 /* can be used by http_reopen() */
10921 * Call with s = pointer to string, n = length.
10922 * Returns number of bytes actually written on success, or
10923 * -1 on i/o error, -2 if called improperly.
10927 http_tol(s,n) CHAR *s; int n; {
10932 if (httpfd == -1) {
10933 debug(F100,"http_tol socket is closed","",0);
10936 debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
10938 ckhexdump("http_tol",s,n);
10939 #endif /* COMMENT */
10942 if (tls_http_active_flag) {
10944 /* Write using SSL */
10946 r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
10947 switch (SSL_get_error(tls_http_con,r)) {
10948 case SSL_ERROR_NONE:
10949 debug(F111,"http_tol","SSL_write",r);
10955 case SSL_ERROR_WANT_WRITE:
10956 debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
10958 case SSL_ERROR_WANT_READ:
10959 debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
10961 case SSL_ERROR_SYSCALL:
10962 if ( r == 0 ) { /* EOF */
10968 int gle = GetLastError();
10969 debug(F111,"http_tol SSL_ERROR_SYSCALL",
10970 "GetLastError()",gle);
10971 rc = os2socketerror(gle);
10974 else if ( rc == -2 )
10979 case SSL_ERROR_WANT_X509_LOOKUP:
10980 debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
10983 case SSL_ERROR_SSL:
10984 debug(F100,"http_tol SSL_ERROR_SSL","",0);
10987 case SSL_ERROR_ZERO_RETURN:
10988 debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
10992 debug(F100,"http_tol SSL_ERROR_?????","",0);
10997 #endif /* CK_SSL */
11000 try++; /* Increase the try counter */
11007 debug(F101,"http_tol BSDSELECT","",0);
11011 WSASafeToCancel = 1;
11015 #endif /* STREAMING */
11017 FD_SET(httpfd, &wfds);
11018 if (select(FD_SETSIZE, NULL,
11022 #endif /* __DECC_VER */
11023 #endif /* __DECC */
11024 &wfds, NULL, &tv) < 0) {
11025 int s_errno = socket_errno;
11026 debug(F101,"http_tol select failed","",s_errno);
11028 printf("http_tol select failed: %d\n", s_errno);
11029 #endif /* BETADEBUG */
11031 WSASafeToCancel = 0;
11032 if (!win95selectbug)
11036 if (!FD_ISSET(httpfd, &wfds)) {
11040 #endif /* STREAMING */
11041 debug(F111,"http_tol","!FD_ISSET",ttyfd);
11043 WSASafeToCancel = 0;
11044 if (!win95selectbug)
11049 WSASafeToCancel = 0;
11051 #else /* BSDSELECT */
11055 debug(F101,"http_tol IBMSELECT","",0);
11056 while (select(&httpfd, 0, 1, 0, 1000) != 1) {
11058 if (tries++ >= 60) {
11059 /* if after 60 seconds we can't get permission to write */
11060 debug(F101,"http_tol select failed","",socket_errno);
11064 if ((count = http_tchk()) < 0) {
11065 debug(F111,"http_tol","http_tchk()",count);
11068 #endif /* COMMENT */
11071 #endif /* IBMSELECT */
11072 #endif /* BSDSELECT */
11074 if ((count = socket_write(httpfd,s,n)) < 0) {
11075 int s_errno = socket_errno; /* maybe a function */
11076 debug(F101,"http_tol socket_write error","",s_errno);
11078 if (os2socketerror(s_errno) < 0)
11081 return(-1); /* Call it an i/o error */
11083 #else /* TCPIPLIB */
11084 if ((count = write(httpfd,s,n)) < 0) {
11085 debug(F101,"http_tol socket_write error","",errno);
11086 return(-1); /* Call it an i/o error */
11088 #endif /* TCPIPLIB */
11090 debug(F111,"http_tol socket_write",s,count);
11092 /* don't try more than 25 times */
11093 debug(F100,"http_tol tried more than 25 times","",0);
11100 debug(F111,"http_tol retry",s,n);
11101 goto http_tol_retry;
11103 debug(F111,"http_tol socket_write",s,count);
11104 return(len); /* success - return total length */
11110 http_inc(timo) int timo; {
11111 int x=-1; unsigned char c; /* The locals. */
11113 if (httpfd == -1) {
11114 #ifdef HTTP_BUFFERING
11117 #endif /* HTTP_BUFFERING */
11118 debug(F100,"http_inc socket is closed","",0);
11124 * In the case of OpenSSL, it is possible that there is still
11125 * data waiting in the SSL session buffers that has not yet
11126 * been read by Kermit. If this is the case we must process
11127 * it without calling select() because select() will not return
11128 * with an indication that there is data to be read from the
11129 * socket. If there is no data pending in the SSL session
11130 * buffers then fall through to the select() code and wait for
11131 * some data to arrive.
11133 if (tls_http_active_flag) {
11136 x = SSL_pending(tls_http_con);
11138 debug(F111,"http_inc","SSL_pending error",x);
11141 } else if ( x > 0 ) {
11143 x = SSL_read(tls_http_con, &c, 1);
11144 error = SSL_get_error(tls_http_con,x);
11146 case SSL_ERROR_NONE:
11147 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11150 ReleaseTCPIPMutex();
11152 return(c); /* Return character. */
11153 } else if (x < 0) {
11155 ReleaseTCPIPMutex();
11161 ReleaseTCPIPMutex();
11165 case SSL_ERROR_WANT_WRITE:
11166 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11168 ReleaseTCPIPMutex();
11171 case SSL_ERROR_WANT_READ:
11172 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11174 ReleaseTCPIPMutex();
11177 case SSL_ERROR_SYSCALL:
11178 if ( x == 0 ) { /* EOF */
11181 ReleaseTCPIPMutex();
11187 int gle = GetLastError();
11188 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11189 "GetLastError()",gle);
11190 rc = os2socketerror(gle);
11193 else if ( rc == -2 )
11197 ReleaseTCPIPMutex();
11201 case SSL_ERROR_WANT_X509_LOOKUP:
11202 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11205 ReleaseTCPIPMutex();
11208 case SSL_ERROR_SSL:
11209 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11212 #endif /* COMMENT */
11214 ReleaseTCPIPMutex();
11217 case SSL_ERROR_ZERO_RETURN:
11218 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11221 ReleaseTCPIPMutex();
11225 debug(F100,"http_inc SSL_ERROR_?????","",0);
11228 ReleaseTCPIPMutex();
11234 #endif /* CK_SSL */
11236 #ifdef HTTP_BUFFERING
11237 /* Skip all the select() stuff if we have bytes buffered locally */
11238 if (http_count > 0)
11239 goto getfrombuffer;
11240 #endif /* HTTP_BUFFERING */
11246 int timeout = timo < 0 ? -timo : 1000 * timo;
11247 debug(F101,"http_inc BSDSELECT","",timo);
11249 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11251 debug(F111,"http_inc","timeout",timeout);
11252 /* Don't move select() initialization out of the loop. */
11254 FD_SET(httpfd, &rfds);
11255 tv.tv_sec = tv.tv_usec = 0L;
11257 tv.tv_usec = (long) 100000L;
11261 WSASafeToCancel = 1;
11263 rc = select(FD_SETSIZE,
11266 #endif /* __DECC */
11267 &rfds, NULL, NULL, &tv);
11269 int s_errno = socket_errno;
11270 debug(F111,"http_inc","select",rc);
11271 debug(F111,"http_inc","socket_errno",s_errno);
11272 #ifdef HTTP_BUFFERING
11275 #endif /* HTTP_BUFFERING */
11279 debug(F111,"http_inc","select",rc);
11281 WSASafeToCancel = 0;
11283 if (FD_ISSET(httpfd, &rfds)) {
11287 /* If waiting forever we have no way of knowing if the */
11288 /* socket closed so try writing a 0-length TCP packet */
11289 /* which should force an error if the socket is closed */
11292 if ((rc = socket_write(httpfd,"",0)) < 0) {
11293 #ifdef HTTP_BUFFERING
11296 #endif /* HTTP_BUFFERING */
11297 int s_errno = socket_errno;
11298 debug(F101,"http_inc socket_write error","",s_errno);
11300 if (os2socketerror(s_errno) < 0)
11303 return(-1); /* Call it an i/o error */
11305 #else /* TCPIPLIB */
11306 if ((rc = write(httpfd,"",0)) < 0) {
11307 #ifdef HTTP_BUFFERING
11310 #endif /* HTTP_BUFFERING */
11311 debug(F101,"http_inc socket_write error","",errno);
11312 return(-1); /* Call it an i/o error */
11314 #endif /* TCPIPLIB */
11320 WSASafeToCancel = 0;
11322 #else /* !BSDSELECT */
11325 Was used by OS/2, currently not used, but might come in handy some day...
11326 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
11327 and timeval stuff since this is the only place where it is used.
11329 int socket = httpfd;
11330 int timeout = timo < 0 ? -timo : 1000 * timo;
11332 debug(F101,"http_inc IBMSELECT","",timo);
11333 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11334 if (select(&socket, 1, 0, 0, 100L) == 1) {
11339 #else /* !IBMSELECT */
11340 SELECT is required for this code
11341 #endif /* IBMSELECT */
11342 #endif /* BSDSELECT */
11345 if (timo && x < 0) { /* select() timed out */
11346 #ifdef HTTP_BUFFERING
11349 #endif /* HTTP_BUFFERING */
11350 debug(F100,"http_inc select() timed out","",0);
11351 return(-1); /* Call it an i/o error */
11355 if ( tls_http_active_flag ) {
11358 x = SSL_read(tls_http_con, &c, 1);
11359 error = SSL_get_error(tls_http_con,x);
11361 case SSL_ERROR_NONE:
11362 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11365 ReleaseTCPIPMutex();
11367 return(c); /* Return character. */
11368 } else if (x < 0) {
11370 ReleaseTCPIPMutex();
11376 ReleaseTCPIPMutex();
11380 case SSL_ERROR_WANT_WRITE:
11381 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11383 ReleaseTCPIPMutex();
11386 case SSL_ERROR_WANT_READ:
11387 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11389 ReleaseTCPIPMutex();
11392 case SSL_ERROR_SYSCALL:
11393 if ( x == 0 ) { /* EOF */
11396 ReleaseTCPIPMutex();
11402 int gle = GetLastError();
11403 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11404 "GetLastError()",gle);
11405 rc = os2socketerror(gle);
11408 else if ( rc == -2 )
11412 ReleaseTCPIPMutex();
11416 case SSL_ERROR_WANT_X509_LOOKUP:
11417 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11420 ReleaseTCPIPMutex();
11423 case SSL_ERROR_SSL:
11424 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11427 #endif /* COMMENT */
11429 ReleaseTCPIPMutex();
11432 case SSL_ERROR_ZERO_RETURN:
11433 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11436 ReleaseTCPIPMutex();
11440 debug(F100,"http_inc SSL_ERROR_?????","",0);
11443 ReleaseTCPIPMutex();
11448 #endif /* CK_SSL */
11450 #ifdef HTTP_BUFFERING
11452 Buffering code added by fdc 15 Dec 2005 for non-SSL case only because HTTP
11453 GETs were orders of magnitude too slow due to the single-byte read()s. The
11454 file-descriptor swapping is pretty gross, but the more elegant solution
11455 (calling a nettchk() like routine with the fd as a parameter) doesn't work,
11456 because nettchk() relies on too many other routines that, like itself, are
11457 hardwired for ttyfd.
11460 if (--http_count >= 0) {
11461 c = http_inbuf[http_bufp++];
11469 debug(F101,"http_inc nettchk","",x);
11470 if (x > HTTP_INBUFLEN)
11473 x = socket_read(httpfd,http_inbuf,x);
11474 #else /* Not TCPIPLIB */
11475 x = read(httpfd,http_inbuf,x);
11476 #endif /* TCPIPLIB */
11480 c = http_inbuf[http_bufp++];
11481 http_count = x - 1;
11484 #else /* Not HTTP_BUFFERING */
11486 x = socket_read(httpfd,&c,1);
11487 #else /* Not TCPIPLIB */
11488 x = read(httpfd,&c,1);
11489 #endif /* TCPIPLIB */
11490 #endif /* HTTP_BUFFERING */
11493 int s_errno = socket_errno;
11494 debug(F101,"ttbufr socket_read","",x);
11495 debug(F101,"ttbufr socket_errno","",s_errno);
11497 if (x == 0 || os2socketerror(s_errno) < 0) {
11499 ReleaseTCPIPMutex();
11502 ReleaseTCPIPMutex();
11505 http_close(); /* *** *** */
11514 http_set_code_reply(char * msg)
11516 http_set_code_reply(msg)
11518 #endif /* CK_ANSIC */
11524 while ( *p != SP && *p != NUL ) {
11530 http_code = atoi(buf);
11535 ckstrncpy(http_reply_str,p,HTTPBUFLEN);
11540 http_get(char * agent, char ** hdrlist, char * user,
11541 char * pwd, char array, char * local, char * remote,
11544 http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
11545 char * agent; char ** hdrlist; char * user;
11546 char * pwd; char array; char * local; char * remote;
11548 #endif /* CK_ANSIC */
11550 char * request = NULL;
11551 int i, j, len = 0, hdcnt = 0, rc = 0;
11554 char buf[HTTPBUFLEN], *p;
11557 struct utimbuf u_t;
11560 struct utimbuf u_t;
11566 #endif /* SYSUTIMH */
11570 time_t local_t = 0;
11574 char * headers[HTTPHEADCNT];
11582 debug(F101,"http_get httpfd","",httpfd);
11583 debug(F110,"http_agent",agent,0);
11584 debug(F110,"http_user",user,0);
11585 debug(F110,"http_local",local,0);
11586 debug(F110,"http_remote",remote,0);
11589 if (!remote) remote = "";
11595 for (i = 0; i < HTTPHEADCNT; i++)
11599 len += strlen(HTTP_VERSION);
11600 len += strlen(remote);
11604 for (i = 0; hdrlist[i]; i++)
11605 len += strlen(hdrlist[i]) + 2;
11607 len += (int) strlen(http_host_port) + 8;
11610 len += 13 + strlen(agent);
11613 readpass("Password: ",passwd,64);
11616 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11617 j = b8tob64(b64in,strlen(b64in),b64out,256);
11618 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11625 len += 19; /* Connection: close */
11627 len += 3; /* blank line + null */
11629 request = malloc(len);
11633 sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION); /* safe */
11634 ckstrncat(request,"Host: ", len);
11635 ckstrncat(request,http_host_port, len);
11636 ckstrncat(request,"\r\n",len);
11638 ckstrncat(request,"User-agent: ",len);
11639 ckstrncat(request,agent,len);
11640 ckstrncat(request,"\r\n",len);
11643 ckstrncat(request,"Authorization: Basic ",len);
11644 ckstrncat(request,b64out,len);
11645 ckstrncat(request,"\r\n",len);
11648 for (i = 0; hdrlist[i]; i++) {
11649 ckstrncat(request,hdrlist[i],len);
11650 ckstrncat(request,"\r\n",len);
11654 ckstrncat(request,"Connection: close\r\n",len);
11656 ckstrncat(request,"\r\n",len);
11659 if (http_tol((CHAR *)request,strlen(request)) < 0)
11671 /* Process the headers */
11672 local_t = time(NULL);
11676 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11678 if ( buf[i] == 10 ) { /* found end of line */
11679 if (i > 0 && buf[i-1] == 13)
11684 if (array && !nullline && hdcnt < HTTPHEADCNT)
11685 makestr(&headers[hdcnt++],buf);
11686 if (!ckstrcmp(buf,"HTTP",4,0)) {
11688 j = ckindex(" ",buf,0,0,0);
11690 while ( isspace(*p) )
11693 case '1': /* Informational message */
11695 case '2': /* Success */
11697 case '3': /* Redirection */
11698 case '4': /* Client failure */
11699 case '5': /* Server failure */
11700 default: /* Unknown */
11702 printf("Failure: Server reports %s\n",p);
11706 http_set_code_reply(p);
11708 } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11709 mod_t = http_date(&buf[15]);
11710 } else if (!ckstrcmp(buf,"Date",4,0)) {
11711 srv_t = http_date(&buf[4]);
11712 #endif /* CMDATE2TM */
11713 } else if (!ckstrcmp(buf,"Connection:",11,0)) {
11714 if ( ckindex("close",buf,11,0,0) != 0 )
11716 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11717 len = atoi(&buf[16]);
11718 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11719 if ( ckindex("chunked",buf,18,0,0) != 0 )
11721 debug(F101,"http_get chunked","",chunked);
11728 if (ch < 0 && first) {
11734 if (http_fnd == 0) {
11740 /* Now we have the contents of the file */
11741 if ( local && local[0] ) {
11742 if (zopeno(ZOFILE,local,NULL,NULL))
11749 while ((len = http_get_chunk_len()) > 0) {
11750 while (len && (ch = http_inc(0)) >= 0) {
11753 zchout(ZOFILE,(CHAR)ch);
11757 if ((ch = http_inc(0)) != CR)
11759 if ((ch = http_inc(0)) != LF)
11763 while (len && (ch = http_inc(0)) >= 0) {
11766 zchout(ZOFILE,(CHAR)ch);
11775 if ( chunked ) { /* Parse Trailing Headers */
11777 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11779 if ( buf[i] == 10 ) { /* found end of line */
11780 if (i > 0 && buf[i-1] == 13)
11785 if (array && !nullline && hdcnt < HTTPHEADCNT)
11786 makestr(&headers[hdcnt++],buf);
11788 if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11789 mod_t = http_date(&buf[15]);
11790 } else if (!ckstrcmp(buf,"Date",4,0)) {
11791 srv_t = http_date(&buf[4]);
11793 #endif /* CMDATE2TM */
11794 else if (!ckstrcmp(buf,"Connection:",11,0)) {
11795 if ( ckindex("close",buf,11,0,0) != 0 )
11805 if ( zfile ) { /* Set timestamp */
11808 u_t.actime = srv_t ? srv_t : local_t;
11809 u_t.modtime = mod_t ? mod_t : local_t;
11812 u_t.actime = srv_t ? srv_t : local_t;
11813 u_t.modtime = mod_t ? mod_t : local_t;
11816 u_t[0].tv_sec = srv_t ? srv_t : local_t;
11817 u_t[1].tv_sec = mod_t ? mod_t : local_t;
11819 u_t.mtime = srv_t ? srv_t : local_t;
11820 u_t.atime = mod_t ? mod_t : local_t;
11822 #endif /* SYSUTIMEH */
11825 #endif /* NOSETTIME */
11830 http_mkarray(headers,hdcnt,array);
11835 for (i = 0; i < hdcnt; i++) {
11844 http_head(char * agent, char ** hdrlist, char * user,
11845 char * pwd, char array, char * local, char * remote,
11848 http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
11849 char * agent; char ** hdrlist; char * user;
11850 char * pwd; char array; char * local; char * remote;
11852 #endif /* CK_ANSIC */
11854 char * request = NULL;
11855 int i, j, len = 0, hdcnt = 0, rc = 0;
11858 char buf[HTTPBUFLEN], *p;
11866 char * headers[HTTPHEADCNT];
11874 for (i = 0; i < HTTPHEADCNT; i++)
11877 len = 9; /* HEAD */
11878 len += strlen(HTTP_VERSION);
11879 len += strlen(remote);
11883 for (i = 0; hdrlist[i]; i++)
11884 len += strlen(hdrlist[i]) + 2;
11886 len += strlen(http_host_port) + 8;
11889 len += 13 + strlen(agent);
11892 readpass("Password: ",passwd,64);
11895 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11896 j = b8tob64(b64in,strlen(b64in),b64out,256);
11897 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11904 len += 19; /* Connection: close */
11906 len += 3; /* blank line + null */
11908 request = (char *)malloc(len);
11912 sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
11913 ckstrncat(request,"Host: ", len);
11914 ckstrncat(request,http_host_port, len);
11915 ckstrncat(request,"\r\n",len);
11917 ckstrncat(request,"User-agent: ",len);
11918 ckstrncat(request,agent,len);
11919 ckstrncat(request,"\r\n",len);
11922 ckstrncat(request,"Authorization: Basic ",len);
11923 ckstrncat(request,b64out,len);
11924 ckstrncat(request,"\r\n",len);
11927 for (i = 0; hdrlist[i]; i++) {
11928 ckstrncat(request,hdrlist[i],len);
11929 ckstrncat(request,"\r\n",len);
11933 ckstrncat(request,"Connection: close\r\n",len);
11935 ckstrncat(request,"\r\n",len);
11937 if ( local && local[0] ) {
11938 if (!zopeno(ZOFILE,local,NULL,NULL)) {
11945 if (http_tol((CHAR *)request,strlen(request)) < 0)
11957 /* Process the headers */
11959 local_t = time(NULL);
11962 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11964 if (buf[i] == 10) { /* found end of line */
11965 if (i > 0 && buf[i-1] == 13)
11970 if (array && !nullline && hdcnt < HTTPHEADCNT)
11971 makestr(&headers[hdcnt++],buf);
11972 if (!ckstrcmp(buf,"HTTP",4,0)) {
11974 j = ckindex(" ",buf,0,0,0);
11976 while (isspace(*p))
11979 case '1': /* Informational message */
11981 case '2': /* Success */
11983 case '3': /* Redirection */
11984 case '4': /* Client failure */
11985 case '5': /* Server failure */
11986 default: /* Unknown */
11988 printf("Failure: Server reports %s\n",p);
11991 http_set_code_reply(p);
11993 if (!ckstrcmp(buf,"Connection:",11,0)) {
11994 if ( ckindex("close",buf,11,0,0) != 0 )
11997 if ( local && local[0] ) {
11999 zsout(ZOFILE,"\r\n");
12002 printf("%s\r\n",buf);
12009 if (ch < 0 && first) {
12015 if ( http_fnd == 0 )
12019 http_mkarray(headers,hdcnt,array);
12022 if ( local && local[0] )
12027 for (i = 0; i < hdcnt; i++) {
12036 http_index(char * agent, char ** hdrlist, char * user, char * pwd,
12037 char array, char * local, char * remote, int stdio)
12039 http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
12040 char * agent; char ** hdrlist; char * user; char * pwd;
12041 char array; char * local; char * remote; int stdio;
12042 #endif /* CK_ANSIC */
12044 char * request = NULL;
12045 int i, j, len = 0, hdcnt = 0, rc = 0;
12048 char buf[HTTPBUFLEN], *p;
12056 char * headers[HTTPHEADCNT];
12066 for (i = 0; i < HTTPHEADCNT; i++)
12069 len = 10; /* INDEX */
12070 len += strlen(HTTP_VERSION);
12071 len += strlen(remote);
12075 for (i = 0; hdrlist[i]; i++)
12076 len += strlen(hdrlist[i]) + 2;
12078 len += strlen(http_host_port) + 8;
12081 len += 13 + strlen(agent);
12084 readpass("Password: ",passwd,64);
12087 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12088 j = b8tob64(b64in,strlen(b64in),b64out,256);
12089 memset(pwd,0,strlen(pwd));
12096 len += 19; /* Connection: close */
12098 len += 3; /* blank line + null */
12100 request = malloc(len);
12104 sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
12105 ckstrncat(request,"Host: ", len);
12106 ckstrncat(request,http_host_port, len);
12107 ckstrncat(request,"\r\n",len);
12109 ckstrncat(request,"User-agent: ",len);
12110 ckstrncat(request,agent,len);
12111 ckstrncat(request,"\r\n",len);
12114 ckstrncat(request,"Authorization: Basic ",len);
12115 ckstrncat(request,b64out,len);
12116 ckstrncat(request,"\r\n",len);
12119 for (i = 0; hdrlist[i]; i++) {
12120 ckstrncat(request,hdrlist[i],len);
12121 ckstrncat(request,"\r\n",len);
12125 ckstrncat(request,"Connection: close\r\n",len);
12127 ckstrncat(request,"\r\n",len);
12129 if (http_tol((CHAR *)request,strlen(request)) < 0)
12141 /* Process the headers */
12142 local_t = time(NULL);
12146 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12148 if (buf[i] == 10) { /* found end of line */
12149 if (i > 0 && buf[i-1] == 13)
12154 if (array && !nullline && hdcnt < HTTPHEADCNT)
12155 makestr(&headers[hdcnt++],buf);
12156 if (!ckstrcmp(buf,"HTTP",4,0)) {
12158 j = ckindex(" ",buf,0,0,0);
12160 while (isspace(*p))
12163 case '1': /* Informational message */
12165 case '2': /* Success */
12167 case '3': /* Redirection */
12168 case '4': /* Client failure */
12169 case '5': /* Server failure */
12170 default: /* Unknown */
12172 printf("Failure: Server reports %s\n",p);
12175 http_set_code_reply(p);
12176 } else if ( !nullline ) {
12177 if (!ckstrcmp(buf,"Connection:",11,0)) {
12178 if ( ckindex("close",buf,11,0,0) != 0 )
12180 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12181 len = atoi(&buf[16]);
12182 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12183 if ( ckindex("chunked",buf,18,0,0) != 0 )
12185 debug(F101,"http_index chunked","",chunked);
12187 printf("%s\n",buf);
12195 if (ch < 0 && first) {
12201 if ( http_fnd == 0 ) {
12207 /* Now we have the contents of the file */
12208 if ( local && local[0] ) {
12209 if (zopeno(ZOFILE,local,NULL,NULL))
12216 while ((len = http_get_chunk_len()) > 0) {
12217 while (len && (ch = http_inc(0)) >= 0) {
12220 zchout(ZOFILE,(CHAR)ch);
12224 if ((ch = http_inc(0)) != CR)
12226 if ((ch = http_inc(0)) != LF)
12230 while (len && (ch = http_inc(0)) >= 0) {
12233 zchout(ZOFILE,(CHAR)ch);
12242 if ( chunked ) { /* Parse Trailing Headers */
12244 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12246 if ( buf[i] == 10 ) { /* found end of line */
12247 if (i > 0 && buf[i-1] == 13)
12252 if (array && !nullline && hdcnt < HTTPHEADCNT)
12253 makestr(&headers[hdcnt++],buf);
12254 if (!ckstrcmp(buf,"Connection:",11,0)) {
12255 if ( ckindex("close",buf,11,0,0) != 0 )
12268 http_mkarray(headers,hdcnt,array);
12273 for (i = 0; i < hdcnt; i++) {
12282 http_put(char * agent, char ** hdrlist, char * mime, char * user,
12283 char * pwd, char array, char * local, char * remote,
12284 char * dest, int stdio)
12286 http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
12287 char * agent; char ** hdrlist; char * mime; char * user;
12288 char * pwd; char array; char * local; char * remote; char * dest;
12290 #endif /* CK_ANSIC */
12292 char * request=NULL;
12293 int i, j, len = 0, hdcnt = 0, rc = 0;
12296 char buf[HTTPBUFLEN], *p;
12305 char * headers[HTTPHEADCNT];
12313 if (!mime) mime = "";
12314 if (!remote) remote = "";
12315 if (!local) local = "";
12316 if (!*local) return(-1);
12319 for (i = 0; i < HTTPHEADCNT; i++)
12322 filelen = zchki(local);
12326 /* Compute length of request header */
12328 len += strlen(HTTP_VERSION);
12329 len += strlen(remote);
12333 for (i = 0; hdrlist[i]; i++)
12334 len += strlen(hdrlist[i]) + 2;
12336 len += strlen(http_host_port) + 8;
12339 len += 13 + strlen(agent);
12342 readpass("Password: ",passwd,64);
12345 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12346 j = b8tob64(b64in,strlen(b64in),b64out,256);
12347 memset(pwd,0,strlen(pwd));
12353 len += 16 + strlen(mime); /* Content-type: */
12354 len += 32; /* Content-length: */
12355 len += 32; /* Date: */
12357 len += 19; /* Connection: close */
12359 len += 3; /* blank line + null */
12361 request = malloc(len);
12365 sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
12366 ckstrncat(request,"Date: ",len);
12368 ckstrncat(request,http_now(),len);
12370 ckstrncat(request,...,len);
12371 #endif /* CMDATE2TM */
12372 ckstrncat(request,"\r\n",len);
12373 ckstrncat(request,"Host: ", len);
12374 ckstrncat(request,http_host_port, len);
12375 ckstrncat(request,"\r\n",len);
12377 ckstrncat(request,"User-agent: ",len);
12378 ckstrncat(request,agent,len);
12379 ckstrncat(request,"\r\n",len);
12382 ckstrncat(request,"Authorization: Basic ",len);
12383 ckstrncat(request,b64out,len);
12384 ckstrncat(request,"\r\n",len);
12387 for (i = 0; hdrlist[i]; i++) {
12388 ckstrncat(request,hdrlist[i],len);
12389 ckstrncat(request,"\r\n",len);
12392 ckstrncat(request,"Content-type: ",len);
12393 ckstrncat(request,mime,len);
12394 ckstrncat(request,"\r\n",len);
12395 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12396 ckstrncat(request,buf,len);
12398 ckstrncat(request,"Connection: close\r\n",len);
12400 ckstrncat(request,"\r\n",len);
12402 /* Now we have the contents of the file */
12403 if (zopeni(ZIFILE,local)) {
12405 putreq: /* Send request */
12406 if (http_tol((CHAR *)request,strlen(request)) <= 0) {
12417 /* Request headers have been sent */
12420 while (zchin(ZIFILE,&ch) == 0) {
12422 if (i == HTTPBUFLEN) {
12423 if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
12435 if (http_tol((CHAR *)buf,i) < 0) {
12446 /* Process the response headers */
12447 local_t = time(NULL);
12451 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12453 if (buf[i] == 10) { /* found end of line */
12454 if (i > 0 && buf[i-1] == 13)
12459 if (array && !nullline && hdcnt < HTTPHEADCNT)
12460 makestr(&headers[hdcnt++],buf);
12461 if (!ckstrcmp(buf,"HTTP",4,0)) {
12463 j = ckindex(" ",buf,0,0,0);
12465 while (isspace(*p))
12468 case '1': /* Informational message */
12470 case '2': /* Success */
12472 case '3': /* Redirection */
12473 case '4': /* Client failure */
12474 case '5': /* Server failure */
12475 default: /* Unknown */
12477 printf("Failure: Server reports %s\n",p);
12480 http_set_code_reply(p);
12482 if (!ckstrcmp(buf,"Connection:",11,0)) {
12483 if ( ckindex("close",buf,11,0,0) != 0 )
12485 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12486 len = atoi(&buf[16]);
12487 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12488 if ( ckindex("chunked",buf,18,0,0) != 0 )
12490 debug(F101,"http_put chunked","",chunked);
12493 printf("%s\n",buf);
12500 if (ch < 0 && first) {
12506 if ( http_fnd == 0 ) {
12512 /* Any response data? */
12513 if ( dest && dest[0] ) {
12514 if (zopeno(ZOFILE,dest,NULL,NULL))
12521 while ((len = http_get_chunk_len()) > 0) {
12522 while (len && (ch = http_inc(0)) >= 0) {
12525 zchout(ZOFILE,(CHAR)ch);
12529 if ((ch = http_inc(0)) != CR)
12531 if ((ch = http_inc(0)) != LF)
12535 while (len && (ch = http_inc(0)) >= 0) {
12538 zchout(ZOFILE,(CHAR)ch);
12547 if ( chunked ) { /* Parse Trailing Headers */
12549 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12551 if ( buf[i] == 10 ) { /* found end of line */
12552 if (i > 0 && buf[i-1] == 13)
12557 if (array && !nullline && hdcnt < HTTPHEADCNT)
12558 makestr(&headers[hdcnt++],buf);
12559 if (!ckstrcmp(buf,"Connection:",11,0)) {
12560 if ( ckindex("close",buf,11,0,0) != 0 )
12575 http_mkarray(headers,hdcnt,array);
12580 for (i = 0; i < hdcnt; i++) {
12589 http_delete(char * agent, char ** hdrlist, char * user,
12590 char * pwd, char array, char * remote)
12592 http_delete(agent, hdrlist, user, pwd, array, remote)
12593 char * agent; char ** hdrlist; char * user;
12594 char * pwd; char array; char * remote;
12595 #endif /* CK_ANSIC */
12597 char * request=NULL;
12598 int i, j, len = 0, hdcnt = 0, rc = 0;
12601 char buf[HTTPBUFLEN], *p;
12609 char * headers[HTTPHEADCNT];
12618 for (i = 0; i < HTTPHEADCNT; i++)
12622 /* Compute length of request header */
12623 len = 11; /* DELETE */
12624 len += strlen(HTTP_VERSION);
12625 len += strlen(remote);
12629 for (i = 0; hdrlist[i]; i++)
12630 len += strlen(hdrlist[i]) + 2;
12632 len += strlen(http_host_port) + 8;
12635 len += 13 + strlen(agent);
12638 readpass("Password: ",passwd,64);
12641 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12642 j = b8tob64(b64in,strlen(b64in),b64out,256);
12643 memset(pwd,0,strlen(pwd));
12649 len += 32; /* Date: */
12651 len += 19; /* Connection: close */
12653 len += 3; /* blank line + null */
12655 request = malloc(len);
12659 sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
12660 ckstrncat(request,"Date: ",len);
12662 ckstrncat(request,http_now(),len);
12664 ckstrncat(request,...,len);
12665 #endif /* CMDATE2TM */
12666 ckstrncat(request,"\r\n",len);
12667 ckstrncat(request,"Host: ", len);
12668 ckstrncat(request,http_host_port, len);
12669 ckstrncat(request,"\r\n",len);
12671 ckstrncat(request,"User-agent: ",len);
12672 ckstrncat(request,agent,len);
12673 ckstrncat(request,"\r\n",len);
12676 ckstrncat(request,"Authorization: Basic ",len);
12677 ckstrncat(request,b64out,len);
12678 ckstrncat(request,"\r\n",len);
12681 for (i = 0; hdrlist[i]; i++) {
12682 ckstrncat(request,hdrlist[i],len);
12683 ckstrncat(request,"\r\n",len);
12687 ckstrncat(request,"Connection: close\r\n",len);
12689 ckstrncat(request,"\r\n",len);
12691 if (http_tol((CHAR *)request,strlen(request)) < 0)
12703 /* Process the response headers */
12704 local_t = time(NULL);
12708 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12710 if (buf[i] == 10) { /* found end of line */
12711 if (i > 0 && buf[i-1] == 13)
12716 if (array && !nullline && hdcnt < HTTPHEADCNT)
12717 makestr(&headers[hdcnt++],buf);
12718 if (!ckstrcmp(buf,"HTTP",4,0)) {
12720 j = ckindex(" ",buf,0,0,0);
12722 while (isspace(*p))
12725 case '1': /* Informational message */
12727 case '2': /* Success */
12729 case '3': /* Redirection */
12730 case '4': /* Client failure */
12731 case '5': /* Server failure */
12732 default: /* Unknown */
12734 printf("Failure: Server reports %s\n",p);
12737 http_set_code_reply(p);
12739 if (!ckstrcmp(buf,"Connection:",11,0)) {
12740 if ( ckindex("close",buf,11,0,0) != 0 )
12742 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12743 len = atoi(&buf[16]);
12744 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12745 if ( ckindex("chunked",buf,18,0,0) != 0 )
12747 debug(F101,"http_delete chunked","",chunked);
12749 printf("%s\n",buf);
12756 if (ch < 0 && first) {
12762 if ( http_fnd == 0 ) {
12768 /* Any response data? */
12770 while ((len = http_get_chunk_len()) > 0) {
12771 while (len && (ch = http_inc(0)) >= 0) {
12775 if ((ch = http_inc(0)) != CR)
12777 if ((ch = http_inc(0)) != LF)
12781 while (len && (ch = http_inc(0)) >= 0) {
12787 if ( chunked ) { /* Parse Trailing Headers */
12789 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12791 if ( buf[i] == 10 ) { /* found end of line */
12792 if (i > 0 && buf[i-1] == 13)
12797 if (array && !nullline && hdcnt < HTTPHEADCNT)
12798 makestr(&headers[hdcnt++],buf);
12799 if (!ckstrcmp(buf,"Connection:",11,0)) {
12800 if ( ckindex("close",buf,11,0,0) != 0 )
12812 http_mkarray(headers,hdcnt,array);
12817 for (i = 0; i < hdcnt; i++) {
12826 http_post(char * agent, char ** hdrlist, char * mime, char * user,
12827 char * pwd, char array, char * local, char * remote,
12828 char * dest, int stdio)
12830 http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
12832 char * agent; char ** hdrlist; char * mime; char * user;
12833 char * pwd; char array; char * local; char * remote; char * dest;
12835 #endif /* CK_ANSIC */
12837 char * request=NULL;
12838 int i, j, len = 0, hdcnt = 0, rc = 0;
12841 char buf[HTTPBUFLEN], *p;
12850 char * headers[HTTPHEADCNT];
12860 for (i = 0; i < HTTPHEADCNT; i++)
12863 filelen = zchki(local);
12867 /* Compute length of request header */
12868 len = 9; /* POST */
12869 len += strlen(HTTP_VERSION);
12870 len += strlen(remote);
12874 for (i = 0; hdrlist[i]; i++)
12875 len += strlen(hdrlist[i]) + 2;
12877 len += strlen(http_host_port) + 8;
12880 len += 13 + strlen(agent);
12883 readpass("Password: ",passwd,64);
12886 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12887 j = b8tob64(b64in,strlen(b64in),b64out,256);
12888 memset(pwd,0,strlen(pwd));
12894 len += 16 + strlen(mime); /* Content-type: */
12895 len += 32; /* Content-length: */
12896 len += 32; /* Date: */
12898 len += 19; /* Connection: close */
12900 len += 3; /* blank line + null */
12902 request = malloc(len);
12906 sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
12907 ckstrncat(request,"Date: ",len);
12908 ckstrncat(request,http_now(),len);
12909 ckstrncat(request,"\r\n",len);
12910 ckstrncat(request,"Host: ", len);
12911 ckstrncat(request,http_host_port, len);
12912 ckstrncat(request,"\r\n",len);
12914 ckstrncat(request,"User-agent: ",len);
12915 ckstrncat(request,agent,len);
12916 ckstrncat(request,"\r\n",len);
12919 ckstrncat(request,"Authorization: Basic ",len);
12920 ckstrncat(request,b64out,len);
12921 ckstrncat(request,"\r\n",len);
12924 for (i = 0; hdrlist[i]; i++) {
12925 ckstrncat(request,hdrlist[i],len);
12926 ckstrncat(request,"\r\n",len);
12929 ckstrncat(request,"Content-type: ",len);
12930 ckstrncat(request,mime,len);
12931 ckstrncat(request,"\r\n",len);
12933 ckstrncat(request,"Connection: close\r\n",len);
12935 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12936 ckstrncat(request,buf,len);
12937 ckstrncat(request,"\r\n",len);
12939 /* This is apparently a mistake - the previous ckstrncat() already */
12940 /* appended a blank line to the request. There should only be one. */
12941 /* Servers are not required by RFC 2616 to ignore extraneous empty */
12942 /* lines. -fdc, 28 Aug 2005. */
12943 ckstrncat(request,"\r\n",len);
12944 #endif /* COMMENT */
12946 /* Now we have the contents of the file */
12948 if (zopeni(ZIFILE,local)) {
12950 if (http_tol((CHAR *)request,strlen(request)) < 0)
12964 while (zchin(ZIFILE,&ch) == 0) {
12966 if (i == HTTPBUFLEN) {
12967 http_tol((CHAR *)buf,HTTPBUFLEN);
12972 http_tol((CHAR *)buf,HTTPBUFLEN);
12975 /* Process the response headers */
12976 local_t = time(NULL);
12980 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12982 if (buf[i] == 10) { /* found end of line */
12983 if (i > 0 && buf[i-1] == 13)
12988 if (array && !nullline && hdcnt < HTTPHEADCNT)
12989 makestr(&headers[hdcnt++],buf);
12990 if (!ckstrcmp(buf,"HTTP",4,0)) {
12992 j = ckindex(" ",buf,0,0,0);
12994 while (isspace(*p))
12997 case '1': /* Informational message */
12999 case '2': /* Success */
13001 case '3': /* Redirection */
13002 case '4': /* Client failure */
13003 case '5': /* Server failure */
13004 default: /* Unknown */
13006 printf("Failure: Server reports %s\n",p);
13009 http_set_code_reply(p);
13011 if (!ckstrcmp(buf,"Connection:",11,0)) {
13012 if ( ckindex("close",buf,11,0,0) != 0 )
13014 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
13015 len = atoi(&buf[16]);
13016 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
13017 if ( ckindex("chunked",buf,18,0,0) != 0 )
13019 debug(F101,"http_post chunked","",chunked);
13022 printf("%s\n",buf);
13029 if (ch < 0 && first) {
13035 if (http_fnd == 0) {
13041 /* Any response data? */
13042 if ( dest && dest[0] ) {
13043 if (zopeno(ZOFILE,dest,NULL,NULL))
13050 while ((len = http_get_chunk_len()) > 0) {
13051 while (len && (ch = http_inc(0)) >= 0) {
13054 zchout(ZOFILE,(CHAR)ch);
13058 if ((ch = http_inc(0)) != CR)
13060 if ((ch = http_inc(0)) != LF)
13064 while (len && (ch = http_inc(0)) >= 0) {
13067 zchout(ZOFILE,(CHAR)ch);
13076 if ( chunked ) { /* Parse Trailing Headers */
13078 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
13080 if ( buf[i] == 10 ) { /* found end of line */
13081 if (i > 0 && buf[i-1] == 13)
13086 if (array && !nullline && hdcnt < HTTPHEADCNT)
13087 makestr(&headers[hdcnt++],buf);
13088 if (!ckstrcmp(buf,"Connection:",11,0)) {
13089 if ( ckindex("close",buf,11,0,0) != 0 )
13104 http_mkarray(headers,hdcnt,array);
13108 for (i = 0; i < hdcnt; i++) {
13117 http_connect(int socket, char * agent, char ** hdrlist, char * user,
13118 char * pwd, char array, char * host_port)
13120 http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
13122 char * agent; char ** hdrlist; char * user;
13123 char * pwd; char array; char * host_port;
13124 #endif /* CK_ANSIC */
13126 char * request=NULL;
13127 int i, j, len = 0, hdcnt = 0, rc = 0;
13129 char buf[HTTPBUFLEN], *p, ch;
13137 char * headers[HTTPHEADCNT];
13140 tcp_http_proxy_errno = 0;
13146 for (i = 0; i < HTTPHEADCNT; i++)
13150 /* Compute length of request header */
13151 len = 12; /* CONNECT */
13152 len += strlen(HTTP_VERSION);
13153 len += strlen(host_port);
13154 len += (int) strlen(http_host_port) + 8;
13156 len += strlen("Proxy-Connection: Keep-Alive\r\n");
13158 for (i = 0; hdrlist[i]; i++)
13159 len += strlen(hdrlist[i]) + 2;
13161 if (agent && agent[0])
13162 len += 13 + strlen(agent);
13163 if (user && user[0]) {
13165 readpass("Password: ",passwd,64);
13168 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
13169 j = b8tob64(b64in,strlen(b64in),b64out,256);
13170 memset(pwd,0,strlen(pwd));
13176 len += 32; /* Date: */
13177 len += 3; /* blank line + null */
13179 request = malloc(len);
13183 sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
13184 ckstrncat(request,"Date: ",len);
13186 ckstrncat(request,http_now(),len);
13188 strcat(request,...);
13189 #endif /* CMDATE2TM */
13190 ckstrncat(request,"\r\n",len);
13191 ckstrncat(request,"Host: ", len);
13192 ckstrncat(request,http_host_port, len);
13193 ckstrncat(request,"\r\n",len);
13194 if (agent && agent[0]) {
13195 ckstrncat(request,"User-agent: ",len);
13196 ckstrncat(request,agent,len);
13197 ckstrncat(request,"\r\n",len);
13199 if (user && user[0]) {
13200 ckstrncat(request,"Proxy-authorization: Basic ",len);
13201 ckstrncat(request,b64out,len);
13202 ckstrncat(request,"\r\n",len);
13203 ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
13205 ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
13207 for (i = 0; hdrlist[i]; i++) {
13208 ckstrncat(request,hdrlist[i],len);
13209 ckstrncat(request,"\r\n",len);
13212 ckstrncat(request,"\r\n",len);
13213 len = strlen(request);
13217 if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
13222 if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
13226 #endif /* TCPIPLIB */
13228 /* Process the response headers */
13229 local_t = time(NULL);
13232 while (!nullline &&
13234 (socket_read(socket,&ch,1) == 1) &&
13236 (read(socket,&ch,1) == 1) &&
13237 #endif /* TCPIPLIB */
13240 if (buf[i] == 10) { /* found end of line */
13241 if (i > 0 && buf[i-1] == 13)
13247 if (array && !nullline && hdcnt < HTTPHEADCNT)
13248 makestr(&headers[hdcnt++],buf);
13249 if (!ckstrcmp(buf,"HTTP",4,0)) {
13251 j = ckindex(" ",buf,0,0,0);
13253 while (isspace(*p))
13255 tcp_http_proxy_errno = atoi(p);
13257 case '1': /* Informational message */
13259 case '2': /* Success */
13262 case '3': /* Redirection */
13263 case '4': /* Client failure */
13264 case '5': /* Server failure */
13265 default: /* Unknown */
13267 printf("Failure: Server reports %s\n",p);
13270 http_set_code_reply(p);
13272 printf("%s\n",buf);
13279 if ( http_fnd == 0 )
13283 http_mkarray(headers,hdcnt,array);
13286 if ( !connected ) {
13287 if ( socket == ttyfd ) {
13290 else if ( socket == httpfd ) {
13296 for (i = 0; i < hdcnt; i++) {
13302 #endif /* NOHTTP */
13306 #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
13307 #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
13308 #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
13310 #ifndef CKQUERYTYPE
13313 #define CKQUERYTYPE CHAR
13315 #endif /* UNIXWARE */
13316 #endif /* CKQUERYTYPE */
13318 #ifndef CKQUERYTYPE
13319 #define CKQUERYTYPE char
13320 #endif /* CKQUERYTYPE */
13322 /* 1 is success, 0 is failure */
13324 locate_srv_dns(host, service, protocol, addr_pp, naddrs)
13328 struct sockaddr **addr_pp;
13331 int nout, j, count;
13333 unsigned char bytes[2048];
13336 unsigned char *p=NULL;
13337 CKQUERYTYPE query[MAX_DNS_NAMELEN];
13342 #endif /* CK_ANSIC */
13343 struct sockaddr *addr = NULL;
13344 struct sockaddr_in *sin = NULL;
13345 struct hostent *hp = NULL;
13347 int priority, weight, size, len, numanswers, numqueries, rdlen;
13348 unsigned short port;
13351 #endif /* CK_ANSIC */
13352 int hdrsize = sizeof(HEADER);
13353 struct srv_dns_entry {
13354 struct srv_dns_entry *next;
13357 unsigned short port;
13360 struct srv_dns_entry *head = NULL;
13361 struct srv_dns_entry *srv = NULL, *entry = NULL;
13365 addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
13372 * First build a query of the form:
13374 * service.protocol.host
13376 * which will most likely be something like:
13378 * _telnet._tcp.host
13381 if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
13386 /* Realm names don't (normally) end with ".", but if the query
13387 doesn't end with "." and doesn't get an answer as is, the
13388 resolv code will try appending the local domain. Since the
13389 realm names are absolutes, let's stop that.
13391 But only if a name has been specified. If we are performing
13392 a search on the prefix alone then the intention is to allow
13393 the local domain or domain search lists to be expanded.
13395 h = host + strlen (host);
13396 ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
13397 ((h > host) && (h[-1] != '.')?".":NULL),
13398 NULL,NULL,NULL,NULL,NULL);
13400 size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
13402 if (size < hdrsize)
13405 /* We got a reply - See how many answers it contains. */
13409 numqueries = ntohs(answer.hdr.qdcount);
13410 numanswers = ntohs(answer.hdr.ancount);
13412 p += sizeof(HEADER);
13415 * We need to skip over all of the questions, so we have to iterate
13416 * over every query record. dn_expand() is able to tell us the size
13417 * of compressed DNS names, so we use it.
13419 while (numqueries--) {
13420 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13423 INCR_CHECK(p, len + 4);
13427 * We're now pointing at the answer records. Only process them if
13428 * they're actually T_SRV records (they might be CNAME records,
13431 * But in a DNS reply, if you get a CNAME you always get the associated
13432 * "real" RR for that CNAME. RFC 1034, 3.6.2:
13434 * CNAME RRs cause special action in DNS software. When a name server
13435 * fails to find a desired RR in the resource set associated with the
13436 * domain name, it checks to see if the resource set consists of a CNAME
13437 * record with a matching class. If so, the name server includes the CNAME
13438 * record in the response and restarts the query at the domain name
13439 * specified in the data field of the CNAME record. The one exception to
13440 * this rule is that queries which match the CNAME type are not restarted.
13442 * In other words, CNAMEs do not need to be expanded by the client.
13444 while (numanswers--) {
13446 /* First is the name; use dn_expand() to get the compressed size. */
13447 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13450 INCR_CHECK(p, len);
13452 CHECK(p,2); /* Query type */
13453 type = NTOHSP(p,2);
13455 CHECK(p, 6); /* Query class */
13456 class = NTOHSP(p,6); /* Also skip over 4-byte TTL */
13458 CHECK(p,2); /* Record data length */
13459 rdlen = NTOHSP(p,2);
13461 * If this is an SRV record, process it. Record format is:
13468 if (class == C_IN && type == T_SRV) {
13470 priority = NTOHSP(p,2);
13472 weight = NTOHSP(p,2);
13474 port = NTOHSP(p,2);
13475 len = dn_expand(answer.
13477 answer.bytes + size,
13484 INCR_CHECK(p, len);
13486 * We got everything. Insert it into our list, but make sure
13487 * it's in the right order. Right now we don't do anything
13488 * with the weight field
13490 srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
13494 srv->priority = priority;
13495 srv->weight = weight;
13497 makestr(&s,(char *)query); /* strdup() is not portable */
13500 if (head == NULL || head->priority > srv->priority) {
13505 * Confusing. Insert an entry into this spot only if:
13506 * . The next person has a higher priority (lower
13507 * priorities are preferred), or:
13508 * . There is no next entry (we're at the end)
13510 for (entry = head; entry != NULL; entry = entry->next)
13511 if ((entry->next &&
13512 entry->next->priority > srv->priority) ||
13513 entry->next == NULL) {
13514 srv->next = entry->next;
13519 INCR_CHECK(p, rdlen);
13523 * Now we've got a linked list of entries sorted by priority.
13524 * Start looking up A records and returning addresses.
13529 for (entry = head; entry != NULL; entry = entry->next) {
13530 hp = gethostbyname(entry->host);
13533 /* Watch out - memset() and memcpy() are not portable... */
13535 switch (hp->h_addrtype) {
13537 for (j = 0; hp->h_addr_list[j]; j++) {
13538 sin = (struct sockaddr_in *) &addr[nout++];
13539 memset ((char *) sin, 0, sizeof (struct sockaddr));
13540 sin->sin_family = hp->h_addrtype;
13541 sin->sin_port = htons(entry->port);
13542 memcpy((char *) &sin->sin_addr,
13543 (char *) hp->h_addr_list[j],
13544 sizeof(struct in_addr)); /* safe */
13545 if (nout + 1 >= count) {
13547 addr = (struct sockaddr *)
13548 realloc((char *) addr,
13549 sizeof(struct sockaddr) * count);
13560 for (entry = head; entry != NULL;) {
13562 entry->host = NULL;
13564 entry = entry->next;
13573 if (nout == 0) { /* No good servers */
13586 #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
13588 #define CHECK(x, y) if (x + y > size + answer.bytes) \
13590 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
13593 locate_txt_rr(prefix, name, retstr)
13594 char *prefix, *name;
13598 unsigned char bytes[2048];
13602 char host[MAX_DNS_NAMELEN], *h;
13604 int type, class, numanswers, numqueries, rdlen, len;
13607 * Form our query, and send it via DNS
13610 if (name == NULL || name[0] == '\0') {
13611 strcpy(host,prefix);
13613 if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
13616 /* Realm names don't (normally) end with ".", but if the query
13617 doesn't end with "." and doesn't get an answer as is, the
13618 resolv code will try appending the local domain. Since the
13619 realm names are absolutes, let's stop that.
13621 But only if a name has been specified. If we are performing
13622 a search on the prefix alone then the intention is to allow
13623 the local domain or domain search lists to be expanded.
13625 h = host + strlen (host);
13626 ckmakmsg(host,sizeof(host),prefix, ".", name,
13627 ((h > host) && (h[-1] != '.'))?".":NULL);
13630 size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
13637 numqueries = ntohs(answer.hdr.qdcount);
13638 numanswers = ntohs(answer.hdr.ancount);
13640 p += sizeof(HEADER);
13643 * We need to skip over the questions before we can get to the answers,
13644 * which means we have to iterate over every query record. We use
13645 * dn_expand to tell us how long each compressed name is.
13648 while (numqueries--) {
13649 len = dn_expand(answer.bytes, answer.bytes + size, p, host,
13653 INCR_CHECK(p, len + 4); /* Name plus type plus class */
13657 * We're now pointing at the answer records. Process the first
13658 * TXT record we find.
13661 while (numanswers--) {
13663 /* First the name; use dn_expand to get the compressed size */
13664 len = dn_expand(answer.bytes, answer.bytes + size, p,
13665 host, sizeof(host));
13668 INCR_CHECK(p, len);
13670 /* Next is the query type */
13672 type = NTOHSP(p,2);
13674 /* Next is the query class; also skip over 4 byte TTL */
13676 class = NTOHSP(p,6);
13678 /* Record data length - make sure we aren't truncated */
13681 rdlen = NTOHSP(p,2);
13683 if (p + rdlen > answer.bytes + size)
13687 * If this is a TXT record, return the string. Note that the
13688 * string has a 1-byte length in the front
13690 /* XXX What about flagging multiple TXT records as an error? */
13692 if (class == C_IN && type == T_TXT) {
13694 if (p + len > answer.bytes + size)
13696 *retstr = malloc(len + 1);
13697 if (*retstr == NULL)
13699 strncpy(*retstr, (char *) p, len);
13700 (*retstr)[len] = '\0';
13701 /* Avoid a common error. */
13702 if ( (*retstr)[len-1] == '.' )
13703 (*retstr)[len-1] = '\0';
13713 #endif /* CK_DNS_SRV */
13716 #ifdef CK_FORWARD_X
13718 #include <sys/un.h>
13719 #define FWDX_UNIX_SOCK
13721 #define AF_LOCAL AF_UNIX
13724 #define PF_LOCAL PF_UNIX
13727 /* Evaluate to actual length of the `sockaddr_un' structure. */
13728 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
13729 + strlen ((ptr)->sun_path))
13733 fwdx_create_listen_socket(screen) int screen; {
13736 #else /* NOPUTENV */
13737 struct sockaddr_in saddr;
13738 int display, port, sock=-1, i;
13739 static char env[512];
13742 * X Windows Servers support multiple displays by listening on
13743 * one socket per display. Display 0 is port 6000; Display 1 is
13746 * We start by trying to open port 6001 so that display 0 is
13747 * reserved for the local X Windows Server.
13750 for ( display=1; display < 1000 ; display++ ) {
13752 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13753 debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
13757 port = 6000 + display;
13758 bzero((char *)&saddr, sizeof(saddr));
13759 saddr.sin_family = AF_INET;
13760 saddr.sin_addr.s_addr = inet_addr(myipaddr);
13761 saddr.sin_port = htons(port);
13763 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13764 i = errno; /* Save error code */
13766 socket_close(sock);
13767 #else /* TCPIPLIB */
13769 #endif /* TCPIPLIB */
13771 debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
13775 debug(F100,"fdwx_create_listen_socket() bind OK","",0);
13779 if ( display > 1000 ) {
13780 debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
13784 if (listen(sock, 5) < 0) {
13785 i = errno; /* Save error code */
13787 socket_close(sock);
13788 #else /* TCPIPLIB */
13790 #endif /* TCPIPLIB */
13791 debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
13794 debug(F100,"fwdx_create_listen_socket() listen OK","",0);
13796 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
13800 ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
13801 ckuitoa(display),":",ckuitoa(screen),
13802 NULL,NULL,NULL,NULL,NULL,NULL);
13804 ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
13808 #endif /* NOPUTENV */
13813 fwdx_open_client_channel(channel) int channel; {
13815 struct sockaddr_in saddr;
13816 #ifdef FWDX_UNIX_SOCK
13817 struct sockaddr_un saddr_un = { AF_LOCAL };
13818 #endif /* FWDX_UNIX_SOCK */
13819 int colon, dot, display, port, sock, i, screen;
13821 char buf[256], * host=NULL, * rest=NULL;
13824 #endif /* TCP_NODELAY */
13826 debug(F111,"fwdx_create_client_channel()","channel",channel);
13828 for ( i=0; i<MAXFWDX ; i++ ) {
13829 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
13831 debug(F110,"fwdx_create_client_channel()","already open",0);
13836 env = getenv("DISPLAY");
13838 env = (char *)tn_get_display();
13840 ckstrncpy(buf,env,256);
13842 ckstrncpy(buf,"127.0.0.1:0.0",256);
13844 bzero((char *)&saddr,sizeof(saddr));
13845 saddr.sin_family = AF_INET;
13847 if (!fwdx_parse_displayname(buf,
13855 if ( host ) free(host);
13856 if ( rest ) free(rest);
13859 if (rest) free(rest);
13861 #ifndef FWDX_UNIX_SOCK
13862 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13863 * we change things to use inet sockets on the ip loopback interface instead,
13864 * and hope that it works.
13866 if (family == FamilyLocal) {
13867 debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
13868 family = FamilyInternet;
13869 if (host) free(host);
13870 if (host = malloc(strlen("localhost") + 1))
13871 strcpy(host, "localhost");
13876 #else /* FWDX_UNIX_SOCK */
13877 if (family == FamilyLocal) {
13878 if (host) free(host);
13879 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13883 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13884 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13885 if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
13888 #endif /* FWDX_UNIX_SOCK */
13890 /* Otherwise, we are assuming FamilyInternet */
13892 ckstrncpy(buf,host,sizeof(buf));
13895 ckstrncpy(buf,myipaddr,sizeof(buf));
13897 debug(F111,"fwdx_create_client_channel()","display",display);
13899 port = 6000 + display;
13900 saddr.sin_port = htons(port);
13902 debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
13903 saddr.sin_addr.s_addr = inet_addr(buf);
13904 if ( saddr.sin_addr.s_addr == (unsigned long) -1
13906 || saddr.sin_addr.s_addr == INADDR_NONE
13907 #endif /* INADDR_NONE */
13910 struct hostent *host;
13911 host = gethostbyname(buf);
13912 if ( host == NULL )
13914 host = ck_copyhostent(host);
13917 /* This is for trying multiple IP addresses - see <netdb.h> */
13918 if (!(host->h_addr_list))
13920 bcopy(host->h_addr_list[0],
13921 (caddr_t)&saddr.sin_addr,
13925 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13926 #endif /* h_addr */
13927 #else /* HADDRLIST */
13928 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13929 #endif /* HADDRLIST */
13932 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13933 debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
13937 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13938 debug(F110,"fwdx_create_client_channel()","connect() failed",0);
13940 socket_close(sock);
13941 #else /* TCPIPLIB */
13943 #endif /* TCPIPLIB */
13948 setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13949 #endif /* TCP_NODELAY */
13952 for (i = 0; i < MAXFWDX; i++) {
13953 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
13954 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
13955 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
13956 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
13957 debug(F111,"fwdx_create_client_channel()","socket",sock);
13965 fwdx_server_avail() {
13967 struct sockaddr_in saddr;
13968 #ifdef FWDX_UNIX_SOCK
13969 struct sockaddr_un saddr_un = { AF_LOCAL };
13970 #endif /* FWDX_UNIX_SOCK */
13971 int colon, dot, display, port, sock, i, screen;
13972 char buf[256], *host=NULL, *rest=NULL;
13975 #endif /* TCP_NODELAY */
13978 env = getenv("DISPLAY");
13980 env = (char *)tn_get_display();
13982 ckstrncpy(buf,env,256);
13984 ckstrncpy(buf,"127.0.0.1:0.0",256);
13986 bzero((char *)&saddr,sizeof(saddr));
13987 saddr.sin_family = AF_INET;
13989 if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
13990 if ( host ) free(host);
13991 if ( rest ) free(rest);
13994 if (rest) free(rest);
13996 #ifndef FWDX_UNIX_SOCK
13997 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13998 * we change things to use inet sockets on the ip loopback interface instead,
13999 * and hope that it works.
14001 if (family == FamilyLocal) {
14002 family = FamilyInternet;
14003 if (host) free(host);
14004 if (host = malloc(strlen("localhost") + 1))
14005 strcpy(host, "localhost");
14010 #else /* FWDX_UNIX_SOCK */
14011 if (family == FamilyLocal) {
14012 debug(F100,"fwdx_server_avail() FamilyLocal","",0);
14013 if (host) free(host);
14014 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
14018 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
14019 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
14020 if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
14025 #endif /* FWDX_UNIX_SOCK */
14027 /* Otherwise, we are assuming FamilyInternet */
14029 ckstrncpy(buf,host,sizeof(buf));
14032 ckstrncpy(buf,myipaddr,sizeof(buf));
14034 debug(F111,"fwdx_server_avail()","display",display);
14036 port = 6000 + display;
14037 saddr.sin_port = htons(port);
14039 debug(F110,"fwdx_server_avail() ip-address",buf,0);
14040 saddr.sin_addr.s_addr = inet_addr(buf);
14041 if ( saddr.sin_addr.s_addr == (unsigned long) -1
14043 || saddr.sin_addr.s_addr == INADDR_NONE
14044 #endif /* INADDR_NONE */
14047 struct hostent *host;
14048 host = gethostbyname(buf);
14049 if ( host == NULL ) {
14050 debug(F110,"fwdx_server_avail() gethostbyname() failed",
14054 host = ck_copyhostent(host);
14057 /* This is for trying multiple IP addresses - see <netdb.h> */
14058 if (!(host->h_addr_list))
14060 bcopy(host->h_addr_list[0],
14061 (caddr_t)&saddr.sin_addr,
14065 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14066 #endif /* h_addr */
14067 #else /* HADDRLIST */
14068 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14069 #endif /* HADDRLIST */
14072 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
14073 debug(F111,"fwdx_server_avail()","socket() < 0",sock);
14077 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
14078 debug(F110,"fwdx_server_avail()","connect() failed",0);
14080 socket_close(sock);
14081 #else /* TCPIPLIB */
14083 #endif /* TCPIPLIB */
14088 socket_close(sock);
14089 #else /* TCPIPLIB */
14091 #endif /* TCPIPLIB */
14096 fwdx_open_server_channel() {
14097 int sock, ready_to_accept, sock2,channel,i;
14100 #endif /* TCP_NODELAY */
14102 static u_int saddrlen;
14104 static SOCKOPT_T saddrlen;
14106 struct sockaddr_in saddr;
14108 extern char tn_msg[];
14121 #endif /* BELLSELECT */
14122 #endif /* BSDSELECT */
14123 unsigned short nchannel;
14126 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
14131 tv.tv_sec = tv.tv_usec = 0L;
14134 FD_SET(sock, &rfds);
14136 ((select(FD_SETSIZE,
14143 #endif /* HPUX1010 */
14147 #endif /* __DECC */
14149 &rfds, NULL, NULL, &tv) > 0) &&
14150 FD_ISSET(sock, &rfds));
14151 #else /* BSDSELECT */
14153 ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
14157 FD_SET(sock, rfds);
14159 ((select(128, rfds, NULL, NULL, 50) > 0) &&
14160 FD_ISSET(sock, rfds));
14162 /* Try this - what's the worst that can happen... */
14164 tv.tv_sec = tv.tv_usec = 0L;
14167 FD_SET(sock, &rfds);
14169 ((select(FD_SETSIZE,
14170 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
14171 FD_ISSET(sock, &rfds));
14172 #endif /* BELLSELECT */
14173 #endif /* IBMSELECT */
14174 #endif /* BSDSELECT */
14176 if ( !ready_to_accept )
14179 if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
14180 int i = errno; /* save error code */
14181 debug(F101,"tcpsrv_open accept errno","",i);
14186 * Now we have the open socket. We must now find a channel to store
14187 * it in, and then notify the client.
14190 for ( channel=0;channel<MAXFWDX;channel++ ) {
14191 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
14195 if ( channel == MAXFWDX ) {
14197 socket_close(sock2);
14198 #else /* TCPIPLIB */
14200 #endif /* TCPIPLIB */
14204 if ( fwdx_send_open(channel) < 0 ) {
14206 socket_close(sock2);
14207 #else /* TCPIPLIB */
14209 #endif /* TCPIPLIB */
14213 setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
14214 #endif /* TCP_NODELAY */
14216 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
14217 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
14220 return(0); /* never reached */
14224 fwdx_close_channel(channel) int channel; {
14227 for ( i=0; i<MAXFWDX ; i++ ) {
14228 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14231 if ( i == MAXFWDX )
14234 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14235 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
14236 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
14237 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
14241 #else /* TCPIPLIB */
14243 #endif /* TCPIPLIB */
14251 debug(F111,"fwdx_close_all()",
14252 "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
14253 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14255 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
14257 socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14258 #else /* TCPIPLIB */
14259 close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14260 #endif /* TCPIPLIB */
14261 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
14264 for (x = 0; x < MAXFWDX; x++) {
14265 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14266 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14267 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
14268 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
14269 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
14270 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
14273 #else /* TCPIPLIB */
14275 #endif /* TCPIPLIB */
14281 /* The following definitions are for Unix */
14282 #ifndef socket_write
14283 #define socket_write(f,s,n) write(f,s,n)
14284 #endif /* socket_write */
14285 #ifndef socket_read
14286 #define socket_read(f,s,n) read(f,s,n)
14287 #endif /* socket_read */
14290 fwdx_write_data_to_channel(channel, data, len)
14291 int channel; char * data; int len;
14293 int sock, count, try=0, length = len, i;
14298 for ( i=0; i<MAXFWDX ; i++ ) {
14299 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14302 if ( i == MAXFWDX ) {
14303 debug(F110,"fwdx_write_data_to_channel",
14304 "attempting to write to closed channel",0);
14308 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14309 debug(F111,"fwdx_write_data_to_channel","socket",sock);
14310 ckhexdump("fwdx_write_data_to_channel",data,len);
14312 fwdx_write_data_to_channel_retry:
14314 if ((count = socket_write(sock,data,len)) < 0) {
14315 int s_errno = socket_errno; /* maybe a function */
14316 debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
14318 printf("fwdx_write_data_to_channel error\r\n");
14319 #endif /* BETATEST */
14321 if (os2socketerror(s_errno) < 0)
14324 return(-1); /* Call it an i/o error */
14327 debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
14332 debug(F111,"fwdx_write_data_to_channel retry",data,len);
14334 goto fwdx_write_data_to_channel_retry;
14337 debug(F111,"fwdx_write_data_to_channel complete",data,length);
14338 return(length); /* success - return total length */
14342 fwdx_check_sockets(fd_set *ibits)
14344 int x, sock, channel, bytes;
14345 static char buffer[32000];
14347 debug(F100,"fwdx_check_sockets()","",0);
14348 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14349 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14350 debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
14354 for (x = 0; x < MAXFWDX; x++) {
14355 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
14356 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
14359 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14360 if (FD_ISSET(sock, ibits))
14362 channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
14363 debug(F111,"fwdx_check_sockets()","channel set",channel);
14365 bytes = socket_read(sock, buffer, sizeof(buffer));
14367 fwdx_send_data_from_channel(channel, buffer, bytes);
14368 else if (bytes == 0) {
14369 fwdx_close_channel(channel);
14370 fwdx_send_close(channel);
14377 fwdx_init_fd_set(fd_set *ibits)
14381 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14382 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14383 debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
14387 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
14389 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
14391 for (x = 0; x < MAXFWDX; x++) {
14392 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14394 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
14397 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
14400 if (set + cnt == 0) {
14409 fwdx_thread( VOID * dummy )
14413 extern int priority;
14417 SetThreadPrty(priority,isWin95() ? 3 : 11);
14419 while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
14420 sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
14423 n = fwdx_init_fd_set(&ifds);
14427 if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
14428 fwdx_check_sockets(&ifds);
14430 } else if (n < 0) {
14431 TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
14439 #endif /* CK_FORWARD_X */
14440 #endif /* TNCODE */
14441 #endif /* NETCONN */