1 char *cknetv = "Network support, 9.0.297, 14 Jul 2011";
3 /* C K C N E T -- Network support */
6 Copyright (C) 1985, 2011,
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 */
262 #include <errno.h> /* Error number symbols */
264 #ifndef ERRNO_INCLUDED
265 #include <errno.h> /* Error number symbols */
266 #endif /* ERRNO_INCLUDED */
267 #endif /* HPUXPRE65 */
270 #include <signal.h> /* Everybody needs this */
272 #ifdef ZILOG /* Zilog has different name for this */
280 #ifdef datageneral /* Data General AOS/VS */
281 #include <:usr:include:vs_tcp_errno.h>
282 #include <:usr:include:sys:vs_tcp_types.h>
285 NOTE: This can be compiled and linked OK with SELECT defined
286 but it doesn't work at all. Anybody who cares and knows how
287 to fix it, feel free.
289 #include <:usr:include:sys:vs_tcp_time.h>
291 #include <:usr:include:sys:socket.h>
292 #include <:usr:include:netinet:in.h>
293 #include <:usr:include:netdb.h>
294 #endif /* datageneral */
297 #define socket_errno errno
298 #endif /* socket_errno */
304 int tcp_rdns = /* Reverse DNS lookup */
306 SET_OFF /* Doesn't seem to work in UCX */
309 #endif /* DEC_TCPIP */
312 int tcp_dns_srv = SET_OFF;
313 #endif /* CK_DNS_SRV */
315 _PROTOTYP( char * cmcvtdate, (char *, int) );
318 _PROTOTYP( int rlog_ctrl, (CHAR *, int) );
319 _PROTOTYP( static int rlog_oob, (CHAR *, int) );
321 _PROTOTYP( static SIGTYP rlogoobh, ( int ) );
322 #endif /* TCPIPLIB */
323 _PROTOTYP( static int rlog_ini, (CHAR *, int,
324 struct sockaddr_in *,
325 struct sockaddr_in *) );
326 int rlog_mode = RL_COOKED;
327 int rlog_stopped = 0;
329 #endif /* RLOGCODE */
332 extern int doconx; /* CONNECT-class command active */
336 /* This variable should probably be generalised for true client/server
337 * support - ie: the fd of the listening server, accepted calls should
338 * be forked or at least handled via a second fd (for IBM's X.25 -
339 * ttyfd always holds the active fd - ie the server becomes inactive
340 * as long as a client is connected, and becomes active again when the
341 * connection is closed)
343 int x25serverfd = 0; /* extern in ckcnet.h */
344 int x25seqno = 0; /* Connection sequence number */
345 int x25lastmsg = -1; /* A cheapskate's state table */
347 #define X25_CLOSED 0 /* Default state: no connection, no STREAM */
348 #define X25_SETUP 1 /* X.25 has been set up (no connection) */
349 #define X25_CONNECTED 2 /* X.25 connection has been established */
350 int x25_state = X25_CLOSED; /* Default state */
357 #ifdef CK_NAWS /* Negotiate About Window Size */
359 _PROTOTYP( int rlog_naws, (void) );
360 #endif /* RLOGCODE */
363 #ifdef OS2 /* For terminal type name string */
370 extern int tt_type, max_tt;
371 extern struct tt_info_rec tt_info[];
372 extern char ttname[];
374 #ifdef CK_AUTHENTICATION
376 #endif /* CK_AUTHENTICATION */
380 extern int winsock_version;
383 #ifdef CK_AUTHENTICATION
385 #endif /* CK_AUTHENTICATION */
389 #ifndef OS2 /* For timeout longjumps */
390 static ckjmpbuf njbuf;
393 #define NAMECPYL 1024 /* Local copy of hostname */
394 char namecopy[NAMECPYL]; /* Referenced by ckctel.c */
395 char namecopy2[NAMECPYL]; /* Referenced by ckctel.c */
397 char http_host_port[NAMECPYL]; /* orig host/port necessary for http */
398 char http_ip[20] = { '\0' }; /* ip address of host */
401 char * http_agent = 0;
402 int httpfd = -1; /* socket for http connections */
404 #define HTTPBUFLEN 1024
405 char http_reply_str[HTTPBUFLEN] = "";
408 char ipaddr[20] = { '\0' }; /* Global copy of IP address */
409 unsigned long myxipaddr = 0L; /* Ditto as a number */
412 char *tcp_address = NULL; /* Preferred IP Address */
413 extern char uidbuf[]; /* User ID buffer */
414 extern char pwbuf[]; /* Password buffer */
417 char * tcp_http_proxy = NULL; /* Name[:port] of http proxy server */
418 int tcp_http_proxy_errno = 0;
419 char * tcp_http_proxy_user = NULL;
420 char * tcp_http_proxy_pwd = NULL;
421 char * tcp_http_proxy_agent = NULL;
422 #define HTTPCPYL 1024
423 static char proxycopy[HTTPCPYL];
427 extern int tt_rows[], tt_cols[];
428 extern int tt_status[VNUM];
430 extern int tt_rows, tt_cols; /* Everybody has this */
433 extern int cmd_cols, cmd_rows;
435 #ifdef STREAMING /* Use blocking writes for streaming */
436 extern int streaming;
437 #endif /* STREAMING */
440 extern int WSASafeToCancel;
441 int win95selectbug = 0; /* For TCP/IP stacks whose select() */
442 /* always fails on write requests such as Cisco and Quarterdeck */
443 #define stricmp _stricmp
448 /* Skip all this if NOTCPOPTS specified. */
453 int tcp_nodelay = 0; /* Nagle algorithm TCP_NODELAY */
454 #endif /* TCP_NODELAY */
457 int tcp_dontroute = 0;
458 #endif /* SO_DONTROUTE */
461 int tcp_linger = 0; /* SO_LINGER */
462 int tcp_linger_tmo = 0; /* SO_LINGER timeout */
463 #endif /* SO_LINGER */
465 #ifdef HPUX /* But the data structures */
466 #ifndef HPUX8 /* needed for linger are not */
467 #ifndef HPUX9 /* defined in HP-UX versions */
468 #ifndef HPUX10 /* prior to 8.00. */
471 #endif /* SO_LINGER */
477 #ifndef SO_OOBINLINE /* Hopefully only HP-UX 7.0 */
478 #define SO_OOBINLINE 0x0100
479 #endif /* SO_OOBINLINE */
484 #define TCPSNDBUFSIZ 16384
487 #endif /* TCPSNDBUFSIZ */
490 #define TCPSNDBUFSIZ -1
491 #endif /* TCPSNDBUFSIZ */
494 int tcp_sendbuf = TCPSNDBUFSIZ;
495 #endif /* SO_SNDBUF */
498 int tcp_recvbuf = -1;
499 #endif /* SO_RCVBUF */
502 int tcp_keepalive = 1;
503 #endif /* SO_KEEPALIVE */
505 #endif /* SOL_SOCKET */
506 #endif /* NOTCPOPTS */
510 Network support not defined.
511 Dummy functions here in case #ifdef's forgotten elsewhere.
513 int /* Open network connection */
514 netopen(name, lcl, nett) char *name; int *lcl, nett; {
517 int /* Close network connection */
521 int /* Check network input buffer */
525 int /* Flush network input buffer */
529 int /* Send network BREAK */
533 int /* Input character from network */
534 netinc(timo) int timo; {
537 int /* Output character to network */
542 #endif /* CK_ANSIC */
547 nettol(s,n) CHAR *s; int n; {
551 #else /* NETCONN is defined (much of this module...) */
555 le_init() { /* LocalEchoInit() */
557 for (i = 0; i < LEBUFSIZ; i++)
566 le_clean() { /* LocalEchoCleanup() */
574 if (le_start != le_end) {
577 LEBUFSIZ) % LEBUFSIZ;
586 le_putchar(ch) CHAR ch;
587 #endif /* CK_ANSIC */
589 if ((le_start - le_end + LEBUFSIZ)%LEBUFSIZ == 1) {
590 debug(F110,"le_putchar","buffer is full",0);
593 le_buf[le_end++] = ch;
594 if (le_end == LEBUFSIZ)
602 le_puts(CHAR * s, int n)
604 le_puts(s,n) CHAR * s; int n;
605 #endif /* CK_ANSIC */
609 CHAR * p = (CHAR *)"le_puts";
611 for (i = 0; i < n; i++)
612 rc = le_putchar((char)s[i]);
613 debug(F101,"le_puts","",rc);
621 le_putstr(s) CHAR * s;
622 #endif /* CK_ANSIC */
626 p = (CHAR *)"le_putstr";
627 ckhexdump(p,s,(int)strlen((char *)s));
628 for (p = s; *p && !rc; p++)
635 le_getchar(CHAR * pch)
637 le_getchar(pch) CHAR * pch;
638 #endif /* CK_ANSIC */
641 if (le_start != le_end) {
642 *pch = le_buf[le_start];
643 le_buf[le_start] = 0;
646 if (le_start == LEBUFSIZ)
649 if (le_start == le_end) {
658 #endif /* NETLEBUF */
662 In edit 190, we moved tn_ini() to be called from within netopen().
663 But tn_ini() calls ttol(), and ttol() checks to see if it's a net
664 connection, but the flag for that isn't set until after netopen()
665 is finished. Since, in this module, we are always doing network
666 output anyway, we just call nettol() directly, instead of going thru
667 ttol(). Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
668 net connections just like regular connections in ttol(), and OS/2
669 has a special routine for this.
678 char * krb5_d_principal = NULL; /* Default principal */
679 char * krb5_d_instance = NULL; /* Default instance */
680 char * krb5_d_realm = NULL; /* Default realm */
681 char * krb5_d_cc = NULL; /* Default credentials cache */
682 char * krb5_d_srv = NULL; /* Default Service */
683 int krb5_d_lifetime = 600; /* Default lifetime (10 hours) */
684 int krb5_d_forwardable = 0; /* creds not forwardable */
685 int krb5_d_proxiable = 0; /* creds not proxiable */
686 int krb5_d_renewable = 0; /* creds not renewable (0 min) */
687 int krb5_autoget = 1; /* Autoget TGTs */
688 int krb5_autodel = 0; /* Auto delete TGTs */
689 int krb5_d_getk4 = 0; /* K5 Kinit gets K4 TGTs */
690 int krb5_checkaddrs = 1; /* Check TGT Addrs */
691 int krb5_d_no_addresses = 0; /* Do not include IP Addresses */
692 char * krb5_d_addrs[KRB5_NUM_OF_ADDRS+1]={NULL,NULL}; /* Addrs to include */
693 int krb5_errno = 0; /* Last K5 errno */
694 char * krb5_errmsg = NULL; /* Last K5 errmsg */
695 char * k5_keytab = NULL;
697 char * krb4_d_principal = NULL; /* Default principal */
698 char * krb4_d_realm = NULL; /* Default realm */
699 char * krb4_d_srv = NULL; /* Default Service */
700 int krb4_d_lifetime = 600; /* Default lifetime (10 hours) */
701 int krb4_d_preauth = 1; /* Use preauth requests */
702 char * krb4_d_instance = NULL; /* Default instance */
703 int krb4_autoget = 1; /* Autoget TGTs */
704 int krb4_autodel = 0; /* Auto delete TGTs */
705 int krb4_checkaddrs = 1; /* Check TGT Addrs */
706 char * k4_keytab = NULL;
708 int krb4_errno = 0; /* Last K4 errno */
709 char * krb4_errmsg = NULL; /* Last K4 errmsg */
711 struct krb_op_data krb_op = { /* Operational data structure */
712 0, NULL /* (version, cachefile) */
715 struct krb4_init_data krb4_init = { /* Kerberos 4 INIT data structure */
716 0, NULL, NULL, NULL, NULL
719 struct krb5_init_data krb5_init = { /* Kerberos 5 INIT data structure */
720 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0,
721 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
722 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
726 struct krb5_list_cred_data krb5_lc = { /* List Credentials data structure */
730 int krb_action = -1; /* Kerberos action to perform */
732 #ifndef CK_AUTHENTICATION
738 ck_krb5_getrealm(cc) char * cc; {
742 ck_krb4_getprincipal() {
746 ck_krb5_getprincipal(cc) char * cc; {
749 #endif /* CK_AUTHENTICATION */
751 /* I N I _ K E R B -- Initialize Kerberos data */
757 krb_action = -1; /* No action specified */
759 krb_op.version = 0; /* Kerberos version (none) */
760 krb_op.cache = NULL; /* Cache file (none) */
764 krb5_init.forwardable = krb5_d_forwardable; /* Init switch values... */
765 krb5_init.proxiable = krb5_d_proxiable;
766 krb5_init.lifetime = krb5_d_lifetime;
768 krb5_init.renewable = krb5_d_renewable;
769 krb5_init.validate = 0;
770 krb5_init.no_addresses = krb5_d_no_addresses;
771 krb5_init.getk4 = krb5_d_getk4;
772 if (krb5_init.postdate) {
773 free(krb5_init.postdate);
774 krb5_init.postdate = NULL;
776 if (krb5_init.service) {
777 free(krb5_init.service);
778 krb5_init.service = NULL;
780 if (!krb5_d_cc || !krb5_d_cc[0]) { /* Set default cache */
782 p = ck_krb5_get_cc_name();
783 makestr(&krb5_d_cc,(p && p[0]) ? p : NULL);
785 if (!krb5_d_realm || !krb5_d_realm[0]) { /* Set default realm */
787 p = ck_krb5_getrealm(krb5_d_cc);
788 makestr(&krb5_d_realm,(p && p[0]) ? p : NULL);
790 makestr(&krb5_init.instance,krb5_d_instance);
791 makestr(&krb5_init.realm,krb5_d_realm); /* Set realm from default */
792 if (krb5_init.password) {
793 memset(krb5_init.password,0xFF,strlen(krb5_init.password));
794 free(krb5_init.password);
795 krb5_init.password = NULL;
797 if (!krb5_d_principal) { /* Default principal */
798 /* a Null principal indicates the user should be prompted */
799 char * p = ck_krb5_getprincipal(krb5_d_cc);
801 p = (char *)uidbuf; /* Principal = user */
802 makestr(&krb5_d_principal,(p && p[0]) ? p : NULL);
804 makestr(&krb5_init.principal,krb5_d_principal);
805 for (i = 0; i <= KRB5_NUM_OF_ADDRS; i++) {
806 if (krb5_init.addrs[i])
807 free(krb5_init.addrs[i]);
808 krb5_init.addrs[i] = NULL;
810 for (i = 0; i <= KRB5_NUM_OF_ADDRS && krb5_d_addrs[i]; i++) {
811 makestr(&krb5_init.addrs[i],krb5_d_addrs[i]);
816 krb4_init.lifetime = krb4_d_lifetime;
817 krb4_init.preauth = krb4_d_preauth;
818 makestr(&krb4_init.instance,krb4_d_instance);
819 if (!krb4_d_realm || !krb4_d_realm[0]) {/* Set default realm */
821 p = ck_krb4_getrealm();
822 makestr(&krb4_d_realm,(p && p[0]) ? p : NULL);
824 makestr(&krb4_init.realm,krb4_d_realm);
825 if (krb4_init.password) {
826 memset(krb4_init.password,0xFF,strlen(krb4_init.password));
827 free(krb4_init.password);
828 krb4_init.password = NULL;
830 if (!krb4_d_principal) { /* Default principal */
831 /* a Null principal indicates the user should be prompted */
832 char * p = ck_krb4_getprincipal();
834 p = (char *)uidbuf; /* Principal = user */
835 makestr(&(krb4_d_principal),(p && p[0]) ? p : NULL);
837 makestr(&(krb4_init.principal),krb4_d_principal);
840 /* D O A U T H -- AUTHENTICATE action routine */
843 doauth(cx) int cx; { /* AUTHENTICATE action routine */
844 int rc = 0; /* Return code */
846 #ifdef CK_AUTHENTICATION
848 if (!ck_security_loaddll()) /* Load various DLLs */
851 if (krb_op.version == 4) { /* Version = 4 */
853 sho_auth(AUTHTYPE_KERBEROS_V4);
855 if (!ck_krb4_is_installed()) {
856 printf("?Kerberos 4 is not installed\n");
859 switch (krb_action) { /* Perform V4 functions */
860 case KRB_A_IN: /* INIT */
861 rc |= !(ck_krb4_initTGT(&krb_op,&krb4_init) < 0);
863 case KRB_A_DE: /* DESTROY */
864 rc |= !(ck_krb4_destroy(&krb_op) < 0);
866 case KRB_A_LC: /* LIST-CREDENTIALS */
867 rc |= !(ck_krb4_list_creds(&krb_op) < 0);
871 if (krb_op.version == 5) { /* V5 functions */
873 sho_auth(AUTHTYPE_KERBEROS_V5);
875 if (!ck_krb5_is_installed()) {
876 printf("?Kerberos 5 is not installed\n");
879 switch (krb_action) {
880 case KRB_A_IN: /* INIT */
881 rc |= !(ck_krb5_initTGT(&krb_op,&krb5_init,
882 krb5_init.getk4 ? &krb4_init : 0) < 0);
884 case KRB_A_DE: /* DESTROY */
885 rc |= !(ck_krb5_destroy(&krb_op) < 0);
887 case KRB_A_LC: /* LIST-CREDENTIALS */
888 if (krb_op.version == 0)
890 rc |= !(ck_krb5_list_creds(&krb_op,&krb5_lc) < 0);
897 rc = sho_auth(0); /* Show all */
900 #endif /* CK_AUTHENTICATION */
903 #endif /* CK_KERBEROS */
907 #ifndef NOLISTEN /* For incoming connections */
911 #endif /* INADDR_ANY */
913 _PROTOTYP( int ttbufr, ( VOID ) );
914 _PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
916 static unsigned short tcpsrv_port = 0;
918 #endif /* NOLISTEN */
921 static char svcbuf[80]; /* TCP service string */
922 static int svcnum = 0; /* TCP port number */
924 #endif /* TCPSOCKET */
927 TCPIPLIB means use separate socket calls for i/o, while on UNIX the
928 normal file system calls are used for TCP/IP sockets too.
929 Means "DEC_TCPIP or MULTINET or WINTCP or OS2 or BEBOX" (see ckcnet.h),
934 /* For buffered network reads... */
936 If the buffering code is written right, it shouldn't matter
937 how long this buffer is.
941 #define TTIBUFL 64240 /* 44 * 1460 (MSS) */
943 #define TTIBUFL 32120 /* 22 * 1460 (MSS) */
946 #define TTIBUFL 8191 /* Let's use 8K. */
949 CHAR ttibuf[TTIBUFL+1];
952 select() is used in preference to alarm()/signal(), but different systems
953 use different forms of select()...
955 #ifndef NOSELECT /* Option to override BSDSELECT */
958 Note: Although BELLV10 does have TCP/IP support, and does use the unique
959 form of select() that is evident in this module (and in ckutio.c), it does
960 not have a sockets library and so we can't build Kermit TCP/IP support for
961 it. For this, somebody would have to write TCP/IP streams code.
965 #define FD_SETSIZE 128
966 #endif /* FD_SETSIZE */
968 #ifdef WINTCP /* VMS with Wollongong WIN/TCP */
969 #ifndef OLD_TWG /* TWG 3.2 has only select(read) */
973 #ifdef CMU_TCPIP /* LIBCMU can do select */
979 #ifdef OS2 /* OS/2 with TCP/IP */
986 #endif /* DEC_TCPIP */
987 #endif /* CMU_TCPIP */
990 #endif /* NOSELECT */
992 Others (TGV, TCPware, ...) use alarm()/signal(). The BSDSELECT case does not
993 compile at all; the IBMSELECT case compiles and links but crashes at runtime.
994 NOTE: If any of these can be converted to select(), they should be for two
995 reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
996 their socket_read() calls to be interrupted; subsequent socket_read()'s tend
997 to fail with EBUSY. This happened in the UCX case before it was converted
1002 static /* These are used in CKVTIO.C */
1003 #endif /* VMS */ /* And in CKONET.C */
1009 Read bytes from network into internal buffer ttibuf[].
1010 To be called when input buffer is empty, i.e. when ttibn == 0.
1012 Other network reading routines, like ttinc, ttinl, ttxin, should check the
1013 internal buffer first, and call this routine for a refill if necessary.
1015 Returns -1 on error, 0 if nothing happens. When data is read successfully,
1016 returns number of bytes read, and sets global ttibn to that number and
1017 ttibp (the buffer pointer) to zero.
1019 _PROTOTYP( int ttbufr, ( VOID ) );
1021 ttbufr() { /* TT Buffer Read */
1024 if (ttnet != NET_TCPB) /* First make sure current net is */
1025 return(-1); /* TCP/IP; if not, do nothing. */
1028 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1031 if (ttibn > 0) { /* Our internal buffer is not empty, */
1033 ReleaseTCPIPMutex();
1035 return(ttibn); /* so keep using it. */
1038 if (ttyfd == -1) { /* No connection, error */
1040 ReleaseTCPIPMutex();
1045 ttibp = 0; /* Else reset pointer to beginning */
1048 count = 512; /* This works for WIN/TCP */
1051 count = 512; /* UCX */
1055 #else /* Multinet, etc. */
1056 count = ttchk(); /* Check network input buffer, */
1057 if (ttibn > 0) { /* which can put a char there! */
1058 debug(F111,"ttbufr","ttchk() returns",count);
1060 ReleaseTCPIPMutex();
1064 if (count < 0) { /* Read error - connection closed */
1066 ReleaseTCPIPMutex();
1070 else if (count > TTIBUFL) /* Too many to read */
1072 else if (count == 0) /* None, so force blocking read */
1075 #endif /* DEC_TCPIP */
1077 debug(F101,"ttbufr count 1","",count);
1080 if (ssl_active_flag || tls_active_flag) {
1083 if (ssl_active_flag)
1084 count = SSL_read(ssl_con, ttibuf, count);
1086 count = SSL_read(tls_con, ttibuf, count);
1087 error = SSL_get_error(ssl_active_flag?ssl_con:tls_con,count);
1089 case SSL_ERROR_NONE:
1090 debug(F111,"ttbufr SSL_ERROR_NONE","count",count);
1092 ttibp = 0; /* Reset buffer pointer. */
1095 ReleaseTCPIPMutex();
1097 return(ttibn); /* Return buffer count. */
1098 } else if (count < 0) {
1100 ReleaseTCPIPMutex();
1106 ReleaseTCPIPMutex();
1110 case SSL_ERROR_WANT_WRITE:
1111 debug(F100,"ttbufr SSL_ERROR_WANT_WRITE","",0);
1113 ReleaseTCPIPMutex();
1116 case SSL_ERROR_WANT_READ:
1117 debug(F100,"ttbufr SSL_ERROR_WANT_READ","",0);
1119 ReleaseTCPIPMutex();
1122 case SSL_ERROR_SYSCALL:
1123 if ( count == 0 ) { /* EOF */
1126 ReleaseTCPIPMutex();
1132 int gle = GetLastError();
1133 debug(F111,"ttbufr SSL_ERROR_SYSCALL",
1134 "GetLastError()",gle);
1135 rc = os2socketerror(gle);
1138 else if ( rc == -2 )
1142 ReleaseTCPIPMutex();
1146 case SSL_ERROR_WANT_X509_LOOKUP:
1147 debug(F100,"ttbufr SSL_ERROR_WANT_X509_LOOKUP","",0);
1150 ReleaseTCPIPMutex();
1154 if (bio_err!=NULL) {
1156 extern char ssl_err[];
1157 BIO_printf(bio_err,"ttbufr SSL_ERROR_SSL\n");
1158 ERR_print_errors(bio_err);
1159 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
1160 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
1161 debug(F110,"ttbufr SSL_ERROR_SSL",ssl_err,0);
1164 } else if (ssl_debug_flag) {
1165 debug(F100,"ttbufr SSL_ERROR_SSL","",0);
1167 fprintf(stderr,"ttbufr SSL_ERROR_SSL\n");
1168 ERR_print_errors_fp(stderr);
1172 #endif /* COMMENT */
1174 ReleaseTCPIPMutex();
1177 case SSL_ERROR_ZERO_RETURN:
1178 debug(F100,"ttbufr SSL_ERROR_ZERO_RETURN","",0);
1181 ReleaseTCPIPMutex();
1185 debug(F100,"ttbufr SSL_ERROR_?????","",0);
1188 ReleaseTCPIPMutex();
1197 This is for nonblocking reads, which we don't do any more. This code didn't
1198 work anyway, in the sense that a broken connection was never sensed.
1200 if ((count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count)) < 1) {
1201 if (count == -1 && socket_errno == EWOULDBLOCK) {
1202 debug(F100,"ttbufr finds nothing","",0);
1204 ReleaseTCPIPMutex();
1208 debug(F101,"ttbufr socket_read error","",socket_errno);
1210 ReleaseTCPIPMutex();
1215 } else if (count == 0) {
1216 debug(F100,"ttbufr socket eof","",0);
1218 ReleaseTCPIPMutex();
1224 /* This is for blocking reads */
1231 if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
1238 FD_SET(ttyfd, &efds);
1239 tv.tv_sec = tv.tv_usec = 0L;
1240 debug(F100,"Out-of-Band BSDSELECT","",0);
1242 WSASafeToCancel = 1;
1244 if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
1245 FD_ISSET(ttyfd, &efds))
1248 WSASafeToCancel = 0;
1250 #else /* !BSDSELECT */
1252 /* Is used by OS/2 ... */
1253 /* ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set */
1254 /* and timeval stuff since this is the only place where it is used. */
1256 debug(F100,"Out-of-Band IBMSELECT","",0);
1257 if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
1259 #else /* !IBMSELECT */
1261 If we can't use select(), then we use the regular alarm()/signal()
1264 debug(F101,"Out-of-Band data not supported","",0);
1267 #endif /* IBMSELECT */
1268 #endif /* BSDSELECT */
1269 #endif /* BELLSELECT */
1271 /* Get the Urgent Data */
1272 /* if OOBINLINE is disabled this should be only a single byte */
1273 /* MS Winsock has a bug in Windows 95. Extra bytes are delivered */
1274 /* That were never sent. */
1276 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
1278 count = socket_recv(ttyfd,&ttibuf[ttibp+ttibn],count,MSG_OOB);
1280 ReleaseTCPIPMutex();
1283 int s_errno = socket_errno;
1284 debug(F101, "ttbufr socket_recv MSG_OOB","",count);
1285 debug(F101, "ttbufr socket_errno","",s_errno);
1287 if (count < 0 && (s_errno == 0 || s_errno == 23)) {
1288 /* These appear in OS/2 - don't know why */
1289 /* ignore it and read as normal data */
1290 /* and break, then we will attempt to read */
1291 /* the port using normal read() techniques */
1292 debug(F100,"ttbufr handing as in-band data","",0);
1295 netclos(); /* *** *** */
1297 ReleaseTCPIPMutex();
1302 netclos(); /* *** *** */
1304 ReleaseTCPIPMutex();
1307 #endif /* OS2ONLY */
1308 } else { /* we got out-of-band data */
1309 ckhexdump("ttbufr out-of-band chars",&ttibuf[ttibp+ttibn],count);
1312 #endif /* BETADEBUG */
1313 #ifdef RLOGCODE /* blah */
1314 if (ttnproto == NP_RLOGIN ||
1315 ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
1316 ((ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) &&
1321 When urgent data is read with MSG_OOB and not OOBINLINE
1322 then urgent data and normal data are not mixed. So
1323 treat the entire buffer as urgent data.
1325 rlog_oob(&ttibuf[ttibp+ttibn], count);
1327 ReleaseTCPIPMutex();
1331 #endif /* RLOGCODE */ /* blah */
1334 I haven't written this yet, nor do I know what it should do
1336 if (ttnproto == NP_TELNET) {
1339 ReleaseTCPIPMutex();
1343 #endif /* COMMENT */
1345 /* For any protocols we don't have a special out-of-band */
1346 /* handler for, just put the bytes in the normal buffer */
1349 ttibp += 0; /* Reset buffer pointer. */
1352 /* Got some bytes. */
1353 debug(F101,"ttbufr count 2","",count);
1355 ttibuf[ttibp+ttibn] = '\0';
1356 debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
1359 ReleaseTCPIPMutex();
1361 return(ttibn); /* Return buffer count. */
1366 #endif /* SO_OOBINLINE */
1369 count = socket_read(ttyfd,&ttibuf[ttibp+ttibn],count);
1371 int s_errno = socket_errno;
1372 debug(F101,"ttbufr socket_read","",count);
1373 debug(F101,"ttbufr socket_errno","",s_errno);
1375 if (count == 0 || os2socketerror(s_errno) < 0) {
1377 ReleaseTCPIPMutex();
1380 ReleaseTCPIPMutex();
1383 netclos(); /* *** *** */
1387 #endif /* COMMENT */ /* (blocking vs nonblock reads...) */
1389 ttibp = 0; /* Reset buffer pointer. */
1392 debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
1394 ttibuf[ttibp+ttibn] = '\0';
1395 debug(F111,"ttbufr ttibuf",&ttibuf[ttibp],ttibn);
1399 ReleaseTCPIPMutex();
1401 return(ttibn); /* Return buffer count. */
1404 #endif /* TCPIPLIB */
1408 #ifndef BSDSELECT /* Non-TCPIPLIB case */
1412 #endif /* BSDSELECT */
1413 #endif /* BELLSELECT */
1414 #endif /* IBMSELECT */
1416 #define TELNET_PORT 23 /* Should do lookup, but it won't change */
1417 #define RLOGIN_PORT 513
1418 #define KERMIT_PORT 1649
1419 #define KLOGIN_PORT 543
1420 #define EKLOGIN_PORT 2105
1424 C-Kermit network open/close functions for BSD-sockets.
1425 Much of this code shared by SunLink X.25, which also uses the socket library.
1428 /* N E T O P N -- Open a network connection. */
1431 name of host (or host:service),
1432 lcl - local-mode flag to be set if this function succeeds,
1433 network type - value defined in ckunet.h.
1438 ck_copyhostent(struct hostent * h)
1439 #else /* CK_ANSIC */
1440 ck_copyhostent(h) struct hostent * h;
1441 #endif /* CK_ANSIC */
1444 * The hostent structure is dynamic in nature.
1447 * char * * h_aliases;
1450 * char * * h_addr_list;
1451 * #define h_addr h_addr_list[0]
1453 #define HOSTENTCNT 5
1454 static struct hostent hosts[HOSTENTCNT] = {{NULL,NULL,0,0,NULL},
1455 {NULL,NULL,0,0,NULL},
1456 {NULL,NULL,0,0,NULL},
1457 {NULL,NULL,0,0,NULL},
1458 {NULL,NULL,0,0,NULL}};
1459 static int next = 0;
1466 if (next == HOSTENTCNT)
1469 if ( hosts[next].h_name ) {
1470 free(hosts[next].h_name);
1471 hosts[next].h_name = NULL;
1473 if ( hosts[next].h_aliases ) {
1474 pp = hosts[next].h_aliases;
1479 free(hosts[next].h_aliases);
1482 if ( hosts[next].h_addr_list ) {
1483 pp = hosts[next].h_addr_list;
1488 free(hosts[next].h_addr_list);
1490 #endif /* HADDRLIST */
1492 makestr(&hosts[next].h_name,h->h_name);
1494 for ( cnt=0,pp=h->h_aliases; pp && *pp; pp++,cnt++) ;
1495 /* The following can give warnings in non-ANSI builds */
1496 hosts[next].h_aliases = (char **) malloc(sizeof(char *) * (cnt+1));
1497 for ( i=0; i<cnt; i++) {
1498 hosts[next].h_aliases[i] = NULL;
1499 makestr(&hosts[next].h_aliases[i],h->h_aliases[i]);
1501 hosts[next].h_aliases[i] = NULL;
1503 hosts[next].h_aliases = NULL;
1505 hosts[next].h_addrtype = h->h_addrtype;
1506 hosts[next].h_length = h->h_length;
1510 if (h->h_addr_list) {
1511 for ( cnt=0,pp=h->h_addr_list; pp && *pp; pp++,cnt++) ;
1512 /* The following can give warnings non-ANSI builds */
1513 hosts[next].h_addr_list = (char **) malloc(sizeof(char *) * (cnt+1));
1514 for ( i=0; i<cnt; i++) {
1515 hosts[next].h_addr_list[i] = malloc(h->h_length);
1516 bcopy(h->h_addr_list[i],hosts[next].h_addr_list[i],h->h_length);
1518 hosts[next].h_addr_list[i] = NULL;
1520 hosts[next].h_addr_list = NULL;
1522 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1524 #else /* HADDRLIST */
1525 bcopy(h->h_addr, &hosts[next].h_addr, h->h_length);
1526 #endif /* HADDRLIST */
1528 return(&hosts[next++]);
1533 Most other BSD sockets implementations define these in header files
1537 unsigned short s_port;
1542 struct in_addr h_addr;
1547 getservbyname(service, connection) char *service,*connection; {
1548 static struct servent servrec;
1552 if (strcmp(service, "telnet") == 0) port = 23;
1553 else if (strcmp(service, "smtp") == 0) port = 25;
1554 else port = atoi(service);
1556 debug(F101,"getservbyname return port ","",port);
1559 servrec.s_port = htons(port);
1562 return((struct servent *) NULL);
1566 gethostbyname(hostname) char *hostname; {
1567 return((struct hostent *) NULL);
1571 inet_addr(name) char *name; {
1574 addr = rhost(&name);
1575 debug(F111,"inet_addr ",name,(int)addr);
1580 inet_ntoa(in) struct in_addr in; {
1581 static char name[80];
1582 ckmakxmsg(name, ckuitoa(in.s_net),".",ckuitoa(in.s_host),".",
1583 ckuitoa(in.s_lh),".", ckuitoa(in.s_impno));
1587 #ifdef DEC_TCPIP /* UCX */
1589 int ucx_port_bug = 0; /* Explained below */
1591 #ifdef OLDIP /* Very old VAXC or GCC */
1593 Note that my oldest VAX C (V3.1-051) does not need (or want) OLDIP,
1594 hence the "Very old" in the comment - SMS, 2010/03/15.
1596 #define getservbyname my_getservbyname
1599 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1600 extern void C$$TRANSLATE();
1601 extern void C$$SOCK_TRANSLATE();
1603 globalref int (*C$$GA_UCX_GETSERVBYNAME)();
1604 extern VOID C$$TRANSLATE();
1605 extern VOID C$$SOCK_TRANSLATE();
1606 #endif /* CK_ANSIC */
1609 my_getservbyname (service, proto) char *service, *proto; {
1610 static struct servent sent;
1613 unsigned long status;
1614 unsigned short st[2];
1616 unsigned long spare;
1624 char sbuf[30], pbuf[30];
1627 debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
1630 ckstrncpy(p, service, 29);
1631 while (*p = toupper(*p), *p++) {}
1633 ckstrncpy(p, proto, 29);
1634 while (*p = toupper(*p), *p++) {}
1640 /* reset file pointer or something like that!?!? */
1641 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1643 par.prot = pbuf; /* that is don't care */
1644 e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1647 if ((e & 1) == 0L) {
1651 if ((s.sb.st[0] & 1) == 0) {
1652 C$$SOCK_TRANSLATE(&s.sb.st[0]);
1656 sent.s_port is supposed to be returned by UCX in network byte order.
1657 However, UCX 2.0 through 2.0C did not do this; 2.0D and later do it.
1658 But there is no way of knowing which UCX version, so we have a user-settable
1659 runtime variable. Note: UCX 2.0 was only for the VAX.
1661 debug(F101,"UCX getservbyname port","",sent.s_port);
1662 debug(F101,"UCX getservbyname ntohs(port)","",ntohs(sent.s_port));
1664 sent.s_port = htons(sent.s_port);
1665 debug(F100,"UCX-PORT-BUG ON: swapping bytes","",0);
1666 debug(F101,"UCX swapped port","",sent.s_port);
1667 debug(F101,"UCX swapped ntohs(port)","",ntohs(sent.s_port));
1671 #endif /* def OLDIP */
1672 #endif /* DEC_TCPIP */
1673 #endif /* EXCELAN */
1680 #endif /* TCPSOCKET */
1685 ck_linger(sock, onoff, timo) int sock; int onoff; int timo; {
1687 The following, from William Bader, turns off the socket linger parameter,
1688 which makes a close() block until all data is sent. "I don't think that
1689 disabling linger can ever cause kermit to lose data, but you telnet to a
1690 flaky server (or to our modem server when the modem is in use), disabling
1691 linger prevents kermit from hanging on the close if you try to exit."
1693 Modified by Jeff Altman to be generally useful.
1697 struct linger set_linger_opt;
1698 struct linger get_linger_opt;
1705 nettype != NET_TCPA && nettype != NET_TCPB &&
1706 nettype != NET_SSH || ttmdm >= 0) {
1708 tcp_linger_tmo = timo;
1711 x = sizeof(get_linger_opt);
1712 if (getsockopt(sock, SOL_SOCKET, SO_LINGER,
1713 (char *)&get_linger_opt, &x)) {
1714 debug(F111,"TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1715 } else if (x != sizeof(get_linger_opt)) {
1720 } get_linger_opt16, set_linger_opt16;
1721 if ( x == sizeof(get_linger_opt16) ) {
1722 debug(F111,"TCP setlinger warning: SO_LINGER","len is 16-bit",x);
1723 if (getsockopt(sock,
1724 SOL_SOCKET, SO_LINGER,
1725 (char *)&get_linger_opt16, &x)
1728 "TCP ck_linger can't get SO_LINGER",ck_errstr(),errno);
1729 } else if (get_linger_opt16.s_onoff != onoff ||
1730 get_linger_opt16.s_linger != timo)
1732 set_linger_opt16.s_onoff = onoff;
1733 set_linger_opt16.s_linger = timo;
1734 if (setsockopt(sock,
1737 (char *)&set_linger_opt16,
1738 sizeof(set_linger_opt16))
1741 "TCP ck_linger can't set SO_LINGER",
1745 tcp_linger = get_linger_opt16.s_onoff;
1746 tcp_linger_tmo = get_linger_opt16.s_linger;
1749 "TCP ck_linger new SO_LINGER","",
1750 set_linger_opt16.s_onoff);
1751 tcp_linger = set_linger_opt16.s_onoff;
1752 tcp_linger_tmo = set_linger_opt16.s_linger;
1756 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1757 get_linger_opt16.s_onoff);
1758 tcp_linger = get_linger_opt16.s_onoff;
1759 tcp_linger_tmo = get_linger_opt16.s_linger;
1765 debug(F111,"TCP ck_linger error: SO_LINGER","len",x);
1766 debug(F111,"TCP ck_linger SO_LINGER",
1767 "expected len",sizeof(get_linger_opt));
1768 debug(F111,"TCP ck_linger SO_LINGER","linger_opt.l_onoff",
1769 get_linger_opt.l_onoff);
1770 debug(F111,"TCP linger SO_LINGER","linger_opt.l_linger",
1771 get_linger_opt.l_linger);
1772 } else if (get_linger_opt.l_onoff != onoff ||
1773 get_linger_opt.l_linger != timo) {
1774 set_linger_opt.l_onoff = onoff;
1775 set_linger_opt.l_linger = timo;
1776 if (setsockopt(sock,
1779 (char *)&set_linger_opt,
1780 sizeof(set_linger_opt))) {
1781 debug(F111,"TCP ck_linger can't set SO_LINGER",ck_errstr(),errno);
1782 tcp_linger = get_linger_opt.l_onoff;
1783 tcp_linger_tmo = get_linger_opt.l_linger;
1786 "TCP ck_linger new SO_LINGER",
1788 set_linger_opt.l_onoff
1790 tcp_linger = set_linger_opt.l_onoff;
1791 tcp_linger_tmo = set_linger_opt.l_linger;
1795 debug(F101,"TCP ck_linger SO_LINGER unchanged","",
1796 get_linger_opt.l_onoff);
1797 tcp_linger = get_linger_opt.l_onoff;
1798 tcp_linger_tmo = get_linger_opt.l_linger;
1802 debug(F100,"TCP ck_linger SO_LINGER not defined","",0);
1803 #endif /* SO_LINGER */
1805 debug(F100,"TCP ck_linger SO_SOCKET not defined","",0);
1806 #endif /* SOL_SOCKET */
1811 sendbuf(sock,size) int sock; int size; {
1813 The following, from William Bader, allows changing of socket buffer sizes,
1814 in case that might affect performance.
1816 Modified by Jeff Altman to be generally useful.
1827 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
1833 if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1834 debug(F111,"TCP sendbuf can't get SO_SNDBUF",ck_errstr(),errno);
1835 } else if (x != sizeof(i)) {
1838 if (x == sizeof(i16)) {
1839 debug(F111,"TCP sendbuf warning: SO_SNDBUF","len is 16-bit",x);
1840 if (getsockopt(sock,
1841 SOL_SOCKET, SO_SNDBUF,
1844 debug(F111,"TCP sendbuf can't get SO_SNDBUF",
1846 } else if (size <= 0) {
1848 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i16);
1850 } else if (i16 != size) {
1852 if (setsockopt(sock,
1858 debug(F111,"TCP sendbuf can't set SO_SNDBUF",
1861 debug(F101,"TCP sendbuf old SO_SNDBUF","",i16);
1862 debug(F101,"TCP sendbuf new SO_SNDBUF","",j16);
1867 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i16);
1874 debug(F111,"TCP sendbuf error: SO_SNDBUF","len",x);
1875 debug(F111,"TCP sendbuf SO_SNDBUF","expected len",sizeof(i));
1876 debug(F111,"TCP sendbuf SO_SNDBUF","i",i);
1877 } else if (size <= 0) {
1879 debug(F101,"TCP sendbuf SO_SNDBUF retrieved","",i);
1881 } else if (i != size) {
1883 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&j, sizeof(j))) {
1884 debug(F111,"TCP sendbuf can't set SO_SNDBUF",ck_errstr(),errno);
1887 debug(F101,"TCP sendbuf old SO_SNDBUF","",i);
1888 debug(F101,"TCP sendbuf new SO_SNDBUF","",j);
1893 debug(F101,"TCP sendbuf SO_SNDBUF unchanged","",i);
1898 debug(F100,"TCP sendbuf SO_SNDBUF not defined","",0);
1899 #endif /* SO_SNDBUF */
1901 debug(F100,"TCP sendbuf SO_SOCKET not defined","",0);
1902 #endif /* SOL_SOCKET */
1907 recvbuf(sock,size) int sock; int size; {
1909 The following, from William Bader, allows changing of socket buffer sizes,
1910 in case that might affect performance.
1912 Modified by Jeff Altman to be generally useful.
1923 nettype != NET_TCPA && nettype != NET_TCPB &&
1924 nettype != NET_SSH || ttmdm >= 0) {
1929 if (getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1930 debug(F111,"TCP recvbuf can't get SO_RCVBUF",ck_errstr(),errno);
1931 } else if (x != sizeof(i)) {
1934 if ( x == sizeof(i16) ) {
1935 debug(F111,"TCP recvbuf warning: SO_RCVBUF","len is 16-bit",x);
1936 if (getsockopt(sock,
1937 SOL_SOCKET, SO_RCVBUF,
1940 debug(F111,"TCP recvbuf can't get SO_RCVBUF",
1942 } else if (size <= 0) {
1944 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i16);
1946 } else if (i16 != size) {
1948 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j16,
1950 debug(F111,"TCP recvbuf can' set SO_RCVBUF",
1953 debug(F101,"TCP recvbuf old SO_RCVBUF","",i16);
1954 debug(F101,"TCP recvbuf new SO_RCVBUF","",j16);
1959 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i16);
1966 debug(F111,"TCP recvbuf error: SO_RCVBUF","len",x);
1967 debug(F111,"TCP recvbuf SO_RCVBUF","expected len",sizeof(i));
1968 debug(F111,"TCP recvbuf SO_RCVBUF","i",i);
1969 } else if (size <= 0) {
1971 debug(F101,"TCP recvbuf SO_RCVBUF retrieved","",i);
1973 } else if (i != size) {
1975 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&j, sizeof(j))) {
1976 debug(F111,"TCP recvbuf can't set SO_RCVBUF",ck_errstr(),errno);
1979 debug(F101,"TCP recvbuf old SO_RCVBUF","",i);
1980 debug(F101,"TCP recvbuf new SO_RCVBUF","",j);
1985 debug(F101,"TCP recvbuf SO_RCVBUF unchanged","",i);
1990 debug(F100,"TCP recvbuf SO_RCVBUF not defined","",0);
1991 #endif /* SO_RCVBUF */
1993 debug(F100,"TCP recvbuf SO_SOCKET not defined","",0);
1994 #endif /* SOL_SOCKET */
1999 keepalive(sock,onoff) int sock; int onoff; {
2002 int get_keepalive_opt;
2003 int set_keepalive_opt;
2006 debug(F111,"TCP keepalive","sock",sock);
2007 debug(F111,"TCP keepalive","nettype",nettype);
2008 debug(F111,"TCP keepalive","ttmdm",ttmdm);
2014 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2016 tcp_keepalive = onoff;
2019 x = sizeof(get_keepalive_opt);
2020 if (getsockopt(sock,
2021 SOL_SOCKET, SO_KEEPALIVE, (char *)&get_keepalive_opt, &x)) {
2022 debug(F111,"TCP keepalive can't get SO_KEEPALIVE",ck_errstr(),errno);
2023 } else if (x != sizeof(get_keepalive_opt)) {
2025 short get_keepalive_opt16;
2026 short set_keepalive_opt16;
2027 if (x == sizeof(get_keepalive_opt16)) {
2028 debug(F111,"TCP keepalive warning: SO_KEEPALIVE",
2030 if (getsockopt(sock,
2031 SOL_SOCKET, SO_KEEPALIVE,
2032 (char *)&get_keepalive_opt16, &x)
2035 "TCP keepalive can't get SO_KEEPALIVE",
2039 } else if (get_keepalive_opt16 != onoff) {
2040 set_keepalive_opt16 = onoff;
2041 if (setsockopt(sock,
2044 (char *)&set_keepalive_opt16,
2045 sizeof(set_keepalive_opt16))
2048 "TCP keepalive can't clear SO_KEEPALIVE",
2052 tcp_keepalive = get_keepalive_opt16;
2055 "TCP keepalive new SO_KEEPALIVE","",
2056 set_keepalive_opt16);
2057 tcp_keepalive = set_keepalive_opt16;
2061 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged","",
2062 get_keepalive_opt16);
2063 tcp_keepalive = onoff;
2069 debug(F111,"TCP keepalive error: SO_KEEPALIVE","len",x);
2071 "TCP keepalive SO_KEEPALIVE",
2073 sizeof(get_keepalive_opt)
2076 "TCP keepalive SO_KEEPALIVE",
2080 } else if (get_keepalive_opt != onoff) {
2081 set_keepalive_opt = onoff;
2082 if (setsockopt(sock,
2085 (char *)&set_keepalive_opt,
2086 sizeof(set_keepalive_opt))
2089 "TCP keepalive can't clear SO_KEEPALIVE",
2093 tcp_keepalive = get_keepalive_opt;
2096 "TCP keepalive new SO_KEEPALIVE",
2100 tcp_keepalive = onoff;
2104 debug(F101,"TCP keepalive SO_KEEPALIVE unchanged",
2108 tcp_keepalive = onoff;
2112 debug(F100,"TCP keepalive SO_KEEPALIVE not defined","",0);
2113 #endif /* SO_KEEPALIVE */
2115 debug(F100,"TCP keepalive SO_SOCKET not defined","",0);
2116 #endif /* SOL_SOCKET */
2121 dontroute(sock,onoff) int sock; int onoff; {
2124 int get_dontroute_opt;
2125 int set_dontroute_opt;
2132 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2134 tcp_dontroute = onoff;
2137 x = sizeof(get_dontroute_opt);
2138 if (getsockopt(sock,
2139 SOL_SOCKET, SO_DONTROUTE, (char *)&get_dontroute_opt, &x)) {
2140 debug(F111,"TCP dontroute can't get SO_DONTROUTE",ck_errstr(),errno);
2141 } else if (x != sizeof(get_dontroute_opt)) {
2143 short get_dontroute_opt16;
2144 short set_dontroute_opt16;
2145 if (x == sizeof(get_dontroute_opt16)) {
2146 debug(F111,"TCP dontroute warning: SO_DONTROUTE",
2148 if (getsockopt(sock,
2149 SOL_SOCKET, SO_DONTROUTE,
2150 (char *)&get_dontroute_opt16, &x)
2153 "TCP dontroute can't get SO_DONTROUTE",
2157 } else if (get_dontroute_opt16 != onoff) {
2158 set_dontroute_opt16 = onoff;
2159 if (setsockopt(sock,
2162 (char *)&set_dontroute_opt16,
2163 sizeof(set_dontroute_opt16))
2166 "TCP dontroute can't clear SO_DONTROUTE",
2170 tcp_dontroute = get_dontroute_opt16;
2173 "TCP dontroute new SO_DONTROUTE","",
2174 set_dontroute_opt16);
2175 tcp_dontroute = set_dontroute_opt16;
2179 debug(F101,"TCP dontroute SO_DONTROUTE unchanged","",
2180 get_dontroute_opt16);
2181 tcp_dontroute = onoff;
2187 debug(F111,"TCP dontroute error: SO_DONTROUTE","len",x);
2189 "TCP dontroute SO_DONTROUTE",
2191 sizeof(get_dontroute_opt)
2194 "TCP dontroute SO_DONTROUTE",
2198 } else if (get_dontroute_opt != onoff) {
2199 set_dontroute_opt = onoff;
2200 if (setsockopt(sock,
2203 (char *)&set_dontroute_opt,
2204 sizeof(set_dontroute_opt))
2207 "TCP dontroute can't clear SO_DONTROUTE",
2211 tcp_dontroute = get_dontroute_opt;
2214 "TCP dontroute new SO_DONTROUTE",
2218 tcp_dontroute = onoff;
2222 debug(F101,"TCP dontroute SO_DONTROUTE unchanged",
2226 tcp_dontroute = onoff;
2230 debug(F100,"TCP dontroute SO_DONTROUTE not defined","",0);
2231 #endif /* SO_DONTROUTE */
2233 debug(F100,"TCP dontroute SO_SOCKET not defined","",0);
2234 #endif /* SOL_SOCKET */
2239 no_delay(sock,onoff) int sock; int onoff; {
2242 int get_nodelay_opt;
2243 int set_nodelay_opt;
2250 nettype != NET_TCPA && nettype != NET_TCPB && nettype != NET_SSH
2252 tcp_nodelay = onoff;
2255 x = sizeof(get_nodelay_opt);
2256 if (getsockopt(sock,IPPROTO_TCP,TCP_NODELAY,
2257 (char *)&get_nodelay_opt,&x)) {
2259 "TCP no_delay can't get TCP_NODELAY",
2262 } else if (x != sizeof(get_nodelay_opt)) {
2264 short get_nodelay_opt16;
2265 short set_nodelay_opt16;
2266 if (x == sizeof(get_nodelay_opt16)) {
2267 debug(F111,"TCP no_delay warning: TCP_NODELAY","len is 16-bit",x);
2268 if (getsockopt(sock,
2269 IPPROTO_TCP, TCP_NODELAY,
2270 (char *)&get_nodelay_opt16, &x)
2273 "TCP no_delay can't get TCP_NODELAY",
2276 } else if (get_nodelay_opt16 != onoff) {
2277 set_nodelay_opt16 = onoff;
2278 if (setsockopt(sock,
2281 (char *)&set_nodelay_opt16,
2282 sizeof(set_nodelay_opt16))
2285 "TCP no_delay can't clear TCP_NODELAY",
2288 tcp_nodelay = get_nodelay_opt16;
2291 "TCP no_delay new TCP_NODELAY",
2294 tcp_nodelay = onoff;
2298 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",
2300 tcp_nodelay = onoff;
2306 debug(F111,"TCP no_delay error: TCP_NODELAY","len",x);
2307 debug(F111,"TCP no_delay TCP_NODELAY","expected len",
2308 sizeof(get_nodelay_opt));
2309 debug(F111,"TCP no_delay TCP_NODELAY","nodelay_opt",get_nodelay_opt);
2310 } else if (get_nodelay_opt != onoff) {
2311 set_nodelay_opt = onoff;
2312 if (setsockopt(sock,
2315 (char *)&set_nodelay_opt,
2316 sizeof(set_nodelay_opt))) {
2318 "TCP no_delay can't clear TCP_NODELAY",
2322 tcp_nodelay = get_nodelay_opt;
2324 debug(F101,"TCP no_delay new TCP_NODELAY","",set_nodelay_opt);
2325 tcp_nodelay = onoff;
2329 debug(F101,"TCP no_delay TCP_NODELAY unchanged","",get_nodelay_opt);
2330 tcp_nodelay = onoff;
2334 debug(F100,"TCP no_delay TCP_NODELAY not defined","",0);
2335 #endif /* TCP_NODELAY */
2337 debug(F100,"TCP no_delay SO_SOCKET not defined","",0);
2338 #endif /* SOL_SOCKET */
2341 #endif /* datageneral */
2342 #endif /* NOTCPOPTS */
2345 #ifndef X25_WR_FACILITY
2346 /* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
2348 bzero(s,n) char *s; int n; {
2351 #endif /* X25_WR_FACILITY */
2362 #ifdef hp9000s500 /* HP-9000/500 HP-U 5.21 */
2366 /****** THIS SECTION ADDED BY STEVE RANCE - OS9 NETWORK SERVER
2367 * ------------------------------------------------------
2369 * Due to OS9's Lack of a select() call, the following seems to be
2370 * enough to fool the rest of the code into compiling. The only
2371 * effect that I can see is using control L to refresh the status
2372 * display gets qued up until some network packets arrive.
2374 * This solution is by no means elegant but works enough to be
2377 * Also with the defines I had specified in my makefile I had to
2378 * have an #endif right at the end of the file when compiling.
2379 * I did not bother speding time to find out why.
2381 * COPTS = -to=osk -d=OSK -d=TCPSOCKET -d=SELECT -d=VOID=void -d=SIG_V \
2382 * -d=DYNAMIC -d=PARSENSE -d=KANJI -d=MYCURSES -d=ZFCDAT \
2383 * -d=CK_APC -d=CK_REDIR -d=RENAME -d=CK_TTYFD -d=NOOLDMODEMS \
2384 * -d=CK_ANSIC -d=CK_XYZ -tp=68040d -l=netdb.l -l=socklib.l \
2385 * -l=termlib.l -l=math.l -l=sys_clib.l
2387 * stever@ozemail.com.au
2391 #define BSDSELECT /* switch on BSD select code */
2392 #define FD_SETSIZE 32 /* Max # of paths in OS9 */
2393 #define FD_ZERO(p) ((*p)=0)
2394 #define FD_SET(n,b) ((*b)|=(1<<(n)))
2395 #define FD_ISSET(n,b) 1 /* always say data is ready */
2396 #define select(a,b,c,d,e) 1 /* always say 1 path has data */
2397 typedef int fd_set; /* keep BSD Code Happy */
2398 struct timeval {int tv_sec,tv_usec;}; /* keep BSD Code Happy */
2400 /****** END OF OS9 MODS FROM STEVE RANCE **************************/
2403 #include <sys/time.h>
2404 #endif /* hp9000s500 */
2405 #endif /* datageneral */
2406 #endif /* BELLV10 */
2409 #include <sys/select.h>
2410 #endif /* SELECT_H */
2411 #endif /* BSDSELECT */
2415 #include <sys/select.h>
2416 #endif /* CK_SCOV5 */
2420 /* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
2423 tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
2425 static struct servent *service, servrec;
2426 static struct hostent *host;
2427 static struct sockaddr_in saddr;
2446 #endif /* BELLSELECT */
2447 #endif /* BSDSELECT */
2449 debug(F101,"tcpsocket_open nett","",nett);
2452 if (nett != NET_TCPB)
2453 return(-1); /* BSD socket support */
2455 netclos(); /* Close any previous connection. */
2456 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2458 /* Jeff's version from 30 Dec 2005 doesn't inhibit Telnet */
2459 if (ttnproto != NP_TCPRAW &&
2460 ttnproto != NP_SSL_RAW &&
2461 ttnproto != NP_TLS_RAW)
2462 ttnproto = NP_NONE; /* No protocol selected yet. */
2464 /* fdc's version from 4 Dec 2005 works ok */
2465 if (ttnproto != NP_TCPRAW)
2466 ttnproto = NP_NONE; /* No protocol selected yet. */
2467 #endif /* COMMENT */
2468 debug(F110,"tcpsocket_open namecopy",namecopy,0);
2470 /* Assign the socket number to ttyfd and then fill in tcp structures */
2471 ttyfd = atoi(&name[1]);
2472 debug(F111,"tcpsocket_open","ttyfd",ttyfd);
2476 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2480 no_delay(ttyfd,tcp_nodelay);
2481 #endif /* TCP_NODELAY */
2483 keepalive(ttyfd,tcp_keepalive);
2484 #endif /* SO_KEEPALIVE */
2486 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2487 #endif /* SO_LINGER */
2489 sendbuf(ttyfd,tcp_sendbuf);
2490 #endif /* SO_SNDBUF */
2492 recvbuf(ttyfd,tcp_recvbuf);
2493 #endif /* SO_RCVBUF */
2494 #endif /* datageneral */
2495 #endif /* SOL_SOCKET */
2496 #endif /* NOTCPOPTS */
2498 #ifdef NT_TCP_OVERLAPPED
2499 OverlappedWriteInit();
2500 OverlappedReadInit();
2501 #endif /* NT_TCP_OVERLAPPED */
2504 /* Get the name of the host we are connected to */
2506 saddrlen = sizeof(saddr);
2507 getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
2509 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2511 if (tcp_rdns == SET_ON
2513 || tcp_rdns == SET_AUTO &&
2514 (ck_krb5_is_installed() || ck_krb4_is_installed())
2515 #endif /* CK_KERBEROS */
2517 && (tcp_http_proxy == NULL)
2520 && !(ssl_only_flag || tls_only_flag)
2522 ) { /* Reverse DNS */
2524 printf(" Reverse DNS Lookup... ");
2527 host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET);
2528 debug(F110,"tcpsocket_open gethostbyaddr",host ? "OK" : "FAILED",0);
2530 host = ck_copyhostent(host);
2531 debug(F100,"tcpsocket_open gethostbyaddr != NULL","",0);
2536 ckstrncpy(name, host->h_name, 80);
2537 ckstrncat(name, ":", 80);
2538 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)), 80);
2544 printf("%s connected on port %d\n",
2546 ntohs(saddr.sin_port)
2553 if (tcp_rdns != SET_ON || !host) {
2554 ckstrncpy(name,ipaddr,80);
2555 ckstrncat(name,":",80);
2556 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
2562 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
2564 if (!quiet) fflush(stdout);
2565 ttnet = nett; /* TCP/IP (sockets) network */
2568 if (ntohs(saddr.sin_port) == 513)
2569 ttnproto = NP_LOGIN;
2571 #endif /* RLOGCODE */
2572 /* Assume the service is TELNET. */
2574 /* Jeff's code from 2005/12/30 */
2575 if (ttnproto != NP_TCP_RAW &&
2576 ttnproto != NP_SSL_RAW &&
2577 ttnproto != NP_TLS_RAW)
2579 /* fdc's code from 2005/12/04 */
2580 if (ttnproto != NP_TCPRAW)
2581 #endif /* COMMENT */
2582 ttnproto = NP_TELNET; /* Yes, set global flag. */
2584 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
2585 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
2586 host->h_name : ipaddr,
2591 #endif /* CK_SECURITY */
2592 if (tn_ini() < 0) /* Start/Reset TELNET negotiations */
2593 if (ttchk() < 0) /* Did it fail due to connect loss? */
2596 if (*lcl < 0) *lcl = 1; /* Local mode. */
2598 return(0); /* Done. */
2600 #endif /* NOTUSED */
2602 /* T C P S R V _ O P E N -- Open a TCP/IP Server connection */
2604 Calling conventions same as ttopen(), except third argument is network
2605 type rather than modem type.
2608 tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
2612 int ready_to_accept = 0;
2613 static struct servent *service, *service2, servrec;
2614 static struct hostent *host;
2615 static struct sockaddr_in saddr;
2616 struct sockaddr_in l_addr;
2619 static u_int saddrlen;
2621 static SOCKOPT_T saddrlen;
2636 #endif /* BELLSELECT */
2637 #endif /* BSDSELECT */
2642 debug(F101,"tcpsrv_open nett","",nett);
2645 if (nett != NET_TCPB)
2646 return(-1); /* BSD socket support */
2648 netclos(); /* Close any previous connection. */
2649 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
2650 /* Don't do this. */
2653 if (ttnproto != NP_TCPRAW)
2654 ttnproto = NP_NONE; /* No protocol selected yet. */
2655 #endif /* COMMENT */
2658 if (ttnproto != NP_TCP_RAW &&
2659 ttnproto != NP_SSL_RAW &&
2660 ttnproto != NP_TLS_RAW)
2661 ttnproto = NP_NONE; /* No protocol selected yet. */
2662 #endif /* COMMENT */
2663 debug(F110,"tcpsrv_open namecopy",namecopy,0);
2665 p = namecopy; /* Was a service requested? */
2666 while (*p != '\0' && *p != ':')
2667 p++; /* Look for colon */
2668 if (*p == ':') { /* Have a colon */
2669 *p++ = '\0'; /* Get service name or number */
2670 } else { /* Otherwise use kermit */
2673 debug(F110,"tcpsrv_open service requested",p,0);
2674 if (isdigit(*p)) { /* Use socket number without lookup */
2676 service->s_port = htons((unsigned short)atoi(p));
2677 } else { /* Otherwise lookup the service name */
2678 service = getservbyname(p, "tcp");
2680 if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
2682 service->s_port = htons(1649);
2685 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
2687 " Warning: login service on port %d instead of port 513\n",
2688 ntohs(service->s_port));
2689 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
2690 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
2692 #endif /* RLOGCODE */
2694 fprintf(stderr, "Cannot find port for service: %s\n", p);
2695 debug(F111,"tcpsrv_open can't get service",p,errno);
2696 errno = 0; /* rather than mislead */
2700 /* If we currently have a listen active but port has changed then close */
2702 debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
2703 debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
2704 if (tcpsrfd != -1 &&
2705 tcpsrv_port != ntohs((unsigned short)service->s_port)) {
2706 debug(F100,"tcpsrv_open closing previous connection","",0);
2708 socket_close(tcpsrfd);
2711 #endif /* TCPIPLIB */
2714 debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
2715 if (tcpsrfd == -1) {
2717 /* Set up socket structure and get host address */
2719 bzero((char *)&saddr, sizeof(saddr));
2720 debug(F100,"tcpsrv_open bzero ok","",0);
2721 saddr.sin_family = AF_INET;
2724 inaddrx = inet_addr(tcp_address);
2725 saddr.sin_addr.s_addr = *(unsigned long *)&inaddrx;
2727 saddr.sin_addr.s_addr = inet_addr(tcp_address);
2728 #endif /* INADDRX */
2730 saddr.sin_addr.s_addr = INADDR_ANY;
2732 /* Get a file descriptor for the connection. */
2734 saddr.sin_port = service->s_port;
2737 debug(F100,"tcpsrv_open calling socket","",0);
2738 if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
2739 perror("TCP socket error");
2740 debug(F101,"tcpsrv_open socket error","",errno);
2745 /* Specify the Port may be reused */
2747 debug(F100,"tcpsrv_open calling setsockopt","",0);
2748 x = setsockopt(tcpsrfd,
2749 SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
2750 debug(F101,"tcpsrv_open setsockopt","",x);
2752 /* Now bind to the socket */
2753 printf("\nBinding socket to port %d ...\n",
2754 ntohs((unsigned short)service->s_port));
2755 if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
2756 i = errno; /* Save error code */
2758 socket_close(tcpsrfd);
2759 #else /* TCPIPLIB */
2761 #endif /* TCPIPLIB */
2766 errno = i; /* and report this error */
2767 debug(F101,"tcpsrv_open bind errno","",errno);
2768 printf("?Unable to bind to socket (errno = %d)\n",errno);
2771 debug(F100,"tcpsrv_open bind OK","",0);
2772 printf("Listening ...\n");
2773 if (listen(tcpsrfd, 15) < 0) {
2774 i = errno; /* Save error code */
2776 socket_close(tcpsrfd);
2777 #else /* TCPIPLIB */
2779 #endif /* TCPIPLIB */
2784 errno = i; /* And report this error */
2785 debug(F101,"tcpsrv_open listen errno","",errno);
2788 debug(F100,"tcpsrv_open listen OK","",0);
2789 tcpsrv_port = ntohs((unsigned short)service->s_port);
2793 if (ck_ssleay_is_installed()) {
2794 if (!ssl_tn_init(SSL_SERVER)) {
2796 if (bio_err!=NULL) {
2797 BIO_printf(bio_err,"do_ssleay_init() failed\n");
2798 ERR_print_errors(bio_err);
2801 fprintf(stderr,"do_ssleay_init() failed\n");
2802 ERR_print_errors_fp(stderr);
2804 if (tls_only_flag || ssl_only_flag) {
2806 socket_close(ttyfd);
2807 socket_close(tcpsrfd);
2808 #else /* TCPIPLIB */
2811 #endif /* TCPIPLIB */
2818 /* we will continue to accept the connection */
2819 /* without SSL or TLS support unless required. */
2820 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2821 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2822 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2823 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2824 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
2825 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
2826 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
2827 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
2832 printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
2833 ntohs((unsigned short)service->s_port));
2834 saddrlen = sizeof(saddr);
2837 tv.tv_sec = tv.tv_usec = 0L;
2839 tv.tv_usec = (long) -timo * 10000L;
2842 debug(F101,"tcpsrv_open BSDSELECT","",timo);
2844 debug(F101,"tcpsrv_open not BSDSELECT","",timo);
2845 #endif /* BSDSELECT */
2848 while (!ready_to_accept) {
2851 FD_SET(tcpsrfd, &rfds);
2853 ((select(FD_SETSIZE,
2860 #endif /* HPUX1010 */
2865 #else /* def INTSELECT */
2867 #endif /* def INTSELECT [else] */
2870 &rfds, NULL, NULL, &tv) > 0) &&
2871 FD_ISSET(tcpsrfd, &rfds));
2872 #else /* BSDSELECT */
2874 #define ck_sleepint 250
2876 (select(&tcpsrfd, 1, 0, 0,
2878 (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
2883 FD_SET(tcpsrfd, rfds);
2885 ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
2886 (timo > 0 ? timo * 1000L)) > 0) &&
2887 FD_ISSET(tcpsrfd, rfds));
2889 /* Try this - what's the worst that can happen... */
2892 FD_SET(tcpsrfd, &rfds);
2894 ((select(FD_SETSIZE,
2895 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
2896 FD_ISSET(tcpsrfd, &rfds));
2898 #endif /* BELLSELECT */
2899 #endif /* IBMSELECT */
2900 #endif /* BSDSELECT */
2903 if (ready_to_accept || timo == 0) {
2904 if ((ttyfd = accept(tcpsrfd,
2905 (struct sockaddr *)&saddr,&saddrlen)) < 0) {
2906 i = errno; /* save error code */
2908 socket_close(tcpsrfd);
2909 #else /* TCPIPLIB */
2911 #endif /* TCPIPLIB */
2916 errno = i; /* and report this error */
2917 debug(F101,"tcpsrv_open accept errno","",errno);
2920 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2926 no_delay(ttyfd,tcp_nodelay);
2927 debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
2928 #endif /* TCP_NODELAY */
2930 keepalive(ttyfd,tcp_keepalive);
2931 debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
2932 #endif /* SO_KEEPALIVE */
2934 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
2935 debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
2936 #endif /* SO_LINGER */
2938 sendbuf(ttyfd,tcp_sendbuf);
2939 #endif /* SO_SNDBUF */
2941 recvbuf(ttyfd,tcp_recvbuf);
2942 #endif /* SO_RCVBUF */
2943 #endif /* SOL_SOCKET */
2944 #endif /* datageneral */
2945 #endif /* NOTCPOPTS */
2947 ttnet = nett; /* TCP/IP (sockets) network */
2948 tcp_incoming = 1; /* This is an incoming connection */
2949 sstelnet = 1; /* Do server-side Telnet protocol */
2951 /* See if the service is TELNET. */
2952 x = (unsigned short)service->s_port;
2953 service2 = getservbyname("telnet", "tcp");
2954 if (service2 && x == service2->s_port) {
2956 /* Jeff 2005/12/30 */
2957 if (ttnproto != NP_TCPRAW && /* Yes... */
2958 ttnproto != NP_SSL_RAW &&
2959 ttnproto != NP_TLS_RAW) /* and if raw port not requested */
2961 /* fdc 2005/12/04 */
2962 if (ttnproto != NP_TCPRAW) /* Yes and if raw port not requested */
2964 ttnproto = NP_TELNET; /* set protocol to TELNET. */
2966 ckstrncpy(ipaddr,(char *)inet_ntoa(saddr.sin_addr),20);
2969 printf(" Reverse DNS Lookup... ");
2972 if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
2973 host = ck_copyhostent(host);
2974 debug(F100,"tcpsrv_open gethostbyaddr != NULL","",0);
2980 ckstrncpy(&name[1],host->h_name,78);
2981 ckstrncat(name,":",80-strlen(name));
2982 ckstrncat(name,p,80-strlen(name));
2988 printf("%s connected on port %s\n",host->h_name,p);
2990 if (!quiet) printf("Failed.\n");
2992 } else if (!quiet) printf("(OK)\n");
2994 if (!tcp_rdns || !host) {
2995 ckstrncpy(name,ipaddr,80);
2996 ckstrncat(name,":",80);
2997 ckstrncat(name,ckuitoa(ntohs(saddr.sin_port)),80);
3003 printf("%s connected on port %d\n",ipaddr,ntohs(saddr.sin_port));
3005 if (!quiet) fflush(stdout);
3008 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
3009 ck_auth_init((tcp_rdns && host && host->h_name && host->h_name[0]) ?
3010 (char *)host->h_name : ipaddr,
3015 #endif /* CK_SECURITY */
3018 if (ck_ssleay_is_installed() && !ssl_failed) {
3019 if (ck_ssl_incoming(ttyfd) < 0) {
3021 socket_close(ttyfd);
3022 socket_close(tcpsrfd);
3023 #else /* TCPIPLIB */
3026 #endif /* TCPIPLIB */
3037 /* Find out our own IP address. */
3038 l_slen = sizeof(l_addr);
3039 bzero((char *)&l_addr, l_slen);
3041 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
3042 char * s = (char *)inet_ntoa(l_addr.sin_addr);
3043 ckstrncpy(myipaddr, s,20);
3044 debug(F110,"getsockname",myipaddr,0);
3046 #endif /* EXCELAN */
3047 #endif /* datageneral */
3049 if (tn_ini() < 0) /* Start TELNET negotiations. */
3050 if (ttchk() < 0) { /* Disconnected? */
3051 i = errno; /* save error code */
3053 socket_close(tcpsrfd);
3054 #else /* TCPIPLIB */
3056 #endif /* TCPIPLIB */
3061 errno = i; /* and report this error */
3062 debug(F101,"tcpsrv_open accept errno","",errno);
3065 debug(F101,"tcpsrv_open service","",x);
3066 if (*lcl < 0) /* Set local mode. */
3071 if ( ttnproto == NP_K5U2U ) {
3072 if (k5_user_to_user_server_auth() != 0) {
3073 i = errno; /* save error code */
3075 socket_close(tcpsrfd);
3076 #else /* TCPIPLIB */
3078 #endif /* TCPIPLIB */
3083 errno = i; /* and report this error */
3084 debug(F101,"tcpsrv_open accept errno","",errno);
3088 #endif /* KRB5_U2U */
3089 #endif /* CK_KERBEROS */
3090 return(0); /* Done. */
3092 i = errno; /* save error code */
3094 socket_close(tcpsrfd);
3095 #else /* TCPIPLIB */
3097 #endif /* TCPIPLIB */
3102 errno = i; /* and report this error */
3103 debug(F101,"tcpsrv_open accept errno","",errno);
3107 #endif /* NOLISTEN */
3109 #endif /* TCPSOCKET */
3114 ckname2addr(name) char * name;
3119 struct hostent *host;
3121 if (name == NULL || *name == '\0')
3124 host = gethostbyname(name);
3126 host = ck_copyhostent(host);
3127 return(inet_ntoa(*((struct in_addr *) host->h_addr)));
3134 ckaddr2name(addr) char * addr;
3139 struct hostent *host;
3140 struct in_addr sin_addr;
3142 if (addr == NULL || *addr == '\0')
3145 sin_addr.s_addr = inet_addr(addr);
3146 host = gethostbyaddr((char *)&sin_addr,4,AF_INET);
3148 host = ck_copyhostent(host);
3149 return((char *)host->h_name);
3154 #endif /* TCPSOCKET */
3156 unsigned long peerxipaddr = 0L;
3161 static char namebuf[256];
3162 static struct hostent *host;
3163 static struct sockaddr_in saddr;
3165 static GPEERNAME_T saddrlen;
3168 static size_t saddrlen;
3171 /* It's size_t in 4.2 but int in 4.1 and earlier. */
3172 /* Note: the 4.2 man page lies; believe socket.h. */
3173 static size_t saddrlen;
3176 static size_t saddrlen;
3177 #else /* UNIXWARE */
3180 * Coincidentally, the condition for integer arguments in select(),
3181 * which is actually "defined( _DECC_V4_SOURCE)", works for an integer
3182 * argument in getpeername(). Sadly, due to a lack of foresight,
3183 * "defined( _DECC_V4_SOURCE)" doesn't work with DEC C V4.0, so the
3184 * user-specified INTSELECT is used instead. Most likely, "size_t"
3185 * should be used instead of "unsigned int", but I'm a coward.
3188 static int saddrlen;
3189 #else /* def INTSELECT */
3190 static unsigned int saddrlen;
3191 #endif /* def INTSELECT [else] */
3194 static unsigned int saddrlen;
3197 static socklen_t saddrlen;
3199 static int saddrlen;
3200 #endif /* CK_64BIT */
3201 #endif /* MACOSX10 */
3202 #endif /* DEC_TCPIP */
3203 #endif /* UNIXWARE */
3206 #endif /* GPEERNAME_T */
3207 saddrlen = sizeof(saddr);
3208 if (getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen) < 0) {
3209 debug(F111,"ckgetpeer failure",ckitoa(ttyfd),errno);
3212 host = gethostbyaddr((char *)&saddr.sin_addr,4,AF_INET);
3214 host = ck_copyhostent(host);
3215 ckstrncpy(namebuf,(char *)host->h_name,80);
3217 ckstrncpy(namebuf,(char *)inet_ntoa(saddr.sin_addr),80);
3219 peerxipaddr = ntohl(saddr.sin_addr.s_addr);
3220 debug(F111,"ckgetpeer",namebuf,peerxipaddr);
3224 #endif /* TCPSOCKET */
3227 /* Get fully qualified IP hostname */
3232 ckgetfqhostname(char * name)
3234 ckgetfqhostname(name) char * name;
3235 #endif /* CK_ANSIC */
3237 #ifdef NOCKGETFQHOST
3241 #else /* If the following code dumps core, define NOCKGETFQHOST and rebuild. */
3243 static char namebuf[256];
3244 struct hostent *host=NULL;
3245 struct sockaddr_in r_addr;
3248 debug(F110,"ckgetfqhn()",name,0);
3250 ckstrncpy(namebuf,name,256);
3251 namebuf[255] = '\0';
3252 i = ckindex(":",namebuf,0,0,0);
3254 namebuf[i-1] = '\0';
3256 bzero((char *)&r_addr, sizeof(r_addr));
3258 host = gethostbyname(namebuf);
3260 host = ck_copyhostent(host);
3261 debug(F100,"ckgetfqhn() gethostbyname != NULL","",0);
3262 r_addr.sin_family = host->h_addrtype;
3265 /* This is for trying multiple IP addresses - see <netdb.h> */
3266 if (!(host->h_addr_list))
3268 bcopy(host->h_addr_list[0],
3269 (caddr_t)&r_addr.sin_addr,
3273 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3275 #else /* HADDRLIST */
3276 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
3277 #endif /* HADDRLIST */
3280 debug(F111,"BCOPY","host->h_addr",host->h_addr);
3281 #endif /* EXCELAN */
3282 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
3283 (caddr_t)&r_addr.sin_addr);
3284 #endif /* COMMENT */
3285 debug(F111,"BCOPY","host->h_length",host->h_length);
3288 /* Windows 95/98 requires a 1 second wait between calls to Microsoft */
3289 /* provided DNS functions. Otherwise, the TTL of the DNS response */
3294 host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET);
3296 host = ck_copyhostent(host);
3297 debug(F100,"ckgetfqhn() gethostbyaddr != NULL","",0);
3298 ckstrncpy(namebuf, host->h_name, 256);
3306 #endif /* HADDRLIST */
3309 ckstrncat(namebuf,&name[i-1],256-strlen(namebuf)-strlen(&name[i-1]));
3310 debug(F110,"ckgetfqhn()",namebuf,0);
3312 #endif /* NOCKGETFQHOST */
3319 setnproto(p) char * p;
3320 #endif /* CK_ANSIC */
3323 if (!strcmp("kermit",p))
3324 ttnproto = NP_KERMIT;
3325 else if (!strcmp("telnet",p))
3326 ttnproto = NP_TELNET;
3327 else if (!strcmp("http",p))
3328 ttnproto = NP_TCPRAW;
3330 else if (!strcmp("login",p))
3331 ttnproto = NP_RLOGIN;
3332 #endif /* RLOGCODE */
3334 /* Commonly used SSL ports (might not be in services file) */
3335 else if (!strcmp("https",p)) {
3336 ttnproto = NP_SSL_RAW;
3338 } else if (!strcmp("ssl-telnet",p)) {
3339 ttnproto = NP_TELNET;
3341 } else if (!strcmp("telnets",p)) {
3342 ttnproto = NP_TELNET;
3348 else if (!strcmp("klogin",p)) {
3349 if (ck_krb5_is_installed())
3350 ttnproto = NP_K5LOGIN;
3351 else if (ck_krb4_is_installed())
3352 ttnproto = NP_K4LOGIN;
3354 ttnproto = NP_RLOGIN;
3355 } else if (!strcmp("eklogin",p)) {
3356 if (ck_krb5_is_installed())
3357 ttnproto = NP_EK5LOGIN;
3358 else if (ck_krb4_is_installed())
3359 ttnproto = NP_EK4LOGIN;
3361 ttnproto = NP_RLOGIN;
3363 #endif /* RLOGCODE */
3364 #endif /* CK_KERBEROS */
3369 case 23: /* Telnet */
3370 ttnproto = NP_TELNET;
3373 ttnproto = NP_RLOGIN;
3376 ttnproto = NP_KERMIT;
3381 /* Jeff 2005/12/30 */
3382 ttnproto = NP_SSL_RAW;
3384 /* fdc 2005/12/04 */
3386 #endif /* COMMENT */
3391 ttnproto = NP_TELNET;
3397 if (ck_krb5_is_installed())
3398 ttnproto = NP_K5LOGIN;
3399 else if (ck_krb4_is_installed())
3400 ttnproto = NP_K4LOGIN;
3402 ttnproto = NP_RLOGIN;
3405 if (ck_krb5_is_installed())
3406 ttnproto = NP_EK5LOGIN;
3407 else if (ck_krb4_is_installed())
3408 ttnproto = NP_EK4LOGIN;
3410 ttnproto = NP_RLOGIN;
3412 #endif /* CK_KERBEROS */
3414 ttnproto = NP_TCPRAW;
3423 /* ckgetservice() is used to determine the port number for a given */
3424 /* service taking into account the use of DNS SRV records. */
3426 static struct servent servrec;
3427 static struct servent *
3428 ckgetservice(hostname, servicename, ip, iplen)
3429 char *hostname; char * servicename; char * ip; int iplen;
3431 struct servent * service = NULL;
3433 struct sockaddr * dns_addrs = NULL;
3435 #endif /* CK_DNS_SRV */
3437 if (isdigit(*servicename)) { /* Use socket number without lookup */
3439 service->s_port = htons((unsigned short)atoi(servicename));
3440 } else { /* Otherwise lookup the service name */
3442 if (tcp_dns_srv && !quiet) {
3443 printf(" DNS SRV Lookup... ");
3447 locate_srv_dns(hostname,
3454 /* Use the first one. Eventually we should cycle through all */
3455 /* the returned IP addresses and port numbers. */
3456 struct sockaddr_in *sin = NULL;
3460 for ( i=0;i<dns_naddrs;i++ ) {
3461 sin = (struct sockaddr_in *) &dns_addrs[i];
3462 printf("dns_addrs[%d] = %s %d\r\n", i,
3463 (char *)inet_ntoa(sin->sin_addr),
3464 ntohs(sin->sin_port));
3466 #endif /* BETADEBUG */
3467 sin = (struct sockaddr_in *) &dns_addrs[0];
3468 if ( ip && iplen > 0 )
3469 ckstrncpy(ip,(char *)inet_ntoa(sin->sin_addr),iplen);
3471 service->s_port = sin->sin_port;
3477 #endif /* CK_DNS_SRV */
3478 service = getservbyname(servicename, "tcp");
3481 if (!ckstrcmp("kermit",servicename,-1,0)) { /* Kermit service port */
3483 service->s_port = htons(1649);
3484 } else if (!ckstrcmp("telnet",servicename,-1,0)) { /* Telnet port */
3486 service->s_port = htons(23);
3487 } else if (!ckstrcmp("http",servicename,-1,0)) {
3489 service->s_port = htons(80);
3492 else if (!ckstrcmp("login",servicename,-1,0)) {
3494 service->s_port = htons(513);
3496 #endif /* RLOGCODE */
3498 /* Commonly used SSL ports (might not be in services file) */
3499 else if (!ckstrcmp("https",servicename,-1,0)) {
3501 service->s_port = htons(443);
3502 } else if (!ckstrcmp("ssl-telnet",servicename,-1,0)) {
3504 service->s_port = htons(151);
3505 } else if (!ckstrcmp("telnets",servicename,-1,0)) {
3507 service->s_port = htons(992);
3512 else if (!ckstrcmp("klogin",servicename,-1,0)) {
3514 service->s_port = htons(543);
3515 } else if (!ckstrcmp("eklogin",servicename,-1,0)) {
3517 service->s_port = htons(2105);
3519 #endif /* RLOGCODE */
3520 #endif /* CK_KERBEROS */
3525 /* N E T O P E N -- Open a network connection */
3527 Calling conventions same as ttopen(), except third argument is network
3528 type rather than modem type. Designed to be called from within ttopen.
3531 #define XXNAMELEN 256
3532 static char xxname[XXNAMELEN];
3535 netopen(name, lcl, nett) char *name; int *lcl, nett; {
3537 int i, x, rc_inet_addr = 0, dns = 0;
3542 #endif /* SO_OOBINLINE */
3543 struct servent *service=NULL;
3544 struct hostent *host=NULL;
3545 struct sockaddr_in r_addr;
3546 struct sockaddr_in sin;
3547 struct sockaddr_in l_addr;
3550 struct sockaddr_in send_socket;
3551 #endif /* EXCELAN */
3554 /* inet_addr() is of type struct in_addr */
3556 extern struct in_addr inet_addr();
3559 extern struct in_addr inet_addr();
3560 #endif /* HPUX5WINTCP */
3561 #endif /* datageneral */
3566 #else /* INADDR_NONE */
3568 #endif /* INADDR_NONE */
3569 #endif /* INADDRX */
3570 #endif /* TCPSOCKET */
3573 /* This causes big trouble */
3575 #define INADDR_NONE 0xffffffff
3576 #endif /* INADDR_NONE */
3577 #endif /* COMMENT */
3579 #ifdef SUNX25 /* Code for SunLink X.25 support */
3580 #define X29PID 1 /* X.29 Protocol ID */
3581 _PROTOTYP(SIGTYP x25oobh, (int) );
3583 #ifndef X25_WR_FACILITY
3586 FACILITY_DB x25facil;
3587 #endif /* X25_WR_FACILITY */
3588 static int needh = 1;
3590 extern int linkid, lcn, x25ver;
3593 extern int revcall, closgr, cudata;
3594 extern char udata[];
3597 #ifdef IBMX25 /* Variables for IBM X25 */
3598 extern int x25port; /* Logical port to use */
3599 extern x25addr_t local_nua; /* Local X.25 address */
3600 extern x25addr_t remote_nua; /* Remote X.25 address */
3601 extern char x25name[]; /* X25 device name (sx25a0) */
3602 extern char x25dev[]; /* X25 device file /dev/x25pkt */
3603 ulong bind_flags = 0; /* Flags for binding the X25 stream */
3604 ulong token = 0; /* Temporary return code */
3607 debug(F101,"netopen nett","",nett);
3608 *ipaddr = '\0'; /* Initialize IP address string */
3611 if (nett == NET_SX25) { /* If network type is X.25 */
3612 netclos(); /* Close any previous net connection */
3613 ttnproto = NP_NONE; /* No protocol selected yet */
3615 /* Set up host structure */
3616 bzero((char *)&x25host,sizeof(x25host));
3617 if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
3618 fprintf (stderr,"Invalid X.121 host address %s\n",name);
3622 x25host.datalen = X29PIDLEN;
3623 x25host.data[0] = X29PID;
3625 /* Set call user data if specified */
3627 ckstrncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
3628 x25host.datalen += (int)strlen(udata);
3631 /* Open SunLink X.25 socket */
3632 if (!quiet && *name) {
3633 printf(" Trying %s... ", name);
3636 if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
3637 debug(F101,"netopen socket error","",errno);
3638 perror ("X.25 socket error");
3642 /* Setting X.25 out-of-band data handler */
3644 if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
3645 perror("X.25 set process group id error");
3648 (VOID) signal(SIGURG,x25oobh);
3650 /* Set reverse charge call and closed user group if requested */
3651 bzero ((char *)&x25facil,sizeof(x25facil));
3653 #ifndef X25_WR_FACILITY
3654 /* New SunLink (7.0 or 8.0, not sure which)... */
3655 x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
3656 x25facil.f_reverse_charge = revcall ? 1 : 0;
3657 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3658 perror ("Setting X.25 reverse charge");
3661 if (closgr > -1) { /* Closed User Group (Outgoing) */
3662 bzero ((char *)&x25facil,sizeof(x25facil));
3663 x25facil.type = T_CUG;
3664 x25facil.f_cug_req = CUG_REQ_ACS;
3665 x25facil.f_cug_index = closgr;
3666 if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
3667 perror ("Setting X.25 closed user group");
3672 /* Old SunLink 6.0 (or 7.0?)... */
3673 if (revcall) x25facil.reverse_charge = revcall;
3675 x25facil.cug_req = 1;
3676 x25facil.cug_index = closgr;
3678 if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
3679 perror ("Setting X.25 facilities");
3682 #endif /* X25_WR_FACILITY */
3684 /* Need X.25 header with bits Q and M */
3685 if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
3686 perror ("Setting X.25 header");
3690 /* Connects to remote host via SunLink X.25 */
3691 if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
3693 debug(F101,"netopen connect errno","",i);
3695 perror("netopen x25 connect");
3706 /* Get X.25 link identification used for the connection */
3707 if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
3708 perror ("Getting X.25 link id");
3712 /* Get X.25 logical channel number used for the connection */
3713 if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
3714 perror ("Getting X.25 lcn");
3718 /* Get SunLink X.25 version */
3719 if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
3720 perror ("Getting SunLink X.25 version");
3723 ttnet = nett; /* Sunlink X.25 network */
3724 ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */
3725 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3727 } else /* Note that SUNX25 support can coexist with TCP/IP support. */
3732 if (nett == NET_IX25) { /* IBM AIX X.25 */
3733 netclos(); /* Close any previous net connection */
3734 ttnproto = NP_NONE; /* No protocol selected yet */
3736 /* find out who we are - this is not so easy on AIX */
3737 /* riehm: need to write the code that finds this out
3738 * automatically, or at least allow it to be configured
3741 if (!local_nua[0] && !x25local_nua(local_nua)) {
3745 /* Initialise the X25 API (once per process? once per connection?) */
3747 debug(F110, "Opening ", x25dev, 0 );
3748 /* set O_NDELAY to allow polling? */
3749 if ((ttyfd = open(x25dev, O_RDWR)) < 0) {
3750 perror ("X.25 device open error");
3751 debug(F101,"netopen: device open error","",errno);
3755 /* push the NPI onto the STREAM */
3756 if (ioctl(ttyfd,I_PUSH,"npi") < 0 ) {
3760 perror( "kermit: netopen(): couldn't push npi on the X25 stream" );
3761 debug(F101,"netopen: can't push npi on the X25 stream","",errno);
3765 /* set up server mode - bind the x25 port and wait for
3766 * incoming connections
3768 if (name[0] == '*') { /* Server */
3769 /* set up a server - see the warning in x25bind() */
3770 bind_flags |= TOKEN_REQUEST;
3772 /* bind kermit to the local X25 address */
3773 token = x25bind(ttyfd,
3776 (int)strlen( udata ),
3782 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3786 /* Currently not connected to a remote host */
3788 remote_nua[0] = '\0';
3790 /* store the fd so that incoming calls can have their own fd
3791 * This is almost support for a true server (ie: a'la ftpd)
3792 * but we're not quite there yet.
3795 x25serverfd = ttyfd;
3797 * wait for an incoming call
3798 * this should happen in the "server" command and not in
3799 * the "set host *" command.
3801 if ((ttyfd = x25getcall(ttyfd)) < 0) {
3805 } else { /* Client */
3806 /* Bind kermit to the local X25 address */
3817 debug(F100,"netopen: couldn't bind to local X25 address","",0);
3821 /* riehm: this should be done via the CONNECT command, not HOST! */
3824 /* call the remote host */
3825 /* name == address of remote host as char* */
3826 if (x25call(ttyfd, name, udata) < 0 ) {
3828 "netopen: couldn't connect to remote X25 address",
3833 strcpy(remote_nua, name);
3836 ttnet = nett; /* AIX X.25 network */
3837 if (lcl) if (*lcl < 0) *lcl = 1; /* Local mode */
3840 } else /* Note that IBMX25 support can coexist with TCP/IP support. */
3843 /* Add support for other networks here. */
3845 if (nett != NET_TCPB) return(-1); /* BSD socket support */
3848 netclos(); /* Close any previous connection. */
3849 ckstrncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */
3850 debug(F110,"netopen namecopy",namecopy,0);
3854 return(tcpsrv_open(name, lcl, nett, 0));
3855 #endif /* NOLISTEN */
3857 p = namecopy; /* Was a service requested? */
3858 while (*p != '\0' && *p != ':') p++; /* Look for colon */
3859 if (*p == ':') { /* Have a colon */
3860 debug(F110,"netopen name has colon",namecopy,0);
3861 *p++ = '\0'; /* Get service name or number */
3864 Here we have to check for various popular syntaxes:
3865 host:port (our original syntax)
3866 URL such as telnet:host or telnet://host/
3867 Or even telnet://user:password@host:port/path/
3868 Or a malformed URL such as generated by Netscape 4.0 like:
3869 telnet:telnet or telnet::host.
3873 * REPLACE THIS CODE WITH urlparse() but not on the day of the
3874 * C-Kermit 8.0 RELEASE.
3877 if (*p == ':') /* a second colon */
3878 *p++ = '\0'; /* get rid of that one too */
3879 while (*p == '/') *p++ = '\0'; /* and slashes */
3880 x = strlen(p); /* Length of remainder */
3881 if (p[x-1] == '/') /* If there is a trailing slash */
3882 p[x-1] = '\0'; /* remove it. */
3883 debug(F110,"netopen namecopy after stripping",namecopy,0);
3884 debug(F110,"netopen p after stripping",p,0);
3885 service = getservbyname(namecopy,"tcp");
3888 !ckstrcmp("rlogin",namecopy,NAMECPYL,0) ||
3889 #endif /* RLOGCODE */
3891 !ckstrcmp("telnets",namecopy,NAMECPYL,0) ||
3893 !ckstrcmp("iksd",namecopy,NAMECPYL,0)
3895 char temphost[256], tempservice[80], temppath[256];
3896 char * q = p, *r = p, *w = p;
3898 extern char pwbuf[];
3899 extern int pwflg, pwcrypt;
3901 if (ttnproto == NP_DEFAULT)
3902 setnproto(namecopy);
3904 /* Check for userid and possibly password */
3905 while (*p != '\0' && *p != '@')
3906 p++; /* look for @ */
3908 /* found username and perhaps password */
3909 debug(F110,"netopen namecopy found @","",0);
3912 while (*w != '\0' && *w != ':')
3916 /* r now points to username, save it and the password */
3917 debug(F110,"netopen namecopy username",r,0);
3918 debug(F110,"netopen namecopy password",w,0);
3920 if ( strcmp(uidbuf,r) || *w )
3921 ckstrncpy(pwbuf,w,PWBUFL+1);
3922 ckstrncpy(uidbuf,r,UIDBUFLEN);
3925 q = p; /* Host after user and pwd */
3927 p = q; /* No username or password */
3929 /* Now we must look for the optional port. */
3930 debug(F110,"netopen x p",p,0);
3931 debug(F110,"netopen x q",q,0);
3933 /* Look for the port/service or a file/directory path */
3934 while (*p != '\0' && *p != ':' && *p != '/')
3937 debug(F110,"netopen found port",q,0);
3938 *p++ = '\0'; /* Found a port name or number */
3941 /* Look for the end of port/service or a file/directory path */
3942 while (*p != '\0' && *p != '/')
3947 debug(F110,"netopen port",r,0);
3948 ckstrncpy(tempservice,r,80);
3949 ckstrncpy(temphost,q,256);
3950 ckstrncpy(temppath,p,256);
3951 ckstrncpy(namecopy,temphost,NAMECPYL);
3952 debug(F110,"netopen tempservice",tempservice,0);
3953 debug(F110,"netopen temphost",temphost,0);
3954 debug(F110,"netopen temppath",temppath,0);
3956 /* move port/service to a buffer that won't go away */
3957 x = strlen(namecopy);
3958 p = namecopy + x + 1;
3959 ckstrncpy(p, tempservice, NAMECPYL - x);
3961 /* Handle a path if we found one */
3964 ckstrncpy(temppath,p,256);
3966 /* We didn't find another port, but if q is a service */
3967 /* then assume that namecopy is actually a host. */
3968 if (getservbyname(q,"tcp")) {
3972 /* rlogin is not a valid service */
3973 if (!ckstrcmp("rlogin",namecopy,6,0)) {
3974 ckstrncpy(namecopy,"login",NAMECPYL);
3976 #endif /* RLOGCODE */
3977 /* iksd is not a valid service */
3978 if (!ckstrcmp("iksd",namecopy,6,0)) {
3979 ckstrncpy(namecopy,"kermit",NAMECPYL);
3981 /* Reconstruct namecopy */
3982 ckstrncpy(tempservice,namecopy,80);
3983 ckstrncpy(temphost,q,256);
3984 ckstrncpy(namecopy,temphost,NAMECPYL);
3985 debug(F110,"netopen tempservice",tempservice,0);
3986 debug(F110,"netopen temphost",temphost,0);
3987 debug(F110,"netopen temppath",temppath,0);
3989 /* move port/service to a buffer that won't go away */
3990 x = strlen(namecopy);
3991 p = namecopy + x + 1;
3992 ckstrncpy(p, tempservice, NAMECPYL - x - 1);
3995 debug(F110,"netopen URL result: host",namecopy,0);
3996 debug(F110,"netopen URL result: service",p,0);
3997 debug(F110,"netopen URL result: path",temppath,0);
4000 /* If we have set a path specified, we need to try to GET it */
4001 /* But we have another problem, we have to login first. How */
4002 /* do we specify that a login must be done before the GET? */
4003 /* The user's name if specified is in 'userid' and the */
4004 /* password if any is in 'pwbuf'. */
4005 if ( temppath[0] ) {
4007 extern char * cmarg;
4010 /* If no userid was specified as part of the URL but
4011 * a path was specified, then we
4012 * set the user name to anonymous and the password
4013 * to the current userid.
4015 ckstrncpy(pwbuf,uidbuf,PWBUFL);
4016 ckstrncat(pwbuf,"@",PWBUFL);
4019 ckstrncpy(uidbuf,"anonymous",UIDBUFLEN);
4023 * If a file path was specified we perform the GET
4024 * operation and then terminate the connection.
4026 * If a directory was given instead of a file, then
4027 * we should REMOTE CD to the directory and list its
4028 * contents. But how do we tell the difference?
4030 makestr(&cmarg,temppath);
4033 #endif /* IKS_GET */
4036 } else { /* Otherwise use telnet */
4040 By the time we get here, namecopy[] should hold the null-terminated
4041 hostname or address, and p should point to the service name or number.
4043 debug(F110,"netopen host",namecopy,0);
4044 debug(F110,"netopen service requested",p,0);
4046 /* Use the service port to set the default protocol type if necessary */
4047 if (ttnproto == NP_DEFAULT)
4050 ckstrncpy(namecopy2,namecopy,NAMECPYL);
4051 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4053 fprintf(stderr, "Can't find port for service %s\n", p);
4055 debug(F101,"netopen can't get service","",socket_errno);
4057 debug(F101,"netopen can't get service","",errno);
4058 #endif /* TGVORWIN */
4059 errno = 0; /* (rather than mislead) */
4062 if (!ckstrcmp(namecopy,namecopy2,-1,0))
4063 namecopy2[0] = '\0';
4064 ckstrncpy(svcbuf,ckuitoa(ntohs(service->s_port)),sizeof(svcbuf));
4065 debug(F110,"netopen service ok",svcbuf,0);
4069 if (service && !strcmp("login",p) && service->s_port != htons(513)) {
4071 " Warning: login service on port %d instead of port 513\n",
4072 ntohs(service->s_port)
4074 fprintf(stderr, " Edit SERVICES file if RLOGIN fails to connect.\n");
4075 debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
4077 #endif /* RLOGCODE */
4080 /* For HTTP connections we must preserve the original hostname and */
4081 /* service requested so we can include them in the Host header. */
4082 ckmakmsg(http_host_port,sizeof(http_host_port),namecopy,":",
4083 ckitoa(ntohs(service->s_port)),NULL);
4085 /* 'namecopy' contains the name of the host to which we want to connect */
4086 /* 'svcbuf' contains the service name */
4087 /* 'service->s_port' contains the port number in network byte order */
4089 /* If we are using an http proxy, we need to create a buffer containing */
4090 /* hostname:port-number */
4091 /* to pass to the http_connect() function. Then we need to replace */
4092 /* 'namecopy' with the name of the proxy server and the service->s_port */
4093 /* with the port number of the proxy (default port 80). */
4095 if ( tcp_http_proxy ) {
4096 ckmakmsg(proxycopy,sizeof(proxycopy),namecopy,":",
4097 ckuitoa(ntohs(service->s_port)),NULL);
4098 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
4100 p = namecopy; /* Was a service requested? */
4101 while (*p != '\0' && *p != ':') p++; /* Look for colon */
4102 if (*p == ':') { /* Have a colon */
4103 debug(F110,"netopen name has colon",namecopy,0);
4104 *p++ = '\0'; /* Get service name or number */
4109 service = ckgetservice(namecopy,p,namecopy,NAMECPYL);
4111 fprintf(stderr, "Can't find port for service %s\n", p);
4113 debug(F101,"netopen can't get service for proxy","",socket_errno);
4115 debug(F101,"netopen can't get service for proxy","",errno);
4116 #endif /* TGVORWIN */
4117 errno = 0; /* (rather than mislead) */
4120 ckstrncpy(p,ckuitoa(ntohs(service->s_port)),NAMECPYL-(p-namecopy));
4125 /* Set up socket structure and get host address */
4127 bzero((char *)&r_addr, sizeof(r_addr));
4128 debug(F100,"netopen bzero ok","",0);
4130 NOTE: Originally the inet_addr() check was #ifdef NT, but is enabled for
4131 all as of 20 Sep 97, to allow people to "set host" to a specific numeric IP
4132 address without going through the multihomed host sequence and winding up
4133 at a different place than the one requested.
4136 debug(F101,"netopen INADDR_NONE defined","",INADDR_NONE);
4137 #else /* INADDR_NONE */
4138 debug(F100,"netopen INADDR_NONE not defined","",0);
4139 #endif /* INADDR_NONE */
4141 debug(F100,"netopen INADDRX defined","",0);
4143 debug(F100,"netopen INADDRX not defined","",0);
4144 #endif /* INADDRX */
4148 iax = inet_addr(namecopy);
4149 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4152 iax.s_addr = inet_addr(namecopy);
4153 debug(F111,"netopen inet_addr",namecopy,iax.s_addr);
4154 #else /* INADDR_NONE */
4156 /* In Solaris inet_addr() is of type in_addr_t which is uint32_t */
4157 /* (unsigned) yet it returns -1 (signed) on failure. */
4158 /* It makes a difference in 64-bit builds. */
4159 rc_inet_addr = inet_addr(namecopy); /* Assign return code to an int */
4160 iax = (unsigned) rc_inet_addr; /* and from there to whatever.. */
4163 iax = (unsigned int) inet_addr(namecopy);
4166 #endif /* datageneral */
4167 #endif /* SOLARIS */
4168 debug(F111,"netopen rc_inet_addr",namecopy,rc_inet_addr);
4169 debug(F111,"netopen inet_addr",namecopy,iax);
4170 #endif /* INADDR_NONE */
4171 #endif /* INADDRX */
4175 /* This might give warnings on 64-bit platforms but they should be harmless */
4176 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
4177 /* probably superfluous -- not sure why it's even there, maybe it should be */
4183 iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
4184 #else /* INADDR_NONE */
4186 #endif /* INADDR_NONE */
4187 #endif /* SOLARIS */
4190 printf(" DNS Lookup... ");
4193 if ((host = gethostbyname(namecopy)) != NULL) {
4194 debug(F110,"netopen gethostbyname != NULL",namecopy,0);
4195 host = ck_copyhostent(host);
4196 dns = 1; /* Remember we performed dns lookup */
4197 r_addr.sin_family = host->h_addrtype;
4198 if (tcp_rdns && host->h_name && host->h_name[0]
4200 && (tcp_http_proxy == NULL)
4204 ckstrncpy(xxname,host->h_name,XXNAMELEN);
4205 debug(F110,"netopen xxname[1]",xxname,0);
4206 if ((XXNAMELEN - (int)strlen(name)) > ((int)strlen(svcbuf)+1)){
4207 ckstrncat(xxname,":",XXNAMELEN - (int)strlen(xxname));
4208 ckstrncat(xxname,svcbuf,XXNAMELEN - (int)strlen(xxname));
4209 debug(F110,"netopen xxname[2]",xxname,0);
4211 name = (char *)xxname;
4213 ckstrncpy(name,host->h_name,80); /* Bad Bad Bad */
4214 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4215 ckstrncat(name,":",80-strlen(name));
4216 ckstrncat(name,svcbuf,80-strlen(name));
4218 #endif /* COMMENT */
4220 debug(F110,"netopen name after lookup",name,0);
4224 /* This is for trying multiple IP addresses - see <netdb.h> */
4225 if (!(host->h_addr_list))
4227 bcopy(host->h_addr_list[0],
4228 (caddr_t)&r_addr.sin_addr,
4232 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4234 #else /* HADDRLIST */
4236 r_addr.sin_addr.s_addr = (u_long)host->h_addr;
4238 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
4240 #endif /* HADDRLIST */
4243 debug(F111,"BCOPY","host->h_length",host->h_length);
4247 #endif /* NOMHHOST */
4249 debug(F101,"netopen dns","",dns);
4253 /* inet_addr() is of type struct in_addr */
4256 debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
4257 ina = inet_addr(namecopy);
4258 uu = *(unsigned int *)&ina;
4259 #else /* Not INADDRX */
4260 /* inet_addr() is unsigned long */
4262 debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
4263 uu = inet_addr(namecopy);
4264 #endif /* INADDRX */
4265 debug(F101,"netopen uu","",uu);
4268 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
4269 #else /* INADDR_NONE */
4270 uu != ((unsigned long)-1)
4271 #endif /* INADDR_NONE */
4273 r_addr.sin_addr.s_addr = uu;
4274 r_addr.sin_family = AF_INET;
4277 fprintf(stdout, "\r\n"); /* complete any previous message */
4279 fprintf(stderr, "Can't get address for %s\n", namecopy);
4281 debug(F101,"netopen can't get address","",socket_errno);
4283 debug(F101,"netopen can't get address","",errno);
4284 #endif /* TGVORWIN */
4285 errno = 0; /* Rather than mislead */
4290 /* Get a file descriptor for the connection. */
4292 r_addr.sin_port = service->s_port;
4293 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4294 debug(F110,"netopen trying",ipaddr,0);
4295 if (!quiet && *ipaddr) {
4296 printf(" Trying %s... ", ipaddr);
4300 /* Loop to try additional IP addresses, if any. */
4304 send_socket.sin_family = AF_INET;
4305 send_socket.sin_addr.s_addr = 0;
4306 send_socket.sin_port = 0;
4307 if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
4308 &send_socket, SO_REUSEADDR)) < 0)
4313 Must make sure that all sockets are opened in
4314 Non-overlapped mode since we use the standard
4315 C RTL functions to read and write data.
4316 But it doesn't seem to work as planned.
4319 int optionValue = SO_SYNCHRONOUS_NONALERT;
4320 if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
4321 (char *) &optionValue, sizeof(optionValue))
4325 #endif /* COMMENT */
4328 if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
4329 #endif /* EXCELAN */
4332 experror("TCP socket error");
4335 fprintf(stdout, "\r\n"); /* complete any previous stdout */
4339 errno = socket_errno;
4340 #endif /* OLD_TWG */
4341 socket_perror("TCP socket error");
4342 debug(F101,"netopen socket error","",socket_errno);
4344 perror("TCP socket error");
4345 debug(F101,"netopen socket error","",errno);
4346 #endif /* TGVORWIN */
4347 #endif /* EXCELAN */
4353 /* Not part of the RLOGIN RFC, but the BSD implementation */
4354 /* requires that the client port be a priviliged port (<1024) */
4355 /* on a Unix system this would require SuperUser permissions */
4356 /* thereby saying that the root of the Unix system has given */
4357 /* permission for this connection to be created */
4358 if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
4359 static unsigned short lport = 1024; /* max reserved port */
4364 lport--; /* Make sure we do not reuse a port */
4368 sin.sin_family = AF_INET;
4371 inaddrx = inet_addr(tcp_address);
4372 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4374 sin.sin_addr.s_addr = inet_addr(tcp_address);
4375 #endif /* INADDRX */
4377 sin.sin_addr.s_addr = INADDR_ANY;
4379 sin.sin_port = htons(lport);
4380 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
4383 s_errno = socket_errno;
4384 if (s_errno && /* OS2 bind fails with 0, if already in use */
4386 s_errno != WSAEADDRINUSE
4388 s_errno != SOCEADDRINUSE &&
4389 s_errno != (SOCEADDRINUSE - SOCBASEERR)
4394 if (socket_errno != EADDRINUSE)
4396 if (errno != EADDRINUSE)
4397 #endif /* TGVORWIN */
4401 printf("\nBind failed with errno %d for port %d.\n",
4409 #endif /* TGVORWIN */
4414 debug(F101,"rlogin bind failed","",s_errno);
4417 debug(F101,"rlogin bind failed","",socket_errno);
4419 errno = socket_errno;
4420 #endif /* OLD_TWG */
4421 socket_perror("rlogin bind");
4423 debug(F101,"rlogin bind failed","",errno);
4424 perror("rlogin bind");
4425 #endif /* TGVORWIN */
4429 debug(F101,"rlogin bind s_errno","",s_errno);
4430 perror("rlogin bind");
4433 printf("\r\n"); /* complete any previous message */
4436 debug(F101,"rlogin bind socket_errno","",socket_errno);
4438 errno = socket_errno;
4439 #endif /* OLD_TWG */
4440 socket_perror("rlogin bind");
4442 debug(F101,"rlogin bind errno","",errno);
4443 perror("rlogin bind");
4444 #endif /* TGVORWIN */
4446 debug(F101,"rlogin local port","",lport);
4447 #endif /* COMMENT */
4452 if (lport == 512 /* lowest reserved port to use */ ) {
4453 printf("\nNo reserved ports available.\n");
4458 debug(F101,"rlogin lport","",lport);
4459 ttnproto = NP_RLOGIN;
4461 #endif /* RLOGCODE */
4463 /* If a specific TCP address on the local host is desired we */
4464 /* must bind it to the socket. */
4469 debug(F110,"netopen binding socket to",tcp_address,0);
4470 bzero((char *)&sin,sizeof(sin));
4471 sin.sin_family = AF_INET;
4473 inaddrx = inet_addr(tcp_address);
4474 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
4476 sin.sin_addr.s_addr = inet_addr(tcp_address);
4477 #endif /* INADDRX */
4479 if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
4480 s_errno = socket_errno; /* Save error code */
4482 socket_close(ttyfd);
4483 #else /* TCPIPLIB */
4485 #endif /* TCPIPLIB */
4488 errno = s_errno; /* and report this error */
4489 debug(F101,"netopen bind errno","",errno);
4493 #endif /* datageneral */
4495 /* Now connect to the socket on the other end. */
4498 if (connect(ttyfd, &r_addr) < 0)
4501 WSASafeToCancel = 1;
4503 if (connect(ttyfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
4504 #endif /* EXCELAN */
4507 WSASafeToCancel = 0;
4515 i = errno; /* Save error code */
4516 #endif /* TGVORWIN */
4521 i && /* OS2 bind fails with 0, if already in use */
4525 (i == SOCEADDRINUSE ||
4526 i == (SOCEADDRINUSE - SOCBASEERR))
4530 socket_errno == EADDRINUSE
4533 #endif /* TGVORWIN */
4535 && ttnproto == NP_RLOGIN) {
4537 socket_close(ttyfd); /* Close it. */
4540 #endif /* TCPIPLIB */
4541 continue; /* Try a different lport */
4543 #endif /* RLOGCODE */
4546 if (host && host->h_addr_list && host->h_addr_list[1]) {
4548 host->h_addr_list++;
4549 bcopy(host->h_addr_list[0],
4550 (caddr_t)&r_addr.sin_addr,
4553 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4554 debug(F110,"netopen h_addr_list",ipaddr,0);
4555 if (!quiet && *ipaddr) {
4556 printf(" Trying %s... ", ipaddr);
4560 socket_close(ttyfd); /* Close it. */
4563 #endif /* TCPIPLIB */
4567 #endif /* HADDRLIST */
4572 errno = i; /* And report this error */
4574 if (errno) experror("netopen connect");
4577 debug(F101,"netopen connect error","",socket_errno);
4578 /* if (errno) socket_perror("netopen connect"); */
4580 errno = socket_errno;
4581 #endif /* OLD_TWG */
4583 socket_perror("netopen connect");
4584 #else /* TGVORWIN */
4585 debug(F101,"netopen connect errno","",errno);
4588 perror("\r\nFailed");
4595 perror("netopen connect");
4596 #endif /* DEC_TCPIP */
4599 perror("netopen connect");
4600 #endif /* CMU_TCPIP */
4601 #endif /* TGVORWIN */
4602 #endif /* EXCELAN */
4606 WSASafeToCancel = 0;
4609 } while (!isconnect);
4613 x = socket_ioctl(ttyfd,FIONBIO,&on);
4614 debug(F101,"netopen FIONBIO","",x);
4615 #endif /* NON_BLOCK_IO */
4617 #ifdef NT_TCP_OVERLAPPED
4618 OverlappedWriteInit();
4619 OverlappedReadInit();
4620 #endif /* NT_TCP_OVERLAPPED */
4622 ttnet = nett; /* TCP/IP (sockets) network */
4625 /* We have succeeded in connecting to the HTTP PROXY. So now we */
4626 /* need to attempt to connect through the proxy to the actual host */
4627 /* If that is successful, we have to pretend that we made a direct */
4628 /* connection to the actual host. */
4630 if ( tcp_http_proxy ) {
4632 char * agent = "Kermit 95"; /* Default user agent */
4634 char * agent = "C-Kermit";
4637 if (http_connect(ttyfd,
4638 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
4640 tcp_http_proxy_user,
4649 ckstrncpy(namecopy,proxycopy,NAMECPYL);
4650 p = namecopy; /* Was a service requested? */
4651 while (*p != '\0' && *p != ':') p++; /* Look for colon */
4656 /* Jeff - Does this next block of code that set's the protocol */
4657 /* need to be here anymore? 5/10/2000 */
4659 /* There are certain magic port numbers that when used require */
4660 /* the use of specific protocols. Check this now before we */
4661 /* set the SO_OOBINLINE state or we might get it wrong. */
4662 x = ntohs((unsigned short)service->s_port);
4664 /* See if the service is TELNET. */
4665 if (x == TELNET_PORT) {
4666 /* Yes, so if raw port not requested */
4668 /* Jeff 2005/12/30 */
4669 if (ttnproto != NP_TCPRAW && ttnproto != NP_SSL_RAW &&
4670 ttnproto != NP_TLS_RAW && ttnproto != NP_NONE)
4672 /* fdc 2005/12/04 */
4673 if (ttnproto != NP_TCPRAW && ttnproto != NP_NONE)
4674 #endif /* COMMENT */
4675 ttnproto = NP_TELNET; /* Select TELNET protocol. */
4678 else if (x == RLOGIN_PORT) {
4679 ttnproto = NP_RLOGIN;
4682 /* There is no good way to do this. If the user didn't tell */
4683 /* which one to use up front. We may guess wrong if the user */
4684 /* has both Kerberos versions installed and valid TGTs for each */
4685 else if (x == KLOGIN_PORT &&
4686 ttnproto != NP_K4LOGIN &&
4687 ttnproto != NP_K5LOGIN) {
4688 if (ck_krb5_is_installed() &&
4689 ck_krb5_is_tgt_valid())
4690 ttnproto = NP_K5LOGIN;
4691 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4692 ttnproto = NP_K4LOGIN;
4694 ttnproto = NP_K4LOGIN;
4695 } else if (x == EKLOGIN_PORT &&
4696 ttnproto != NP_EK4LOGIN &&
4697 ttnproto != NP_EK5LOGIN) {
4698 if (ck_krb5_is_installed() && ck_krb5_is_tgt_valid())
4699 ttnproto = NP_EK5LOGIN;
4700 else if (ck_krb4_is_installed() && ck_krb4_is_tgt_valid())
4701 ttnproto = NP_EK4LOGIN;
4703 ttnproto = NP_EK4LOGIN;
4705 #endif /* CK_KERBEROS */
4706 #endif /* RLOGCODE */
4708 else if (x == KERMIT_PORT) { /* IKS uses Telnet protocol */
4709 if (ttnproto == NP_NONE)
4710 ttnproto = NP_KERMIT;
4712 #endif /* IKS_OPTION */
4716 The symbol SO_OOBINLINE is not known to Ultrix 2.0.
4717 It means "leave out of band data inline". The normal value is 0x0100,
4718 but don't try this on systems where the symbol is undefined.
4721 Note from Jeff Altman: 12/13/95
4722 In implementing rlogin protocol I have come to the conclusion that it is
4723 a really bad idea to read out-of-band data inline.
4724 At least Windows and OS/2 does not handle this well.
4725 And if you need to know that data is out-of-band, then it becomes
4726 absolutely pointless.
4728 Therefore, at least on OS2 and Windows (NT) I have changed the value of
4729 on to 0, so that out-of-band data stays out-of-band.
4732 Actually, OOB data should be read inline when possible. Especially with
4733 protocols that don't care about the Urgent flag. This is true with Telnet.
4734 With Rlogin, you need to be able to catch OOB data. However, the best
4735 way to do this is to set a signal handler on SIGURG. This isn't possible
4736 on OS/2 and Windows. But it is in UNIX. We will also need OOB data for
4737 FTP so better create a general mechanism.
4739 The reason for making OOB data be inline is that the standard ttinc/ttoc
4740 calls can be used for reading that data on UNIX systems. If we didn't
4741 have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
4746 if (ttnproto == NP_RLOGIN
4748 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4749 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4750 #endif /* CK_KERBEROS */
4753 #else /* TCPIPLIB */
4754 if (ttnproto == NP_RLOGIN
4756 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
4757 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
4758 #endif /* CK_KERBEROS */
4760 debug(F100,"Installing rlogoobh on SIGURG","",0);
4761 signal(SIGURG, rlogoobh);
4764 debug(F100,"Ignoring SIGURG","",0);
4765 signal(SIGURG, SIG_DFL);
4767 #endif /* TCPIPLIB */
4768 #endif /* RLOGCODE */
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);
4780 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4783 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4787 Maybe this applies to all SVR4 versions, but the other (else) way has been
4788 compiling and working fine on all the others, so best not to change it.
4790 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4793 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4798 rc = setsockopt(ttyfd,
4804 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
4807 #ifdef VMS /* or, at least, VMS with gcc */
4808 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4811 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
4813 setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
4818 #endif /* SOLARIS */
4819 #endif /* MOTSV88R4 */
4823 #endif /* datageneral */
4824 #endif /* SO_OOBINLINE */
4830 no_delay(ttyfd,tcp_nodelay);
4831 #endif /* TCP_NODELAY */
4833 keepalive(ttyfd,tcp_keepalive);
4834 #endif /* SO_KEEPALIVE */
4836 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
4837 #endif /* SO_LINGER */
4839 sendbuf(ttyfd,tcp_sendbuf);
4840 #endif /* SO_SNDBUF */
4842 recvbuf(ttyfd,tcp_recvbuf);
4843 #endif /* SO_RCVBUF */
4844 #endif /* SOL_SOCKET */
4845 #endif /* datageneral */
4846 #endif /* NOTCPOPTS */
4849 /* Find out our own IP address. */
4850 /* We need the l_addr structure for [E]KLOGIN. */
4851 l_slen = sizeof(l_addr);
4852 bzero((char *)&l_addr, l_slen);
4854 if (!getsockname(ttyfd, (struct sockaddr *)&l_addr, &l_slen)) {
4855 char * s = (char *)inet_ntoa(l_addr.sin_addr);
4856 ckstrncpy(myipaddr, s, 20);
4857 debug(F110,"getsockname",myipaddr,0);
4859 #endif /* EXCELAN */
4860 #endif /* datageneral */
4863 This is really only needed for Kerberos IV but is useful information in any
4864 case. If we connect to a name that is really a pool, we need to get the
4865 name of the machine we are actually connecting to for K4 to authenticate
4866 properly. This way we also update the names properly.
4868 However, it is a security hole when used with insecure DNS.
4870 Note: This does not work on Windows 95 or Windows NT 3.5x. This is because
4871 of the Microsoft implementation of gethostbyaddr() in both Winsock 1.1
4872 and Winsock 2.0 on those platforms. Their algorithm is:
4874 1. Check the HOSTENT cache.
4875 2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.
4876 3. Do a DNS query if the DNS server is configured for name resolution.
4877 4. Do an additional NetBIOS remote adapter status to an IP address for its
4878 NetBIOS name table. This step is specific only to the Windows NT version
4879 3.51 implementation.
4881 The problem is the use of the HOSTENT cache. It means that gethostbyaddr()
4882 can not be used to resolve the real name of machine if it was originally
4883 accessed by an alias used to represent a cluster.
4885 if ((tcp_rdns && dns || tcp_rdns == SET_ON
4887 || tcp_rdns == SET_AUTO &&
4888 (ck_krb5_is_installed() || ck_krb4_is_installed())
4889 #endif /* CK_KERBEROS */
4892 && (tcp_http_proxy == NULL)
4895 && !(ssl_only_flag || tls_only_flag)
4903 printf(" Reverse DNS Lookup... ");
4906 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
4908 host = ck_copyhostent(host);
4909 debug(F100,"netopen gethostbyname != NULL","",0);
4915 if (!s) { /* This can happen... */
4916 debug(F100,"netopen host->h_name is NULL","",0);
4919 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
4920 /* The compiler says "Integral value implicitly converted to */
4921 /* pointer in assignment." The prototype is right there */
4922 /* in <arpa/inet.h> so what's the problem? */
4923 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
4924 if (!*s) { /* No name so substitute the address */
4925 debug(F100,"netopen host->h_name is empty","",0);
4926 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
4927 if (!s) /* Trust No 1 */
4929 if (*s) { /* If it worked, use this string */
4930 ckstrncpy(ipaddr,s,20);
4932 s = ipaddr; /* Otherwise stick with the IP */
4933 if (!*s) /* or failing that */
4934 s = namecopy; /* the name we were called with. */
4936 if (*s) { /* Copying into our argument? */
4937 ckstrncpy(name,s,80); /* Bad Bad Bad */
4938 if ( (80-strlen(name)) > (strlen(svcbuf)+1) ) {
4939 ckstrncat(name,":",80-strlen(name));
4940 ckstrncat(name,svcbuf,80-strlen(name));
4948 printf(" %s connected on port %s\n",s,p);
4950 /* This is simply for testing the DNS entries */
4951 if (host->h_aliases) {
4952 char ** a = host->h_aliases;
4954 printf(" alias => %s\n",*a);
4958 #endif /* BETADEBUG */
4961 if (!quiet) printf("Failed.\n");
4963 } else if (!quiet) printf("(OK)\n");
4964 if (!quiet) fflush(stdout);
4966 /* This should already have been done but just in case */
4967 ckstrncpy(ipaddr,(char *)inet_ntoa(r_addr.sin_addr),20);
4971 /* Before Initialization Telnet/Rlogin Negotiations Init Kerberos */
4973 if (tcp_http_proxy) {
4974 for (i=strlen(proxycopy); i >= 0 ; i--)
4975 if ( proxycopy[i] == ':' )
4976 proxycopy[i] = '\0';
4981 tcp_http_proxy ? proxycopy :
4983 (tcp_rdns && host && host->h_name && host->h_name[0]) ?
4984 (char *)host->h_name : (namecopy2[0] ? namecopy2 :
4985 (namecopy[0] ? namecopy : ipaddr)),
4990 #endif /* CK_SECURITY */
4992 if (ck_ssleay_is_installed()) {
4993 if (!ssl_tn_init(SSL_CLIENT)) {
4994 debug(F100,"netopen ssl_tn_init() failed","",0);
4995 if (bio_err!=NULL) {
4996 BIO_printf(bio_err,"ssl_tn_init() failed\n");
4997 ERR_print_errors(bio_err);
5000 fprintf(stderr,"ssl_tn_init() failed\n");
5001 ERR_print_errors_fp(stderr);
5003 if (tls_only_flag || ssl_only_flag) {
5004 debug(F100,"netopen ssl/tls required","",0);
5009 /* we will continue to accept the connection */
5010 /* without SSL or TLS support unless required. */
5011 if ( TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5012 TELOPT_DEF_S_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5013 if ( TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5014 TELOPT_DEF_S_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5015 if ( TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) != TN_NG_MU )
5016 TELOPT_DEF_C_ME_MODE(TELOPT_START_TLS) = TN_NG_RF;
5017 if ( TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) != TN_NG_MU )
5018 TELOPT_DEF_C_U_MODE(TELOPT_START_TLS) = TN_NG_RF;
5019 } else if ( ck_ssl_outgoing(ttyfd) < 0 ) {
5020 debug(F100,"ck_ssl_outgoing() failed","",0);
5028 if (ttnproto == NP_RLOGIN
5030 || ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN
5031 || ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN
5032 #endif /* CK_KERBEROS */
5033 ) { /* Similar deal for rlogin */
5034 if (rlog_ini(((tcp_rdns && host && host->h_name && host->h_name[0]) ?
5035 (CHAR *)host->h_name : (CHAR *)ipaddr),
5039 debug(F100,"rlogin initialization failed","",0);
5044 #endif /* RLOGCODE */
5045 if (tn_ini() < 0) { /* Start Telnet negotiations. */
5047 return(-1); /* Gone, so open failed. */
5055 if ( ttnproto == NP_K5U2U ) {
5056 if (k5_user_to_user_client_auth()) {
5061 #endif /* KRB5_U2U */
5062 #endif /* CK_KERBEROS */
5064 debug(F101,"netopen service","",svcnum);
5065 debug(F110,"netopen name",name,0);
5066 debug(F110,"netopen ipaddr",ipaddr,0);
5067 ckstrncpy(hostipaddr,ipaddr,63);
5069 if (lcl) if (*lcl < 0) /* Local mode. */
5071 #endif /* TCPSOCKET */
5072 return(0); /* Done. */
5075 /* N E T C L O S -- Close current network connection. */
5078 _PROTOTYP(VOID slrestor,(VOID));
5080 int tls_norestore = 0;
5082 #endif /* NOLOCAL */
5086 static int close_in_progress = 0;
5088 debug(F101,"netclos","",ttyfd);
5091 if (!tt_push_inited)
5093 #endif /* NETLEBUF */
5095 if (ttyfd == -1) /* Was open? */
5096 return(0); /* Wasn't. */
5098 if (close_in_progress)
5100 close_in_progress = 1; /* Remember */
5103 /* This function call should not be here since this is a direct call */
5104 /* from an I/O routine to a user interface level function. However, */
5105 /* the reality is that we do not have pure interfaces. If we ever */
5106 /* decide to clean this up the UI level should assign this function */
5107 /* via a pointer assignment. - Jeff 9/10/1999 */
5112 #endif /* NOLOCAL */
5114 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5116 if (ttyfd > -1) /* Was. */
5120 y = 1; /* Turn on nonblocking reads */
5121 z = socket_ioctl(ttyfd,FIONBIO,&y);
5122 debug(F111,"netclos FIONBIO","on",z);
5125 if (ttnproto == NP_TELNET) {
5126 if (!TELOPT_ME(TELOPT_LOGOUT)
5128 /* Jeff 2005/12/30 */
5130 && !ssl_raw_flag && !tls_raw_flag
5132 #endif /* COMMENT */
5134 /* Send LOGOUT option before close */
5135 if (tn_sopt(DO,TELOPT_LOGOUT) >= 0) {
5136 TELOPT_UNANSWERED_DO(TELOPT_LOGOUT) = 1;
5137 /* It would be nice to call tn_wait but we can't */
5140 tn_push(); /* Place any waiting data into input*/
5144 if (ssl_active_flag) {
5146 BIO_printf(bio_err,"calling SSL_shutdown\n");
5147 SSL_shutdown(ssl_con);
5148 ssl_active_flag = 0;
5150 if (tls_active_flag) {
5152 BIO_printf(bio_err,"calling SSL_shutdown\n");
5153 SSL_shutdown(tls_con);
5154 tls_active_flag = 0;
5158 ck_cancio(); /* Cancel any outstanding reads. */
5161 x = socket_close(ttyfd); /* Close it. */
5165 if (ttnet == NET_IX25) {
5166 /* riehm: should send a disc_req - but only if link is still OK */
5170 /* we were the passive client of a server, now we
5171 * go back to being the normal client.
5172 * I hope that kermit can cope with the logic that
5173 * there can still be a connection after netclos
5176 ttyfd = x25serverfd;
5179 * need to close the server connection too - because
5180 * all file descriptors connected to the NPI have the
5183 * The problem is that any waiting connections get
5184 * lost, the client doesn't realise, and hangs.
5188 x25_state = X25_CLOSED; /* riehm: dead code? */
5193 #endif /* TCPIPLIB */
5195 ttyfd = -1; /* Mark it as closed. */
5198 ReleaseTCPIPMutex();
5202 fwdx_close_all(); /* Shut down any Forward X sockets */
5203 #endif /* CK_FORWARD_X */
5204 tn_reset(); /* The Reset Telnet Option table. */
5205 debug(F100,"netclose setting tn_init = 0","",0);
5206 tn_init = 0; /* Remember about telnet protocol... */
5207 sstelnet = 0; /* Client-side Telnet */
5209 *ipaddr = '\0'; /* Zero the IP address string */
5210 tcp_incoming = 0; /* No longer incoming */
5211 /* Don't reset ttnproto so that we can remember which protocol is in use */
5215 Empty the internal buffers so they won't be used as invalid input on
5216 the next connect attempt (rlogin).
5220 #endif /* TCPIPLIB */
5222 /* If we are automatically destroying Kerberos credentials on Close */
5225 if (krb4_autodel == KRB_DEL_CL) {
5226 extern struct krb_op_data krb_op;
5228 krb_op.cache = NULL;
5229 ck_krb4_destroy(&krb_op);
5233 if (krb5_autodel == KRB_DEL_CL) {
5234 extern struct krb_op_data krb_op;
5235 extern char * krb5_d_cc;
5237 krb_op.cache = krb5_d_cc;
5238 ck_krb5_destroy(&krb_op);
5241 #endif /* CK_KERBEROS */
5242 close_in_progress = 0; /* Remember we are done. */
5248 os2socketerror( int s_errno ) {
5250 if (s_errno > 0 && s_errno <= SOCBASEERR) {
5251 /* in OS/2, there is a problem with threading in that
5252 * the value of errno is not thread safe. It can be
5253 * set to a value from a previous library call and if
5254 * it was not cleared it will appear here. Only treat
5255 * valid socket error codes as errors in this function.
5257 debug(F100,"os2socketerror errno.h","",0);
5261 #endif /* OS2ONLY */
5264 case 0: /* NO ERROR */
5265 debug(F100,"os2socketerror NOERROR","",0);
5271 case SOCECONNRESET - SOCBASEERR:
5273 debug(F100,"os2socketerror ECONRESET","",0);
5274 tn_debug("ECONRESET");
5275 netclos(); /* *** *** */
5276 return(-1); /* Connection is broken. */
5278 case WSAECONNABORTED:
5280 case SOCECONNABORTED:
5281 case SOCECONNABORTED - SOCBASEERR:
5283 debug(F100,"os2socketerror ECONNABORTED","",0);
5284 tn_debug("ECONNABORTED");
5285 netclos(); /* *** *** */
5286 return(-1); /* Connection is broken. */
5291 case SOCENETRESET - SOCBASEERR:
5293 debug(F100,"os2socketerror ENETRESET","",0);
5294 tn_debug("ENETRESET");
5295 netclos(); /* *** *** */
5296 return(-1); /* Connection is broken. */
5301 case SOCENOTCONN - SOCBASEERR:
5303 debug(F100,"os2socketerror ENOTCONN","",0);
5304 tn_debug("ENOTCONN");
5305 netclos(); /* *** *** */
5306 return(-1); /* Connection is broken. */
5309 debug(F100,"os2socketerror ESHUTDOWN","",0);
5310 tn_debug("ESHUTDOWN");
5311 netclos(); /* *** *** */
5312 return(-1); /* Connection is broken. */
5315 case WSAEWOULDBLOCK:
5317 case SOCEWOULDBLOCK:
5318 case SOCEWOULDBLOCK - SOCBASEERR:
5320 debug(F100,"os2socketerror EWOULDBLOCK","",0);
5323 case ERROR_IO_INCOMPLETE:
5324 case ERROR_IO_PENDING:
5325 case ERROR_OPERATION_ABORTED:
5335 /* N E T T C H K -- Check if network up, and how many bytes can be read */
5337 Returns number of bytes waiting, or -1 if connection has been dropped.
5339 int /* Check how many bytes are ready */
5340 nettchk() { /* for reading from network */
5348 extern int ionoblock; /* For Overlapped I/O */
5351 debug(F101,"nettchk entry ttibn","",ttibn);
5352 debug(F101,"nettchk entry ttibp","",ttibp);
5363 #endif /* NETLEBUF */
5367 socket_errno = 0; /* This is a function call in NT, and BeOS */
5372 debug(F100,"nettchk socket is closed","",0);
5376 Note: this socket_ioctl() call does NOT return an error if the
5377 connection has been broken. (At least not in MultiNet.)
5380 /* Another trick that can be tried here is something like this: */
5382 if (ttnet == NET_TCPB) {
5384 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5385 if (x < 0) { /* "Connection reset by peer" */
5386 perror("TCP/IP"); /* or somesuch... */
5387 ttclos(0); /* Close our end too. */
5391 #endif /* COMMENT */
5395 if (ssl_active_flag) {
5398 if ( IsConnectMode() ) {
5399 debug(F101,"nettchk (ssl_active_flag) returns","",count);
5403 #endif /* IKSDONLY */
5404 count = SSL_pending(ssl_con);
5406 debug(F111,"nettchk","SSL_pending error",count);
5411 return(count); /* Don't perform a read */
5412 } else if (tls_active_flag) {
5415 if ( IsConnectMode() ) {
5416 debug(F101,"nettchk (tls_active_flag) returns","",count);
5420 #endif /* IKSDONLY */
5421 count = SSL_pending(tls_con);
5423 debug(F111,"nettchk","TLS_pending error",count);
5428 return(count); /* Don't perform a read */
5432 if (socket_ioctl(ttyfd,FIONREAD,
5434 /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
5436 /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
5437 /* Cast needed for DECC 4.1 & later? */
5438 /* Maybe, but __DECC_VER only exists in 5.0 and later */
5441 #endif /* COMMENT */
5444 debug(F101,"nettchk socket_ioctl error","",socket_errno);
5445 /* If the connection is gone, the connection is gone. */
5447 #ifdef NT_TCP_OVERLAPPED
5448 /* Is there anything in the overlapped I/O buffers? */
5449 count += OverlappedDataWaiting();
5450 #endif /* NT_TCP_OVERLAPPED */
5452 return(count>0?count:-1);
5454 debug(F101,"nettchk count","",count);
5455 #ifdef NT_TCP_OVERLAPPED
5456 /* Is there anything in the overlapped I/O buffers? */
5457 count += OverlappedDataWaiting();
5458 debug(F101,"nettchk count w/overlapped","",count);
5459 #endif /* NT_TCP_OVERLAPPED */
5463 if ( IsConnectMode() ) {
5464 debug(F101,"nettchk (FIONREAD) returns","",count);
5467 #endif /* IKSDONLY */
5470 /* For the sake of efficiency, if there is still data in the ttibuf */
5471 /* do not go to the bother of checking to see of the connection is */
5472 /* still valid. The handle is still good, so just return the count */
5473 /* of the bytes that we already have left to process. */
5475 if ( count > 0 || ttibn > 0 ) {
5477 debug(F101,"nettchk (count+ttibn > 0) returns","",count);
5480 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5482 ttibp = 0; /* reset for next read */
5485 if ( count > 0 || ttibn > 0 ) {
5486 debug(F101,"nettchk returns","",count+ttibn);
5487 return(count+ttibn);
5493 The following code works well in most settings, but messes things up in
5494 others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
5495 make it impossible to ever make a new connection to the same host again with
5496 CONNECT, once it has been logged out from the first time. Not even if you
5497 HANGUP first, or SET HOST<CR>, or SET LINE<CR>. Reportedly, however, it
5498 does work OK in later releases of UCX. But there is no way we can
5499 accommodate both old and new -- we might have static linking or dynamic
5500 linking, etc etc. If we have static, I only have access to 2.0, where this
5501 doesn't work, etc etc blah blah.
5503 In the following lines, we define a symbol NOCOUNT for builds where we want
5504 to omit this code. By default, it is omitted for CMU/Tek. You can force
5505 omission of it for other combinations by defining NOCOUNT in CFLAGS. You
5506 can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
5512 #endif /* NOCOUNT */
5517 #endif /* CMU_TCPIP */
5518 #endif /* NOCOUNT */
5519 #endif /* NONOCOUNT */
5522 /* From this point forward we have a possible race condition in K95
5523 * due to its use of multiple threads. Therefore, we must ensure
5524 * that only one thread attempt to read/write from the socket at a
5525 * time. Otherwise, it is possible for a buffer to be overwritten.
5527 /* we know now that count >= 0 and that ttibn == 0 */
5532 && ttnproto != NP_EK4LOGIN && ttnproto != NP_EK5LOGIN
5533 #endif /* CK_KERBEROS */
5534 #endif /* RLOGCODE */
5539 Here we need to tell the difference between a 0 count on an active
5540 connection, and a 0 count because the remote end of the socket broke the
5541 connection. There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
5542 the status of the connection, so we have to do a read. -1 means there was
5543 no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
5544 down. But if, by chance, we actually get a character, we have to put it
5545 where it won't be lost.
5547 #ifndef NON_BLOCK_IO
5550 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5553 y = 1; /* Turn on nonblocking reads */
5554 z = socket_ioctl(ttyfd,FIONBIO,&y);
5555 debug(F111,"nettchk FIONBIO","on",z);
5561 #endif /* NON_BLOCK_IO */
5562 #ifdef NT_TCP_OVERLAPPED
5563 ionoblock = 1; /* For Overlapped I/O */
5564 #endif /* NT_TCP_OVERLAPPED */
5566 if ( ssl_active_flag || tls_active_flag ) {
5569 x = SSL_read( ssl_active_flag?ssl_con:tls_con,
5570 &ttibuf[ttibp+ttibn],
5571 TTIBUFL-ttibp-ttibn );
5572 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,x)) {
5573 case SSL_ERROR_NONE:
5574 debug(F111,"nettchk SSL_ERROR_NONE","x",x);
5576 case SSL_ERROR_WANT_WRITE:
5577 debug(F100,"nettchk SSL_ERROR_WANT_WRITE","",0);
5580 case SSL_ERROR_WANT_READ:
5581 debug(F100,"nettchk SSL_ERROR_WANT_READ","",0);
5584 case SSL_ERROR_SYSCALL:
5585 if ( x == 0 ) { /* EOF */
5588 goto nettchk_return;
5591 int gle = GetLastError();
5593 #ifndef NON_BLOCK_IO
5596 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5599 y = 0; /* Turn off nonblocking reads */
5600 z = socket_ioctl(ttyfd,FIONBIO,&y);
5601 debug(F111,"nettchk FIONBIO","off",z);
5607 #endif /* NON_BLOCK_IO */
5608 #ifdef NT_TCP_OVERLAPPED
5609 ionoblock = 0; /* For Overlapped I/O */
5610 #endif /* NT_TCP_OVERLAPPED */
5612 debug(F111,"nettchk SSL_ERROR_SYSCALL",
5613 "GetLastError()",gle);
5614 rc = os2socketerror(gle);
5617 else if ( rc == -2 )
5619 goto nettchk_return;
5623 case SSL_ERROR_WANT_X509_LOOKUP:
5624 debug(F100,"nettchk SSL_ERROR_WANT_X509_LOOKUP","",0);
5627 if (bio_err!=NULL) {
5629 extern char ssl_err[];
5630 BIO_printf(bio_err,"nettchk() SSL_ERROR_SSL\n");
5631 ERR_print_errors(bio_err);
5632 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
5633 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
5634 debug(F110,"nettchk SSL_ERROR_SSL",ssl_err,0);
5637 } else if (ssl_debug_flag) {
5638 debug(F100,"nettchk SSL_ERROR_SSL","",0);
5640 fprintf(stderr,"nettchk() SSL_ERROR_SSL\n");
5641 ERR_print_errors_fp(stderr);
5646 goto nettchk_return;
5651 case SSL_ERROR_ZERO_RETURN:
5652 debug(F100,"nettchk SSL_ERROR_ZERO_RETURN","",0);
5655 goto nettchk_return;
5657 debug(F100,"nettchk SSL_ERROR_?????","",0);
5660 goto nettchk_return;
5670 x = socket_read(ttyfd,&ttibuf[ttibp+ttibn],
5671 TTIBUFL-ttibp-ttibn); /* Returns -1 if no data */
5673 x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */
5676 s_errno = socket_errno; /* socket_errno may be a function */
5677 debug(F101,"nettchk socket_read","",x);
5679 #ifndef NON_BLOCK_IO
5682 RequestSSLMutex(SEM_INDEFINITE_WAIT);
5685 y = 0; /* Turn off nonblocking reads */
5686 z = socket_ioctl(ttyfd,FIONBIO,&y);
5687 debug(F111,"nettchk FIONBIO","off",z);
5693 #endif /* NON_BLOCK_IO */
5694 #ifdef NT_TCP_OVERLAPPED
5695 ionoblock = 0; /* For Overlapped I/O */
5696 #endif /* NT_TCP_OVERLAPPED */
5699 debug(F101,"nettchk socket_read errno","",s_errno);
5701 if (os2socketerror(s_errno) < 0) {
5703 goto nettchk_return;
5706 } else if (x == 0) {
5707 debug(F100,"nettchk connection closed","",0);
5708 netclos(); /* *** *** */
5710 goto nettchk_return;
5712 if (x >= 1) { /* Oops, actually got a byte? */
5714 /* In OS/2 we read directly into ttibuf[] */
5715 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5719 if ( ssl_active_flag || tls_active_flag ) {
5720 ckhexdump("nettchk got real data",&ttibuf[ttibp+ttibn],x);
5725 debug(F101,"nettchk socket_read char","",c);
5726 debug(F101,"nettchk ttibp","",ttibp);
5727 debug(F101,"nettchk ttibn","",ttibn);
5729 In the case of Overlapped I/O the character would have come from
5730 the beginning of the buffer, so put it back.
5737 ttibuf[ttibp+ttibn] = c;
5744 if (ttnet == NET_TCPB) {
5746 x = read(ttyfd,&dummy,0); /* Try to read nothing */
5747 if (x < 0) { /* "Connection reset by peer" */
5748 perror("TCP/IP"); /* or somesuch... */
5749 ttclos(0); /* Close our end too. */
5751 goto nettchk_return;
5754 #endif /* NOCOUNT */
5759 if (ttnproto == NP_EK4LOGIN)
5760 count += krb4_des_avail(ttyfd);
5761 #endif /* RLOGCODE */
5765 if (ttnproto == NP_EK5LOGIN)
5766 count += krb5_des_avail(ttyfd);
5767 #endif /* RLOGCODE */
5769 if (ttnproto == NP_K5U2U)
5770 count += krb5_u2u_avail(ttyfd);
5771 #endif /* KRB5_U2U */
5773 #endif /* CK_KERBEROS */
5775 debug(F101,"nettchk returns","",count+ttibn);
5780 ReleaseTCPIPMutex();
5784 #else /* Not TCPIPLIB */
5786 UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
5790 #endif /* TCPIPLIB */
5792 But what about X.25?
5798 nettout(i) int i; { /* Catch the alarm interrupts */
5799 debug(F100,"nettout caught timeout","",0);
5801 cklongjmp(njbuf, -1);
5809 donetinc(void * threadinfo)
5810 #else /* CK_ANSIC */
5811 donetinc(threadinfo) VOID * threadinfo;
5812 #endif /* CK_ANSIC */
5815 extern int TlsIndex;
5817 if (threadinfo) { /* Thread local storage... */
5818 TlsSetValue(TlsIndex,threadinfo);
5828 #endif /* CK_LOGIN */
5830 if (ttbufr() < 0) /* Keep trying to refill it. */
5831 break; /* Till we get an error. */
5832 if (ttibn > 0) /* Or we get a character. */
5836 #endif /* TCPIPLIB */
5840 failnetinc(void * threadinfo)
5841 #else /* CK_ANSIC */
5842 failnetinc(threadinfo) VOID * threadinfo;
5843 #endif /* CK_ANSIC */
5845 ; /* Nothing to do on an error */
5848 /* N E T X I N -- Input block of characters from network */
5851 netxin(n,buf) int n; CHAR * buf; {
5855 #endif /* TCPIPLIB */
5858 debug(F100,"netxin socket is closed","",0);
5864 if (ttnproto == NP_EK4LOGIN) {
5865 if ((len = krb4_des_read(ttyfd,buf,n)) < 0)
5870 #endif /* RLOGCODE */
5874 if (ttnproto == NP_EK5LOGIN) {
5875 if ((len = krb5_des_read(ttyfd,(char *)buf,n,0)) < 0)
5880 #endif /* RLOGCODE */
5882 if (ttnproto == NP_K5U2U) {
5883 if ((len = krb5_u2u_read(ttyfd,(char *)buf,n)) < 0)
5888 #endif /* KRB5_U2U */
5890 #endif /* CK_KERBEROS */
5894 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
5897 if ((rc = ttbufr()) <= 0) {
5899 ReleaseTCPIPMutex();
5906 memcpy(buf,&ttibuf[ttibp],len); /* safe */
5910 memcpy(buf,&ttibuf[ttibp],n); /* safe */
5916 ReleaseTCPIPMutex();
5918 #else /* TCPIPLIB */
5919 for (i = 0; i < n; i++) {
5920 if ((j = netinc(0)) < 0) {
5929 #endif /* TCPIPLIB */
5932 #ifdef CK_ENCRYPTION
5933 /* This would be great if it worked. But what if the buffer we read */
5934 /* contains a telnet negotiation that changes the state of the */
5935 /* encryption. If so, we would be either decrypting unencrypted text */
5936 /* or not decrypting encrypted text. So we must move this call to */
5937 /* all functions that call ttxin(). In OS2 that means os2_netxin() */
5938 /* where the Telnet Negotiations are handled. */
5940 ck_tn_decrypt(buf,len);
5941 #endif /* CK_ENCRYPTION */
5942 #endif /* COMMENT */
5947 /* N E T I N C -- Input character from network */
5951 #endif /* NETLEBUF */
5954 #endif /* TTLEBUF */
5962 netinc(timo) int timo; {
5964 int x; unsigned char c; /* The locals. */
5968 debug(F111,"netinc","ttpush",ttpush);
5974 if (le_getchar((CHAR *)&c) > 0) {
5975 debug(F111,"netinc le_getchar","c",c);
5979 #endif /* NETLEBUF */
5982 debug(F100,"netinc socket is closed","",0);
5989 if (ttnproto == NP_EK4LOGIN) {
5990 if ((x = krb4_des_read(ttyfd,&c,1)) == 0)
5997 #endif /* RLOGCODE */
6001 if (ttnproto == NP_EK5LOGIN) {
6002 if ((x = krb5_des_read(ttyfd,&c,1,0)) == 0)
6009 #endif /* RLOGCODE */
6011 if (ttnproto == NP_K5U2U) {
6012 if ((x = krb5_u2u_read(ttyfd,&c,1)) == 0)
6019 #endif /* KRB5_U2U */
6021 #endif /* CK_KERBEROS */
6024 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6026 if (ttibn > 0) { /* Something in internal buffer? */
6028 debug(F100,"netinc char in buf","",0); /* Yes. */
6029 #endif /* COMMENT */
6030 x = 0; /* Success. */
6031 } else { /* Else must read from network. */
6032 x = -1; /* Assume failure. */
6034 debug(F101,"netinc goes to net, timo","",timo);
6038 * In the case of OpenSSL, it is possible that there is still
6039 * data waiting in the SSL session buffers that has not yet
6040 * been read by Kermit. If this is the case we must process
6041 * it without calling select() because select() will not return
6042 * with an indication that there is data to be read from the
6043 * socket. If there is no data pending in the SSL session
6044 * buffers then fall through to the select() code and wait for
6045 * some data to arrive.
6047 if (ssl_active_flag) {
6048 x = SSL_pending(ssl_con);
6050 debug(F111,"netinc","SSL_pending error",x);
6053 ReleaseTCPIPMutex();
6056 } else if ( x > 0 ) {
6057 if ( ttbufr() >= 0 ) {
6060 ReleaseTCPIPMutex();
6066 } else if (tls_active_flag) {
6067 x = SSL_pending(tls_con);
6069 debug(F111,"netinc","TLS_pending error",x);
6072 ReleaseTCPIPMutex();
6075 } else if ( x > 0 ) {
6076 if ( ttbufr() >= 0 ) {
6079 ReleaseTCPIPMutex();
6088 if (timo == 0) { /* Untimed case. */
6089 while (1) { /* Wait forever if necessary. */
6090 if (ttbufr() < 0) /* Refill buffer. */
6091 break; /* Error, fail. */
6092 if (ttibn > 0) { /* Success. */
6097 } else /* Timed case... */
6100 #ifdef NT_TCP_OVERLAPPED
6101 /* This code is for use on NT when we are using */
6102 /* Overlapped I/O to handle reads. In the case */
6103 /* of outstanding reads select() doesn't work */
6105 if (WaitForOverlappedReadData(timo)) {
6107 if (ttbufr() < 0) /* Keep trying to refill it. */
6108 break; /* Till we get an error. */
6109 if (ttibn > 0) { /* Or we get a character. */
6115 #else /* NT_TCP_OVERLAPPED */
6119 int timeout = timo < 0 ? -timo : 1000 * timo;
6120 debug(F101,"netinc BSDSELECT","",timo);
6122 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6124 debug(F111,"netinc","timeout",timeout);
6125 /* Don't move select() initialization out of the loop. */
6127 FD_SET(ttyfd, &rfds);
6128 tv.tv_sec = tv.tv_usec = 0L;
6130 tv.tv_usec = (long) 100000L;
6134 WSASafeToCancel = 1;
6136 rc = select(FD_SETSIZE,
6140 #else /* def INTSELECT */
6142 #endif /* def INTSELECT [else] */
6143 #else /* def __DECC */
6145 #endif /* def __DECC [else] */
6146 &rfds, NULL, NULL, &tv);
6148 int s_errno = socket_errno;
6149 debug(F111,"netinc","select",rc);
6150 debug(F111,"netinc","socket_errno",s_errno);
6153 ReleaseTCPIPMutex();
6158 debug(F111,"netinc","select",rc);
6160 WSASafeToCancel = 0;
6162 if (!FD_ISSET(ttyfd, &rfds)) {
6164 if (le_inbuf() > 0) {
6169 /* If waiting forever we have no way of knowing if the */
6170 /* socket closed so try writing a 0-length TCP packet */
6171 /* which should force an error if the socket is closed */
6173 if ((rc = socket_write(ttyfd,"",0)) < 0) {
6174 int s_errno = socket_errno;
6175 debug(F101,"netinc socket_write error","",s_errno);
6177 if (os2socketerror(s_errno) < 0) {
6178 ReleaseTCPIPMutex();
6181 ReleaseTCPIPMutex();
6183 return(-1); /* Call it an i/o error */
6189 if (ttbufr() < 0) { /* Keep trying to refill it. */
6191 break; /* Till we get an error. */
6193 if (ttibn > 0) { /* Or we get a character. */
6201 WSASafeToCancel = 0;
6203 #else /* !BSDSELECT */
6206 Was used by OS/2, currently not used, but might come in handy some day...
6207 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
6208 and timeval stuff since this is the only place where it is used.
6211 int timeout = timo < 0 ? -timo : 1000 * timo;
6213 debug(F101,"netinc IBMSELECT","",timo);
6214 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
6215 if (select(&socket, 1, 0, 0, 100L) == 1) {
6217 if (ttbufr() < 0) { /* Keep trying to refill it. */
6219 break; /* Till we get an error. */
6221 if (ttibn > 0) { /* Or we get a character. */
6229 else if (le_inbuf() > 0) {
6235 #else /* !IBMSELECT */
6237 /* Actually, under WinSock we have a better mechanism than select() */
6238 /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
6239 SOCKET socket = ttyfd;
6240 debug(F101,"netinc NTSELECT","",timo);
6241 if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
6242 sizeof(timo)) == NO_ERROR)
6244 if (ttbufr() < 0) /* Keep trying to refill it. */
6245 break; /* Till we get an error. */
6246 if (ttibn > 0) { /* Or we get a character. */
6253 If we can't use select(), then we use the regular alarm()/signal()
6256 debug(F101,"netinc alarm","",timo);
6257 x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
6258 ttimoff(); /* Timer off. */
6259 #endif /* WINSOCK */
6260 #endif /* IBMSELECT */
6261 #endif /* BSDSELECT */
6262 #endif /* NT_TCP_OVERLAPPED */
6267 if (le_inbuf() > 0) { /* If data was inserted into the */
6268 if (le_getchar((CHAR *)&c) > 0) {/* Local Echo buffer while the */
6269 #ifdef OS2 /* was taking place do not mix */
6270 ReleaseTCPIPMutex(); /* the le data with the net data */
6276 if (x < 0) { /* Return -1 if we failed. */
6277 debug(F100,"netinc timed out","",0);
6279 ReleaseTCPIPMutex();
6282 } else { /* Otherwise */
6283 c = ttibuf[ttibp]; /* Return the first char in ttibuf[] */
6286 debug(F101,"netinc returning","",c);
6287 #endif /* COMMENT */
6289 debug(F101,"netinc 0 ttibn","",ttibn);
6290 debug(F101,"netinc 0 ttibp","",ttibp);
6294 extern int tt_type_mode;
6295 if ( !ISVTNT(tt_type_mode) )
6297 ckhexdump("netinc &ttbuf[ttibp]",&ttibuf[ttibp],ttibn);
6299 #endif /* BETADEBUG */
6305 ReleaseTCPIPMutex();
6307 #ifdef CK_ENCRYPTION
6308 if (TELOPT_U(TELOPT_ENCRYPTION))
6309 ck_tn_decrypt(&c,1);
6310 #endif /* CK_ENCRYPTION */
6313 #else /* Not using TCPIPLIB */
6315 #endif /* TCPIPLIB */
6318 /* N E T T O L -- Output a string of bytes to the network */
6320 Call with s = pointer to string, n = length.
6321 Returns number of bytes actually written on success, or
6322 -1 on i/o error, -2 if called improperly.
6326 nettol(s,n) CHAR *s; int n; {
6333 debug(F100,"nettol socket is closed","",0);
6336 debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
6338 ckhexdump("nettol",s,n);
6339 #endif /* COMMENT */
6344 if (ttnproto == NP_EK4LOGIN) {
6345 return(krb4_des_write(ttyfd,s,n));
6347 #endif /* RLOGCODE */
6351 if (ttnproto == NP_EK5LOGIN) {
6352 return(krb5_des_write(ttyfd,s,n,0));
6354 #endif /* RLOGCODE */
6356 if (ttnproto == NP_K5U2U) {
6357 return(krb5_u2u_write(ttyfd,s,n));
6359 #endif /* KRB5_U2U */
6361 #endif /* CK_KERBEROS */
6363 #ifdef CK_ENCRYPTION
6364 if (TELOPT_ME(TELOPT_ENCRYPTION))
6366 #endif /* CK_ENCRYPTION */
6369 if (ssl_active_flag || tls_active_flag) {
6371 /* Write using SSL */
6373 if (ssl_active_flag)
6374 r = SSL_write(ssl_con, s, len /* >1024?1024:len */);
6376 r = SSL_write(tls_con, s, len /* >1024?1024:len */);
6377 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,r)) {
6378 case SSL_ERROR_NONE:
6379 debug(F111,"nettol","SSL_write",r);
6385 case SSL_ERROR_WANT_WRITE:
6386 debug(F100,"nettol SSL_ERROR_WANT_WRITE","",0);
6388 case SSL_ERROR_WANT_READ:
6389 debug(F100,"nettol SSL_ERROR_WANT_READ","",0);
6391 case SSL_ERROR_SYSCALL:
6392 if ( r == 0 ) { /* EOF */
6398 int gle = GetLastError();
6399 debug(F111,"nettol SSL_ERROR_SYSCALL",
6400 "GetLastError()",gle);
6401 rc = os2socketerror(gle);
6404 else if ( rc == -2 )
6409 case SSL_ERROR_WANT_X509_LOOKUP:
6410 debug(F100,"nettol SSL_ERROR_WANT_X509_LOOKUP","",0);
6414 debug(F100,"nettol SSL_ERROR_SSL","",0);
6415 if (bio_err!=NULL) {
6417 extern char ssl_err[];
6418 BIO_printf(bio_err,"nettol() SSL_ERROR_SSL\n");
6419 ERR_print_errors(bio_err);
6420 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6421 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6422 debug(F110,"nettol SSL_ERROR_SSL",ssl_err,0);
6425 } else if (ssl_debug_flag) {
6426 debug(F100,"nettol SSL_ERROR_SSL","",0);
6428 fprintf(stderr,"nettol() SSL_ERROR_SSL\n");
6429 ERR_print_errors_fp(stderr);
6437 case SSL_ERROR_ZERO_RETURN:
6438 debug(F100,"nettol SSL_ERROR_ZERO_RETURN","",0);
6442 debug(F100,"nettol SSL_ERROR_?????","",0);
6450 try++; /* Increase the try counter */
6452 if (ttnet == NET_TCPB) {
6457 debug(F101,"nettol BSDSELECT","",0);
6461 WSASafeToCancel = 1;
6465 #endif /* STREAMING */
6467 FD_SET(ttyfd, &wfds);
6468 if (select(FD_SETSIZE, NULL,
6472 #endif /* __DECC_VER */
6474 &wfds, NULL, &tv) < 0) {
6475 int s_errno = socket_errno;
6476 debug(F101,"nettol select failed","",s_errno);
6478 printf("nettol select failed: %d\n", s_errno);
6479 #endif /* BETADEBUG */
6481 WSASafeToCancel = 0;
6482 if (!win95selectbug)
6486 if (!FD_ISSET(ttyfd, &wfds)) {
6490 #endif /* STREAMING */
6491 debug(F111,"nettol","!FD_ISSET",ttyfd);
6493 WSASafeToCancel = 0;
6494 if (!win95selectbug)
6499 WSASafeToCancel = 0;
6501 #else /* BSDSELECT */
6505 debug(F101,"nettol IBMSELECT","",0);
6506 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6508 if (tries++ >= 60) {
6509 /* if after 60 seconds we can't get permission to write */
6510 debug(F101,"nettol select failed","",socket_errno);
6513 if ((count = nettchk()) < 0) {
6514 debug(F111,"nettol","nettchk()",count);
6519 #endif /* IBMSELECT */
6520 #endif /* BSDSELECT */
6521 if ((count = socket_write(ttyfd,s,n)) < 0) {
6522 int s_errno = socket_errno; /* maybe a function */
6523 debug(F101,"nettol socket_write error","",s_errno);
6525 if (os2socketerror(s_errno) < 0)
6528 return(-1); /* Call it an i/o error */
6531 debug(F111,"nettol socket_write",s,count);
6533 /* don't try more than 25 times */
6534 debug(F100,"nettol tried more than 25 times","",0);
6541 debug(F111,"nettol retry",s,n);
6544 debug(F111,"nettol socket_write",s,count);
6545 return(len); /* success - return total length */
6550 debug(F100,"nettol TCPIPLIB not defined","",0);
6552 #endif /* TCPIPLIB */
6555 /* N E T T O C -- Output character to network */
6557 Call with character to be transmitted.
6558 Returns 0 if transmission was successful, or
6559 -1 upon i/o error, or -2 if called improperly.
6566 #endif /* CK_ANSIC */
6574 debug(F100,"nettoc socket is closed","",0);
6578 debug(F101,"nettoc cc","",cc);
6583 if (ttnproto == NP_EK4LOGIN) {
6584 return(krb4_des_write(ttyfd,&cc,1)==1?0:-1);
6586 #endif /* RLOGCODE */
6590 if (ttnproto == NP_EK5LOGIN) {
6591 return(krb5_des_write(ttyfd,&cc,1,0)==1?0:-1);
6593 #endif /* RLOGCODE */
6595 if (ttnproto == NP_K5U2U) {
6596 return(krb5_u2u_write(ttyfd,&cc,1)==1?0:-1);
6598 #endif /* KRB5_U2U */
6600 #endif /* CK_KERBEROS */
6602 #ifdef CK_ENCRYPTION
6603 if ( TELOPT_ME(TELOPT_ENCRYPTION) )
6604 ck_tn_encrypt(&cc,1);
6605 #endif /* CK_ENCRYPTION */
6607 if (ssl_active_flag || tls_active_flag) {
6609 /* Write using SSL */
6611 if (ssl_active_flag)
6612 len = SSL_write(ssl_con, &cc, 1);
6614 len = SSL_write(tls_con, &cc, 1);
6615 switch (SSL_get_error(ssl_active_flag?ssl_con:tls_con,len)) {
6616 case SSL_ERROR_NONE:
6617 debug(F111,"nettoc","SSL_write",len);
6618 return(len == 1 ? 0 : -1);
6619 case SSL_ERROR_WANT_WRITE:
6620 case SSL_ERROR_WANT_READ:
6622 case SSL_ERROR_SYSCALL:
6623 if ( len == 0 ) { /* EOF */
6629 int gle = GetLastError();
6630 debug(F111,"nettoc SSL_ERROR_SYSCALL",
6631 "GetLastError()",gle);
6632 rc = os2socketerror(gle);
6635 else if ( rc == -2 )
6641 if (bio_err!=NULL) {
6643 extern char ssl_err[];
6644 BIO_printf(bio_err,"nettoc() SSL_ERROR_SSL\n");
6645 ERR_print_errors(bio_err);
6646 len = BIO_read(bio_err,ssl_err,SSL_ERR_BFSZ);
6647 ssl_err[len < SSL_ERR_BFSZ ? len : SSL_ERR_BFSZ] = '\0';
6648 debug(F110,"nettoc SSL_ERROR_SSL",ssl_err,0);
6651 } else if (ssl_debug_flag) {
6652 debug(F100,"nettoc SSL_ERROR_SSL","",0);
6654 fprintf(stderr,"nettoc() SSL_ERROR_SSL\n");
6655 ERR_print_errors_fp(stderr);
6659 case SSL_ERROR_WANT_X509_LOOKUP:
6660 case SSL_ERROR_ZERO_RETURN:
6667 if (ttnet == NET_TCPB) {
6672 debug(F101,"nettoc BSDSELECT","",0);
6678 #endif /* STREAMING */
6681 FD_SET(ttyfd, &wfds);
6682 if (select(FD_SETSIZE, NULL,
6686 #endif /* __DECC_VER */
6688 &wfds, NULL, &tv) < 0) {
6689 int s_errno = socket_errno;
6690 debug(F101,"nettoc select failed","",s_errno);
6692 printf("nettoc select failed: %d\n", s_errno);
6693 #endif /* BETADEBUG */
6695 WSASafeToCancel = 0;
6696 if (!win95selectbug)
6700 if (!FD_ISSET(ttyfd, &wfds)) {
6704 #endif /* STREAMING */
6705 debug(F111,"nettoc","!FD_ISSET",ttyfd);
6707 WSASafeToCancel = 0;
6708 if (!win95selectbug)
6713 WSASafeToCancel = 0;
6715 #else /* BSDSELECT */
6719 while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
6721 if (tries++ >= 60) {
6722 /* if after 60 seconds we can't get permission to write */
6723 debug(F101,"nettoc select failed","",socket_errno);
6726 if ((count = nettchk()) < 0) {
6727 debug(F111,"nettoc","nettchk()",count);
6732 #endif /* IBMSELECT */
6733 #endif /* BSDSELECT */
6734 if (socket_write(ttyfd,&cc,1) < 1) {
6735 int s_errno = socket_errno; /* maybe a function */
6736 debug(F101,"nettoc socket_write error","",s_errno);
6738 if (os2socketerror(s_errno) < 0)
6743 debug(F101,"nettoc socket_write","", cc);
6748 #endif /* TCPIPLIB */
6752 /* N E T F L U I -- Flush network input buffer */
6757 netgetc(int timo) /* Input function to point to... */
6758 #else /* CK_ANSIC */
6759 netgetc(timo) int timo;
6760 #endif /* CK_ANSIC */
6761 { /* ...in the tn_doop() call */
6763 return netinc(timo);
6764 #else /* TCPIPLIB */
6766 #endif /* TCPIPLIB */
6775 ttpush = -1; /* Clear the peek-ahead char */
6776 while (le_data && (le_inbuf() > 0)) {
6778 if (le_getchar(&ch) > 0) {
6779 debug(F101,"ttflui le_inbuf ch","",ch);
6782 #endif /* NETLEBUF */
6786 RequestTCPIPMutex(SEM_INDEFINITE_WAIT);
6789 if (ttnproto == NP_TELNET) {
6790 /* Netflui must process Telnet negotiations or get out of sync */
6791 if ((n = nettchk()) <= 0)
6796 extern int duplex; /* this really shouldn't be here but ... */
6797 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6798 if (tx == 1) duplex = 1;
6799 else if (tx == 2) duplex = 0;
6806 ttibuf[ttibp+ttibn] = '\0';
6807 debug(F111,"netflui 1",ttibuf,ttibn);
6808 #ifdef CK_ENCRYPTION
6809 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6810 ck_tn_decrypt(&ttibuf[ttibp],ttibn);
6812 #endif /* CK_ENCRYPTION */
6813 ttibn = ttibp = 0; /* Flush internal buffer *FIRST* */
6816 if ((n = nettchk()) > 0) { /* Now see what's waiting on the net */
6817 if (n > TTIBUFL) n = TTIBUFL; /* and sponge it up */
6818 debug(F101,"netflui 2","",n); /* ... */
6819 n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
6820 if (n >= 0) ttibuf[n] = '\0';
6821 debug(F111,"netflui 3",ttibuf,n);
6822 #ifdef CK_ENCRYPTION
6823 if (TELOPT_U(TELOPT_ENCRYPTION)) {
6824 ck_tn_decrypt(&ttibuf[ttibp],n);
6826 #endif /* CK_ENCRYPTION */
6830 #else /* !TCPIPLIB */
6834 if (ttnproto == NP_TELNET) {
6835 if ((n = ttchk()) <= 0)
6838 /* Netflui must process Telnet negotiations or get out of sync */
6841 extern int duplex; /* this really shouldn't be here but ... */
6842 int tx = tn_doop((CHAR)(ch & 0xff),duplex,netgetc);
6843 if (tx == 1) duplex = 1;
6844 else if (tx == 2) duplex = 0;
6850 if ((n = ttchk()) > 0) {
6851 debug(F101,"netflui non-TCPIPLIB","",n);
6852 while ((n--) && ttinc(1) > -1) /* Don't worry, ttinc() is buffered */
6853 ; /* and it handles the decryption... */
6855 #endif /* TCPIPLIB */
6858 ReleaseTCPIPMutex();
6864 /* The following two functions are required for encrypted rlogin */
6865 /* They are called with nettoc() or nettol() are transmitting */
6866 /* encrypted data. They call a function to encrypt the data */
6867 /* and that function needs to be able to write to/read from the */
6868 /* network in an unimpeded manner. Hence, these two simple fns. */
6870 net_write(fd, buf, len)
6872 register const char *buf;
6876 register int wrlen = len;
6879 cc = socket_write(fd, buf, wrlen);
6881 cc = write(fd,buf,wrlen);
6882 #endif /* TCPIPLIB */
6884 int s_errno = socket_errno;
6885 debug(F101,"net_write error","",s_errno);
6887 if (os2socketerror(s_errno) < 0)
6901 } while (wrlen > 0);
6905 net_read(fd, buf, len)
6914 cc = socket_read(fd, buf, len);
6916 cc = read(fd,buf,len);
6919 int s_errno = socket_errno;
6920 debug(F101,"net_read error","",s_errno);
6922 if (os2socketerror(s_errno) < 0)
6925 return(cc); /* errno is already set */
6938 #endif /* CK_KERBEROS */
6941 /* getlocalipaddr() attempts to resolve an IP Address for the local machine.
6942 * If the host is multi-homed it returns only one address.
6944 * Two techniques are used.
6945 * (1) get the local host name and perform a DNS lookup, then take
6947 * (2) open a UDP socket, use it to connect to a fictitious host (it's OK,
6948 * no data is sent), then retrieve the local address from the socket.
6949 * Note: the second technique won't work on Microsoft systems. See
6950 * Article ID: Q129065 PRB: Getsockname() Returns IP Address 0.0.0.0 for UDP
6953 /* Technique number one cannot work reliably if the machine is a laptop
6954 * and the hostname is associated with a physical adapter which is not
6955 * installed and a PPP connection is being used instead. This is because
6956 * the hostname DNS lookup will succeed for the physical adapter even though
6957 * it would be impossible to use it. In NT4 SP4, the gethostbyname()
6958 * when given the result of gethostname() returns not the real DNS entries
6959 * for that name+domain. Instead it returns all of the static and dynamic
6960 * IP addresses assigned to any physical or virtual adapter defined in the
6961 * system regardless of whether or not it is installed. The order of the
6962 * addresses is fixed according to the binding order in the NT registry.
6966 * It appears that calling gethostbyname(NULL) is more reliable than
6967 * calling gethostbyname(gethostname()) on Windows. So on Windows we will
6968 * only call gethostbyname(NULL).
6974 struct sockaddr_in l_sa;
6975 struct sockaddr_in r_sa;
6976 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
6979 struct in_addr laddr;
6981 /* if still not resolved, then try second strategy */
6982 /* This second strategy does not work on Windows */
6984 debug(F100,"getlocalipaddr","",0);
6985 memset(&l_sa,0,slen);
6986 memset(&r_sa,0,slen);
6988 /* get a UDP socket */
6989 sock = socket(AF_INET, SOCK_DGRAM, 0);
6991 /* connect to arbirary port and address (NOT loopback) */
6992 r_sa.sin_family = AF_INET;
6993 r_sa.sin_port = htons(IPPORT_ECHO);
6995 /* The following is an "illegal conversion" in AOS/VS */
6996 /* (and who knows where else) */
6999 inaddrx = inet_addr("128.127.50.1");
7000 r_sa.sin_addr.s_addr = *(unsigned long *)&inaddrx;
7002 r_sa.sin_addr.s_addr = inet_addr("128.127.50.1");
7003 #endif /* INADDRX */
7004 rc = connect(sock, (struct sockaddr *) &r_sa, sizeof(struct sockaddr));
7005 if (!rc) { /* get local address */
7006 getsockname(sock,(struct sockaddr *)&l_sa,&slen);
7008 socket_close(sock); /* We're done with the socket */
7011 #endif /* TCPIPLIB */
7012 if (l_sa.sin_addr.s_addr != INADDR_ANY) {
7013 myxipaddr = ntohl(l_sa.sin_addr.s_addr);
7014 ckstrncpy(myipaddr,(char *)inet_ntoa(l_sa.sin_addr),20);
7015 debug(F110,"getlocalipaddr setting buf to",myipaddr,0);
7020 return getlocalipaddrs(myipaddr,sizeof(myipaddr),0);
7021 #else /* datageneral */
7023 #endif /* datageneral */
7027 getlocalipaddrs(buf,bufsz,index)
7031 /* getlocalipaddrs */ {
7033 char localhost[256];
7034 struct hostent * host=NULL;
7035 struct sockaddr_in l_sa;
7036 struct sockaddr_in r_sa;
7037 GSOCKNAME_T slen = sizeof(struct sockaddr_in);
7041 char messageBuf[60];
7042 struct in_addr laddr;
7043 #endif /* COMMENT */
7045 debug(F100,"getlocalipaddrs","",0);
7046 memset(&l_sa,0,slen);
7047 memset(&r_sa,0,slen);
7049 /* init local address (to zero) */
7050 l_sa.sin_addr.s_addr = INADDR_ANY;
7053 rc = gethostname(localhost, 256);
7054 debug(F110,"getlocalipaddrs localhost",localhost,0);
7056 /* This doesn't work on some platforms, e.g. Solaris */
7058 localhost[0] = '\0';
7060 if ( winsock_version < 20 ) {
7061 rc = gethostname(localhost, 256);
7062 debug(F110,"getlocalipaddrs localhost",localhost,0);
7065 #endif /* CKGHNLHOST */
7067 /* resolve host name for local address */
7068 debug(F110,"getlocalipaddrs","calling gethostbyname()",0);
7069 host = gethostbyname(localhost);
7070 /* debug(F111,"getlocalipaddrs","gethostbyname() returned",host); */
7073 host = ck_copyhostent(host);
7074 if ( index < 0 || index > 63 || !host->h_addr_list[index] ) {
7078 l_sa.sin_addr.s_addr =
7079 *((unsigned long *) (host->h_addr_list[index]));
7080 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),20);
7081 debug(F110,"getlocalipaddrs setting buf to",buf,0);
7084 /* This is for reporting multiple IP Address */
7085 while (host->h_addr_list && host->h_addr_list[0]) {
7086 l_sa.sin_addr.s_addr =
7087 *((unsigned long *) (host->h_addr_list[0]));
7088 ckstrncpy(messageBuf,
7089 (char *)inet_ntoa(l_sa.sin_addr),60);
7091 if (!strcmp(messageBuf,tcp_address))
7092 ckstrncpy(myipaddr,tcp_address,20);
7094 debug(F110,"getlocalipaddrs ip address list", messageBuf, 0);
7095 host->h_addr_list++;
7097 #endif /* COMMENT */
7098 #else /* HADDRLIST */
7103 l_sa.sin_addr.s_addr = *((unsigned long *) (host->h_addr));
7104 ckstrncpy(buf,(char *)inet_ntoa(l_sa.sin_addr),bufsz);
7105 debug(F110,"getlocalipaddrs setting buf to",buf,0);
7106 #endif /* HADDRLIST */
7109 "getlocalipaddrs: gethostbyname() failed",
7114 #endif /* datageneral */
7118 #ifdef RLOGCODE /* TCP/IP RLOGIN protocol support code */
7122 unsigned char id[4];
7123 unsigned short rows, cols, ypix, xpix;
7126 if (ttnet != NET_TCPB)
7128 if (ttnproto != NP_RLOGIN
7130 && ttnproto != NP_K4LOGIN
7131 && ttnproto != NP_EK4LOGIN
7132 && ttnproto != NP_K5LOGIN
7133 && ttnproto != NP_EK5LOGIN
7134 #endif /* CK_KERBEROS */
7137 if (!TELOPT_ME(TELOPT_NAWS))
7140 debug(F100,"rlogin Window Size sent","",0);
7142 nawsbuf.id[0] = nawsbuf.id[1] = 0377;
7143 nawsbuf.id[2] = nawsbuf.id[3] = 's';
7145 nawsbuf.rows = htons((unsigned short) (VscrnGetHeight(VTERM)
7146 -(tt_status[VTERM]?1:0)));
7147 nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
7149 nawsbuf.rows = htons((unsigned short) tt_rows);
7150 nawsbuf.cols = htons((unsigned short) tt_cols);
7152 nawsbuf.ypix = htons(0); /* y pixels */
7154 nawsbuf.xpix = htons(0); /* x pixels */
7155 if (ttol((CHAR *)(&nawsbuf), sizeof(nawsbuf)) < 0)
7165 rlog_ini(CHAR * hostname, int port,
7166 struct sockaddr_in * l_addr, struct sockaddr_in * r_addr)
7167 #else /* CK_ANSIC */
7168 rlog_ini(hostname, port, l_addr, r_addr)
7171 struct sockaddr_in * l_addr;
7172 struct sockaddr_in * r_addr;
7173 #endif /* CK_ANSIC */
7179 #endif /* RLOGOUTBUF */
7182 #define CONSPDLEN 16
7183 CHAR localuser[UIDBUFLEN+1];
7184 CHAR remoteuser[UIDBUFLEN+1];
7186 CHAR term_speed[TERMLEN+CONSPDLEN+1];
7189 #endif /* CONGSPD */
7191 extern int tt_type, max_tt;
7192 extern struct tt_info_rec tt_info[];
7197 tn_reset(); /* This call will reset all of the Telnet */
7198 /* options and then quit. We need to do */
7199 /* this since we use the Telnet options */
7200 /* to hold various state information */
7201 duplex = 0; /* Rlogin is always remote echo */
7206 But compute the values anyway before the first read since the out-
7207 of-band NAWS request would arrive before the first data byte (NULL).
7210 /* Console terminal screen rows and columns */
7211 debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
7212 -(tt_status[VTERM]?1:0));
7213 debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
7215 if (VscrnGetWidth(VTERM) < 0 ||
7216 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0) < 0) {
7217 ttgwsiz(); /* Try to get screen dimensions */
7220 "rlog_ini tt_rows 2",
7222 VscrnGetHeight(VTERM)-(tt_status[VTERM]?1:0)
7224 debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
7226 debug(F101,"rlog_ini tt_rows 1","",tt_rows);
7227 debug(F101,"rlog_ini tt_cols 1","",tt_cols);
7228 if (tt_rows < 0 || tt_cols < 0) { /* Not known yet */
7229 ttgwsiz(); /* Try to find out */
7231 debug(F101,"rlog_ini tt_rows 2","",tt_rows);
7232 debug(F101,"rlog_ini tt_cols 2","",tt_cols);
7234 #endif /* CK_TTGWSIZ */
7236 ttflui(); /* Start by flushing the buffers */
7238 rlog_mode = RL_COOKED;
7240 /* Determine the user's local username ... */
7242 localuser[0] = '\0';
7245 char localuid[UIDBUFLEN+1];
7246 ckstrncpy((char *)localuser,(char *)GetLocalUser(),UIDBUFLEN);
7249 if ( !localuser[0] )
7252 char * user = getenv("USER");
7255 userlen = strlen(user);
7256 debug(F111,"rlogin getenv(USER)",user,userlen);
7257 ckstrncpy((char *)localuser,user,UIDBUFLEN);
7258 debug(F110,"rlog_ini localuser 1",localuser,0);
7260 if ( !localuser[0] )
7261 strcpy((char *)localuser,"unknown");
7262 else if (ck_lcname) {
7263 cklower((char *)localuser);
7264 debug(F110,"rlog_ini localuser 2",localuser,0);
7267 /* And the username to login with */
7269 ckstrncpy((char *)remoteuser,uidbuf,UIDBUFLEN);
7270 debug(F110,"rlog_ini remoteuser 1",remoteuser,0);
7271 } else if (localuser[0]) {
7272 ckstrncpy((char *)remoteuser,(char *)localuser,UIDBUFLEN);
7273 debug(F110,"rlog_ini remoteuser 2",remoteuser,0);
7275 remoteuser[0] = '\0';
7276 debug(F110,"rlog_ini remoteuser 3",remoteuser,0);
7279 cklower((char *)remoteuser);
7280 debug(F110,"rlog_ini remoteuser 4",remoteuser,0);
7282 /* The command to issue is the terminal type and speed */
7283 term_speed[0] = '\0';
7284 if (tn_term) { /* SET TELNET TERMINAL-TYPE value */
7285 if (*tn_term) { /* (if any) takes precedence. */
7286 ckstrncpy((char *)term_speed, tn_term, TERMLEN);
7289 } else { /* Otherwise the local terminal type */
7291 /* In terminal-emulating versions, it's the SET TERM TYPE value */
7292 ckstrncpy(term_speed, (tt_type >= 0 && tt_type <= max_tt) ?
7293 tt_info[tt_type].x_name : "network", TERMLEN);
7295 /* In the others, we just look at the TERM environment variable */
7297 char *p = getenv("TERM");
7299 ckstrncpy((char *)term_speed,p,TERMLEN);
7301 term_speed[0] = '\0';
7303 for (p = (char *) term_speed; *p; p++) {
7304 if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
7306 else if (isupper(*p))
7314 n = strlen((char *)term_speed);
7315 if (n > 0) { /* We have a terminal type */
7316 if (!flag) { /* If not user-specified */
7317 for (i = 0; i < n; i++) /* then lowercase it. */
7318 if (isupper(term_speed[i]))
7319 term_speed[i] = tolower(term_speed[i]);
7321 debug(F110,"rlog_ini term_speed 1",term_speed,0);
7324 /* conspd() is not yet defined in all ck*tio.c modules */
7327 ckstrncat((char *)term_speed,"/",sizeof(term_speed));
7328 ckstrncat((char *)term_speed,ckltoa(conspd),sizeof(term_speed));
7330 #endif /* CONGSPD */
7331 ckstrncat((char *)term_speed,"/19200",sizeof(term_speed));
7332 debug(F110,"rlog_ini term_speed 2",term_speed,0);
7334 term_speed[0] = '\0';
7335 debug(F110,"rlog_ini term_speed 3",term_speed,0);
7339 if (ttnproto == NP_K4LOGIN || ttnproto == NP_EK4LOGIN ||
7340 ttnproto == NP_K5LOGIN || ttnproto == NP_EK5LOGIN) {
7341 int kver, encrypt, rc;
7363 rc = ck_krb_rlogin(hostname, port,
7364 localuser, remoteuser, term_speed,
7365 l_addr, r_addr, kver, encrypt);
7366 if (!rc) { /* success */
7367 TELOPT_ME(TELOPT_NAWS) = 1;
7372 #endif /* CK_KERBEROS */
7373 if (ttnproto == NP_RLOGIN) {
7376 * The rcmds start the connection with a series of init data:
7378 * a port number upon which client is listening for stderr data
7379 * the user's name on the client machine
7380 * the user's name on the server machine
7381 * the terminal_type/speed or command to execute
7383 outbuf[outbytes++] = 0;
7384 strcpy((char *)outbuf+outbytes,(char *)localuser);
7385 outbytes += strlen((char *)localuser) + 1;
7386 strcpy((char *)outbuf+outbytes,(char *)remoteuser);
7387 outbytes += strlen((char *)remoteuser) + 1;
7388 strcpy((char *)outbuf+outbytes,(char *)term_speed);
7389 outbytes += strlen((char *)term_speed) + 1;
7390 rc = ttol((CHAR *)outbuf,outbytes);
7391 #else /* RLOGOUTBUF */
7392 ttoc(0); /* Send an initial NUL as wake-up */
7393 /* Send each variable with the trailing NUL */
7394 rc = ttol(localuser,strlen((char *)localuser)+1);
7396 rc = ttol(remoteuser,strlen((char *)remoteuser)+1);
7398 rc = ttol(term_speed,strlen((char *)term_speed)+1);
7399 #endif /* RLOGOUTBUF */
7401 /* Now we are supposed to get back a single NUL as confirmation */
7404 debug(F101,"rlogin first ttinc","",rc);
7406 debug(F101,"rlogin ttinc 1","",rc);
7408 "Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
7410 } else if (rc < 0) {
7411 debug(F101,"rlogin ttinc errno","",errno);
7412 /* printf("Network error: %d\n", errno); */
7419 /* two control messages are defined:
7421 a double flag byte of 'o' indicates a one-byte message which is
7422 identical to what was once carried out of band.
7424 a double flag byte of 'q' indicates a zero-byte message. This
7425 message is interpreted as two \377 data bytes. This is just a
7426 quote rule so that binary data from the server does not confuse the
7434 if ((n >= 5) && (cp[2] == 'o') && (cp[3] == 'o')) {
7435 if (rlog_oob(&cp[4],1))
7438 } else if ((n >= 4) && (cp[2] == 'q') && (cp[3] == 'q')) {
7439 /* this is somewhat of a hack */
7448 rlog_oob(oobdata, count) CHAR * oobdata; int count; {
7452 debug(F111,"rlogin out_of_band","count",count);
7454 for (i = 0; i<count; i++) {
7455 debug(F101,"rlogin out_of_band","",oobdata[i]);
7456 if (oobdata[i] & 0x01)
7459 if (oobdata[i] & 0x02) { /* Flush Buffered Data not yet displayed */
7460 debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
7462 /* Only flush the data if in fact we are in a mode that won't */
7463 /* get out of sync. Ie, not when we are in protocol mode. */
7475 if (oobdata[i] & 0x10) { /* Switch to RAW mode */
7476 debug(F101,"rlogin Raw Mode command","",oobdata[i]);
7480 if (oobdata[i] & 0x20) { /* Switch to COOKED mode */
7481 debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
7482 rlog_mode = RL_COOKED;
7484 if (oobdata[i] & 0x80)
7485 { /* Send Window Size Info */
7486 debug(F101,"rlogin Window Size command","",oobdata[i]);
7487 /* Remember to send WS Info when Window Size changes */
7488 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7489 TELOPT_ME(TELOPT_NAWS) = 1;
7498 rlogoobh(sig) int sig; {
7500 char /* Or should it be char for all? */
7503 #endif /* SOLARIS */
7506 /* int count = 0; */ /* (not used) */
7508 while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
7510 * We need to do some special processing here.
7511 * Just in case the socket is blocked for input
7521 debug(F101,"rlogin out_of_band","",oobdata);
7522 if (oobdata == 0x02) { /* Flush Buffered Data not yet displayed */
7523 debug(F101,"rlogin Flush Buffered Data command","",oobdata);
7526 if (oobdata & 0x10) { /* Switch to raw mode */
7527 debug(F101,"rlogin Raw Mode command","",oobdata);
7530 if (oobdata & 0x20) { /* Switch to cooked mode */
7531 debug(F101,"rlogin Cooked Mode command","",oobdata);
7532 rlog_mode = RL_COOKED;
7534 if (oobdata & 0x80) { /* Send Window Size Info */
7535 debug(F101,"rlogin Window Size command","",oobdata);
7536 /* Remember to send WS Info when Window Size changes */
7537 if ( !TELOPT_ME(TELOPT_NAWS) ) {
7538 TELOPT_ME(TELOPT_NAWS) = 1;
7543 #endif /* TCPIPLIB */
7544 #endif /* RLOGCODE */
7546 /* Send network BREAK */
7548 Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
7553 if (ttnet == NET_TCPB) {
7554 if (ttnproto == NP_TELNET) {
7556 buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
7559 nettol((char *) buf, 2)
7565 if (tn_deb || debses || deblog) {
7566 extern char tn_msg[];
7567 ckmakmsg(tn_msg,TN_MSG_LEN,"TELNET SENT ",TELCMD(BREAK),
7569 debug(F101,tn_msg,"",BREAK);
7570 if (debses || tn_deb) tn_debug(tn_msg);
7574 debug(F100,"netbreak no TNCODE","",0);
7578 /* Insert other TCP/IP protocols here */
7580 /* Insert other networks here */
7583 #endif /* NETCONN */
7589 SunLink X.25 support by Marcello Frutig, Catholic University,
7590 Rio de Janeiro, Brazil, 1990.
7593 /* PAD X.3, X.28 and X.29 support */
7595 static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
7597 /* Initialize PAD */
7599 extern CHAR padparms[];
7603 padparms[PAD_BREAK_CHARACTER] = 0; /* Break character */
7604 padparms[PAD_ESCAPE] = 1; /* Escape permitted */
7605 padparms[PAD_ECHO] = 1; /* Kermit PAD does echo */
7606 padparms[PAD_DATA_FORWARD_CHAR] = 2; /* forward character CR */
7607 padparms[PAD_DATA_FORWARD_TIMEOUT] = 0; /* no timeout forward condition */
7608 padparms[PAD_FLOW_CONTROL_BY_PAD] = 0; /* not used */
7609 padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1; /* allow PAD service signals */
7610 padparms[PAD_BREAK_ACTION] = 21; /* brk action: INT pk + brk ind*/
7611 padparms[PAD_SUPPRESSION_OF_DATA] = 0; /* no supression of user data */
7612 padparms[PAD_PADDING_AFTER_CR] = 0; /* no padding after CR */
7613 padparms[PAD_LINE_FOLDING] = 0; /* no line fold */
7614 padparms[PAD_LINE_SPEED] = 0; /* line speed - don't care */
7615 padparms[PAD_FLOW_CONTROL_BY_USER] = 0; /* flow cont of PAD - not used */
7616 padparms[PAD_LF_AFTER_CR] = 0; /* no LF insertion after CR */
7617 padparms[PAD_PADDING_AFTER_LF] = 0; /* no padding after LF */
7618 padparms[PAD_EDITING] = 1; /* can edit */
7619 padparms[PAD_CHAR_DELETE_CHAR] = 8; /* character delete character */
7620 padparms[PAD_BUFFER_DELETE_CHAR] = 21; /* buffer delete character */
7621 padparms[PAD_BUFFER_DISPLAY_CHAR] = 18; /* buffer display character */
7624 /* Set PAD parameters */
7627 setpad(s,n) CHAR *s; int n; {
7634 for (i = 0; i < n; i++) {
7635 if (*ps > MAXPADPARMS)
7638 padparms[*ps] = *(ps+1);
7644 /* Read PAD parameters */
7647 readpad(s,n,r) CHAR *s; int n; CHAR *r; {
7652 *pr++ = X29_PARAMETER_INDICATION;
7654 for (i = 0; i < n; i++, ps++) {
7655 if (*ps > MAXPADPARMS) {
7656 x29err[i+2] = *ps++;
7659 *pr++ = padparms[*ps++];
7663 for (i = 1; i < MAXPADPARMS; i++) {
7665 *pr++ = padparms[i];
7671 qbitpkt(s,n) CHAR *s; int n; {
7675 CHAR x29resp[(MAXPADPARMS*2)+1];
7681 if ((int)strlen((char *)x29err) > 2) {
7682 ttol(x29err,(int)strlen((char *)x29err));
7686 case X29_READ_PARMS:
7687 readpad (ps+1,n/2,x29resp);
7689 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7690 if ((int)strlen((char *)x29err) > 2) {
7691 ttol(x29err,(int)strlen((char *)x29err));
7696 case X29_SET_AND_READ_PARMS:
7698 readpad (ps+1,n/2,x29resp);
7700 ttol(x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
7701 if ((int)strlen((char *)x29err) > 2) {
7702 ttol (x29err,(int)strlen((char *)x29err));
7707 case X29_INVITATION_TO_CLEAR:
7710 case X29_INDICATION_OF_BREAK:
7716 /* PAD break action processor */
7720 extern char x25obuf[MAXOX25];
7723 extern unsigned char tosend;
7724 static CHAR indbrk[3] = {
7725 X29_INDICATION_OF_BREAK,
7726 PAD_SUPPRESSION_OF_DATA,
7729 CHAR intudat, cause, diag;
7731 if (x25stat() < 0) return; /* Ignore if no virtual call established */
7733 if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
7734 if (ttol((CHAR *)x25obuf,obufl) < 0) {
7735 perror ("\r\nCan't send characters");
7738 bzero (x25obuf,sizeof(x25obuf));
7743 switch (padparms[PAD_BREAK_ACTION]) {
7745 case 0 : break; /* do nothing */
7746 case 1 : /* send interrupt packet with interrupt user data field = 1 */
7750 case 2 : /* send reset packet with cause and diag = 0 */
7752 x25reset (cause,diag);
7754 case 5 : /* send interrupt packet with interrupt user data field = 0 */
7758 /* send indication of break without a parameter field */
7759 ttoc(X29_INDICATION_OF_BREAK);
7762 case 8 : active = 0; /* leave data transfer */
7765 case 21: /* send interrupt packet with interrupt user data field = 0 */
7768 setpad (indbrk+1,2); /* set pad to discard input */
7770 /* send indication of break with parameter field */
7771 ttol (indbrk,sizeof(indbrk));
7777 /* X.25 support functions */
7779 X25_CAUSE_DIAG diag;
7782 Convert a null-terminated string representing an X.121 address
7783 to a packed BCD form.
7786 pkx121(str,bcd) char *str; CHAR *bcd; {
7792 if (i >= 15 || str [i] < '0' || str [i] > '9')
7804 /* Reads and prints X.25 diagnostic */
7810 bzero ((char *)&diag,sizeof(diag));
7811 if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
7812 perror ("Reading X.25 diagnostic");
7815 if (diag.datalen > 0) {
7816 printf ("X.25 Diagnostic :");
7817 for (i = 0; i < (int)diag.datalen; i++)
7818 printf(" %02h",diag.data[i])+
7824 /* X.25 Out-of-Band Signal Handler */
7827 x25oobh(foo) int foo; {
7832 (VOID) signal(SIGURG,x25oobh);
7834 if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
7835 perror ("Getting signal type");
7840 if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
7841 perror ("Receiving X.25 interrupt data");
7845 printf ("\r\nInterrupt received, data = %d\r\n", t);
7848 printf ("\r\nVirtual circuit reset\r\n");
7852 printf ("\r\nReset timeout\r\n");
7855 printf ("\r\nClear timeout\r\n");
7858 printf ("\r\nMessage discarded, too long\r\n");
7861 if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
7867 /* Send a X.25 interrupt packet */
7873 x25intr(intr) char intr;
7874 #endif /* CK_ANSIC */
7876 if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
7877 debug(F100,"X.25 intr","",0);
7881 /* Reset X.25 virtual circuit */
7884 x25reset(char cause, char diagn)
7886 x25reset(cause, diagn) char cause; char diagn;
7887 #endif /* CK_ANSIC */
7889 bzero ((char *)&diag,sizeof(diag));
7892 diag.data[0] = cause;
7893 diag.data[1] = diagn;
7894 if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
7896 debug(F100,"X.25 reset","",0);
7900 /* Clear X.25 virtual circuit */
7904 debug(F100,"X.25 clear","",0);
7905 bzero ((char *)&diag,sizeof(diag));
7906 diag.flags = (1 << DIAG_TYPE);
7910 ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
7911 return(ttclos(0)); /* Close socket */
7917 if (ttyfd == -1) return (-1);
7924 static int qbiton = 1 << Q_BIT;
7925 ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
7931 static int qbitoff = 0;
7932 ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
7935 /* Read n characters from X.25 circuit into buf */
7938 x25xin(n,buf) int n; CHAR *buf; {
7943 x = read(ttyfd,buf,n);
7944 if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
7945 /* If return -1 : invitation to clear; -2 : PAD changes */
7946 if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
7951 #ifdef COMMENT /* Disabled by Stephen Riehm 19.12.97 */
7953 * if buf[] is full, then this null lands in nirvana!
7954 * I was unable to find any code which needs a trailing null in buf[]
7956 if (x > 0) buf[x] = '\0';
7957 #endif /* COMMENT */
7959 debug(F101,"x25xin x","",x);
7964 #ifdef COMMENT /* NO LONGER NEEDED! */
7965 /* X.25 read a line */
7970 x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
7972 x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
7973 #endif /* CK_ANSIC */
7974 #else /* not PARSENSE */
7976 x25inl(CHAR *dest, int max,int timo, CHAR eol)
7978 x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
7979 #endif /* __SDTC__ */
7980 #endif /*PARSENSE */
7983 int pktype, goteol, rest, n;
7985 extern int ttprty, ttpflg;
7988 ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask */
7990 debug(F101,"x25inl max","",max);
7991 debug(F101,"x25inl eol","",eol);
7996 n = read(ttyfd,pdest,rest);
7998 pktype = *pdest & 0x7f;
8001 if (qbitpkt(pdest+1,--n) < 0) return(-2);
8004 if (flag == 0) { /* if not in packet, search start */
8005 for (i = 1; (i < n) &&
8006 !(flag = ((dest[i] & 0x7f) == start));
8008 if (flag == 0) { /* not found, discard junk */
8009 debug(F101,"x25inl skipping","",n);
8011 } else { /* found, discard junk before start */
8014 for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
8017 for (i = 0; (i < n) && /* search for eol */
8018 !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
8023 } while ((rest > 0) && (!goteol));
8027 debug (F111,"x25inl X.25 got",(char *) dest,n);
8028 if (timo) ttimoff();
8029 if (ttpflg++ == 0 && ttprty == 0) {
8030 if ((ttprty = parchk(dest,start,n)) > 0) {
8032 debug(F101,"x25inl senses parity","",ttprty);
8033 debug(F110,"x25inl packet before",(char *)dest,0);
8035 for (j = 0; j < n; j++)
8036 dest[j] &= 0x7f; /* Strip parity from packet */
8037 debug(F110,"x25inl packet after ",dest,0);
8039 debug(F101,"parchk","",ttprty);
8040 if (ttprty < 0) { ttprty = 0; n = -1; }
8049 #endif /* COMMENT */
8054 * IBM X25 support - using the NPI streams interface
8055 * written by Stephen Riehm, pc-plus, Munich Germany
8058 /* riehm: missing functions / TODO list */
8061 x25intr() - Send an interrupt packet
8064 /* return an error message depending on packet type */
8067 static char buf[30];
8069 case NBADADDR: return "invalid address";
8070 case NBADOPT: return "invalid options";
8071 case NACCESS: return "no permission";
8072 case NNOADDR: return "unable to allocate address";
8073 case NOUTSTATE: return "invalid state";
8074 case NBADSEQ: return "invalid sequence number";
8075 case NSYSERR: return "system error";
8076 case NBADDATA: return "invalid data size";
8077 case NBADFLAG: return "invalid flag";
8078 case NNOTSUPPORT: return "unsupported primitive";
8079 case NBOUND: return "address in use";
8080 case NBADQOSPARAM: return "bad QOS parameters";
8081 case NBADQOSTYPE: return "bad QOS type";
8082 case NBADTOKEN: return "bad token value";
8083 case NNOPROTOID: return "protocol id could not be allocated";
8084 case NODDCUD: return "odd length call user data";
8086 ckmakmsg(buf,sizeof(buf),"Unknown NPI error ",ckitoa(n),NULL,NULL);
8091 /* turn a meaningless primitive number into a meaningful primitive name */
8094 static char buf[30];
8096 case N_BIND_ACK: return "N_BIND_ACK";
8097 case N_BIND_REQ: return "N_BIND_REQ";
8098 case N_CONN_CON: return "N_CONN_CON";
8099 case N_CONN_IND: return "N_CONN_IND";
8100 case N_CONN_REQ: return "N_CONN_REQ";
8101 case N_CONN_RES: return "N_CONN_RES";
8102 case N_DATACK_IND: return "N_DATAACK_IND";
8103 case N_DATACK_REQ: return "N_DATAACK_REQ";
8104 case N_DATA_IND: return "N_DATA_IND";
8105 case N_DATA_REQ: return "N_DATA_REQ";
8106 case N_DISCON_IND: return "N_DISCON_IND";
8107 case N_DISCON_REQ: return "N_DISCON_REQ";
8108 case N_ERROR_ACK: return "N_ERROR_ACK";
8109 case N_EXDATA_IND: return "N_EXDATA_IND";
8110 case N_EXDATA_REQ: return "N_EXDATA_REQ";
8111 case N_INFO_ACK: return "N_INFO_ACK";
8112 case N_INFO_REQ: return "N_INFO_REQ";
8113 case N_OK_ACK: return "N_OK_ACK";
8114 case N_OPTMGMT_REQ: return "N_OPTMGMT_REQ";
8115 case N_RESET_CON: return "N_RESET_CON";
8116 case N_RESET_IND: return "N_RESET_IND";
8117 case N_RESET_REQ: return "N_RESET_REQ";
8118 case N_RESET_RES: return "N_RESET_RES";
8119 case N_UDERROR_IND: return "N_UDERROR_IND";
8120 case N_UNBIND_REQ: return "N_UNBIND_REQ";
8121 case N_UNITDATA_REQ: return "N_UNITDATA_REQ";
8122 case N_UNITDATA_IND: return "N_UNITDATA_IND";
8124 ckmakmsg(buf,sizeof(buf),"UNKNOWN (",ckitoa(n),")",NULL);
8129 /*****************************************************************************
8130 * Function: x25getmsg()
8131 * Description: get a STREAMS message, and check it for errors
8134 * fd - file descriptor to x25 device (opened)
8135 * control - control buffer (pre-allocated)
8136 * ctl_size - size of control buffer
8137 * data - data buffer (pre-allocated)
8138 * data_size - size of data buffer
8139 * flags - flags for getmsg()
8140 * expected - expected Primitive type
8143 * >= 0 OK (size of data returned)
8148 x25getmsg( fd, control, ctl_size, data, data_size, get_flags, expected )
8149 int fd; /* X25 device (opened) */
8150 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
8151 int ctl_size; /* size of control buffer */
8152 N_npi_data_t *data; /* data buffer (pre-allocated) */
8153 int data_size; /* size of data buffer */
8154 int *get_flags; /* getmsg() flags */
8155 int expected; /* expected primitive type */
8157 int rc = 0; /* return code */
8158 struct strbuf *get_ctl=NULL; /* getmsg control */
8159 struct strbuf *get_data=NULL; /* getmsg data */
8160 int more = 0; /* flag for more data etc */
8161 int file_status = -1; /* file async status */
8162 N_npi_ctl_t * result; /* pointer to simplify switch() */
8163 int packet_type = -1; /* unknown packet thus far */
8166 printf( "TRACE: entering x25getmsg\n" );
8169 debug( F110, "x25getmsg waiting for packet ", x25prim( expected ), 0);
8170 /* prepare the control structures for getmsg */
8172 if ((get_ctl = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8174 perror("kermit x25getmsg(): get_ctl malloc failed\n");
8175 debug( F100, "x25getmsg malloc failed for get_ctl\n", "", 0);
8178 /* allow getmsg to return an unexpected packet type (which may be
8179 * larger than the expected one)
8181 get_ctl->maxlen = NPI_MAX_CTL;
8183 get_ctl->buf = (char *)control;
8186 "kermit x25getmsg(): internal error. control buffer MUST be pre-allocated!\n"
8188 debug(F100,"x25getmsg internal error. no buffer pre-allocated","",0);
8192 if ((get_data = (struct strbuf*)malloc(sizeof(struct strbuf))) == NULL)
8194 perror("kermit x25getmsg(): get_data malloc failed\n");
8195 debug( F100, "x25getmsg malloc failed for get_data\n", "", 0);
8198 get_data->maxlen = (NPI_MAX_DATA < data_size ) ?
8202 get_data->buf = (char *)data;
8205 /* get an X.25 packet -
8206 * it may be any kind of packet, so check for special cases
8207 * it may be split into multiple parts - so loop if necessary
8211 printf( "kermit: x25getmsg(): getting a message\n" );
8214 if ((more = getmsg(fd, get_ctl, get_data, get_flags)) < 0) {
8216 printf( "kermit: x25getmsg(): getmsg returned an error\n" );
8217 perror( "getmsg error was" );
8219 debug(F101, "x25getmsg getmsg returned an error\n", "", errno);
8220 if ((errno == EAGAIN) && (get_data && (get_data->len > 0)) ) {
8221 /* was in non-blocking mode, nothing to get, but we're
8222 * already waiting for the rest of the packet -
8223 * switch to blocking mode for the next read.
8224 * file_status used to reset file status before returning
8226 if ((file_status = fcntl(fd, F_GETFL, 0)) < 0
8227 || fcntl(fd, F_SETFL, file_status & ~O_NDELAY) < 0)
8229 perror("x25getmsg(): couldn't change x25 blocking mode");
8231 "x25getmsg fcntl returned an error\n", "", errno);
8236 /* loop again into a blocking getmsg() */
8240 /* no data to get in non-blocking mode - return empty handed */
8241 perror( "x25getmsg(): getmsg failed" );
8242 debug(F101,"x25getmsg getmsg returned an error\n", "", errno);
8246 } else if (more & MORECTL) {
8247 /* panic - the control information was larger than the
8248 * maximum control buffer size!
8250 /* riehm: close connection? */
8252 printf("x25getmsg(): received partial control packet - panic\n");
8254 debug( F101, "x25getmsg getmsg bad control block\n", "", errno);
8259 if (result = (N_npi_ctl_t *)control) {
8260 packet_type = result->bind_ack.PRIM_type;
8261 if (packet_type != N_OK_ACK) {
8262 x25lastmsg = packet_type;
8266 /* printf( "kermit: x25getmsg(): getting " ); */
8267 if (get_ctl->len > 0) {
8268 x25dump_prim(result);
8271 "x25getmsg got packet ",
8272 x25prim( result->bind_ack.PRIM_type ),
8277 if (get_ctl->len >= (int)sizeof(result->bind_ack.PRIM_type)) {
8278 /* not as pretty as a switch(), but switch can't handle
8279 * runtime variable values :-(
8281 if (packet_type == expected ) {
8282 /* got what we wanted, special case for DATA_IND
8284 /* riehm: check Q-bit ? */
8286 printf("x25getmsg(): got expected packet\nrc is %d\n", rc);
8288 if (packet_type == N_DATA_IND ) {
8289 /* data received. May be incomplete, even though
8290 * getmsg returned OK
8292 if (result->data_ind.DATA_xfer_flags & N_MORE_DATA_FLAG)
8294 if (result->data_ind.DATA_xfer_flags & N_RC_FLAG)
8295 printf( "x25getmsg(): data packet wants ack\n" );
8297 } else if( packet_type == N_DISCON_IND) {
8298 printf( "X25 diconnected\n" );
8299 /* riehm: need to acknowledge a disconnection? */
8301 /* x25unbind( ttyfd ); */
8303 } else if( packet_type == N_ERROR_ACK) {
8304 errno = result->error_ack.UNIX_error;
8305 perror( "X25 error received" );
8308 printf("x25getmsg(): failed %s\n", x25err(packet_type));
8314 /* Panic - no control data */
8315 printf( "kermit: x25getmsg(): no control data with packet\n" );
8318 #endif /* COMMENT */
8320 if (get_data && (get_data->len >= 0)) {
8321 get_data->buf += get_data->len;
8322 get_data->maxlen -= get_data->len;
8325 && (get_data && (get_data->maxlen > 0))
8326 && (more & MOREDATA)
8329 /* return the file status to its original value, unless its still
8330 * set to -1, or one of the fcntl's failed */
8331 if ((file_status >= 0) && fcntl(fd, F_SETFL, file_status) < 0)
8335 * Verify that we received an expected primitive
8336 * there is apparantly an error case where the primitive is set
8337 * correctly, but there is not enough data in the control structure
8339 if ((packet_type != expected) && (get_ctl->len >= ctl_size) ) {
8341 "x25getmsg(): %s NOT received. Primitive received was %s\n",
8342 x25prim( expected ), x25prim( packet_type ));
8343 debug(F110, "x25getmsg got an unexpected packet ",
8344 x25prim(packet_type),
8351 if (get_data && ( get_data->len >= 0)) {
8356 if (get_ctl) { free(get_ctl); get_ctl = NULL; }
8357 if (get_data) { free(get_data); get_data = NULL; }
8361 printf( "kermit x25getmsg(): returning %d\n", rc );
8363 #endif /* COMMENT */
8364 debug(F110, "x25getmsg returning packet ", x25prim( packet_type ), 0);
8367 printf( "TRACE: leaving x25getmsg\n" );
8372 /*****************************************************************************
8373 * Function: x25putmsg()
8376 * send a message to a X25 STREAM
8379 * fd - file descriptor to x25 device (opened)
8380 * control - control buffer (pre-allocated)
8381 * data - data buffer (pre-allocated)
8382 * data_len - length of data to be transmitted
8383 * put_flags - flags for putmsg()
8386 * >= 0 number of bytes transmitted
8390 x25putmsg(fd, control, data, data_len, put_flags)
8391 int fd; /* X25 device (opened) */
8392 N_npi_ctl_t *control; /* control buffer (pre-allocated) */
8393 N_npi_data_t *data; /* data buffer (pre-allocated) */
8394 int data_len; /* length of data (not the size of
8396 int *put_flags; /* putmsg() flags */
8398 int rc = 0; /* return code */
8399 ulong type; /* primitive type */
8400 struct strbuf *put_ctl = NULL; /* putmsg control */
8401 struct strbuf *put_data = NULL; /* putmsg data */
8404 printf( "TRACE: entering x25putmsg\n" );
8408 printf( "kermit: x25putmsg(): putting " );
8409 x25dump_prim( control );
8410 printf( "\tdata:\t\t" );
8411 x25dump_data( data, 0, data_len );
8412 debug(F110,"x25putmsg: putting packet ",x25prim(control->PRIM_type),0);
8416 put_ctl = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8417 if (put_ctl == NULL) {
8418 perror("kermit x25putmsg(): put_ctl malloc failed\n");
8421 put_ctl->maxlen = 0; /* unused by putmsg */
8422 put_ctl->len = NPI_MAX_CTL;
8423 put_ctl->buf = (char *)control;
8425 if (data && ( data_len > 0)) {
8426 put_data = (struct strbuf *)malloc( sizeof( struct strbuf ) );
8427 if( put_data == NULL) {
8428 perror("kermit x25putmsg(): put_data malloc failed\n");
8431 put_data->maxlen = 0; /* unused by putmsg */
8432 put_data->len = data_len;
8433 put_data->buf = (char *)data;
8437 rc = putmsg (fd, put_ctl, put_data, 0);
8439 printf("x25putmsg(): couldn't put %s\n",x25prim(control->PRIM_type));
8440 perror("kermit: x25putmsg(): putmsg failed");
8444 /* riehm: this should perhaps be discounted! */
8445 x25lastmsg = control->PRIM_type;
8449 printf( "kermit debug: x25putmsg() returning %d\n", data_len );
8451 #endif /* COMMENT */
8452 debug( F101, "x25putmsg block size put ", "", data_len);
8455 printf( "TRACE: leaving x25putmsg\n" );
8461 /*****************************************************************************
8463 * Description: The bind submitted to NPI provides the information required
8464 * by the packet layer for it to listen for suitable incoming
8469 * This routine needs to be called in a completely different manner for
8470 * the client and server side. When starting a client, the
8471 * num_waiting_calls and CUD information should all be set to 0! The
8472 * client's CUD must be inserted in the CONN_REQ data block.
8473 * When starting a server, the CUD must be set to a CUD pattern, and
8474 * the number of waiting calls should be set to a number other than 0.
8475 * (num waiting calls is the number of incomming calls which are to be
8476 * put on hold while the server is servicing another client.)
8478 * Who invented this crap?
8481 * fd - X25 device (opened)
8482 * addr - local address
8483 * cud - User Data (null terminated)
8484 * cud_len - User Data length
8485 * num_waiting_calls - number of outstanding calls allowed on this stream
8486 * line - logical port number (1)
8487 * flags - 0, DEFAULT_LISTENER or TOKEN_REQUEST
8490 * if binding is successful, 0 is returned for a client, and a token is
8491 * returned for a server
8493 * Return code: 0 if successful
8494 * -1 if unsuccessful
8495 *****************************************************************************/
8498 x25bind(fd, addr, cud, cud_len, num_waiting_calls, line, bind_flags)
8499 int fd; /* X25 device (opened) */
8500 char * addr; /* local address */
8501 char * cud; /* Call User Data (null terminated) */
8502 int cud_len; /* User Data length */
8503 int num_waiting_calls; /* Outstanding calls allowed */
8504 int line; /* logical port number */
8505 ulong bind_flags; /* 0, DEFAULT_LISTENER or TOKEN_REQUEST */
8507 ulong rc; /* return code */
8508 int get_flags; /* priority flag passed to getmsg */
8509 int put_flags = 0; /* output flags for putmsg, always 0 */
8510 ulong type; /* primitive type */
8511 N_bind_req_t *bind_req; /* pointer to N_BIND_REQ primitive */
8512 N_bind_ack_t *bind_ack; /* pointer to N_BIND_ACK primitive */
8513 char *addtl_info; /* pointer to info in addition to
8514 * the N_BIND_REQ primitive that is
8515 * passed in the control structure
8517 int addr_len = 0; /* length of address string */
8518 ulong bind_req_t_size; /* for debugging only */
8521 printf("TRACE: entering x25bind\n" );
8525 printf("TRACE: x25bind( %d, %s, %s, %d, %d )\n",
8526 fd, addr, cud, line, bind_flags
8531 * Allocate and zero out space to hold the control portion of the
8532 * message passed to putmsg. This will contain the N_BIND_REQ
8533 * primitive and any additional info required for that.
8535 * Note: allocated space is the size of the union typedef
8536 * N_npi_ctl_t to allow the use fo the generic x25putmsg routine.
8538 bind_req = (N_bind_req_t *) malloc(sizeof( N_npi_ctl_t));
8539 if (bind_req == NULL) {
8540 perror("kermit: x25bind(): bind_req malloc failed");
8541 debug(F100, "x25bind bind_req malloc failed", "", 0);
8544 bzero((char *)bind_req, sizeof(N_npi_ctl_t));
8546 /* Build the Bind Request Primitive */
8547 bind_req->PRIM_type = (ulong) N_BIND_REQ;
8549 /* Note that the address length is n+2 and NOT n. Two bytes MUST preceed
8550 * the actual address in an N_BIND_REQ. The first byte contains the
8551 * line number being used with this address, and the second byte is the
8552 * X.121 address prefix, which must be zero.
8554 addr_len = strlen(addr);
8555 bind_req->ADDR_length = (ulong) (addr_len + 2);
8556 bind_req->ADDR_offset = (ulong)(sizeof(N_bind_req_t));
8557 bind_req->CONIND_number = (ulong)num_waiting_calls; /* server only */
8558 bind_req->BIND_flags = (ulong) bind_flags; /* 0 in client */
8559 bind_req->PROTOID_length = (ulong) cud_len; /* 0 in client */
8561 bind_req->PROTOID_offset = (ulong) 0;
8563 /* need to remember the trailing NULL in the address - not
8564 * counted in the address length
8566 bind_req->PROTOID_offset
8567 = (ulong) (sizeof(N_bind_req_t) + bind_req->ADDR_length);
8571 * Now fill in the additional information required with this primitive
8572 * (address and protocol information (Call User Data))
8574 addtl_info = (char *) ((void *)bind_req + bind_req->ADDR_offset);
8576 * The bitwise "&" ensures that the line number is only one byte long
8578 *addtl_info++ = (char) line & 0xff;
8579 *addtl_info++ = (char) 0; /* X.121 format */
8580 bcopy( addr, addtl_info, addr_len ); /* include trailing null */
8581 addtl_info += addr_len;
8583 bcopy( cud, addtl_info, cud_len );
8585 * Call putmsg() to put the bind request message on the stream
8588 (N_npi_ctl_t*)bind_req,
8589 (N_npi_data_t *)NULL,
8593 printf( "kermit: x25bind(): x25putmsg failed\n" );
8598 * Allocate and zero out space for the N_BIND_ACK primitive
8600 bind_ack = (N_bind_ack_t *) malloc(sizeof(N_npi_ctl_t));
8601 if (bind_ack == NULL){
8602 perror("kermit: x25bind(): bind_ack malloc failed");
8605 bzero(bind_ack, sizeof(N_npi_ctl_t));
8607 * Initialize the control structure and flag variable sent to getmsg
8611 /* get the ACK for the bind */
8613 printf( "kermit: x25bind() trying to get a BIND_ACK\n" );
8615 rc = (ulong)x25getmsg( fd, (N_npi_ctl_t*)bind_ack,
8616 (int)sizeof( N_bind_ack_t ), (N_npi_data_t*)NULL, 0, &get_flags,
8619 /* turn quantitive return code into a qualitative one */
8622 /* if all went well, get the token from the acknowledgement packet */
8623 if ((bind_flags & TOKEN_REQUEST ) && ( rc >= 0)) {
8624 rc = bind_ack->TOKEN_value;
8627 /* free up the memory we allocated earlier */
8632 printf( "TRACE: leaving x25bind\n" );
8638 /*****************************************************************************
8640 * Description: This routine builds and sends an N_CONN_REQ primitive, then
8641 * checks for an N_CONN_CON primitive in return.
8644 * fd - file descriptor of stream
8645 * caddr - called address (remote address)
8647 * Functions Referenced:
8655 * -1 if not successful
8656 *****************************************************************************/
8658 x25call(fd, remote_nua, cud)
8659 int fd; /* X25 device (opened) */
8660 char * remote_nua; /* remote address to call */
8661 char * cud; /* call user data */
8663 int rc; /* return code */
8664 int flags; /* Connection flags */
8665 int get_flags; /* priority flags for getmsg */
8666 ulong type; /* primitive type */
8667 N_conn_req_t *connreq_ctl; /* pointer to N_CONN_REQ primitive */
8668 N_npi_data_t *connreq_data; /* pointer to N_CONN_REQ data (CUD) */
8669 int connreq_data_len; /* length of filled data buffer */
8670 N_conn_con_t *conncon_ctl; /* pointer to N_CONN_CON primitive */
8671 N_npi_data_t *conncon_data; /* pointer to any data associated with
8672 * the N_CONN_CON primitive */
8673 char *addtl_info; /* pointer to additional info needed
8674 * for N_CONN_REQ primitive */
8675 int addr_len; /* length of address */
8678 printf( "TRACE: entering x25call\n" );
8682 printf( "x25call( %d, %s )\n", fd, remote_nua );
8683 printf( "connecting to %s on fd %d\n", remote_nua, fd );
8687 * Allocate and zero out space for the N_CONN_REQ primitive
8688 * use the size of the generic NPI primitive control buffer
8690 connreq_ctl = (N_conn_req_t *) malloc(sizeof(N_npi_ctl_t));
8691 if (connreq_ctl == NULL){
8692 perror("kermit: x25call(): connreq_ctl malloc failed");
8695 bzero(connreq_ctl,sizeof(N_npi_ctl_t));
8697 * Build the Connection Request Primitive
8700 connreq_ctl->PRIM_type = (ulong) N_CONN_REQ;
8702 /* Note that the address length is nchai+1 and not n+2. The line number
8703 * is only passed with the address for the bind. The first byte of
8704 * the address for the N_CONN primitives contains the X.121
8705 * address prefix, which must be zero. The remaining bytes are the
8708 addr_len = strlen( remote_nua );
8709 connreq_ctl->DEST_length = (ulong) (addr_len + 1);
8710 connreq_ctl->DEST_offset = (ulong) sizeof(N_conn_req_t);
8711 /* connreq_ctl->CONN_flags = (ulong)EX_DATA_OPT | REC_CONF_OPT; */
8712 connreq_ctl->CONN_flags = (ulong) 0;
8713 connreq_ctl->QOS_length = (ulong) 0; /* unsupported in AIX 4.1 */
8714 connreq_ctl->QOS_offset = (ulong) 0; /* unsupported in AIX 4.1 */
8716 addtl_info = (char *) ((void*)connreq_ctl + connreq_ctl->DEST_offset);
8717 *addtl_info++ = (char) 0; /* X.121 format */
8718 bcopy( remote_nua, addtl_info, addr_len );
8721 * setup the data buffer for the connection request
8723 connreq_data = (N_npi_data_t *) malloc(sizeof(N_npi_data_t));
8724 if (connreq_data == NULL){
8725 perror("kermit: x25call(): connreq_data malloc failed");
8728 bzero(connreq_data,sizeof(N_npi_data_t));
8730 /* facility selection needs to be put in the front of connreq_data */
8731 connreq_data_len = 0;
8732 connreq_data_len += x25facilities( (char *)connreq_data );
8735 (char *)((char *)connreq_data + connreq_data_len),
8738 connreq_data_len += strlen( cud );
8742 * Call putmsg() to put the connection request message on the stream
8744 rc = x25putmsg( fd, (N_npi_ctl_t*)connreq_ctl, connreq_data,
8745 connreq_data_len, &flags );
8751 * Allocate and zero out space for the N_CONN_CON primitive
8753 if ((conncon_ctl = (N_conn_con_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8754 perror("kermit: x25call(): conncon_ctl malloc failed");
8757 bzero(conncon_ctl, sizeof(N_npi_ctl_t));
8760 * Allocate and zero out space for any data associated with N_CONN_CON
8762 if ( (conncon_data = (N_npi_data_t *) malloc(NPI_MAX_DATA)) == NULL) {
8763 perror("kermit: x25call(): conncon_data malloc failed");
8766 bzero(conncon_data, NPI_MAX_DATA);
8768 /* Initialize and build the structures for getmsg */
8771 rc = x25getmsg( fd, (N_npi_ctl_t*)conncon_ctl, (int)sizeof( N_conn_con_t ),
8772 conncon_data, NPI_MAX_DATA, &get_flags, N_CONN_CON );
8774 /* turn quantitive return code into a qualitative one */
8777 /* Free the space that we no longer need */
8778 if (connreq_ctl) { free(connreq_ctl); connreq_ctl = NULL; }
8779 if (conncon_ctl) { free(conncon_ctl); conncon_ctl = NULL; }
8780 if (conncon_data) { free(conncon_data); conncon_data = NULL; }
8783 printf( "TRACE: leaving x25call\n" );
8789 /*****************************************************************************
8790 * Function: x25getcall
8792 * Description: This routine checks for an incomming call, verified
8793 * that it is a CONNIND (connection indication) message, and then
8794 * accepts the call and returns the file descriptor of the new stream
8797 * fd - file descriptor of listening stream
8800 * callfd - file descriptor of connected incomming call.
8801 * - set to -1 if an error occured
8803 *****************************************************************************/
8805 x25getcall(fd) int fd; {
8806 int x25callfd; /* fd of incomming call */
8807 N_conn_ind_t *connind_ctl; /* connind controll buffer */
8808 N_npi_data_t *connind_data; /* connind data buffer */
8809 int get_flags; /* flags for getmsg */
8810 ulong flags; /* connection flags */
8811 int rc; /* return code */
8813 extern x25addr_t remote_nua; /* remote X.25 addr global var */
8816 printf( "TRACE: entering x25getcall\n" );
8819 /* allocate space for connection indication buffers */
8820 if ((connind_ctl = (N_conn_ind_t *)malloc(sizeof(N_npi_ctl_t))) == NULL) {
8821 perror("kermit: x25getcall(): connind_ctl malloc failed");
8824 bzero(connind_ctl, sizeof(N_npi_ctl_t));
8826 if ((connind_data = (N_npi_data_t *)malloc(NPI_MAX_DATA)) == NULL) {
8827 perror("kermit: x25getcall(): connind_data malloc failed");
8830 bzero(connind_data, NPI_MAX_DATA);
8832 /* initialise control structures */
8835 /* call getmsg to check for a connection indication */
8837 (N_npi_ctl_t*)connind_ctl,
8838 (int)sizeof(N_conn_ind_t),
8845 printf( "x25getcall(): errno is: %d\n", errno );
8847 perror ("x25getcall(): getmsg failed");
8851 /* a connection indication was received
8852 * - pull it to bits and answer the call
8854 x25seqno = connind_ctl->SEQ_number;
8855 flags = connind_ctl->CONN_flags;
8857 printf( "setting remote_nua to a new value due to incomming call\n" );
8860 * no guarantee that the address is null terminated, ensure that
8861 * after copying that it is (assumption: remote_nua is longer than
8864 bzero(remote_nua, sizeof(remote_nua));
8865 /* note: connind_ctl contains a x121 address, which has a null as
8866 * the FIRST character - strip it off!
8868 ckstrncpy(remote_nua,
8869 (char*)((char*)connind_ctl + connind_ctl->SRC_offset + 1),
8870 connind_ctl->SRC_length - 1
8873 printf( "remote_nua set to new value of %s\n", remote_nua );
8876 /* errors handled by callee */
8877 x25callfd = x25accept(x25seqno, flags);
8879 /* free the malloc'd buffers */
8880 if (connind_ctl) { free(connind_ctl); connind_ctl = NULL; }
8881 if (connind_data) { free(connind_data); connind_data = NULL; }
8884 printf( "TRACE: leaving x25getcall\n" );
8887 /* return the file descriptor (or error if < 0) */
8888 return( x25callfd );
8891 /*****************************************************************************
8892 * Function: x25accept
8894 * Description: accept an incomming call
8895 * This essentially means opening a new STREAM and sending
8896 * an acknowledge back to the caller.
8899 * seqno - sequence number for acknowledgement
8900 * flags - flags passed to us by the caller
8903 * fd - file descriptor of new STREAM
8904 * set to -1 if an error occured
8906 *****************************************************************************/
8908 x25accept(seqno,flags)
8909 ulong seqno; /* connection sequence number */
8910 ulong flags; /* connection flags */
8912 int x25callfd; /* fd for incomming call */
8913 int get_flags; /* priority flags for getmsg */
8914 int put_flags = 0; /* flags for putmsg, always 0 */
8915 int addr_len; /* length of local address */
8916 ulong token; /* connection token */
8917 N_conn_res_t *conn_res; /* N_CONN_RES primitive */
8918 N_ok_ack_t *ok_ack; /* N_OK_ACK primitive */
8919 char *addtl_info; /* temp pointer */
8920 int rc; /* temporary return code */
8922 /* global variables from ckcmai.c */
8923 extern int revcall, closgr, cudata;
8924 extern char udata[];
8925 extern x25addr_t local_nua; /* local X.25 address */
8926 extern char x25name[]; /* x25 device name (sx25a0) */
8927 extern char x25dev[]; /* x25 device file /dev/x25pkt */
8928 extern int x25port; /* logical port to use */
8929 ulong bind_flags = 0; /* flags for binding the X25 stream */
8932 printf( "TRACE: entering x25accept\n" );
8935 /* open a new packet level stream */
8936 if ((x25callfd = open(x25dev, O_RDWR)) < 0) {
8937 perror ("kermit: x25accept(): X.25 device open error");
8938 debug(F101,"x25accept() device open error","",errno);
8942 /* push the NPI onto the STREAM */
8943 if (ioctl(x25callfd,I_PUSH,"npi") < 0) {
8944 perror( "kermit: x25accept(): couldn't push npi on the X25 stream" );
8945 debug(F101,"x25accept can't push npi on the X25 stream","",errno);
8949 /* bind kermit server to the local X25 address */
8950 /* taken from /usr/samples/sx25/npi/npiserver.c (AIX 4) */
8951 bind_flags |= TOKEN_REQUEST;
8952 token = x25bind(x25callfd,local_nua,(char *)NULL,0,0,x25port,bind_flags);
8954 printf( "kermit: x25accept(): couldn't bind to local X25 address\n" );
8959 /* allocate connection response primitive */
8960 if ((conn_res = (N_conn_res_t *)malloc( NPI_MAX_CTL )) == NULL) {
8961 perror("kermit: x25accept(): conn_res malloc failed");
8964 bzero((char *)conn_res, NPI_MAX_CTL);
8966 /* setup connection response primitive */
8967 addr_len = strlen( local_nua );
8968 conn_res->PRIM_type = (ulong)N_CONN_RES;
8969 conn_res->TOKEN_value = token;
8970 /* note address length is n+1 to accomodate the X.121 address prefix */
8971 conn_res->RES_length = (ulong)(addr_len + 1);
8972 conn_res->RES_offset = (ulong)sizeof( N_conn_res_t );
8973 conn_res->SEQ_number = seqno;
8974 conn_res->CONN_flags = 0;
8975 conn_res->QOS_length = 0; /* unsupported - must be 0 (!?) */
8976 conn_res->QOS_offset = 0;
8978 addtl_info = (char *)((char *)conn_res + conn_res->RES_offset);
8979 *addtl_info++ = (char)0; /* X.121 address prefix */
8980 bcopy( local_nua, addtl_info, addr_len );
8983 * send off the connect response
8985 if (x25putmsg(x25callfd,
8986 (N_npi_ctl_t*)conn_res,
8987 (N_npi_data_t *)NULL,
8991 perror("kermit: x25accept(): putmsg connect response failed");
8996 * Allocate and zero out space for the OK_ACK primitive
8998 if ((ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t))) == NULL) {
8999 perror("kermit: x25call(): ok_ack malloc failed");
9002 bzero(ok_ack, sizeof(N_npi_ctl_t));
9004 /* Initialize and build the structures for getmsg */
9007 rc = (int)x25getmsg(x25callfd,
9008 (N_npi_ctl_t*)ok_ack,
9009 (int)sizeof(N_ok_ack_t),
9010 (N_npi_data_t*)NULL,
9016 /* sequence number is only for disconnecting when not connected !? */
9020 /* free up malloc'ed buffer space */
9021 if (conn_res) { free(conn_res); conn_res = NULL; }
9022 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9025 printf( "TRACE: leaving x25accept\n" );
9028 return( ( rc >= 0 ) ? x25callfd : -1 );
9031 /*****************************************************************************
9032 * Function: x25unbind
9034 * Description: This subroutine builds and sends an unbind request and gets
9035 * the acknowledgement for it.
9038 * fd - File descriptor of the stream
9040 * Functions Referenced:
9048 * -1 - if not successful
9049 *****************************************************************************/
9051 x25unbind(fd) int fd; { /* X25 device (opened) */
9052 int rc; /* return code */
9053 int flags; /* bind flags */
9054 int get_flags; /* priority flag for getmsg */
9055 ulong type; /* primitive type */
9056 N_unbind_req_t *unbind_req; /* pointer to N_UNBIND_REQ */
9057 N_ok_ack_t *ok_ack; /* pointer to N_OK_ACK */
9060 printf( "TRACE: entering x25unbind\n" );
9064 /* printf( "x25unbind( %d )\n", fd ); */
9066 debug(F101,"x25unbind closing x25 connection #","",fd);
9068 /* Allocate and zero out space to hold the N_UNBIND_REQ primitive */
9069 unbind_req = (N_unbind_req_t *) malloc(sizeof(N_npi_ctl_t));
9070 if (unbind_req == NULL) {
9071 perror("kermit: x25unbind(): unbind_req malloc failed");
9074 bzero(unbind_req, sizeof(N_npi_ctl_t));
9077 * Build the Unbind Request Primitive
9080 unbind_req->PRIM_type = (ulong) N_UNBIND_REQ;
9083 * Call putmsg() to put the bind request message on the stream
9086 (N_npi_ctl_t*)unbind_req,
9087 (N_npi_data_t *)NULL,
9091 perror ("kermit: x25unbind(): putmsg failed");
9095 /* Allocate and Zero out space for the N_OK_ACK primitive */
9096 ok_ack = (N_ok_ack_t *) malloc(sizeof(N_npi_ctl_t));
9097 if (ok_ack == NULL) {
9098 perror("kermit x25unbind(): ok_ack malloc failed\n");
9101 bzero(ok_ack, sizeof(N_npi_ctl_t));
9103 /* Initialize and build the control structure for getmsg */
9106 /* Call getmsg() to check for an acknowledgement */
9108 (N_npi_ctl_t*)ok_ack,
9109 (int)sizeof(N_ok_ack_t),
9110 (N_npi_data_t*)NULL,
9116 perror ("kermit: x25unbind: getmsg failed");
9120 /* Free up the space that we no longer need */
9121 if (unbind_req) { free(unbind_req); unbind_req = NULL; }
9122 if (ok_ack) { free(ok_ack); ok_ack = NULL; }
9125 printf( "TRACE: leaving x25unbind\n" );
9131 /*****************************************************************************
9135 * Read n characters from X.25 circuit into buf (AIX only)
9138 * data_buf_len maximum size of data buffer
9139 * data_buf pointer to pre-allocated buffer space
9142 * the number of characters actually read
9145 x25xin(data_buf_len,data_buf) int data_buf_len; CHAR *data_buf; {
9146 struct strbuf getmsg_ctl; /* streams control structure */
9147 struct strbuf getmsg_data; /* streams data structure */
9148 int rc = 0; /* return code */
9149 int getmsg_flags; /* packet priority flags */
9150 char * ctl_buf; /* npi control buffer */
9151 N_npi_ctl_t * result; /* pointer to simplify switch() */
9154 printf( "TRACE: entering x25xin\n" );
9157 /* ensure that no maximum's are overridden */
9158 data_buf_len = (NPI_MAX_DATA < data_buf_len) ? NPI_MAX_DATA : data_buf_len;
9160 /* allocate space for packet control info */
9161 if ((ctl_buf = (char *)malloc(NPI_MAX_CTL)) == NULL) {
9162 perror( "kermit: x25xin(): ctl_buf malloc" );
9166 /* riehm: need zeroed buffer for getmsg? */
9167 bzero( ctl_buf, NPI_MAX_CTL );
9168 /* clear data buffer */
9169 bzero( data_buf, data_buf_len );
9170 #endif /* COMMENT */
9172 getmsg_flags = 0; /* get the first packet available */
9174 rc = x25getmsg(ttyfd,
9185 printf( "kermit: x25xin(): got " );
9186 x25dump_data( data_buf, 0, rc );
9188 printf( "x25xin(): attempt to get data resulted in an error\n" );
9191 #endif /* COMMENT */
9194 if (ctl_buf) { free(ctl_buf); ctl_buf = NULL; }
9197 printf( "TRACE: leaving x25xi\n" );
9203 /*****************************************************************************
9204 * Function: x25write
9207 * write a block of characters to the X25 STREAM (AIX)
9210 * fd file descriptor to write to
9211 * databuf buffer containing data to write
9212 * databufsize size of the buffer to write
9215 * size the number of bytes actually transmitted
9218 x25write(fd, databuf, databufsize)
9219 int fd; /* X25 STREAMS file descriptor (ttyfd) */
9220 char *databuf; /* buffer to write */
9221 int databufsize; /* buffer size */
9223 N_data_req_t *data_req_ctl;
9224 int rc; /* return code (size transmitted) */
9225 int write_flags = 0; /* always 0 !? */
9228 printf( "TRACE: entering x25write\n" );
9231 if ((data_req_ctl = (N_data_req_t *)malloc(NPI_MAX_CTL) ) == NULL) {
9232 perror( "kermit: x25write(): data_req_ctl malloc" );
9235 data_req_ctl->PRIM_type = N_DATA_REQ;
9236 data_req_ctl->DATA_xfer_flags = 0;
9238 /* riehm: possible extension
9239 * possibly need to think about splitting up the data buffer
9240 * into multiple parts if databufsize > NPI_MAX_DATA
9245 printf( "kermit: x25write(): writing data to x25 stream\n" );
9246 printf( "\tdata:\t" );
9247 x25dump_data(databuf, 0, databufsize);
9249 #endif /* COMMENT */
9251 (N_npi_ctl_t*)data_req_ctl,
9252 (N_npi_data_t*)databuf,
9256 if (data_req) { free(data_req_ctl); data_req = NULL; }
9259 printf( "TRACE: leaving x25write\n" );
9265 /*****************************************************************************
9266 * Function: x25local_nua
9269 * This routine is only interesting for IBM computers. In order
9270 * to set up a connection (see x25bind()) you need to know the
9271 * local NUA (x25 address). Unfortunately, you need all this code
9272 * to find that out, I just hope this works for everyone else!
9275 * a pre-allocated character buffer, long enough to hold an X.25 address
9276 * and the tailing null.
9279 * the length of the address string.
9283 x25local_nua(char *buf) {
9284 struct CuAt *response; /* structure to fill with info from ODM */
9285 CLASS_SYMBOL retClass; /* ODM class */
9286 char query[64]; /* odm database query */
9287 int rc = 0; /* return value (length of local NUA) */
9288 extern char x25name[]; /* x25 device name (sx25a0) */
9291 printf( "TRACE: entering x25local_nua\n" );
9294 /* set up query string */
9295 if (x25name[0] == '\0') {
9297 printf( "kermit: x25local_nua(): No x25 device set, trying sx25a0\n" );
9299 strcpy( x25name, "sx25a0" );
9301 ckmakmsg(query, sizeof(query), "name like ",x25name,
9302 " and attribute like local_nua");
9304 /* initialise ODM database */
9306 if (odm_initialize() == -1) {
9307 printf( "x25local_nua(): can't initialize ODM database");
9309 case ODMI_INVALID_PATH:
9310 printf( "invalid path\n" );
9312 case ODMI_MALLOC_ERR:
9313 printf( "malloc failed\n" );
9316 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9321 /* open the CuAt class */
9322 retClass = odm_open_class(CuAt_CLASS);
9323 if (((int)retClass) == -1) {
9324 printf( "kermit: x25local_nua(): can't open CuAt class in odm. " );
9326 case ODMI_CLASS_DNE:
9327 printf( "CuAt class doesn't exist\n" );
9329 case ODMI_CLASS_PERMS:
9330 printf( "permission to CuAt class file denied\n" );
9332 case ODMI_MAGICNO_ERR:
9333 printf( "CuAt is an invalid ODM object class\n" );
9336 printf( "cannot open CuAt class - and don't know why!\n" );
9338 case ODMI_INVALID_PATH:
9339 printf( "invalid path\n" );
9341 case ODMI_TOOMANYCLASSES:
9342 printf( "too many object classes have been opened\n" );
9345 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9351 printf("retClass= %d\n", retClass);
9354 response = (struct CuAt *)odm_get_first( retClass, query, NULL );
9355 if (((int)response) == -1) {
9356 printf( "kermit: x25local_nua(): odm query failed " );
9358 case ODMI_BAD_CRIT: /* Programming error */
9359 printf( "bad search criteria\n" );
9361 case ODMI_CLASS_DNE:
9362 printf( "CuAt class doesn't exist\n" );
9364 case ODMI_CLASS_PERMS:
9365 printf( "permission to CuAt class file denied\n" );
9367 case ODMI_INTERNAL_ERR:
9368 printf("odm internal error\nPlease contact your administrator\n" );
9370 case ODMI_INVALID_CLXN:
9371 printf("CuAt is invalid or inconsistent odm class collection\n");
9373 case ODMI_INVALID_PATH:
9374 printf( "invalid path\n" );
9376 case ODMI_MAGICNO_ERR:
9377 printf( "CuAt is an invalid ODM object class\n" );
9379 case ODMI_MALLOC_ERR:
9380 printf( "malloc failed\n" );
9383 printf( "cannot open CuAt class - and don't know why!\n" );
9385 case ODMI_TOOMANYCLASSES:
9386 printf( "too many object classes have been opened\n" );
9389 printf( "unknown error %d\nPlease call IBM\n", odmerrno );
9394 /* check for a meaningfull response */
9395 if (response != NULL) {
9396 if (response->value != NULL) {
9397 strcpy(buf, response->value);
9401 printf( "attribute name is: %s\n", (char *)response->attribute );
9402 printf( "I think my address is %s\n", (char*)response->value );
9406 printf( "kermit: x25local_nua(): couldn't find the local NUA\n" );
9411 printf( "Error: ODMI_BAD_CRIT - bad criteria\n" );
9413 case ODMI_CLASS_DNE:
9414 printf( "Error: ODMI_CLASS_DNE - class doesn't exist\n" );
9416 case ODMI_CLASS_PERMS:
9417 printf( "Error: ODMI_CLASS_PERMS - class permissions\n" );
9419 case ODMI_INTERNAL_ERR:
9420 printf( "Error: ODMI_INTERNAL_ERR - panic\n" );
9422 case ODMI_INVALID_CLXN:
9423 printf( "Error: ODMI_INVALID_CLXN - invalid collection\n" );
9425 case ODMI_INVALID_PATH:
9426 printf( "Error: ODMI_INVALID_PATH - invalid path - what path?\n" );
9428 case ODMI_MAGICNO_ERR:
9429 printf( "Error: ODMI_MAGICNO_ERR - invalid object magic\n" );
9431 case ODMI_MALLOC_ERR:
9432 printf( "Error: ODMI_MALLOC_ERR - malloc failed\n" );
9435 printf( "Error: ODMI_OPEN_ERR - cannot open class\n" );
9437 case ODMI_TOOMANYCLASSES:
9438 printf( "Error: ODMI_TOOMANYCLASSES - too many classes\n" );
9441 printf( "Unknown error!\n" );
9446 /* close the database again */
9447 odm_close_class( retClass );
9449 /* forget about ODM all together */
9453 printf( "TRACE: leaving x25local_nua\n" );
9456 debug(F110, "x25local_nua local address is ", buf, 0);
9460 /*****************************************************************************
9461 * Function: x25facilities
9464 * build up the facilities data packet for a connection request
9467 * a pre-allocated char buffer, normally NPI_MAX_DATA big.
9470 * the number of characters inserted into the buffer
9473 x25facilities(buffer) char *buffer; {
9476 char *p; /* temp pointer */
9477 char *start; /* temp pointer */
9480 printf( "TRACE: entering x25facilities\n" );
9487 printf( "kermit: x25facilities(): getting X25 facilities\n" );
9492 printf("reverse charge: %d\n", revcall );
9499 printf("closed user group: %d\n", closgr );
9507 printf( "no facilities\n" );
9511 /* set the size of the facilities buffer */
9512 *buffer = (char)( p - start ) & 0xff;
9515 printf( "kermit: x25facilities(): returning %d\n", (int)(p - buffer) );
9519 printf( "TRACE: leaving x25facilities\n" );
9522 /* return the size of the facilities with size byte */
9523 /* 1 == no facilities, 0 byte returned as facilities size */
9524 return( (int)(p - buffer) );
9528 * reset the connection
9531 x25reset(cause, diagn) char cause; char diagn; {
9532 /* not implemented */
9535 printf( "TRACE: entering x25reset\n" );
9539 printf( "TRACE: leaving x25reset\n" );
9546 * clear the x25 connection - ie: hang up
9550 int get_flags = 0; /* priority flag for getmsg */
9551 int put_flags = 0; /* send flags, always 0 */
9552 ulong type; /* primitive type */
9553 N_discon_req_t *discon_req; /* pointer to N_DISCON_REQ */
9554 N_discon_ind_t *discon_ind; /* pointer to N_DISCON_IND */
9555 N_npi_data_t *discon_data; /* pointer to N_DISCON_IND data */
9556 int rc = 0; /* return code */
9559 printf( "TRACE: entering x25clear\n" );
9563 /* printf( "x25clear(): checking last msg: %s\n", x25prim(x25lastmsg)); */
9567 * The following checks are used to ensure that we don't disconnect
9568 * or unbind twice - this seems to throw the NPI interface right out of
9571 switch(x25lastmsg) {
9579 /* printf("x25clear(): actively disconnecting\n"); */
9582 discon_req = (N_discon_req_t *)malloc(NPI_MAX_CTL);
9583 if (discon_req == NULL) {
9584 perror("kermit x25clear(): discon_req malloc failed\n");
9585 /* fallthrough, try to unbind the NPI anyway */
9587 discon_req->PRIM_type = N_DISCON_REQ;
9588 discon_req->DISCON_reason = 0; /* not used by AIX */
9589 discon_req->RES_length = 0;
9590 discon_req->RES_offset = (ulong)(sizeof(N_discon_req_t));
9591 discon_req->SEQ_number = x25seqno; /* global */
9593 if (x25putmsg(ttyfd,
9594 (N_npi_ctl_t*)discon_req,
9595 (N_npi_data_t*)NULL,
9599 perror("x25putmsg failed in x25clear()");
9601 discon_ind = (N_discon_ind_t *)malloc(NPI_MAX_CTL);
9602 discon_data = (N_npi_data_t *)malloc(NPI_MAX_DATA);
9603 if((discon_ind == NULL) || (discon_data == NULL)) {
9604 perror("x25clear(): discon_ind malloc failed\n");
9605 /* fallthrough, try to unbind the NPI anyway */
9608 (N_npi_ctl_t*)discon_ind,
9610 (N_npi_data_t*)discon_data,
9615 perror("x25getmsg failed in x25clear()");
9616 /* fallthrough, try to unbind the NPI anyway */
9624 if (x25lastmsg != N_UNBIND_REQ) {
9625 rc = x25unbind(ttyfd);
9629 printf( "TRACE: leaving x25clear\n" );
9637 * only for debugging
9639 * turn the internal representation of a datablock into something
9640 * half-way readable. Because the length is known, we can print
9641 * the string including null's etc (important, because the first(!)
9642 * byte of an X121 address is a null! (X121 addr == 0 + X25 addr)
9644 x25dump_data(char *addr, ulong offset, ulong length) {
9645 char *ptr = addr + offset;
9647 /* allocate enough memory for all unprintable chars */
9648 char *buf = (char *)malloc( length * 4 );
9649 char *bptr = buf; /* pointer to current place in the print buffer */
9652 if (isprint(*ptr)) {
9656 strcpy(bptr,ckctox(*ptr,1)); bptr += 2;
9664 printf( "%s", buf );
9666 printf( " (%d+%d)\n", offset, length );
9668 if (buf) { free(buf); buf = NULL; }
9673 * only for debugging
9674 * print as much useful information about a packet as possible
9676 x25dump_prim(primitive) N_npi_ctl_t *primitive; {
9677 printf("Primitive");
9678 switch (primitive->PRIM_type) {
9680 printf( "\tN_BIND_ACK\n\taddress:\t" );
9681 x25dump_data( (char *)primitive,
9682 primitive->bind_ack.ADDR_offset,
9683 primitive->bind_ack.ADDR_length );
9684 printf( "\tproto id:\t" );
9685 x25dump_data( (char *)primitive,
9686 primitive->bind_ack.PROTOID_offset,
9687 primitive->bind_ack.PROTOID_length );
9688 printf( "\tconnind:\t%d\n\ttoken:\t\t%d\n",
9689 primitive->bind_ack.CONIND_number,
9690 primitive->bind_ack.TOKEN_value );
9694 printf( "\tN_BIND_REQ\n\taddress:\t" );
9695 x25dump_data( (char *)primitive,
9696 primitive->bind_req.ADDR_offset,
9697 primitive->bind_req.ADDR_length );
9698 printf( "\tproto id:\t" );
9699 x25dump_data( (char *)primitive,
9700 primitive->bind_req.PROTOID_offset,
9701 primitive->bind_req.PROTOID_length );
9702 printf( "\tconnind:\t%d\n\tflags:\t\t%d\n",
9703 primitive->bind_req.CONIND_number,
9704 primitive->bind_req.BIND_flags );
9708 printf( "\tN_CONN_CON\n" );
9709 printf( "\tRES\t\t" );
9710 x25dump_data( (char *)primitive,
9711 primitive->conn_con.RES_offset,
9712 primitive->conn_con.RES_length );
9713 printf( "\tflags:\t%d\n", primitive->conn_con.CONN_flags );
9717 printf( "\tN_CONN_IND\n" );
9718 printf( "\tsource:\t\t" );
9719 x25dump_data( (char *)primitive,
9720 primitive->conn_ind.SRC_offset,
9721 primitive->conn_ind.SRC_length );
9722 printf( "\tdestination:\t" );
9723 x25dump_data( (char *)primitive,
9724 primitive->conn_ind.DEST_offset,
9725 primitive->conn_ind.DEST_length );
9726 printf( "\tSEQ_number:\t%d\n", primitive->conn_ind.SEQ_number );
9727 printf( "\tflags:\t%d\n", primitive->conn_ind.CONN_flags );
9731 printf( "\tN_CONN_REQ\n\tdestination:\t" );
9732 x25dump_data( (char *)primitive,
9733 primitive->conn_req.DEST_offset,
9734 primitive->conn_req.DEST_length );
9735 printf( "\tflags:\t%d\n", primitive->conn_req.CONN_flags );
9739 printf( "\tN_CONN_RES\n" );
9740 printf( "\tTOKEN_value\t%d\n", primitive->conn_res.TOKEN_value );
9741 printf( "\tSEQ_number\t%d\n", primitive->conn_res.SEQ_number );
9742 printf( "\tCONN_flags\t%d\n", primitive->conn_res.CONN_flags );
9743 printf( "\tRES\t\t" );
9744 x25dump_data( (char *)primitive,
9745 primitive->conn_res.RES_offset,
9746 primitive->conn_res.RES_length );
9750 printf( "\tN_DATACK_IND\n" );
9754 printf( "\tN_DATACK_REQ\n" );
9755 printf( "\tflags:\t%d\n", primitive->data_req.DATA_xfer_flags );
9759 printf( "\tN_DATA_IND\n" );
9760 printf( "\tflags:\t%d\n", primitive->data_ind.DATA_xfer_flags );
9764 printf( "\tN_DATA_REQ\n" );
9768 printf( "\tN_DISCON_IND\n" );
9769 printf( "\torigin:\t%d\n", primitive->discon_ind.DISCON_orig );
9770 printf( "\treason:\t\t%d\n", primitive->discon_ind.DISCON_reason );
9771 printf( "\tseq no:\t\t%d\n", primitive->discon_ind.SEQ_number );
9772 printf( "\tRES:\t" );
9773 x25dump_data( (char *)primitive,
9774 primitive->discon_ind.RES_offset,
9775 primitive->discon_ind.RES_length );
9779 printf( "\tN_DISCON_REQ\n" );
9780 printf( "\tDISCON_reason:\t%d\n",
9781 primitive->discon_req.DISCON_reason );
9782 printf( "\tRES:\t" );
9783 x25dump_data( (char *)primitive,
9784 primitive->discon_req.RES_offset,
9785 primitive->discon_req.RES_length );
9786 printf( "\tSEQ_number:\t%d\n", primitive->discon_req.SEQ_number );
9790 printf( "\tN_ERROR_ACK\n" );
9791 printf( "\tCaused by:\t%s\n",
9792 x25prim( primitive->error_ack.ERROR_prim ) );
9793 printf( "\tNPI error:\t%s\n",
9794 x25err( primitive->error_ack.NPI_error ));
9795 errno = primitive->error_ack.UNIX_error;
9800 printf( "\tN_EXDATA_ACK\n" );
9804 printf( "\tN_EXDATA_REQ\n" );
9808 printf( "\tN_INFO_ACK\n" );
9809 printf( "\tNSDU size:\t%d\n", primitive->info_ack.NSDU_size );
9810 printf( "\tENSDU size:\t%d\n", primitive->info_ack.ENSDU_size );
9811 printf( "\tCDATA size:\t%d\n", primitive->info_ack.CDATA_size );
9812 printf( "\tDDATA size:\t%d\n", primitive->info_ack.DDATA_size );
9813 printf( "\tADDR size:\t%d\n", primitive->info_ack.ADDR_size );
9814 printf( "\tNIDU size:\t%d\n", primitive->info_ack.NIDU_size );
9818 printf( "\tN_INFO_REQ\n" );
9822 printf( "\tN_OK_ACK\n" );
9826 printf( "\tN_OPTMGMT_REQ\n" );
9830 printf( "\tN_RESET_CON\n" );
9834 printf( "\tN_RESET_IND\n" );
9835 printf( "\treason:\t\t%d\n", primitive->reset_ind.RESET_reason );
9836 printf( "\torigin:\t\t%d\n", primitive->reset_ind.RESET_orig );
9840 printf( "\tN_RESET_REQ\n" );
9841 printf( "\treason:\t\t%d\n", primitive->reset_req.RESET_reason );
9845 printf( "\tN_RESET_RES\n" );
9849 printf( "\tN_UDERROR_IND\n" );
9853 printf( "\tN_UNBIND_REQ\n" );
9856 case N_UNITDATA_REQ:
9857 printf( "\tN_UNITDATA_REQ\n" );
9860 case N_UNITDATA_IND:
9861 printf( "\tN_UNITDATA_IND\n" );
9865 (void) printf( "Unknown NPI error %d", primitive->PRIM_type );
9871 /* it looks like signal handling is not needed with streams! */
9872 /* x25oobh() - handle SIGURG signals - take from isode ? */
9878 Which time.h files to include... See ckcdeb.h for defaults.
9879 Note that 0, 1, 2, or all 3 of these can be included according to
9880 the symbol definitions.
9886 #endif /* NOTIMEH */
9890 #include <sys/time.h>
9891 #endif /* SYSTIMEH */
9892 #endif /* NOSYSTIMEH */
9896 #include <sys/timeb.h>
9897 #endif /* SYSTIMEBH */
9898 #endif /* NOSYSTIMEBH */
9904 #include <sys/time.h>
9910 #include <sys/time.h>
9913 #include <sys/time.h>
9916 #include <posix/time.h>
9919 #include <sys/time.h>
9925 /* #include <utime.h> */
9929 #endif /* SYSTIMEH */
9938 #include <sys/utime.h>
9940 #define utimbuf _utimbuf
9942 #define utime _utime
9944 #ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
9945 #include <sys/utime.h> /* for extra fields required by */
9946 #else /* 88Open spec. */
9947 #ifdef UTIMEH /* or <utime.h> if requested */
9948 #include <utime.h> /* (SVR4, POSIX) */
9949 #define SYSUTIMEH /* Use this for both cases. */
9951 #endif /* SYSUTIMEH */
9954 #ifdef VMS /* SMS 2007/02/15 */
9956 #endif /* def VMS */
9958 #ifndef HTTP_VERSION
9959 #define HTTP_VERSION "HTTP/1.1"
9960 #endif /* HTTP_VERSION */
9965 http_date(char * date)
9967 http_date(date) char * date;
9968 #endif /* CK_ANSIC */
9970 /* HTTP dates are of the form: "Sun, 06 Oct 1997 20:11:47 GMT" */
9971 /* There are two older formats which we are required to parse
9972 * that we currently do not:
9974 * RFC 850: "Sunday, 06-Oct-97 20:11:47 GMT"
9975 * asctime(): "Sun Nov 6 20:11:47 1997"
9977 * However, it is required that all dates be sent in the form we
9978 * do accept. The other two formats are for compatibility with
9979 * really old servers.
9981 extern char cmdatebuf[18];
9987 j = ckindex(",",date,0,0,0);
9988 ckstrncpy(ldate,&date[j+1],25);
9991 cmcvtate() date changed to return a string pointer.
9995 dp = (char *)cmcvtdate(ldate,0); /* Convert to normal form */
9998 t_tm = *cmdate2tm(dp,1);
10001 From Lucas Hart, 5 Dec 2001:
10002 "On the systems to which I have access (SunOS 4.1.1, Solaris 8, and Tru64),
10003 setting tm_isdst to -1 maintains the correct timezone offsets, i.e., writes
10004 the specified (GMT) time if the buffer size is 21, or the contemporaneous
10005 localtime if the buffer size is 25. Perhaps tm_isdst should be set in
10006 cmdate2tm(), rather than only in http_date."
10008 #ifndef NOTM_ISDST /* For platforms where */
10009 t_tm.tm_isdst = -1; /* tm_isdst doesn't exist. */
10010 #endif /* NOTM_ISDST */
10012 t = mktime(&t_tm); /* NOT PORTABLE */
10016 #endif /* XX_TIMEZONE */
10020 #endif /* CMDATE2TM */
10024 static char nowstr[32];
10027 time_t ltime; /* NOT PORTABLE */
10031 gmt = gmtime(<ime); /* PROBABLY NOT PORTABLE */
10032 strftime(nowstr,32,"%a, %d %b %Y %H:%M:%S GMT",gmt); /* NOT PORTABLE */
10033 /* not only is it not portable but it's locale-dependent */
10036 This is hopeless. First of all, it seems that HTTP wants Day and Month
10037 NAMES? In English? Whose idea was that? Even worse, the date/time must be
10038 expressed in Zulu (UTC (GMT)), and converting from local time to GMT is a
10039 nightmare. Every platform does it differently, if at all -- even if we
10040 restrict ourselves to UNIX. For example (quoting from recent C-Kermit edit
10041 history), "Fixed a longstanding bug in the BSDI version, in which incoming
10042 file dates were set in GMT rather than local time. It seems in 4.4BSD,
10043 localtime() does not return the local time, but rather Zero Meridian (Zulu)
10044 time (GMT), and must be adjusted by the tm_gmtoff value." Swell. For
10045 greater appreciation of the scope of the problem, just take a look at the
10046 time-related #ifdefs in ckutio.c. The only right way to do this is to add
10047 our own portable API for converting between local time and GMT/UTC/Zulu
10048 that shields us not only from UNIXisms like time_t and struct tm, but also
10049 the unbelievable amount of differences in time-related APIs -- e.g. is
10050 "timezone" an external variable or a function; which header file(s) do we
10051 include, etc etc etc. It's a major project.
10054 x = cmcvtdate("",1);
10056 Evidently this code is not used -- if it is, it must be fixed to use
10057 new (aug 2001) cmcvtdate() calling conventions.
10061 /* yyyymmdd hh:mm:ss */
10062 /* 01234567890123456 */
10063 nowstr[0] = 'X'; /* 1st letter of day */
10064 nowstr[1] = 'x'; /* 2nd letter of day */
10065 nowstr[2] = 'x'; /* 3rd letter of day */
10068 nowstr[5] = cmdate[6];
10069 nowstr[6] = cmdate[7];
10071 nowstr[8] = ' '; /* first letter of month */
10072 nowstr[9] = ' '; /* second letter of month */
10073 nowstr[10] = ' '; /* third letter of month */
10075 nowstr[12] = cmdate[0];
10076 nowstr[13] = cmdate[1];
10077 nowstr[14] = cmdate[2];
10078 nowstr[15] = cmdate[3];
10080 nowstr[17] = cmdate[9];
10081 nowstr[18] = cmdate[10];
10082 nowstr[19] = cmdate[11];
10083 nowstr[20] = cmdate[12];
10084 nowstr[21] = cmdate[13];
10085 nowstr[22] = cmdate[14];
10086 nowstr[23] = cmdate[15];
10087 nowstr[24] = cmdate[16];
10093 #endif /* CMDATE2TM */
10098 #ifndef CK_AUTHENTICATION
10099 /* from ckuusr.h, which this module normally doesn't include */
10100 _PROTOTYP( int dclarray, (char, int) );
10101 #endif /* CK_AUTHENTICATION */
10104 Assign http response pairs to given array.
10105 For best results, response pairs should contain no spaces.
10108 resp = pointer to response list.
10109 n = size of response list.
10110 array = array letter.
10113 >= 1, size of array, on success.
10117 http_mkarray(char ** resp, int n, char array)
10119 http_mkarray(resp, n, array) char ** resp; int n; char array;
10120 #endif /* CK_ANSIC */
10125 extern char ** a_ptr[];
10126 extern int a_dim[];
10128 if (!array || n <= 0)
10130 if ((x = dclarray(array,n)) < 0) {
10131 printf("?Array declaration failure\n");
10134 /* Note: argument array is 0-based but Kermit array is 1-based */
10136 ap[0] = NULL; /* 0th element is empty */
10137 for (i = 1; i <= n; i++) {
10138 ap[i] = resp[i-1]; /* If resp elements were malloc'd */
10148 #define HTTPHEADCNT 64
10150 http_get_chunk_len()
10157 while ((ch = http_inc(0)) >= 0 && i < 24) {
10159 if ( buf[i] == ';' ) /* Find chunk-extension (if any) */
10161 if ( buf[i] == 10 ) { /* found end of line */
10162 if (i > 0 && buf[i-1] == 13)
10169 if ( i < 24 ) { /* buf now contains len in Hex */
10170 len = hextoulong(buf, j == -1 ? i : j-1);
10179 return(httpfd != -1);
10185 return(httpfd != -1 ? http_host_port : "");
10191 if ( httpfd == -1 )
10194 if (tls_http_active_flag) {
10195 SSL_CIPHER * cipher;
10196 const char *cipher_list;
10197 static char buf[128];
10199 cipher = SSL_get_current_cipher(tls_http_con);
10200 cipher_list = SSL_CIPHER_get_name(cipher);
10201 SSL_CIPHER_description(cipher,buf,sizeof(buf));
10204 #endif /* CK_SSL */
10212 char * s = NULL; /* strdup is not portable */
10213 if ( tcp_http_proxy ) {
10215 makestr(&s,(char *)http_host_port);
10217 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10218 if (*p == ':') { /* Have a colon */
10219 *p++ = '\0'; /* Get service name or number */
10223 rc = http_open(s,p,http_ssl,NULL,0,http_agent);
10225 makestr(&s,(char *)http_ip);
10226 rc = http_open(s,ckuitoa(http_port),http_ssl,NULL,0,http_agent);
10235 http_open(char * hostname, char * svcname, int use_ssl, char * rdns_name,
10236 int rdns_len, char * agent)
10237 #else /* CK_ANSIC */
10238 http_open(hostname, svcname, use_ssl, rdns_name, rdns_len, agent)
10245 #endif /* CK_ANSIC */
10247 char namecopy[NAMECPYL];
10252 #ifdef SO_OOBINLINE
10254 #endif /* SO_OOBINLINE */
10255 struct servent *service=NULL;
10256 struct hostent *host=NULL;
10257 struct sockaddr_in r_addr;
10258 struct sockaddr_in sin;
10259 struct sockaddr_in l_addr;
10260 GSOCKNAME_T l_slen;
10262 struct sockaddr_in send_socket;
10263 #endif /* EXCELAN */
10266 /* inet_addr() is of type struct in_addr */
10268 extern struct in_addr inet_addr();
10271 extern struct in_addr inet_addr();
10272 #endif /* HPUX5WINTCP */
10273 #endif /* datageneral */
10274 struct in_addr iax;
10277 struct in_addr iax;
10278 #else /* INADDR_NONE */
10280 #endif /* INADDR_NONE */
10281 #endif /* INADDRX */
10283 if ( rdns_name == NULL || rdns_len < 0 )
10286 *http_ip = '\0'; /* Initialize IP address string */
10287 namecopy[0] = '\0';
10291 debug(F110,"http_open hostname",hostname,0);
10292 debug(F110,"http_open svcname",svcname,0);
10295 if (!hostname) hostname = "";
10296 if (!svcname) svcname = "";
10297 if (!*hostname || !*svcname) return(-1);
10300 service = ckgetservice(hostname,svcname,http_ip,20);
10302 if (service == NULL) {
10304 printf("?Invalid service: %s\r\n",svcname);
10308 /* For HTTP connections we must preserve the original hostname and */
10309 /* service requested so we can include them in the Host header. */
10310 ckmakmsg(http_host_port,sizeof(http_host_port),hostname,":",
10311 ckuitoa(ntohs(service->s_port)),NULL);
10312 http_port = ntohs(service->s_port);
10313 http_ssl = use_ssl;
10314 debug(F111,"http_open",http_host_port,http_port);
10316 /* 'http_ip' contains the IP address to which we want to connect */
10317 /* 'svcnam' contains the service name */
10318 /* 'service->s_port' contains the port number in network byte order */
10320 /* If we are using an http proxy, we need to create a buffer containing */
10321 /* hostname:port-number */
10322 /* to pass to the http_connect() function. Then we need to replace */
10323 /* 'namecopy' with the name of the proxy server and the service->s_port */
10324 /* with the port number of the proxy (default port 80). */
10326 if ( tcp_http_proxy ) {
10328 ckmakmsg(proxycopy,sizeof(proxycopy),hostname,":",
10329 ckuitoa(ntohs(service->s_port)),NULL);
10330 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10332 p = namecopy; /* Was a service requested? */
10333 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10334 if (*p == ':') { /* Have a colon */
10335 debug(F110,"http_open name has colon",namecopy,0);
10336 *p++ = '\0'; /* Get service name or number */
10338 strcpy(++p,"http");
10341 service = ckgetservice(namecopy,p,http_ip,20);
10343 fprintf(stderr, "Can't find port for service %s\n", p);
10345 debug(F101,"http_open can't get service for proxy","",socket_errno);
10347 debug(F101,"http_open can't get service for proxy","",errno);
10348 #endif /* TGVORWIN */
10349 errno = 0; /* (rather than mislead) */
10353 /* copy the proxyname and remove the service if any so we can use
10354 * it as the hostname
10356 ckstrncpy(namecopy,tcp_http_proxy,NAMECPYL);
10357 p = namecopy; /* Was a service requested? */
10358 while (*p != '\0' && *p != ':') p++; /* Look for colon */
10359 if (*p == ':') { /* Have a colon */
10360 *p = '\0'; /* terminate string */
10362 hostname = namecopy; /* use proxy as hostname */
10365 /* Set up socket structure and get host address */
10366 bzero((char *)&r_addr, sizeof(r_addr));
10367 debug(F100,"http_open bzero ok","",0);
10370 debug(F101,"http_open INADDR_NONE defined","",INADDR_NONE);
10371 #else /* INADDR_NONE */
10372 debug(F100,"http_open INADDR_NONE not defined","",0);
10373 #endif /* INADDR_NONE */
10375 debug(F100,"http_open INADDRX defined","",0);
10376 #else /* INADDRX */
10377 debug(F100,"http_open INADDRX not defined","",0);
10378 #endif /* INADDRX */
10382 iax = inet_addr(http_ip[0]?http_ip:hostname);
10383 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10384 #else /* INADDRX */
10386 iax.s_addr = inet_addr(http_ip[0]?http_ip:hostname);
10387 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax.s_addr);
10388 #else /* INADDR_NONE */
10389 #ifndef datageneral
10390 iax = (unsigned int) inet_addr(http_ip[0]?http_ip:hostname);
10393 #endif /* datageneral */
10394 debug(F111,"http_open inet_addr",http_ip[0]?http_ip:hostname,iax);
10395 #endif /* INADDR_NONE */
10396 #endif /* INADDRX */
10401 /* This might give warnings on 64-bit platforms but they should be harmless */
10402 /* because INADDR_NONE should be all 1's anyway, thus the OR part is */
10403 /* probably superfluous -- not sure why it's even there, maybe it should be */
10405 iax.s_addr == INADDR_NONE /* || iax.s_addr == (unsigned long) -1L */
10406 #else /* INADDR_NONE */
10408 #endif /* INADDR_NONE */
10411 printf(" DNS Lookup... ");
10414 if ((host = gethostbyname(http_ip[0] ? http_ip : hostname)) != NULL) {
10415 debug(F100,"http_open gethostbyname != NULL","",0);
10416 host = ck_copyhostent(host);
10417 dns = 1; /* Remember we performed dns lookup */
10418 r_addr.sin_family = host->h_addrtype;
10419 if (tcp_rdns && host->h_name && host->h_name[0] && (rdns_len > 0)
10420 && (tcp_http_proxy == NULL)
10422 ckmakmsg(rdns_name,rdns_len,host->h_name,":",svcname,NULL);
10426 /* This is for trying multiple IP addresses - see <netdb.h> */
10427 if (!(host->h_addr_list))
10429 bcopy(host->h_addr_list[0],
10430 (caddr_t)&r_addr.sin_addr,
10434 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10435 #endif /* h_addr */
10436 #else /* HADDRLIST */
10437 bcopy(host->h_addr, (caddr_t)&r_addr.sin_addr, host->h_length);
10438 #endif /* HADDRLIST */
10441 debug(F111,"BCOPY","host->h_addr",host->h_addr);
10442 #endif /* EXCELAN */
10443 debug(F111,"BCOPY"," (caddr_t)&r_addr.sin_addr",
10444 (caddr_t)&r_addr.sin_addr);
10445 debug(F111,"BCOPY"," r_addr.sin_addr.s_addr",
10446 r_addr.sin_addr.s_addr);
10447 #endif /* COMMENT */
10448 debug(F111,"BCOPY","host->h_length",host->h_length);
10451 #endif /* NOMHHOST */
10455 /* inet_addr() is of type struct in_addr */
10456 struct in_addr ina;
10458 debug(F100,"http_open gethostbyname == NULL: INADDRX","",0);
10459 ina = inet_addr(http_ip[0]?http_ip:hostname);
10460 uu = *(unsigned int *)&ina;
10461 #else /* Not INADDRX */
10462 /* inet_addr() is unsigned long */
10464 debug(F100,"http_open gethostbyname == NULL: Not INADDRX","",0);
10465 uu = inet_addr(http_ip[0]?http_ip:hostname);
10466 #endif /* INADDRX */
10467 debug(F101,"http_open uu","",uu);
10470 !(uu == INADDR_NONE || uu == (unsigned int) -1L)
10471 #else /* INADDR_NONE */
10472 uu != ((unsigned long)-1)
10473 #endif /* INADDR_NONE */
10475 r_addr.sin_addr.s_addr = uu;
10476 r_addr.sin_family = AF_INET;
10479 fprintf(stdout, "\r\n"); /* complete any previous message */
10481 fprintf(stderr, "Can't get address for %s\n",
10482 http_ip[0]?http_ip:hostname);
10484 debug(F101,"http_open can't get address","",socket_errno);
10486 debug(F101,"http_open can't get address","",errno);
10487 #endif /* TGVORWIN */
10488 errno = 0; /* Rather than mislead */
10493 /* Get a file descriptor for the connection. */
10495 r_addr.sin_port = service->s_port;
10496 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10497 debug(F110,"http_open trying",http_ip,0);
10498 if (!quiet && *http_ip) {
10499 printf(" Trying %s... ", http_ip);
10503 /* Loop to try additional IP addresses, if any. */
10507 send_socket.sin_family = AF_INET;
10508 send_socket.sin_addr.s_addr = 0;
10509 send_socket.sin_port = 0;
10510 if ((httpfd = socket(SOCK_STREAM, (struct sockproto *)0,
10511 &send_socket, SO_REUSEADDR)) < 0)
10512 #else /* EXCELAN */
10513 if ((httpfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
10514 #endif /* EXCELAN */
10517 experror("TCP socket error");
10521 errno = socket_errno;
10522 #endif /* OLD_TWG */
10523 socket_perror("TCP socket error");
10524 debug(F101,"http_open socket error","",socket_errno);
10526 perror("TCP socket error");
10527 debug(F101,"http_open socket error","",errno);
10528 #endif /* TGVORWIN */
10529 #endif /* EXCELAN */
10534 /* If a specific TCP address on the local host is desired we */
10535 /* must bind it to the socket. */
10536 #ifndef datageneral
10540 debug(F110,"http_open binding socket to",tcp_address,0);
10541 bzero((char *)&sin,sizeof(sin));
10542 sin.sin_family = AF_INET;
10544 inaddrx = inet_addr(tcp_address);
10545 sin.sin_addr.s_addr = *(unsigned long *)&inaddrx;
10547 sin.sin_addr.s_addr = inet_addr(tcp_address);
10548 #endif /* INADDRX */
10550 if (bind(httpfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
10551 s_errno = socket_errno; /* Save error code */
10553 socket_close(httpfd);
10554 #else /* TCPIPLIB */
10556 #endif /* TCPIPLIB */
10558 errno = s_errno; /* and report this error */
10559 debug(F101,"http_open bind errno","",errno);
10563 #endif /* datageneral */
10565 /* Now connect to the socket on the other end. */
10568 if (connect(httpfd, &r_addr) < 0)
10571 WSASafeToCancel = 1;
10573 if (connect(httpfd, (struct sockaddr *)&r_addr, sizeof(r_addr)) < 0)
10574 #endif /* EXCELAN */
10577 WSASafeToCancel = 0;
10585 i = errno; /* Save error code */
10586 #endif /* TGVORWIN */
10590 if (host && host->h_addr_list && host->h_addr_list[1]) {
10592 host->h_addr_list++;
10593 bcopy(host->h_addr_list[0],
10594 (caddr_t)&r_addr.sin_addr,
10597 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10598 debug(F110,"http_open h_addr_list",http_ip,0);
10599 if (!quiet && *http_ip) {
10600 printf(" Trying %s... ", http_ip);
10604 socket_close(httpfd); /* Close it. */
10607 #endif /* TCPIPLIB */
10610 #endif /* h_addr */
10611 #endif /* HADDRLIST */
10614 errno = i; /* And report this error */
10616 if (errno) experror("http_open connect");
10619 debug(F101,"http_open connect error","",socket_errno);
10620 /* if (errno) socket_perror("http_open connect"); */
10622 errno = socket_errno;
10623 #endif /* OLD_TWG */
10625 socket_perror("http_open connect");
10626 #else /* TGVORWIN */
10627 debug(F101,"http_open connect errno","",errno);
10630 perror("\r\nFailed");
10637 perror("http_open connect");
10638 #endif /* DEC_TCPIP */
10641 perror("http_open connect");
10642 #endif /* CMU_TCPIP */
10643 #endif /* TGVORWIN */
10644 #endif /* EXCELAN */
10648 WSASafeToCancel = 0;
10651 } while (!isconnect);
10653 #ifdef NON_BLOCK_IO
10655 x = socket_ioctl(httpfd,FIONBIO,&on);
10656 debug(F101,"http_open FIONBIO","",x);
10657 #endif /* NON_BLOCK_IO */
10659 /* We have succeeded in connecting to the HTTP PROXY. So now we */
10660 /* need to attempt to connect through the proxy to the actual host */
10661 /* If that is successful, we have to pretend that we made a direct */
10662 /* connection to the actual host. */
10664 if ( tcp_http_proxy ) {
10667 agent = "Kermit 95"; /* Default user agent */
10670 agent = "C-Kermit";
10673 if (http_connect(httpfd,
10674 tcp_http_proxy_agent ? tcp_http_proxy_agent : agent,
10676 tcp_http_proxy_user,
10677 tcp_http_proxy_pwd,
10686 #ifdef SO_OOBINLINE
10687 /* See note on SO_OOBINLINE in netopen() */
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);
10698 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10701 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10705 Maybe this applies to all SVR4 versions, but the other (else) way has been
10706 compiling and working fine on all the others, so best not to change it.
10708 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10711 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10716 rc = setsockopt(httpfd,
10722 debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
10725 #ifdef VMS /* or, at least, VMS with gcc */
10726 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10729 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
10731 setsockopt(httpfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
10736 #endif /* SOLARIS */
10737 #endif /* MOTSV88R4 */
10741 #endif /* datageneral */
10742 #endif /* SO_OOBINLINE */
10745 #ifndef datageneral
10748 no_delay(ttyfd,tcp_nodelay);
10749 #endif /* TCP_NODELAY */
10750 #ifdef SO_KEEPALIVE
10751 keepalive(ttyfd,tcp_keepalive);
10752 #endif /* SO_KEEPALIVE */
10754 ck_linger(ttyfd,tcp_linger, tcp_linger_tmo);
10755 #endif /* SO_LINGER */
10757 sendbuf(ttyfd,tcp_sendbuf);
10758 #endif /* SO_SNDBUF */
10760 recvbuf(ttyfd,tcp_recvbuf);
10761 #endif /* SO_RCVBUF */
10762 #endif /* SOL_SOCKET */
10763 #endif /* datageneral */
10764 #endif /* NOTCPOPTS */
10766 #ifndef datageneral
10767 /* Find out our own IP address. */
10768 /* We need the l_addr structure for [E]KLOGIN. */
10769 l_slen = sizeof(l_addr);
10770 bzero((char *)&l_addr, l_slen);
10772 if (!getsockname(httpfd, (struct sockaddr *)&l_addr, &l_slen)) {
10773 char * s = (char *)inet_ntoa(l_addr.sin_addr);
10774 ckstrncpy(myipaddr, s, 20);
10775 debug(F110,"getsockname",myipaddr,0);
10777 #endif /* EXCELAN */
10778 #endif /* datageneral */
10780 /* See note in netopen() on Reverse DNS lookups */
10781 if (tcp_rdns == SET_ON) {
10787 printf(" Reverse DNS Lookup... ");
10790 if (host = gethostbyaddr((char *)&r_addr.sin_addr,4,PF_INET)) {
10792 host = ck_copyhostent(host);
10793 debug(F100,"http_open gethostbyname != NULL","",0);
10799 if (!s) { /* This can happen... */
10800 debug(F100,"http_open host->h_name is NULL","",0);
10803 /* Something is wrong with inet_ntoa() on HPUX 10.xx */
10804 /* The compiler says "Integral value implicitly converted to */
10805 /* pointer in assignment." The prototype is right there */
10806 /* in <arpa/inet.h> so what's the problem? */
10807 /* Ditto in HP-UX 5.x, but not 8.x or 9.x... */
10808 if (!*s) { /* No name so substitute the address */
10809 debug(F100,"http_open host->h_name is empty","",0);
10810 s = inet_ntoa(r_addr.sin_addr); /* Convert address to string */
10811 if (!s) /* Trust No 1 */
10813 if (*s) { /* If it worked, use this string */
10814 ckstrncpy(http_ip,s,20);
10816 s = http_ip; /* Otherwise stick with the IP */
10817 if (!*s) /* or failing that */
10818 s = http_host_port; /* the name we were called with. */
10820 if (*s) /* return the rdns name */
10821 ckmakmsg(rdns_name,rdns_len,s,":",svcname,NULL);
10828 printf(" %s connected on port %s\n",s,
10829 ckuitoa(ntohs(service->s_port)));
10831 /* This is simply for testing the DNS entries */
10832 if (host->h_aliases) {
10833 char ** a = host->h_aliases;
10835 printf(" alias => %s\n",*a);
10839 #endif /* BETADEBUG */
10842 if (!quiet) printf("Failed.\n");
10844 } else if (!quiet) printf("(OK)\n");
10845 if (!quiet) fflush(stdout);
10848 if ( tcp_http_proxy ) {
10849 /* Erase the IP address since we cannot reuse it */
10852 /* This should already have been done but just in case */
10853 ckstrncpy(http_ip,(char *)inet_ntoa(r_addr.sin_addr),20);
10855 makestr(&http_agent,agent);
10858 if (use_ssl && ck_ssleay_is_installed()) {
10859 if (!ssl_http_init(hostname)) {
10860 if (bio_err!=NULL) {
10861 BIO_printf(bio_err,"ssl_tn_init() failed\n");
10862 ERR_print_errors(bio_err);
10865 fprintf(stderr,"ssl_tn_init() failed\n");
10866 ERR_print_errors_fp(stderr);
10870 } else if ( ck_ssl_http_client(httpfd,hostname) < 0 ) {
10875 #endif /* CK_SSL */
10876 #endif /* TCPSOCKET */
10878 return(0); /* Done. */
10884 #else /* CK_ANSIC */
10886 #endif /* CK_ANSIC */
10889 debug(F101,"http_close","",httpfd);
10891 #ifdef HTTP_BUFFERING
10894 #endif /* HTTP_BUFFERING */
10896 if (httpfd == -1) /* Was open? */
10897 return(0); /* Wasn't. */
10900 if (httpfd > -1) /* Was. */
10904 if (tls_http_active_flag) {
10905 if (ssl_debug_flag)
10906 BIO_printf(bio_err,"calling SSL_shutdown\n");
10907 SSL_shutdown(tls_http_con);
10908 tls_http_active_flag = 0;
10910 #endif /* CK_SSL */
10912 x = socket_close(httpfd); /* Close it. */
10917 #endif /* TCPIPLIB */
10919 httpfd = -1; /* Mark it as closed. */
10920 /* do not erase http_host_port, http_ip, http_port so they */
10921 /* can be used by http_reopen() */
10927 * Call with s = pointer to string, n = length.
10928 * Returns number of bytes actually written on success, or
10929 * -1 on i/o error, -2 if called improperly.
10933 http_tol(s,n) CHAR *s; int n; {
10938 if (httpfd == -1) {
10939 debug(F100,"http_tol socket is closed","",0);
10942 debug(F101,"http_tol TCPIPLIB ttnet","",ttnet);
10944 ckhexdump("http_tol",s,n);
10945 #endif /* COMMENT */
10948 if (tls_http_active_flag) {
10950 /* Write using SSL */
10952 r = SSL_write(tls_http_con, s, len /* >1024?1024:len */);
10953 switch (SSL_get_error(tls_http_con,r)) {
10954 case SSL_ERROR_NONE:
10955 debug(F111,"http_tol","SSL_write",r);
10961 case SSL_ERROR_WANT_WRITE:
10962 debug(F100,"http_tol SSL_ERROR_WANT_WRITE","",0);
10964 case SSL_ERROR_WANT_READ:
10965 debug(F100,"http_tol SSL_ERROR_WANT_READ","",0);
10967 case SSL_ERROR_SYSCALL:
10968 if ( r == 0 ) { /* EOF */
10974 int gle = GetLastError();
10975 debug(F111,"http_tol SSL_ERROR_SYSCALL",
10976 "GetLastError()",gle);
10977 rc = os2socketerror(gle);
10980 else if ( rc == -2 )
10985 case SSL_ERROR_WANT_X509_LOOKUP:
10986 debug(F100,"http_tol SSL_ERROR_WANT_X509_LOOKUP","",0);
10989 case SSL_ERROR_SSL:
10990 debug(F100,"http_tol SSL_ERROR_SSL","",0);
10993 case SSL_ERROR_ZERO_RETURN:
10994 debug(F100,"http_tol SSL_ERROR_ZERO_RETURN","",0);
10998 debug(F100,"http_tol SSL_ERROR_?????","",0);
11003 #endif /* CK_SSL */
11006 try++; /* Increase the try counter */
11013 debug(F101,"http_tol BSDSELECT","",0);
11017 WSASafeToCancel = 1;
11021 #endif /* STREAMING */
11023 FD_SET(httpfd, &wfds);
11024 if (select(FD_SETSIZE, NULL,
11028 #endif /* __DECC_VER */
11029 #endif /* __DECC */
11030 &wfds, NULL, &tv) < 0) {
11031 int s_errno = socket_errno;
11032 debug(F101,"http_tol select failed","",s_errno);
11034 printf("http_tol select failed: %d\n", s_errno);
11035 #endif /* BETADEBUG */
11037 WSASafeToCancel = 0;
11038 if (!win95selectbug)
11042 if (!FD_ISSET(httpfd, &wfds)) {
11046 #endif /* STREAMING */
11047 debug(F111,"http_tol","!FD_ISSET",ttyfd);
11049 WSASafeToCancel = 0;
11050 if (!win95selectbug)
11055 WSASafeToCancel = 0;
11057 #else /* BSDSELECT */
11061 debug(F101,"http_tol IBMSELECT","",0);
11062 while (select(&httpfd, 0, 1, 0, 1000) != 1) {
11064 if (tries++ >= 60) {
11065 /* if after 60 seconds we can't get permission to write */
11066 debug(F101,"http_tol select failed","",socket_errno);
11070 if ((count = http_tchk()) < 0) {
11071 debug(F111,"http_tol","http_tchk()",count);
11074 #endif /* COMMENT */
11077 #endif /* IBMSELECT */
11078 #endif /* BSDSELECT */
11080 if ((count = socket_write(httpfd,s,n)) < 0) {
11081 int s_errno = socket_errno; /* maybe a function */
11082 debug(F101,"http_tol socket_write error","",s_errno);
11084 if (os2socketerror(s_errno) < 0)
11087 return(-1); /* Call it an i/o error */
11089 #else /* TCPIPLIB */
11090 if ((count = write(httpfd,s,n)) < 0) {
11091 debug(F101,"http_tol socket_write error","",errno);
11092 return(-1); /* Call it an i/o error */
11094 #endif /* TCPIPLIB */
11096 debug(F111,"http_tol socket_write",s,count);
11098 /* don't try more than 25 times */
11099 debug(F100,"http_tol tried more than 25 times","",0);
11106 debug(F111,"http_tol retry",s,n);
11107 goto http_tol_retry;
11109 debug(F111,"http_tol socket_write",s,count);
11110 return(len); /* success - return total length */
11116 http_inc(timo) int timo; {
11117 int x=-1; unsigned char c; /* The locals. */
11119 if (httpfd == -1) {
11120 #ifdef HTTP_BUFFERING
11123 #endif /* HTTP_BUFFERING */
11124 debug(F100,"http_inc socket is closed","",0);
11130 * In the case of OpenSSL, it is possible that there is still
11131 * data waiting in the SSL session buffers that has not yet
11132 * been read by Kermit. If this is the case we must process
11133 * it without calling select() because select() will not return
11134 * with an indication that there is data to be read from the
11135 * socket. If there is no data pending in the SSL session
11136 * buffers then fall through to the select() code and wait for
11137 * some data to arrive.
11139 if (tls_http_active_flag) {
11142 x = SSL_pending(tls_http_con);
11144 debug(F111,"http_inc","SSL_pending error",x);
11147 } else if ( x > 0 ) {
11149 x = SSL_read(tls_http_con, &c, 1);
11150 error = SSL_get_error(tls_http_con,x);
11152 case SSL_ERROR_NONE:
11153 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11156 ReleaseTCPIPMutex();
11158 return(c); /* Return character. */
11159 } else if (x < 0) {
11161 ReleaseTCPIPMutex();
11167 ReleaseTCPIPMutex();
11171 case SSL_ERROR_WANT_WRITE:
11172 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11174 ReleaseTCPIPMutex();
11177 case SSL_ERROR_WANT_READ:
11178 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11180 ReleaseTCPIPMutex();
11183 case SSL_ERROR_SYSCALL:
11184 if ( x == 0 ) { /* EOF */
11187 ReleaseTCPIPMutex();
11193 int gle = GetLastError();
11194 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11195 "GetLastError()",gle);
11196 rc = os2socketerror(gle);
11199 else if ( rc == -2 )
11203 ReleaseTCPIPMutex();
11207 case SSL_ERROR_WANT_X509_LOOKUP:
11208 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11211 ReleaseTCPIPMutex();
11214 case SSL_ERROR_SSL:
11215 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11218 #endif /* COMMENT */
11220 ReleaseTCPIPMutex();
11223 case SSL_ERROR_ZERO_RETURN:
11224 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11227 ReleaseTCPIPMutex();
11231 debug(F100,"http_inc SSL_ERROR_?????","",0);
11234 ReleaseTCPIPMutex();
11240 #endif /* CK_SSL */
11242 #ifdef HTTP_BUFFERING
11243 /* Skip all the select() stuff if we have bytes buffered locally */
11244 if (http_count > 0)
11245 goto getfrombuffer;
11246 #endif /* HTTP_BUFFERING */
11252 int timeout = timo < 0 ? -timo : 1000 * timo;
11253 debug(F101,"http_inc BSDSELECT","",timo);
11255 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11257 debug(F111,"http_inc","timeout",timeout);
11258 /* Don't move select() initialization out of the loop. */
11260 FD_SET(httpfd, &rfds);
11261 tv.tv_sec = tv.tv_usec = 0L;
11263 tv.tv_usec = (long) 100000L;
11267 WSASafeToCancel = 1;
11269 rc = select(FD_SETSIZE,
11272 #endif /* __DECC */
11273 &rfds, NULL, NULL, &tv);
11275 int s_errno = socket_errno;
11276 debug(F111,"http_inc","select",rc);
11277 debug(F111,"http_inc","socket_errno",s_errno);
11278 #ifdef HTTP_BUFFERING
11281 #endif /* HTTP_BUFFERING */
11285 debug(F111,"http_inc","select",rc);
11287 WSASafeToCancel = 0;
11289 if (FD_ISSET(httpfd, &rfds)) {
11293 /* If waiting forever we have no way of knowing if the */
11294 /* socket closed so try writing a 0-length TCP packet */
11295 /* which should force an error if the socket is closed */
11298 if ((rc = socket_write(httpfd,"",0)) < 0) {
11299 #ifdef HTTP_BUFFERING
11302 #endif /* HTTP_BUFFERING */
11303 int s_errno = socket_errno;
11304 debug(F101,"http_inc socket_write error","",s_errno);
11306 if (os2socketerror(s_errno) < 0)
11309 return(-1); /* Call it an i/o error */
11311 #else /* TCPIPLIB */
11312 if ((rc = write(httpfd,"",0)) < 0) {
11313 #ifdef HTTP_BUFFERING
11316 #endif /* HTTP_BUFFERING */
11317 debug(F101,"http_inc socket_write error","",errno);
11318 return(-1); /* Call it an i/o error */
11320 #endif /* TCPIPLIB */
11326 WSASafeToCancel = 0;
11328 #else /* !BSDSELECT */
11331 Was used by OS/2, currently not used, but might come in handy some day...
11332 ... and it came in handy! For our TCP/IP layer, it avoids all the fd_set
11333 and timeval stuff since this is the only place where it is used.
11335 int socket = httpfd;
11336 int timeout = timo < 0 ? -timo : 1000 * timo;
11338 debug(F101,"http_inc IBMSELECT","",timo);
11339 for ( ; timeout >= 0; timeout -= (timo ? 100 : 0)) {
11340 if (select(&socket, 1, 0, 0, 100L) == 1) {
11345 #else /* !IBMSELECT */
11346 SELECT is required for this code
11347 #endif /* IBMSELECT */
11348 #endif /* BSDSELECT */
11351 if (timo && x < 0) { /* select() timed out */
11352 #ifdef HTTP_BUFFERING
11355 #endif /* HTTP_BUFFERING */
11356 debug(F100,"http_inc select() timed out","",0);
11357 return(-1); /* Call it an i/o error */
11361 if ( tls_http_active_flag ) {
11364 x = SSL_read(tls_http_con, &c, 1);
11365 error = SSL_get_error(tls_http_con,x);
11367 case SSL_ERROR_NONE:
11368 debug(F111,"http_inc SSL_ERROR_NONE","x",x);
11371 ReleaseTCPIPMutex();
11373 return(c); /* Return character. */
11374 } else if (x < 0) {
11376 ReleaseTCPIPMutex();
11382 ReleaseTCPIPMutex();
11386 case SSL_ERROR_WANT_WRITE:
11387 debug(F100,"http_inc SSL_ERROR_WANT_WRITE","",0);
11389 ReleaseTCPIPMutex();
11392 case SSL_ERROR_WANT_READ:
11393 debug(F100,"http_inc SSL_ERROR_WANT_READ","",0);
11395 ReleaseTCPIPMutex();
11398 case SSL_ERROR_SYSCALL:
11399 if ( x == 0 ) { /* EOF */
11402 ReleaseTCPIPMutex();
11408 int gle = GetLastError();
11409 debug(F111,"http_inc SSL_ERROR_SYSCALL",
11410 "GetLastError()",gle);
11411 rc = os2socketerror(gle);
11414 else if ( rc == -2 )
11418 ReleaseTCPIPMutex();
11422 case SSL_ERROR_WANT_X509_LOOKUP:
11423 debug(F100,"http_inc SSL_ERROR_WANT_X509_LOOKUP","",0);
11426 ReleaseTCPIPMutex();
11429 case SSL_ERROR_SSL:
11430 debug(F100,"http_inc SSL_ERROR_SSL","",0);
11433 #endif /* COMMENT */
11435 ReleaseTCPIPMutex();
11438 case SSL_ERROR_ZERO_RETURN:
11439 debug(F100,"http_inc SSL_ERROR_ZERO_RETURN","",0);
11442 ReleaseTCPIPMutex();
11446 debug(F100,"http_inc SSL_ERROR_?????","",0);
11449 ReleaseTCPIPMutex();
11454 #endif /* CK_SSL */
11456 #ifdef HTTP_BUFFERING
11458 Buffering code added by fdc 15 Dec 2005 for non-SSL case only because HTTP
11459 GETs were orders of magnitude too slow due to the single-byte read()s. The
11460 file-descriptor swapping is pretty gross, but the more elegant solution
11461 (calling a nettchk() like routine with the fd as a parameter) doesn't work,
11462 because nettchk() relies on too many other routines that, like itself, are
11463 hardwired for ttyfd.
11466 if (--http_count >= 0) {
11467 c = http_inbuf[http_bufp++];
11475 debug(F101,"http_inc nettchk","",x);
11476 if (x > HTTP_INBUFLEN)
11479 x = socket_read(httpfd,http_inbuf,x);
11480 #else /* Not TCPIPLIB */
11481 x = read(httpfd,http_inbuf,x);
11482 #endif /* TCPIPLIB */
11486 c = http_inbuf[http_bufp++];
11487 http_count = x - 1;
11490 #else /* Not HTTP_BUFFERING */
11492 x = socket_read(httpfd,&c,1);
11493 #else /* Not TCPIPLIB */
11494 x = read(httpfd,&c,1);
11495 #endif /* TCPIPLIB */
11496 #endif /* HTTP_BUFFERING */
11499 int s_errno = socket_errno;
11500 debug(F101,"ttbufr socket_read","",x);
11501 debug(F101,"ttbufr socket_errno","",s_errno);
11503 if (x == 0 || os2socketerror(s_errno) < 0) {
11505 ReleaseTCPIPMutex();
11508 ReleaseTCPIPMutex();
11511 http_close(); /* *** *** */
11520 http_set_code_reply(char * msg)
11522 http_set_code_reply(msg)
11524 #endif /* CK_ANSIC */
11530 while ( *p != SP && *p != NUL ) {
11536 http_code = atoi(buf);
11541 ckstrncpy(http_reply_str,p,HTTPBUFLEN);
11546 http_get(char * agent, char ** hdrlist, char * user,
11547 char * pwd, char array, char * local, char * remote,
11550 http_get(agent, hdrlist, user, pwd, array, local, remote, stdio)
11551 char * agent; char ** hdrlist; char * user;
11552 char * pwd; char array; char * local; char * remote;
11554 #endif /* CK_ANSIC */
11556 char * request = NULL;
11557 int i, j, len = 0, hdcnt = 0, rc = 0;
11560 char buf[HTTPBUFLEN], *p;
11563 struct utimbuf u_t;
11566 struct utimbuf u_t;
11572 #endif /* SYSUTIMH */
11576 time_t local_t = 0;
11580 char * headers[HTTPHEADCNT];
11588 debug(F101,"http_get httpfd","",httpfd);
11589 debug(F110,"http_agent",agent,0);
11590 debug(F110,"http_user",user,0);
11591 debug(F110,"http_local",local,0);
11592 debug(F110,"http_remote",remote,0);
11595 if (!remote) remote = "";
11601 for (i = 0; i < HTTPHEADCNT; i++)
11605 len += strlen(HTTP_VERSION);
11606 len += strlen(remote);
11610 for (i = 0; hdrlist[i]; i++)
11611 len += strlen(hdrlist[i]) + 2;
11613 len += (int) strlen(http_host_port) + 8;
11616 len += 13 + strlen(agent);
11619 readpass("Password: ",passwd,64);
11622 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11623 j = b8tob64(b64in,strlen(b64in),b64out,256);
11624 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11631 len += 19; /* Connection: close */
11633 len += 3; /* blank line + null */
11635 request = malloc(len);
11639 sprintf(request,"GET %s %s\r\n",remote,HTTP_VERSION); /* safe */
11640 ckstrncat(request,"Host: ", len);
11641 ckstrncat(request,http_host_port, len);
11642 ckstrncat(request,"\r\n",len);
11644 ckstrncat(request,"User-agent: ",len);
11645 ckstrncat(request,agent,len);
11646 ckstrncat(request,"\r\n",len);
11649 ckstrncat(request,"Authorization: Basic ",len);
11650 ckstrncat(request,b64out,len);
11651 ckstrncat(request,"\r\n",len);
11654 for (i = 0; hdrlist[i]; i++) {
11655 ckstrncat(request,hdrlist[i],len);
11656 ckstrncat(request,"\r\n",len);
11660 ckstrncat(request,"Connection: close\r\n",len);
11662 ckstrncat(request,"\r\n",len);
11665 if (http_tol((CHAR *)request,strlen(request)) < 0)
11677 /* Process the headers */
11678 local_t = time(NULL);
11682 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11684 if ( buf[i] == 10 ) { /* found end of line */
11685 if (i > 0 && buf[i-1] == 13)
11690 if (array && !nullline && hdcnt < HTTPHEADCNT)
11691 makestr(&headers[hdcnt++],buf);
11692 if (!ckstrcmp(buf,"HTTP",4,0)) {
11694 j = ckindex(" ",buf,0,0,0);
11696 while ( isspace(*p) )
11699 case '1': /* Informational message */
11701 case '2': /* Success */
11703 case '3': /* Redirection */
11704 case '4': /* Client failure */
11705 case '5': /* Server failure */
11706 default: /* Unknown */
11708 printf("Failure: Server reports %s\n",p);
11712 http_set_code_reply(p);
11714 } else if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11715 mod_t = http_date(&buf[15]);
11716 } else if (!ckstrcmp(buf,"Date",4,0)) {
11717 srv_t = http_date(&buf[4]);
11718 #endif /* CMDATE2TM */
11719 } else if (!ckstrcmp(buf,"Connection:",11,0)) {
11720 if ( ckindex("close",buf,11,0,0) != 0 )
11722 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
11723 len = atoi(&buf[16]);
11724 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
11725 if ( ckindex("chunked",buf,18,0,0) != 0 )
11727 debug(F101,"http_get chunked","",chunked);
11734 if (ch < 0 && first) {
11740 if (http_fnd == 0) {
11746 /* Now we have the contents of the file */
11747 if ( local && local[0] ) {
11748 if (zopeno(ZOFILE,local,NULL,NULL))
11755 while ((len = http_get_chunk_len()) > 0) {
11756 while (len && (ch = http_inc(0)) >= 0) {
11759 zchout(ZOFILE,(CHAR)ch);
11763 if ((ch = http_inc(0)) != CR)
11765 if ((ch = http_inc(0)) != LF)
11769 while (len && (ch = http_inc(0)) >= 0) {
11772 zchout(ZOFILE,(CHAR)ch);
11781 if ( chunked ) { /* Parse Trailing Headers */
11783 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11785 if ( buf[i] == 10 ) { /* found end of line */
11786 if (i > 0 && buf[i-1] == 13)
11791 if (array && !nullline && hdcnt < HTTPHEADCNT)
11792 makestr(&headers[hdcnt++],buf);
11794 if (!ckstrcmp(buf,"Last-Modified",13,0)) {
11795 mod_t = http_date(&buf[15]);
11796 } else if (!ckstrcmp(buf,"Date",4,0)) {
11797 srv_t = http_date(&buf[4]);
11799 #endif /* CMDATE2TM */
11800 else if (!ckstrcmp(buf,"Connection:",11,0)) {
11801 if ( ckindex("close",buf,11,0,0) != 0 )
11811 if ( zfile ) { /* Set timestamp */
11814 u_t.actime = srv_t ? srv_t : local_t;
11815 u_t.modtime = mod_t ? mod_t : local_t;
11818 u_t.actime = srv_t ? srv_t : local_t;
11819 u_t.modtime = mod_t ? mod_t : local_t;
11822 u_t[0].tv_sec = srv_t ? srv_t : local_t;
11823 u_t[1].tv_sec = mod_t ? mod_t : local_t;
11825 u_t.mtime = srv_t ? srv_t : local_t;
11826 u_t.atime = mod_t ? mod_t : local_t;
11828 #endif /* SYSUTIMEH */
11831 #endif /* NOSETTIME */
11836 http_mkarray(headers,hdcnt,array);
11841 for (i = 0; i < hdcnt; i++) {
11850 http_head(char * agent, char ** hdrlist, char * user,
11851 char * pwd, char array, char * local, char * remote,
11854 http_head(agent, hdrlist, user, pwd, array, local, remote, stdio)
11855 char * agent; char ** hdrlist; char * user;
11856 char * pwd; char array; char * local; char * remote;
11858 #endif /* CK_ANSIC */
11860 char * request = NULL;
11861 int i, j, len = 0, hdcnt = 0, rc = 0;
11864 char buf[HTTPBUFLEN], *p;
11872 char * headers[HTTPHEADCNT];
11880 for (i = 0; i < HTTPHEADCNT; i++)
11883 len = 9; /* HEAD */
11884 len += strlen(HTTP_VERSION);
11885 len += strlen(remote);
11889 for (i = 0; hdrlist[i]; i++)
11890 len += strlen(hdrlist[i]) + 2;
11892 len += strlen(http_host_port) + 8;
11895 len += 13 + strlen(agent);
11898 readpass("Password: ",passwd,64);
11901 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
11902 j = b8tob64(b64in,strlen(b64in),b64out,256);
11903 memset(pwd,0,strlen(pwd)); /* NOT PORTABLE */
11910 len += 19; /* Connection: close */
11912 len += 3; /* blank line + null */
11914 request = (char *)malloc(len);
11918 sprintf(request,"HEAD %s %s\r\n",remote,HTTP_VERSION);
11919 ckstrncat(request,"Host: ", len);
11920 ckstrncat(request,http_host_port, len);
11921 ckstrncat(request,"\r\n",len);
11923 ckstrncat(request,"User-agent: ",len);
11924 ckstrncat(request,agent,len);
11925 ckstrncat(request,"\r\n",len);
11928 ckstrncat(request,"Authorization: Basic ",len);
11929 ckstrncat(request,b64out,len);
11930 ckstrncat(request,"\r\n",len);
11933 for (i = 0; hdrlist[i]; i++) {
11934 ckstrncat(request,hdrlist[i],len);
11935 ckstrncat(request,"\r\n",len);
11939 ckstrncat(request,"Connection: close\r\n",len);
11941 ckstrncat(request,"\r\n",len);
11943 if ( local && local[0] ) {
11944 if (!zopeno(ZOFILE,local,NULL,NULL)) {
11951 if (http_tol((CHAR *)request,strlen(request)) < 0)
11963 /* Process the headers */
11965 local_t = time(NULL);
11968 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
11970 if (buf[i] == 10) { /* found end of line */
11971 if (i > 0 && buf[i-1] == 13)
11976 if (array && !nullline && hdcnt < HTTPHEADCNT)
11977 makestr(&headers[hdcnt++],buf);
11978 if (!ckstrcmp(buf,"HTTP",4,0)) {
11980 j = ckindex(" ",buf,0,0,0);
11982 while (isspace(*p))
11985 case '1': /* Informational message */
11987 case '2': /* Success */
11989 case '3': /* Redirection */
11990 case '4': /* Client failure */
11991 case '5': /* Server failure */
11992 default: /* Unknown */
11994 printf("Failure: Server reports %s\n",p);
11997 http_set_code_reply(p);
11999 if (!ckstrcmp(buf,"Connection:",11,0)) {
12000 if ( ckindex("close",buf,11,0,0) != 0 )
12003 if ( local && local[0] ) {
12005 zsout(ZOFILE,"\r\n");
12008 printf("%s\r\n",buf);
12015 if (ch < 0 && first) {
12021 if ( http_fnd == 0 )
12025 http_mkarray(headers,hdcnt,array);
12028 if ( local && local[0] )
12033 for (i = 0; i < hdcnt; i++) {
12042 http_index(char * agent, char ** hdrlist, char * user, char * pwd,
12043 char array, char * local, char * remote, int stdio)
12045 http_index(agent, hdrlist, user, pwd, array, local, remote, stdio)
12046 char * agent; char ** hdrlist; char * user; char * pwd;
12047 char array; char * local; char * remote; int stdio;
12048 #endif /* CK_ANSIC */
12050 char * request = NULL;
12051 int i, j, len = 0, hdcnt = 0, rc = 0;
12054 char buf[HTTPBUFLEN], *p;
12062 char * headers[HTTPHEADCNT];
12072 for (i = 0; i < HTTPHEADCNT; i++)
12075 len = 10; /* INDEX */
12076 len += strlen(HTTP_VERSION);
12077 len += strlen(remote);
12081 for (i = 0; hdrlist[i]; i++)
12082 len += strlen(hdrlist[i]) + 2;
12084 len += strlen(http_host_port) + 8;
12087 len += 13 + strlen(agent);
12090 readpass("Password: ",passwd,64);
12093 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12094 j = b8tob64(b64in,strlen(b64in),b64out,256);
12095 memset(pwd,0,strlen(pwd));
12102 len += 19; /* Connection: close */
12104 len += 3; /* blank line + null */
12106 request = malloc(len);
12110 sprintf(request,"INDEX %s\r\n",HTTP_VERSION);
12111 ckstrncat(request,"Host: ", len);
12112 ckstrncat(request,http_host_port, len);
12113 ckstrncat(request,"\r\n",len);
12115 ckstrncat(request,"User-agent: ",len);
12116 ckstrncat(request,agent,len);
12117 ckstrncat(request,"\r\n",len);
12120 ckstrncat(request,"Authorization: Basic ",len);
12121 ckstrncat(request,b64out,len);
12122 ckstrncat(request,"\r\n",len);
12125 for (i = 0; hdrlist[i]; i++) {
12126 ckstrncat(request,hdrlist[i],len);
12127 ckstrncat(request,"\r\n",len);
12131 ckstrncat(request,"Connection: close\r\n",len);
12133 ckstrncat(request,"\r\n",len);
12135 if (http_tol((CHAR *)request,strlen(request)) < 0)
12147 /* Process the headers */
12148 local_t = time(NULL);
12152 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12154 if (buf[i] == 10) { /* found end of line */
12155 if (i > 0 && buf[i-1] == 13)
12160 if (array && !nullline && hdcnt < HTTPHEADCNT)
12161 makestr(&headers[hdcnt++],buf);
12162 if (!ckstrcmp(buf,"HTTP",4,0)) {
12164 j = ckindex(" ",buf,0,0,0);
12166 while (isspace(*p))
12169 case '1': /* Informational message */
12171 case '2': /* Success */
12173 case '3': /* Redirection */
12174 case '4': /* Client failure */
12175 case '5': /* Server failure */
12176 default: /* Unknown */
12178 printf("Failure: Server reports %s\n",p);
12181 http_set_code_reply(p);
12182 } else if ( !nullline ) {
12183 if (!ckstrcmp(buf,"Connection:",11,0)) {
12184 if ( ckindex("close",buf,11,0,0) != 0 )
12186 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12187 len = atoi(&buf[16]);
12188 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12189 if ( ckindex("chunked",buf,18,0,0) != 0 )
12191 debug(F101,"http_index chunked","",chunked);
12193 printf("%s\n",buf);
12201 if (ch < 0 && first) {
12207 if ( http_fnd == 0 ) {
12213 /* Now we have the contents of the file */
12214 if ( local && local[0] ) {
12215 if (zopeno(ZOFILE,local,NULL,NULL))
12222 while ((len = http_get_chunk_len()) > 0) {
12223 while (len && (ch = http_inc(0)) >= 0) {
12226 zchout(ZOFILE,(CHAR)ch);
12230 if ((ch = http_inc(0)) != CR)
12232 if ((ch = http_inc(0)) != LF)
12236 while (len && (ch = http_inc(0)) >= 0) {
12239 zchout(ZOFILE,(CHAR)ch);
12248 if ( chunked ) { /* Parse Trailing Headers */
12250 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12252 if ( buf[i] == 10 ) { /* found end of line */
12253 if (i > 0 && buf[i-1] == 13)
12258 if (array && !nullline && hdcnt < HTTPHEADCNT)
12259 makestr(&headers[hdcnt++],buf);
12260 if (!ckstrcmp(buf,"Connection:",11,0)) {
12261 if ( ckindex("close",buf,11,0,0) != 0 )
12274 http_mkarray(headers,hdcnt,array);
12279 for (i = 0; i < hdcnt; i++) {
12288 http_put(char * agent, char ** hdrlist, char * mime, char * user,
12289 char * pwd, char array, char * local, char * remote,
12290 char * dest, int stdio)
12292 http_put(agent, hdrlist, mime, user, pwd, array, local, remote, dest, stdio)
12293 char * agent; char ** hdrlist; char * mime; char * user;
12294 char * pwd; char array; char * local; char * remote; char * dest;
12296 #endif /* CK_ANSIC */
12298 char * request=NULL;
12299 int i, j, len = 0, hdcnt = 0, rc = 0;
12302 char buf[HTTPBUFLEN], *p;
12311 char * headers[HTTPHEADCNT];
12319 if (!mime) mime = "";
12320 if (!remote) remote = "";
12321 if (!local) local = "";
12322 if (!*local) return(-1);
12325 for (i = 0; i < HTTPHEADCNT; i++)
12328 filelen = zchki(local);
12332 /* Compute length of request header */
12334 len += strlen(HTTP_VERSION);
12335 len += strlen(remote);
12339 for (i = 0; hdrlist[i]; i++)
12340 len += strlen(hdrlist[i]) + 2;
12342 len += strlen(http_host_port) + 8;
12345 len += 13 + strlen(agent);
12348 readpass("Password: ",passwd,64);
12351 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12352 j = b8tob64(b64in,strlen(b64in),b64out,256);
12353 memset(pwd,0,strlen(pwd));
12359 len += 16 + strlen(mime); /* Content-type: */
12360 len += 32; /* Content-length: */
12361 len += 32; /* Date: */
12363 len += 19; /* Connection: close */
12365 len += 3; /* blank line + null */
12367 request = malloc(len);
12371 sprintf(request,"PUT %s %s\r\n",remote,HTTP_VERSION);
12372 ckstrncat(request,"Date: ",len);
12374 ckstrncat(request,http_now(),len);
12376 ckstrncat(request,...,len);
12377 #endif /* CMDATE2TM */
12378 ckstrncat(request,"\r\n",len);
12379 ckstrncat(request,"Host: ", len);
12380 ckstrncat(request,http_host_port, len);
12381 ckstrncat(request,"\r\n",len);
12383 ckstrncat(request,"User-agent: ",len);
12384 ckstrncat(request,agent,len);
12385 ckstrncat(request,"\r\n",len);
12388 ckstrncat(request,"Authorization: Basic ",len);
12389 ckstrncat(request,b64out,len);
12390 ckstrncat(request,"\r\n",len);
12393 for (i = 0; hdrlist[i]; i++) {
12394 ckstrncat(request,hdrlist[i],len);
12395 ckstrncat(request,"\r\n",len);
12398 ckstrncat(request,"Content-type: ",len);
12399 ckstrncat(request,mime,len);
12400 ckstrncat(request,"\r\n",len);
12401 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12402 ckstrncat(request,buf,len);
12404 ckstrncat(request,"Connection: close\r\n",len);
12406 ckstrncat(request,"\r\n",len);
12408 /* Now we have the contents of the file */
12409 if (zopeni(ZIFILE,local)) {
12411 putreq: /* Send request */
12412 if (http_tol((CHAR *)request,strlen(request)) <= 0) {
12423 /* Request headers have been sent */
12426 while (zchin(ZIFILE,&ch) == 0) {
12428 if (i == HTTPBUFLEN) {
12429 if (http_tol((CHAR *)buf,HTTPBUFLEN) <= 0) {
12441 if (http_tol((CHAR *)buf,i) < 0) {
12452 /* Process the response headers */
12453 local_t = time(NULL);
12457 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12459 if (buf[i] == 10) { /* found end of line */
12460 if (i > 0 && buf[i-1] == 13)
12465 if (array && !nullline && hdcnt < HTTPHEADCNT)
12466 makestr(&headers[hdcnt++],buf);
12467 if (!ckstrcmp(buf,"HTTP",4,0)) {
12469 j = ckindex(" ",buf,0,0,0);
12471 while (isspace(*p))
12474 case '1': /* Informational message */
12476 case '2': /* Success */
12478 case '3': /* Redirection */
12479 case '4': /* Client failure */
12480 case '5': /* Server failure */
12481 default: /* Unknown */
12483 printf("Failure: Server reports %s\n",p);
12486 http_set_code_reply(p);
12488 if (!ckstrcmp(buf,"Connection:",11,0)) {
12489 if ( ckindex("close",buf,11,0,0) != 0 )
12491 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12492 len = atoi(&buf[16]);
12493 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12494 if ( ckindex("chunked",buf,18,0,0) != 0 )
12496 debug(F101,"http_put chunked","",chunked);
12499 printf("%s\n",buf);
12506 if (ch < 0 && first) {
12512 if ( http_fnd == 0 ) {
12518 /* Any response data? */
12519 if ( dest && dest[0] ) {
12520 if (zopeno(ZOFILE,dest,NULL,NULL))
12527 while ((len = http_get_chunk_len()) > 0) {
12528 while (len && (ch = http_inc(0)) >= 0) {
12531 zchout(ZOFILE,(CHAR)ch);
12535 if ((ch = http_inc(0)) != CR)
12537 if ((ch = http_inc(0)) != LF)
12541 while (len && (ch = http_inc(0)) >= 0) {
12544 zchout(ZOFILE,(CHAR)ch);
12553 if ( chunked ) { /* Parse Trailing Headers */
12555 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12557 if ( buf[i] == 10 ) { /* found end of line */
12558 if (i > 0 && buf[i-1] == 13)
12563 if (array && !nullline && hdcnt < HTTPHEADCNT)
12564 makestr(&headers[hdcnt++],buf);
12565 if (!ckstrcmp(buf,"Connection:",11,0)) {
12566 if ( ckindex("close",buf,11,0,0) != 0 )
12581 http_mkarray(headers,hdcnt,array);
12586 for (i = 0; i < hdcnt; i++) {
12595 http_delete(char * agent, char ** hdrlist, char * user,
12596 char * pwd, char array, char * remote)
12598 http_delete(agent, hdrlist, user, pwd, array, remote)
12599 char * agent; char ** hdrlist; char * user;
12600 char * pwd; char array; char * remote;
12601 #endif /* CK_ANSIC */
12603 char * request=NULL;
12604 int i, j, len = 0, hdcnt = 0, rc = 0;
12607 char buf[HTTPBUFLEN], *p;
12615 char * headers[HTTPHEADCNT];
12624 for (i = 0; i < HTTPHEADCNT; i++)
12628 /* Compute length of request header */
12629 len = 11; /* DELETE */
12630 len += strlen(HTTP_VERSION);
12631 len += strlen(remote);
12635 for (i = 0; hdrlist[i]; i++)
12636 len += strlen(hdrlist[i]) + 2;
12638 len += strlen(http_host_port) + 8;
12641 len += 13 + strlen(agent);
12644 readpass("Password: ",passwd,64);
12647 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12648 j = b8tob64(b64in,strlen(b64in),b64out,256);
12649 memset(pwd,0,strlen(pwd));
12655 len += 32; /* Date: */
12657 len += 19; /* Connection: close */
12659 len += 3; /* blank line + null */
12661 request = malloc(len);
12665 sprintf(request,"DELETE %s %s\r\n",remote,HTTP_VERSION);
12666 ckstrncat(request,"Date: ",len);
12668 ckstrncat(request,http_now(),len);
12670 ckstrncat(request,...,len);
12671 #endif /* CMDATE2TM */
12672 ckstrncat(request,"\r\n",len);
12673 ckstrncat(request,"Host: ", len);
12674 ckstrncat(request,http_host_port, len);
12675 ckstrncat(request,"\r\n",len);
12677 ckstrncat(request,"User-agent: ",len);
12678 ckstrncat(request,agent,len);
12679 ckstrncat(request,"\r\n",len);
12682 ckstrncat(request,"Authorization: Basic ",len);
12683 ckstrncat(request,b64out,len);
12684 ckstrncat(request,"\r\n",len);
12687 for (i = 0; hdrlist[i]; i++) {
12688 ckstrncat(request,hdrlist[i],len);
12689 ckstrncat(request,"\r\n",len);
12693 ckstrncat(request,"Connection: close\r\n",len);
12695 ckstrncat(request,"\r\n",len);
12697 if (http_tol((CHAR *)request,strlen(request)) < 0)
12709 /* Process the response headers */
12710 local_t = time(NULL);
12714 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12716 if (buf[i] == 10) { /* found end of line */
12717 if (i > 0 && buf[i-1] == 13)
12722 if (array && !nullline && hdcnt < HTTPHEADCNT)
12723 makestr(&headers[hdcnt++],buf);
12724 if (!ckstrcmp(buf,"HTTP",4,0)) {
12726 j = ckindex(" ",buf,0,0,0);
12728 while (isspace(*p))
12731 case '1': /* Informational message */
12733 case '2': /* Success */
12735 case '3': /* Redirection */
12736 case '4': /* Client failure */
12737 case '5': /* Server failure */
12738 default: /* Unknown */
12740 printf("Failure: Server reports %s\n",p);
12743 http_set_code_reply(p);
12745 if (!ckstrcmp(buf,"Connection:",11,0)) {
12746 if ( ckindex("close",buf,11,0,0) != 0 )
12748 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
12749 len = atoi(&buf[16]);
12750 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
12751 if ( ckindex("chunked",buf,18,0,0) != 0 )
12753 debug(F101,"http_delete chunked","",chunked);
12755 printf("%s\n",buf);
12762 if (ch < 0 && first) {
12768 if ( http_fnd == 0 ) {
12774 /* Any response data? */
12776 while ((len = http_get_chunk_len()) > 0) {
12777 while (len && (ch = http_inc(0)) >= 0) {
12781 if ((ch = http_inc(0)) != CR)
12783 if ((ch = http_inc(0)) != LF)
12787 while (len && (ch = http_inc(0)) >= 0) {
12793 if ( chunked ) { /* Parse Trailing Headers */
12795 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12797 if ( buf[i] == 10 ) { /* found end of line */
12798 if (i > 0 && buf[i-1] == 13)
12803 if (array && !nullline && hdcnt < HTTPHEADCNT)
12804 makestr(&headers[hdcnt++],buf);
12805 if (!ckstrcmp(buf,"Connection:",11,0)) {
12806 if ( ckindex("close",buf,11,0,0) != 0 )
12818 http_mkarray(headers,hdcnt,array);
12823 for (i = 0; i < hdcnt; i++) {
12832 http_post(char * agent, char ** hdrlist, char * mime, char * user,
12833 char * pwd, char array, char * local, char * remote,
12834 char * dest, int stdio)
12836 http_post(agent, hdrlist, mime, user, pwd, array, local, remote, dest,
12838 char * agent; char ** hdrlist; char * mime; char * user;
12839 char * pwd; char array; char * local; char * remote; char * dest;
12841 #endif /* CK_ANSIC */
12843 char * request=NULL;
12844 int i, j, len = 0, hdcnt = 0, rc = 0;
12847 char buf[HTTPBUFLEN], *p;
12856 char * headers[HTTPHEADCNT];
12866 for (i = 0; i < HTTPHEADCNT; i++)
12869 filelen = zchki(local);
12873 /* Compute length of request header */
12874 len = 9; /* POST */
12875 len += strlen(HTTP_VERSION);
12876 len += strlen(remote);
12880 for (i = 0; hdrlist[i]; i++)
12881 len += strlen(hdrlist[i]) + 2;
12883 len += strlen(http_host_port) + 8;
12886 len += 13 + strlen(agent);
12889 readpass("Password: ",passwd,64);
12892 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
12893 j = b8tob64(b64in,strlen(b64in),b64out,256);
12894 memset(pwd,0,strlen(pwd));
12900 len += 16 + strlen(mime); /* Content-type: */
12901 len += 32; /* Content-length: */
12902 len += 32; /* Date: */
12904 len += 19; /* Connection: close */
12906 len += 3; /* blank line + null */
12908 request = malloc(len);
12912 sprintf(request,"POST %s %s\r\n",remote,HTTP_VERSION);
12913 ckstrncat(request,"Date: ",len);
12914 ckstrncat(request,http_now(),len);
12915 ckstrncat(request,"\r\n",len);
12916 ckstrncat(request,"Host: ", len);
12917 ckstrncat(request,http_host_port, len);
12918 ckstrncat(request,"\r\n",len);
12920 ckstrncat(request,"User-agent: ",len);
12921 ckstrncat(request,agent,len);
12922 ckstrncat(request,"\r\n",len);
12925 ckstrncat(request,"Authorization: Basic ",len);
12926 ckstrncat(request,b64out,len);
12927 ckstrncat(request,"\r\n",len);
12930 for (i = 0; hdrlist[i]; i++) {
12931 ckstrncat(request,hdrlist[i],len);
12932 ckstrncat(request,"\r\n",len);
12935 ckstrncat(request,"Content-type: ",len);
12936 ckstrncat(request,mime,len);
12937 ckstrncat(request,"\r\n",len);
12939 ckstrncat(request,"Connection: close\r\n",len);
12941 sprintf(buf,"Content-length: %d\r\n",filelen); /* safe */
12942 ckstrncat(request,buf,len);
12943 ckstrncat(request,"\r\n",len);
12945 /* This is apparently a mistake - the previous ckstrncat() already */
12946 /* appended a blank line to the request. There should only be one. */
12947 /* Servers are not required by RFC 2616 to ignore extraneous empty */
12948 /* lines. -fdc, 28 Aug 2005. */
12949 ckstrncat(request,"\r\n",len);
12950 #endif /* COMMENT */
12952 /* Now we have the contents of the file */
12954 if (zopeni(ZIFILE,local)) {
12956 if (http_tol((CHAR *)request,strlen(request)) < 0)
12970 while (zchin(ZIFILE,&ch) == 0) {
12972 if (i == HTTPBUFLEN) {
12973 http_tol((CHAR *)buf,HTTPBUFLEN);
12978 http_tol((CHAR *)buf,HTTPBUFLEN);
12981 /* Process the response headers */
12982 local_t = time(NULL);
12986 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
12988 if (buf[i] == 10) { /* found end of line */
12989 if (i > 0 && buf[i-1] == 13)
12994 if (array && !nullline && hdcnt < HTTPHEADCNT)
12995 makestr(&headers[hdcnt++],buf);
12996 if (!ckstrcmp(buf,"HTTP",4,0)) {
12998 j = ckindex(" ",buf,0,0,0);
13000 while (isspace(*p))
13003 case '1': /* Informational message */
13005 case '2': /* Success */
13007 case '3': /* Redirection */
13008 case '4': /* Client failure */
13009 case '5': /* Server failure */
13010 default: /* Unknown */
13012 printf("Failure: Server reports %s\n",p);
13015 http_set_code_reply(p);
13017 if (!ckstrcmp(buf,"Connection:",11,0)) {
13018 if ( ckindex("close",buf,11,0,0) != 0 )
13020 } else if (!ckstrcmp(buf,"Content-Length:",15,0)) {
13021 len = atoi(&buf[16]);
13022 } else if (!ckstrcmp(buf,"Transfer-Encoding:",18,0)) {
13023 if ( ckindex("chunked",buf,18,0,0) != 0 )
13025 debug(F101,"http_post chunked","",chunked);
13028 printf("%s\n",buf);
13035 if (ch < 0 && first) {
13041 if (http_fnd == 0) {
13047 /* Any response data? */
13048 if ( dest && dest[0] ) {
13049 if (zopeno(ZOFILE,dest,NULL,NULL))
13056 while ((len = http_get_chunk_len()) > 0) {
13057 while (len && (ch = http_inc(0)) >= 0) {
13060 zchout(ZOFILE,(CHAR)ch);
13064 if ((ch = http_inc(0)) != CR)
13066 if ((ch = http_inc(0)) != LF)
13070 while (len && (ch = http_inc(0)) >= 0) {
13073 zchout(ZOFILE,(CHAR)ch);
13082 if ( chunked ) { /* Parse Trailing Headers */
13084 while (!nullline && (ch = http_inc(0)) >= 0 && i < HTTPBUFLEN) {
13086 if ( buf[i] == 10 ) { /* found end of line */
13087 if (i > 0 && buf[i-1] == 13)
13092 if (array && !nullline && hdcnt < HTTPHEADCNT)
13093 makestr(&headers[hdcnt++],buf);
13094 if (!ckstrcmp(buf,"Connection:",11,0)) {
13095 if ( ckindex("close",buf,11,0,0) != 0 )
13110 http_mkarray(headers,hdcnt,array);
13114 for (i = 0; i < hdcnt; i++) {
13123 http_connect(int socket, char * agent, char ** hdrlist, char * user,
13124 char * pwd, char array, char * host_port)
13126 http_connect(socket, agent, hdrlist, user, pwd, array, host_port)
13128 char * agent; char ** hdrlist; char * user;
13129 char * pwd; char array; char * host_port;
13130 #endif /* CK_ANSIC */
13132 char * request=NULL;
13133 int i, j, len = 0, hdcnt = 0, rc = 0;
13135 char buf[HTTPBUFLEN], *p, ch;
13143 char * headers[HTTPHEADCNT];
13146 tcp_http_proxy_errno = 0;
13152 for (i = 0; i < HTTPHEADCNT; i++)
13156 /* Compute length of request header */
13157 len = 12; /* CONNECT */
13158 len += strlen(HTTP_VERSION);
13159 len += strlen(host_port);
13160 len += (int) strlen(http_host_port) + 8;
13162 len += strlen("Proxy-Connection: Keep-Alive\r\n");
13164 for (i = 0; hdrlist[i]; i++)
13165 len += strlen(hdrlist[i]) + 2;
13167 if (agent && agent[0])
13168 len += 13 + strlen(agent);
13169 if (user && user[0]) {
13171 readpass("Password: ",passwd,64);
13174 ckmakmsg(b64in,sizeof(b64in),user,":",pwd,NULL);
13175 j = b8tob64(b64in,strlen(b64in),b64out,256);
13176 memset(pwd,0,strlen(pwd));
13182 len += 32; /* Date: */
13183 len += 3; /* blank line + null */
13185 request = malloc(len);
13189 sprintf(request,"CONNECT %s %s\r\n",host_port,HTTP_VERSION);
13190 ckstrncat(request,"Date: ",len);
13192 ckstrncat(request,http_now(),len);
13194 strcat(request,...);
13195 #endif /* CMDATE2TM */
13196 ckstrncat(request,"\r\n",len);
13197 ckstrncat(request,"Host: ", len);
13198 ckstrncat(request,http_host_port, len);
13199 ckstrncat(request,"\r\n",len);
13200 if (agent && agent[0]) {
13201 ckstrncat(request,"User-agent: ",len);
13202 ckstrncat(request,agent,len);
13203 ckstrncat(request,"\r\n",len);
13205 if (user && user[0]) {
13206 ckstrncat(request,"Proxy-authorization: Basic ",len);
13207 ckstrncat(request,b64out,len);
13208 ckstrncat(request,"\r\n",len);
13209 ckstrncat(request,"Extension: Security/Remote-Passphrase\r\n",len);
13211 ckstrncat(request,"Proxy-Connection: Keep-Alive\r\n",len);
13213 for (i = 0; hdrlist[i]; i++) {
13214 ckstrncat(request,hdrlist[i],len);
13215 ckstrncat(request,"\r\n",len);
13218 ckstrncat(request,"\r\n",len);
13219 len = strlen(request);
13223 if (socket_write(socket,(CHAR *)request,strlen(request)) < 0) {
13228 if (write(socket,(CHAR *)request,strlen(request)) < 0) { /* Send request */
13232 #endif /* TCPIPLIB */
13234 /* Process the response headers */
13235 local_t = time(NULL);
13238 while (!nullline &&
13240 (socket_read(socket,&ch,1) == 1) &&
13242 (read(socket,&ch,1) == 1) &&
13243 #endif /* TCPIPLIB */
13246 if (buf[i] == 10) { /* found end of line */
13247 if (i > 0 && buf[i-1] == 13)
13253 if (array && !nullline && hdcnt < HTTPHEADCNT)
13254 makestr(&headers[hdcnt++],buf);
13255 if (!ckstrcmp(buf,"HTTP",4,0)) {
13257 j = ckindex(" ",buf,0,0,0);
13259 while (isspace(*p))
13261 tcp_http_proxy_errno = atoi(p);
13263 case '1': /* Informational message */
13265 case '2': /* Success */
13268 case '3': /* Redirection */
13269 case '4': /* Client failure */
13270 case '5': /* Server failure */
13271 default: /* Unknown */
13273 printf("Failure: Server reports %s\n",p);
13276 http_set_code_reply(p);
13278 printf("%s\n",buf);
13285 if ( http_fnd == 0 )
13289 http_mkarray(headers,hdcnt,array);
13292 if ( !connected ) {
13293 if ( socket == ttyfd ) {
13296 else if ( socket == httpfd ) {
13302 for (i = 0; i < hdcnt; i++) {
13308 #endif /* NOHTTP */
13312 #define INCR_CHECK(x,y) x += y; if (x > size + answer.bytes) goto dnsout
13313 #define CHECK(x,y) if (x + y > size + answer.bytes) goto dnsout
13314 #define NTOHSP(x,y) x[0] << 8 | x[1]; x += y
13316 #ifndef CKQUERYTYPE
13319 #define CKQUERYTYPE CHAR
13321 #endif /* UNIXWARE */
13322 #endif /* CKQUERYTYPE */
13324 #ifndef CKQUERYTYPE
13325 #define CKQUERYTYPE char
13326 #endif /* CKQUERYTYPE */
13328 /* 1 is success, 0 is failure */
13330 locate_srv_dns(host, service, protocol, addr_pp, naddrs)
13334 struct sockaddr **addr_pp;
13337 int nout, j, count;
13339 unsigned char bytes[2048];
13342 unsigned char *p=NULL;
13343 CKQUERYTYPE query[MAX_DNS_NAMELEN];
13348 #endif /* CK_ANSIC */
13349 struct sockaddr *addr = NULL;
13350 struct sockaddr_in *sin = NULL;
13351 struct hostent *hp = NULL;
13353 int priority, weight, size, len, numanswers, numqueries, rdlen;
13354 unsigned short port;
13357 #endif /* CK_ANSIC */
13358 int hdrsize = sizeof(HEADER);
13359 struct srv_dns_entry {
13360 struct srv_dns_entry *next;
13363 unsigned short port;
13366 struct srv_dns_entry *head = NULL;
13367 struct srv_dns_entry *srv = NULL, *entry = NULL;
13371 addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
13378 * First build a query of the form:
13380 * service.protocol.host
13382 * which will most likely be something like:
13384 * _telnet._tcp.host
13387 if (((int)strlen(service) + strlen(protocol) + strlen(host) + 5)
13392 /* Realm names don't (normally) end with ".", but if the query
13393 doesn't end with "." and doesn't get an answer as is, the
13394 resolv code will try appending the local domain. Since the
13395 realm names are absolutes, let's stop that.
13397 But only if a name has been specified. If we are performing
13398 a search on the prefix alone then the intention is to allow
13399 the local domain or domain search lists to be expanded.
13401 h = host + strlen (host);
13402 ckmakxmsg(query, sizeof(query), "_",service,"._",protocol,".", host,
13403 ((h > host) && (h[-1] != '.')?".":NULL),
13404 NULL,NULL,NULL,NULL,NULL);
13406 size = res_search(query, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
13408 if (size < hdrsize)
13411 /* We got a reply - See how many answers it contains. */
13415 numqueries = ntohs(answer.hdr.qdcount);
13416 numanswers = ntohs(answer.hdr.ancount);
13418 p += sizeof(HEADER);
13421 * We need to skip over all of the questions, so we have to iterate
13422 * over every query record. dn_expand() is able to tell us the size
13423 * of compressed DNS names, so we use it.
13425 while (numqueries--) {
13426 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13429 INCR_CHECK(p, len + 4);
13433 * We're now pointing at the answer records. Only process them if
13434 * they're actually T_SRV records (they might be CNAME records,
13437 * But in a DNS reply, if you get a CNAME you always get the associated
13438 * "real" RR for that CNAME. RFC 1034, 3.6.2:
13440 * CNAME RRs cause special action in DNS software. When a name server
13441 * fails to find a desired RR in the resource set associated with the
13442 * domain name, it checks to see if the resource set consists of a CNAME
13443 * record with a matching class. If so, the name server includes the CNAME
13444 * record in the response and restarts the query at the domain name
13445 * specified in the data field of the CNAME record. The one exception to
13446 * this rule is that queries which match the CNAME type are not restarted.
13448 * In other words, CNAMEs do not need to be expanded by the client.
13450 while (numanswers--) {
13452 /* First is the name; use dn_expand() to get the compressed size. */
13453 len = dn_expand(answer.bytes,answer.bytes+size,p,query,sizeof(query));
13456 INCR_CHECK(p, len);
13458 CHECK(p,2); /* Query type */
13459 type = NTOHSP(p,2);
13461 CHECK(p, 6); /* Query class */
13462 class = NTOHSP(p,6); /* Also skip over 4-byte TTL */
13464 CHECK(p,2); /* Record data length */
13465 rdlen = NTOHSP(p,2);
13467 * If this is an SRV record, process it. Record format is:
13474 if (class == C_IN && type == T_SRV) {
13476 priority = NTOHSP(p,2);
13478 weight = NTOHSP(p,2);
13480 port = NTOHSP(p,2);
13481 len = dn_expand(answer.
13483 answer.bytes + size,
13490 INCR_CHECK(p, len);
13492 * We got everything. Insert it into our list, but make sure
13493 * it's in the right order. Right now we don't do anything
13494 * with the weight field
13496 srv = (struct srv_dns_entry *)malloc(sizeof(struct srv_dns_entry));
13500 srv->priority = priority;
13501 srv->weight = weight;
13503 makestr(&s,(char *)query); /* strdup() is not portable */
13506 if (head == NULL || head->priority > srv->priority) {
13511 * Confusing. Insert an entry into this spot only if:
13512 * . The next person has a higher priority (lower
13513 * priorities are preferred), or:
13514 * . There is no next entry (we're at the end)
13516 for (entry = head; entry != NULL; entry = entry->next)
13517 if ((entry->next &&
13518 entry->next->priority > srv->priority) ||
13519 entry->next == NULL) {
13520 srv->next = entry->next;
13525 INCR_CHECK(p, rdlen);
13529 * Now we've got a linked list of entries sorted by priority.
13530 * Start looking up A records and returning addresses.
13535 for (entry = head; entry != NULL; entry = entry->next) {
13536 hp = gethostbyname(entry->host);
13539 /* Watch out - memset() and memcpy() are not portable... */
13541 switch (hp->h_addrtype) {
13543 for (j = 0; hp->h_addr_list[j]; j++) {
13544 sin = (struct sockaddr_in *) &addr[nout++];
13545 memset ((char *) sin, 0, sizeof (struct sockaddr));
13546 sin->sin_family = hp->h_addrtype;
13547 sin->sin_port = htons(entry->port);
13548 memcpy((char *) &sin->sin_addr,
13549 (char *) hp->h_addr_list[j],
13550 sizeof(struct in_addr)); /* safe */
13551 if (nout + 1 >= count) {
13553 addr = (struct sockaddr *)
13554 realloc((char *) addr,
13555 sizeof(struct sockaddr) * count);
13566 for (entry = head; entry != NULL;) {
13568 entry->host = NULL;
13570 entry = entry->next;
13579 if (nout == 0) { /* No good servers */
13592 #define INCR_CHECK(x, y) x += y; if (x > size + answer.bytes) \
13594 #define CHECK(x, y) if (x + y > size + answer.bytes) \
13596 #define NTOHSP(x, y) x[0] << 8 | x[1]; x += y
13599 locate_txt_rr(prefix, name, retstr)
13600 char *prefix, *name;
13604 unsigned char bytes[2048];
13608 char host[MAX_DNS_NAMELEN], *h;
13610 int type, class, numanswers, numqueries, rdlen, len;
13613 * Form our query, and send it via DNS
13616 if (name == NULL || name[0] == '\0') {
13617 strcpy(host,prefix);
13619 if ( strlen(prefix) + strlen(name) + 3 > MAX_DNS_NAMELEN )
13622 /* Realm names don't (normally) end with ".", but if the query
13623 doesn't end with "." and doesn't get an answer as is, the
13624 resolv code will try appending the local domain. Since the
13625 realm names are absolutes, let's stop that.
13627 But only if a name has been specified. If we are performing
13628 a search on the prefix alone then the intention is to allow
13629 the local domain or domain search lists to be expanded.
13631 h = host + strlen (host);
13632 ckmakmsg(host,sizeof(host),prefix, ".", name,
13633 ((h > host) && (h[-1] != '.'))?".":NULL);
13636 size = res_search(host, C_IN, T_TXT, answer.bytes, sizeof(answer.bytes));
13643 numqueries = ntohs(answer.hdr.qdcount);
13644 numanswers = ntohs(answer.hdr.ancount);
13646 p += sizeof(HEADER);
13649 * We need to skip over the questions before we can get to the answers,
13650 * which means we have to iterate over every query record. We use
13651 * dn_expand to tell us how long each compressed name is.
13654 while (numqueries--) {
13655 len = dn_expand(answer.bytes, answer.bytes + size, p, host,
13659 INCR_CHECK(p, len + 4); /* Name plus type plus class */
13663 * We're now pointing at the answer records. Process the first
13664 * TXT record we find.
13667 while (numanswers--) {
13669 /* First the name; use dn_expand to get the compressed size */
13670 len = dn_expand(answer.bytes, answer.bytes + size, p,
13671 host, sizeof(host));
13674 INCR_CHECK(p, len);
13676 /* Next is the query type */
13678 type = NTOHSP(p,2);
13680 /* Next is the query class; also skip over 4 byte TTL */
13682 class = NTOHSP(p,6);
13684 /* Record data length - make sure we aren't truncated */
13687 rdlen = NTOHSP(p,2);
13689 if (p + rdlen > answer.bytes + size)
13693 * If this is a TXT record, return the string. Note that the
13694 * string has a 1-byte length in the front
13696 /* XXX What about flagging multiple TXT records as an error? */
13698 if (class == C_IN && type == T_TXT) {
13700 if (p + len > answer.bytes + size)
13702 *retstr = malloc(len + 1);
13703 if (*retstr == NULL)
13705 strncpy(*retstr, (char *) p, len);
13706 (*retstr)[len] = '\0';
13707 /* Avoid a common error. */
13708 if ( (*retstr)[len-1] == '.' )
13709 (*retstr)[len-1] = '\0';
13719 #endif /* CK_DNS_SRV */
13722 #ifdef CK_FORWARD_X
13724 #include <sys/un.h>
13725 #define FWDX_UNIX_SOCK
13727 #define AF_LOCAL AF_UNIX
13730 #define PF_LOCAL PF_UNIX
13733 /* Evaluate to actual length of the `sockaddr_un' structure. */
13734 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
13735 + strlen ((ptr)->sun_path))
13739 fwdx_create_listen_socket(screen) int screen; {
13742 #else /* NOPUTENV */
13743 struct sockaddr_in saddr;
13744 int display, port, sock=-1, i;
13745 static char env[512];
13748 * X Windows Servers support multiple displays by listening on
13749 * one socket per display. Display 0 is port 6000; Display 1 is
13752 * We start by trying to open port 6001 so that display 0 is
13753 * reserved for the local X Windows Server.
13756 for ( display=1; display < 1000 ; display++ ) {
13758 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13759 debug(F111,"fwdx_create_listen_socket()","socket() < 0",sock);
13763 port = 6000 + display;
13764 bzero((char *)&saddr, sizeof(saddr));
13765 saddr.sin_family = AF_INET;
13766 saddr.sin_addr.s_addr = inet_addr(myipaddr);
13767 saddr.sin_port = htons(port);
13769 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13770 i = errno; /* Save error code */
13772 socket_close(sock);
13773 #else /* TCPIPLIB */
13775 #endif /* TCPIPLIB */
13777 debug(F110,"fwdx_create_listen_socket()","bind() < 0",0);
13781 debug(F100,"fdwx_create_listen_socket() bind OK","",0);
13785 if ( display > 1000 ) {
13786 debug(F100,"fwdx_create_listen_socket() Out of Displays","",0);
13790 if (listen(sock, 5) < 0) {
13791 i = errno; /* Save error code */
13793 socket_close(sock);
13794 #else /* TCPIPLIB */
13796 #endif /* TCPIPLIB */
13797 debug(F101,"fdwx_create_listen_socket() listen() errno","",errno);
13800 debug(F100,"fwdx_create_listen_socket() listen OK","",0);
13802 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = sock;
13806 ckmakxmsg(env,sizeof(env),"DISPLAY=",myipaddr,":",
13807 ckuitoa(display),":",ckuitoa(screen),
13808 NULL,NULL,NULL,NULL,NULL,NULL);
13810 ckmakmsg(env,sizeof(env),"DISPLAY=",ckuitoa(display),":",
13814 #endif /* NOPUTENV */
13819 fwdx_open_client_channel(channel) int channel; {
13821 struct sockaddr_in saddr;
13822 #ifdef FWDX_UNIX_SOCK
13823 struct sockaddr_un saddr_un = { AF_LOCAL };
13824 #endif /* FWDX_UNIX_SOCK */
13825 int colon, dot, display, port, sock, i, screen;
13827 char buf[256], * host=NULL, * rest=NULL;
13830 #endif /* TCP_NODELAY */
13832 debug(F111,"fwdx_create_client_channel()","channel",channel);
13834 for ( i=0; i<MAXFWDX ; i++ ) {
13835 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel) {
13837 debug(F110,"fwdx_create_client_channel()","already open",0);
13842 env = getenv("DISPLAY");
13844 env = (char *)tn_get_display();
13846 ckstrncpy(buf,env,256);
13848 ckstrncpy(buf,"127.0.0.1:0.0",256);
13850 bzero((char *)&saddr,sizeof(saddr));
13851 saddr.sin_family = AF_INET;
13853 if (!fwdx_parse_displayname(buf,
13861 if ( host ) free(host);
13862 if ( rest ) free(rest);
13865 if (rest) free(rest);
13867 #ifndef FWDX_UNIX_SOCK
13868 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
13869 * we change things to use inet sockets on the ip loopback interface instead,
13870 * and hope that it works.
13872 if (family == FamilyLocal) {
13873 debug(F100,"fwdx_create_client_channel() FamilyLocal","",0);
13874 family = FamilyInternet;
13875 if (host) free(host);
13876 if (host = malloc(strlen("localhost") + 1))
13877 strcpy(host, "localhost");
13882 #else /* FWDX_UNIX_SOCK */
13883 if (family == FamilyLocal) {
13884 if (host) free(host);
13885 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
13889 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
13890 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
13891 if (connect(sock,(struct sockaddr *)&saddr_un, SUN_LEN(&saddr_un)) < 0)
13894 #endif /* FWDX_UNIX_SOCK */
13896 /* Otherwise, we are assuming FamilyInternet */
13898 ckstrncpy(buf,host,sizeof(buf));
13901 ckstrncpy(buf,myipaddr,sizeof(buf));
13903 debug(F111,"fwdx_create_client_channel()","display",display);
13905 port = 6000 + display;
13906 saddr.sin_port = htons(port);
13908 debug(F110,"fwdx_create_client_channel() ip-address",buf,0);
13909 saddr.sin_addr.s_addr = inet_addr(buf);
13910 if ( saddr.sin_addr.s_addr == (unsigned long) -1
13912 || saddr.sin_addr.s_addr == INADDR_NONE
13913 #endif /* INADDR_NONE */
13916 struct hostent *host;
13917 host = gethostbyname(buf);
13918 if ( host == NULL )
13920 host = ck_copyhostent(host);
13923 /* This is for trying multiple IP addresses - see <netdb.h> */
13924 if (!(host->h_addr_list))
13926 bcopy(host->h_addr_list[0],
13927 (caddr_t)&saddr.sin_addr,
13931 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13932 #endif /* h_addr */
13933 #else /* HADDRLIST */
13934 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
13935 #endif /* HADDRLIST */
13938 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
13939 debug(F111,"fwdx_create_client_channel()","socket() < 0",sock);
13943 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
13944 debug(F110,"fwdx_create_client_channel()","connect() failed",0);
13946 socket_close(sock);
13947 #else /* TCPIPLIB */
13949 #endif /* TCPIPLIB */
13954 setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
13955 #endif /* TCP_NODELAY */
13958 for (i = 0; i < MAXFWDX; i++) {
13959 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == -1) {
13960 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = sock;
13961 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = channel;
13962 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 1;
13963 debug(F111,"fwdx_create_client_channel()","socket",sock);
13971 fwdx_server_avail() {
13973 struct sockaddr_in saddr;
13974 #ifdef FWDX_UNIX_SOCK
13975 struct sockaddr_un saddr_un = { AF_LOCAL };
13976 #endif /* FWDX_UNIX_SOCK */
13977 int colon, dot, display, port, sock, i, screen;
13978 char buf[256], *host=NULL, *rest=NULL;
13981 #endif /* TCP_NODELAY */
13984 env = getenv("DISPLAY");
13986 env = (char *)tn_get_display();
13988 ckstrncpy(buf,env,256);
13990 ckstrncpy(buf,"127.0.0.1:0.0",256);
13992 bzero((char *)&saddr,sizeof(saddr));
13993 saddr.sin_family = AF_INET;
13995 if (!fwdx_parse_displayname(buf,&family,&host,&display,&screen,&rest)) {
13996 if ( host ) free(host);
13997 if ( rest ) free(rest);
14000 if (rest) free(rest);
14002 #ifndef FWDX_UNIX_SOCK
14003 /* if $DISPLAY indicates use of unix domain sockets, but we don't support it,
14004 * we change things to use inet sockets on the ip loopback interface instead,
14005 * and hope that it works.
14007 if (family == FamilyLocal) {
14008 family = FamilyInternet;
14009 if (host) free(host);
14010 if (host = malloc(strlen("localhost") + 1))
14011 strcpy(host, "localhost");
14016 #else /* FWDX_UNIX_SOCK */
14017 if (family == FamilyLocal) {
14018 debug(F100,"fwdx_server_avail() FamilyLocal","",0);
14019 if (host) free(host);
14020 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
14024 ckmakmsg(buf,sizeof(buf),"/tmp/.X11-unix/X",ckitoa(display),NULL,NULL);
14025 strncpy(saddr_un.sun_path, buf, sizeof(saddr_un.sun_path));
14026 if (connect(sock,(struct sockaddr *)&saddr_un,SUN_LEN(&saddr_un)) < 0)
14031 #endif /* FWDX_UNIX_SOCK */
14033 /* Otherwise, we are assuming FamilyInternet */
14035 ckstrncpy(buf,host,sizeof(buf));
14038 ckstrncpy(buf,myipaddr,sizeof(buf));
14040 debug(F111,"fwdx_server_avail()","display",display);
14042 port = 6000 + display;
14043 saddr.sin_port = htons(port);
14045 debug(F110,"fwdx_server_avail() ip-address",buf,0);
14046 saddr.sin_addr.s_addr = inet_addr(buf);
14047 if ( saddr.sin_addr.s_addr == (unsigned long) -1
14049 || saddr.sin_addr.s_addr == INADDR_NONE
14050 #endif /* INADDR_NONE */
14053 struct hostent *host;
14054 host = gethostbyname(buf);
14055 if ( host == NULL ) {
14056 debug(F110,"fwdx_server_avail() gethostbyname() failed",
14060 host = ck_copyhostent(host);
14063 /* This is for trying multiple IP addresses - see <netdb.h> */
14064 if (!(host->h_addr_list))
14066 bcopy(host->h_addr_list[0],
14067 (caddr_t)&saddr.sin_addr,
14071 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14072 #endif /* h_addr */
14073 #else /* HADDRLIST */
14074 bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
14075 #endif /* HADDRLIST */
14078 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
14079 debug(F111,"fwdx_server_avail()","socket() < 0",sock);
14083 if ( connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
14084 debug(F110,"fwdx_server_avail()","connect() failed",0);
14086 socket_close(sock);
14087 #else /* TCPIPLIB */
14089 #endif /* TCPIPLIB */
14094 socket_close(sock);
14095 #else /* TCPIPLIB */
14097 #endif /* TCPIPLIB */
14102 fwdx_open_server_channel() {
14103 int sock, ready_to_accept, sock2,channel,i;
14106 #endif /* TCP_NODELAY */
14108 static u_int saddrlen;
14110 static SOCKOPT_T saddrlen;
14112 struct sockaddr_in saddr;
14114 extern char tn_msg[];
14127 #endif /* BELLSELECT */
14128 #endif /* BSDSELECT */
14129 unsigned short nchannel;
14132 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket;
14137 tv.tv_sec = tv.tv_usec = 0L;
14140 FD_SET(sock, &rfds);
14142 ((select(FD_SETSIZE,
14149 #endif /* HPUX1010 */
14153 #endif /* __DECC */
14155 &rfds, NULL, NULL, &tv) > 0) &&
14156 FD_ISSET(sock, &rfds));
14157 #else /* BSDSELECT */
14159 ready_to_accept = (select(&sock, 1, 0, 0, 50) == 1);
14163 FD_SET(sock, rfds);
14165 ((select(128, rfds, NULL, NULL, 50) > 0) &&
14166 FD_ISSET(sock, rfds));
14168 /* Try this - what's the worst that can happen... */
14170 tv.tv_sec = tv.tv_usec = 0L;
14173 FD_SET(sock, &rfds);
14175 ((select(FD_SETSIZE,
14176 (fd_set *) &rfds, NULL, NULL, &tv) > 0) &&
14177 FD_ISSET(sock, &rfds));
14178 #endif /* BELLSELECT */
14179 #endif /* IBMSELECT */
14180 #endif /* BSDSELECT */
14182 if ( !ready_to_accept )
14185 if ((sock2 = accept(sock,(struct sockaddr *)&saddr,&saddrlen)) < 0) {
14186 int i = errno; /* save error code */
14187 debug(F101,"tcpsrv_open accept errno","",i);
14192 * Now we have the open socket. We must now find a channel to store
14193 * it in, and then notify the client.
14196 for ( channel=0;channel<MAXFWDX;channel++ ) {
14197 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd == -1 )
14201 if ( channel == MAXFWDX ) {
14203 socket_close(sock2);
14204 #else /* TCPIPLIB */
14206 #endif /* TCPIPLIB */
14210 if ( fwdx_send_open(channel) < 0 ) {
14212 socket_close(sock2);
14213 #else /* TCPIPLIB */
14215 #endif /* TCPIPLIB */
14219 setsockopt(sock2,IPPROTO_TCP,TCP_NODELAY,(char *)&on,sizeof(on));
14220 #endif /* TCP_NODELAY */
14222 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].fd = sock2;
14223 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[channel].id = channel;
14226 return(0); /* never reached */
14230 fwdx_close_channel(channel) int channel; {
14233 for ( i=0; i<MAXFWDX ; i++ ) {
14234 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14237 if ( i == MAXFWDX )
14240 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14241 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd = -1;
14242 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id = -1;
14243 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].need_to_send_xauth = 0;
14247 #else /* TCPIPLIB */
14249 #endif /* TCPIPLIB */
14257 debug(F111,"fwdx_close_all()",
14258 "TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket",
14259 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14261 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1 ) {
14263 socket_close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14264 #else /* TCPIPLIB */
14265 close(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket);
14266 #endif /* TCPIPLIB */
14267 TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket = -1;
14270 for (x = 0; x < MAXFWDX; x++) {
14271 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14272 fd = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14273 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd = -1;
14274 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id = -1;
14275 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].need_to_send_xauth = 0;
14276 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend = 0;
14279 #else /* TCPIPLIB */
14281 #endif /* TCPIPLIB */
14287 /* The following definitions are for Unix */
14288 #ifndef socket_write
14289 #define socket_write(f,s,n) write(f,s,n)
14290 #endif /* socket_write */
14291 #ifndef socket_read
14292 #define socket_read(f,s,n) read(f,s,n)
14293 #endif /* socket_read */
14296 fwdx_write_data_to_channel(channel, data, len)
14297 int channel; char * data; int len;
14299 int sock, count, try=0, length = len, i;
14304 for ( i=0; i<MAXFWDX ; i++ ) {
14305 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].id == channel)
14308 if ( i == MAXFWDX ) {
14309 debug(F110,"fwdx_write_data_to_channel",
14310 "attempting to write to closed channel",0);
14314 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[i].fd;
14315 debug(F111,"fwdx_write_data_to_channel","socket",sock);
14316 ckhexdump("fwdx_write_data_to_channel",data,len);
14318 fwdx_write_data_to_channel_retry:
14320 if ((count = socket_write(sock,data,len)) < 0) {
14321 int s_errno = socket_errno; /* maybe a function */
14322 debug(F101,"fwdx_write_data_to_channel socket_write error","",s_errno);
14324 printf("fwdx_write_data_to_channel error\r\n");
14325 #endif /* BETATEST */
14327 if (os2socketerror(s_errno) < 0)
14330 return(-1); /* Call it an i/o error */
14333 debug(F111,"fwdx_write_data_to_channel socket_write",data,count);
14338 debug(F111,"fwdx_write_data_to_channel retry",data,len);
14340 goto fwdx_write_data_to_channel_retry;
14343 debug(F111,"fwdx_write_data_to_channel complete",data,length);
14344 return(length); /* success - return total length */
14348 fwdx_check_sockets(fd_set *ibits)
14350 int x, sock, channel, bytes;
14351 static char buffer[32000];
14353 debug(F100,"fwdx_check_sockets()","",0);
14354 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14355 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14356 debug(F110,"fwdx_check_sockets()","TELOPT_FORWARD_X not negotiated",0);
14360 for (x = 0; x < MAXFWDX; x++) {
14361 if ( TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd == -1 ||
14362 TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend )
14365 sock = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd;
14366 if (FD_ISSET(sock, ibits))
14368 channel = TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].id;
14369 debug(F111,"fwdx_check_sockets()","channel set",channel);
14371 bytes = socket_read(sock, buffer, sizeof(buffer));
14373 fwdx_send_data_from_channel(channel, buffer, bytes);
14374 else if (bytes == 0) {
14375 fwdx_close_channel(channel);
14376 fwdx_send_close(channel);
14383 fwdx_init_fd_set(fd_set *ibits)
14387 if ( sstelnet && !TELOPT_ME(TELOPT_FORWARD_X) ||
14388 !sstelnet && !TELOPT_U(TELOPT_FORWARD_X)) {
14389 debug(F110,"fwdx_init_fd_set()","TELOPT_FORWARD_X not negotiated",0);
14393 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket != -1) {
14395 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.listen_socket, ibits);
14397 for (x = 0; x < MAXFWDX; x++) {
14398 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd != -1) {
14400 if (TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].suspend)
14403 FD_SET(TELOPT_SB(TELOPT_FORWARD_X).forward_x.channel[x].fd, ibits);
14406 if (set + cnt == 0) {
14415 fwdx_thread( VOID * dummy )
14419 extern int priority;
14423 SetThreadPrty(priority,isWin95() ? 3 : 11);
14425 while ( !sstelnet && TELOPT_U(TELOPT_FORWARD_X) ||
14426 sstelnet && TELOPT_ME(TELOPT_FORWARD_X))
14429 n = fwdx_init_fd_set(&ifds);
14433 if ( select(FD_SETSIZE, &ifds, NULL, NULL, &tv) > 0 )
14434 fwdx_check_sockets(&ifds);
14436 } else if (n < 0) {
14437 TELOPT_SB(TELOPT_FORWARD_X).forward_x.thread_started = 0;
14445 #endif /* CK_FORWARD_X */
14446 #endif /* TNCODE */
14447 #endif /* NETCONN */