Is there some trick to making this work on Solaris/SVR4/other sockets over
STREAMS implementations? Is the problem that my call to select() after the
send won't return when the ICMP error arrives (even though I have the socket fd
in both the read and except fd_masks)? Is it only possible to get the error if
I make a blocking recv() call?
There's something in the TLI documentation that claims that TLI endpoints will
get these errors, so it doesn't seem like the kernel is totally broken, but I'd
rather not have to use TLI, as the socket API is much more widespread.
Please send repsonses by mail, and I will summarize to the lists.
@alex
--
inet: du...@cs.columbia.edu
Member of the League for Programming Freedom -- write to l...@uunet.uu.net
I take that back. I think the kernel really is totally broken! I just wrote
two simple programs designed to elicit ICMP port unreachable errors; one uses
sockets, and the other uses TLI. I use nonblocking sockets/TLI endpoints, and
use recv and getsockopt(...SO_ERROR...) to get socket error status, and
t_rcvuderr to get TLI endpoint socket error status. The only combination of
sockets/TLI and SunOS 4/Solaris 2 that gets any error status is sockets/SunOS.
TLI doesn't see any error (other than EAGAIN) on SunOS or Solaris, and the UDP
TLI support from the TI-RPC unsupported package for SunOS doesn't get any
errors either.
I'm enclosing the two simple UDP datagram programs; I would be interested in
knowing if they can detect errors on other non-Sun systems (especially non-BSD
networking systems). I would also welcome any pointers telling me what I'm
doing wrong, and that if I just do XYZ, these programs will work correctly.
@alex
p.s. I find it very amusing that the address format for TCP/UDP/IP TLI
endpoints is a sockaddr_in...
#!/bin/sh
: This is a shar archive. Extract with sh, not csh.
: The rest of this file will extract:
:
: sock.c
: tli.c
:
echo x - sock.c
sed 's/^X//' > sock.c << '//go.sysin dd *'
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <errno.h>
X
Xint
Xmain (int argc, char **argv)
X{
X char message[] = "Hello, World";
X struct sockaddr_in addr;
X int s;
X int flags;
X int optval;
X int optlen;
X int err;
X
X s = socket (PF_INET, SOCK_DGRAM, 0);
X if (s < 0)
X perror ("socket");
X
X flags = fcntl (s, F_GETFL, 0);
X if (flags < 0)
X perror ("fcntl F_GETFL");
X flags |= O_NONBLOCK;
X err = fcntl (s, F_SETFL, flags);
X if (err < 0)
X perror ("fcntl F_SETFL");
X
X addr.sin_family = AF_INET;
X addr.sin_port = 9999;
X addr.sin_addr.s_addr = inet_addr (argv[1]);
X
X err = connect (s, (struct sockaddr *) &addr, sizeof (addr));
X if (err < 0)
X perror ("connect");
X
X err = send (s, message, sizeof (message), 0);
X if (err < 0)
X perror ("send");
X
X sleep (1);
X
X err = recv (s, message, sizeof (message), 0);
X if (err < 0)
X perror ("recv");
X
X optlen = sizeof (optval);
X err = getsockopt (s, SOL_SOCKET, SO_ERROR, (char *) &optval, &optlen);
X if (err < 0)
X perror ("getsockopt");
X
X if (optval)
X {
X errno = optval;
X perror ("socket error");
X }
X
X return 0;
X}
//go.sysin dd *
echo x - tli.c
sed 's/^X//' > tli.c << '//go.sysin dd *'
X#include <stdio.h>
X#include <fcntl.h>
X#include <tiuser.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
Xint
Xmain (int argc, char **argv)
X{
X char message[] = "Hello, World";
X int t;
X int err;
X int flags;
X struct t_unitdata *ud;
X struct t_uderr *uderr;
X struct sockaddr_in addr;
X
X t = t_open ("/dev/udp", O_RDWR, 0);
X if (t < 0)
X t_error ("/dev/udp");
X
X flags = fcntl (t, F_GETFL, 0);
X if (flags < 0)
X perror ("fcntl F_GETFL");
X flags |= O_NONBLOCK;
X err = fcntl (t, F_SETFL, flags);
X if (err < 0)
X perror ("fcntl F_SETFL");
X
X addr.sin_family = AF_INET;
X addr.sin_port = 9999;
X addr.sin_addr.s_addr = inet_addr (argv[1]);
X
X err = t_bind (t, 0, 0);
X if (err < 0)
X t_error ("t_bind");
X
X ud = (struct t_unitdata *) t_alloc (t, T_UNITDATA, T_ALL);
X if (!ud)
X t_error ("t_alloc");
X
X ud->addr.maxlen = sizeof (addr);
X ud->addr.len = sizeof (addr);
X ud->addr.buf = (char *) &addr;
X
X ud->opt.maxlen = 0;
X ud->opt.len = 0;
X ud->opt.buf = 0;
X
X ud->udata.maxlen = sizeof (message);
X ud->udata.len = sizeof (message);
X ud->udata.buf = message;
X
X err = t_sndudata (t, ud);
X if (err < 0)
X t_error ("t_sndudata");
X
X sleep (1);
X
X flags = 0;
X err = t_rcvudata (t, ud, &flags);
X if (err < 0)
X t_error ("t_rcvudata");
X
X if (flags)
X fprintf (stderr, "flags=%#x\n", flags);
X
X uderr = (struct t_uderr *) t_alloc (t, T_UDERROR, T_ALL);
X if (!uderr)
X t_error ("t_alloc");
X
X uderr->addr = ud->addr;
X uderr->opt = ud->opt;
X uderr->error = 0;
X
X err = t_rcvuderr (t, uderr);
X if (err < 0)
X t_error ("t_rcvuderr");
X
X fprintf (stderr, "error=%d\n", uderr->error);
X
X return 0;
X}
//go.sysin dd *
exit