netkit-ntalk (0.17-14) talk/ctl_transact.c

Summary

 talk/ctl_transact.c |   93 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 88 insertions(+), 5 deletions(-)

    
download this patch

Patch contents

--- netkit-ntalk-0.17.orig/talk/ctl_transact.c
+++ netkit-ntalk-0.17/talk/ctl_transact.c
@@ -45,6 +45,7 @@
 /* #include <netinet/ip.h> looks like this is not needed (no functions used) */
 #include <string.h>
 #include <errno.h>
+#include <netdb.h>
 #include "talk.h"
 
 #define CTL_WAIT 2	/* time to wait for a response, in seconds */
@@ -69,15 +70,16 @@
 	if (to_local_talkd < 0 || to_remote_talkd < 0) {
 		p_error("Bad socket");
 	}
-
-#ifdef SO_BSDCOMPAT
+/* agi: SO_BSDCOMPAT is defined, but obsolete in current kernels
+#ifdef SO_BSDCOMPAT */
 	/* 
 	 * Linux does some async error return stuff that
 	 * really disagrees with us. So we disable it.
 	 */
-	setsockopt(to_local_talkd, SOL_SOCKET, SO_BSDCOMPAT, &on, sizeof(on));
+/*	setsockopt(to_local_talkd, SOL_SOCKET, SO_BSDCOMPAT, &on, sizeof(on));
 	setsockopt(to_remote_talkd, SOL_SOCKET, SO_BSDCOMPAT, &on, sizeof(on));
 #endif
+*/
 
 	/*
 	 * Explicitly talk to the local daemon over loopback.
@@ -120,20 +122,45 @@
 		p_error("getsockname");
 	}
 	local_addr_for_remote = rem.sin_addr.s_addr;
+
+#ifdef SUN_HACK
+	personality = P_NORMAL;
+#endif
 }
 
 static void
 send_packet(CTL_MSG *msg, int sock)
 {
 	int cc;
+#ifdef SUN_HACK
+	CTL_MSG_S msg_S;
+	const void *packet;
+	size_t len;
+
+	if (personality == P_SUNOS) {
+		msg2msg_S(msg, &msg_S);
+		packet = &msg_S;
+		len = sizeof(msg_S);
+	} else {
+		packet = msg;
+		len = sizeof(*msg);
+	}
+
+	cc = send(sock, packet, len, 0);
+#else
 	cc = send(sock, msg, sizeof(*msg), 0);
+#endif
 	if (cc<0 && errno == EINTR) {
 		return;
 	}
 	else if (cc<0) {
 	    p_error("Error on write to talk daemon");
 	}
+#ifdef SUN_HACK
+	else if (((size_t) cc) != len) {
+#else
 	else if (cc != sizeof(*msg)) {
+#endif
 	    p_error("Short write to talk daemon");
 	}
 }
@@ -170,6 +197,36 @@
 	send_packet(&tmp, sock);
 }
 
+#ifdef SUN_HACK
+static void
+reconnect(void)
+{
+	struct sockaddr_in loc, rem;
+
+	daemon_port = getservbyname("talk", "udp")->s_port;
+
+	memset(&loc, 0, sizeof(loc));
+	loc.sin_family = AF_INET;
+	loc.sin_port = daemon_port;
+	loc.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+	if (connect(to_local_talkd, (struct sockaddr *)&loc, sizeof(loc))<0) {
+		p_error("Couldn't connect local control socket");
+	}
+
+	memset(&rem, 0, sizeof(rem));
+	rem.sin_family = AF_INET;
+	rem.sin_port = daemon_port;
+	rem.sin_addr = his_machine_addr;
+
+	if (connect(to_remote_talkd, (struct sockaddr *)&rem, sizeof(rem))<0) {
+		p_error("Couldn't connect remote control socket");
+	}
+
+	personality = P_SUNOS;
+}
+#endif
+
 /*
  * SOCKDGRAM is unreliable, so we must repeat messages if we have
  * not received an acknowledgement within a reasonable amount
@@ -192,6 +249,9 @@
 	do {
 		/* resend message until a response is obtained */
 		do {
+#ifdef SUN_HACK
+again:
+#endif
 			send_packet(mesg, sock);
 			read_mask = ctl_mask;
 			wait.tv_sec = CTL_WAIT;
@@ -209,12 +269,35 @@
 		 * request/acknowledgements being sent)
 		 */
 		do {
-			cc = recv(sock, (char *)rp, sizeof (*rp), 0);
+#ifdef SUN_HACK
+			CTL_RESPONSE_S rp_S;
+
+                        if (personality==P_NORMAL)
+#endif
+				cc = recv(sock, (char *)rp,
+					  sizeof (*rp), 0);
+#ifdef SUN_HACK
+                        else
+ 				cc = recv(sock, (char *)&rp_S,
+ 					  sizeof (rp_S), 0);
+#endif
 			if (cc < 0) {
 				if (errno == EINTR)
-					continue;
+					continue;				
+#ifdef SUN_HACK
+				if (errno == ECONNREFUSED &&
+				    personality == P_NORMAL &&
+				    sock == to_remote_talkd) {
+					reconnect();
+					goto again;
+				}
+#endif
 				p_error("Error on read from talk daemon");
 			}
+#ifdef SUN_HACK
+			if (personality==P_SUNOS) 
+				resp_S2resp(&rp_S, rp);
+#endif
 			read_mask = ctl_mask;
 			/* an immediate poll */
 			timerclear(&wait);