+void *sk_getxdmdata(void *sock, int *lenp)
+{
+ Actual_Socket s = (Actual_Socket) sock;
+#ifdef NO_IPV6
+ struct sockaddr_in addr;
+#else
+ struct sockaddr_storage addr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+#endif
+ struct sockaddr *sa = (struct sockaddr *)&addr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+ socklen_t addrlen;
+ char *buf;
+ static unsigned int unix_addr = 0xFFFFFFFF;
+
+ /*
+ * We must check that this socket really _is_ an Actual_Socket.
+ */
+ if (s->fn != &tcp_fn_table)
+ return NULL; /* failure */
+
+ addrlen = sizeof(addr);
+ if (getsockname(s->s, sa, &addrlen) < 0)
+ return NULL;
+ switch(sa->sa_family) {
+ case AF_INET:
+ *lenp = 6;
+ buf = snewn(*lenp, char);
+ PUT_32BIT_MSB_FIRST(buf, ntohl(sin->sin_addr.s_addr));
+ PUT_16BIT_MSB_FIRST(buf+4, ntohs(sin->sin_port));
+ break;
+#ifndef NO_IPV6
+ case AF_INET6:
+ *lenp = 6;
+ buf = snewn(*lenp, char);
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ memcpy(buf, sin6->sin6_addr.s6_addr + 12, 4);
+ PUT_16BIT_MSB_FIRST(buf+4, ntohs(sin6->sin6_port));
+ } else
+ /* This is stupid, but it's what XLib does. */
+ memset(buf, 0, 6);
+ break;
+#endif
+ case AF_UNIX:
+ *lenp = 6;
+ buf = snewn(*lenp, char);
+ PUT_32BIT_MSB_FIRST(buf, unix_addr--);
+ PUT_16BIT_MSB_FIRST(buf+4, getpid());
+ break;
+
+ /* XXX IPV6 */
+
+ default:
+ return NULL;
+ }
+
+ return buf;
+}
+