Subject: kern/7004: sendto() on connected socket fails
To: None <gnats-bugs@gnats.netbsd.org>
From: Jonathan Stone <jonathan@DSG.Stanford.EDU>
List: netbsd-bugs
Date: 02/14/1999 20:40:41
>Number:         7004
>Category:       kern
>Synopsis:       sendto() on connected socket fails
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Feb 14 20:50:01 1999
>Last-Modified:
>Originator:     Jonathan Stone
>Organization:
	
>Release:        NetBSD-current as at 1999-02-14; probably also 1.3.x
>Environment:
	
System: NetBSD Cuisinart.Stanford.EDU 1.3I NetBSD 1.3I (TEST-OLD-AS) #2: Sun Feb 14 16:39:20 PST 1999 jonathan@Cuisinart.Stanford.EDU:/cuisinart/compile/TEST-OLD-AS pmax


>Description:

From the manual page for sendto(2):

DESCRIPTION
     send(), sendto(), and sendmsg() are used to transmit a message to another
     socket.  send() may be used only when the socket is in a connected state,
     while sendto() and sendmsg() may be used at any time.


howver, in NetBSD 1.3I, calling sendto() (and presumably sendmsg) on a
connected socket fails.


>How-To-Repeat:

	The appended trivial program demonstrates the bug.

>Fix:

I dunno.
(i)  Back out the fragment 

			if ((so->so_state & SS_ISCONNECTED) != 0) {
				error = EISCONN;
				goto die;
			}

in sys/netinet/udp_usrreq, rev 1.32, in udp_usrreq()'s handler for
case PRU_SEND?  

(ii) Just go back to the old behaviour from 4.3BSD, 4.4-Lite, FreeBSD,
for sendmsg() and sendto()? ie., dont fake up a connect(), and then
undo it, for a PRU_SEND with an explicit non-null destination address?


------ begin sample program
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PKTLEN 1024

const int mcast_ntp_addr = 0xe0000101;	/* 224.0.1.1 */

int verbose = 0;


int
main()
{
	int s;
	struct sockaddr_in sin, sin2;
	char pkt [PKTLEN];
	struct udp *pkthdr;
	int i, result;

	for (i = 0; i < PKTLEN; i++)
		pkt[i] = i % 256;
		     
	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0) {
		perror("socket()");
	       exit(-1);
	}

	/* build address for our sends */		
	bzero(&sin, sizeof(sin));
	sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(mcast_ntp_addr);
	sin.sin_port = htons(4004);	/* XXX */
#ifdef BSD	/* XXX when exactly did sin_len appear? */
	sin.sin_len = sizeof(struct sockaddr_in);
#endif

	/* Create a second, distinct sockaddr_in for connect() */
	sin2 = sin;
	sin2.sin_port = htons(8008);
	
	
	/* do a sendto() on the unconnected socket */
	if (verbose)
		printf ("first sendto...\n");
	result = sendto(s, &pkt, PKTLEN, 0, (struct sockaddr *)&sin,
			sizeof(struct sockaddr_in));
	if (result < 0)
		perror("first sendto");
	
	/* Do connect() in preparation for sendto() on a connected socket. */
	if (verbose) 
		printf ("connect()ing socket...\n");
	if (connect(s, (struct sockaddr *)&sin2, sizeof(sin2)) == -1) {
		perror("connect");	        
		exit(-1);
	}

	/* Do  sendto() on  a connected socket. Supposed to work. */
	if (verbose) 
		printf ("second sendto..\n");
	result = sendto(s, &pkt, PKTLEN, 0, (struct sockaddr *)&sin,
			sizeof(struct sockaddr_in));
	if (result < 0) {
		perror("second sendto");
		exit(errno);
	}
	
	exit(0);
}
------ end sample program
>Audit-Trail:
>Unformatted: