[alt.sys.sun] Maybe I am missing something....but why doesn't this work?

brad@bradley.bradley.edu (Bradley E. Smith) (05/29/91)

I am not sure why but the following program has problems.....

HARDWARE USED:

SUN 470 SunOS 4.1.1		- NO
SUN SLC SunOS 4.1.1		- NO
IBM RT BSD OS			- YES
AT&T 3B2 WIN TCP 3.2		- YES
AT&T 386 WIN TCP 3.0		- YES

What happens:  As the program is listed below (make sure you change
the host name if you are going to try it), 'bind(2)' fails on the
suns with EADDRNOTAVAIL.  The other machines work just fine.

If I change/remove the x(), and the '{' '}' so that the whole
program is in 1 function (ie I just delete a few lines everything
is in main()).  It works just fine.

Any thoughts?


#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/socket.h>
#include	<errno.h>
#ifdef SYSV
#include	<sys/in.h>
#include	<sys/inet.h>
#else
#include	<netinet/in.h>
#include	<arpa/inet.h>
#endif
#include	<sys/param.h>
#include	<netdb.h>

extern int errno;

main()
{
	x();
}
x()
{
	int sock2, length;	
	struct sockaddr_in backupserver;
	struct hostent *hp;
	extern struct hostent *gethostbyname();
	extern char *inet_ntoa();
	int sockoptval;
	
	sockoptval = 1;

	hp = gethostbyname("bradley");
	if(hp == NULL) {
		sock2 = errno * -1;
		return(sock2);	/* unknown error */
	}
	sock2 = socket(AF_INET, SOCK_STREAM, 0);
	if(sock2 < 0) {
		sock2 = errno * (-1);
		return(sock2);
	}

	if( setsockopt(sock2, SOL_SOCKET, SO_DEBUG, &sockoptval,
	    sizeof(sockoptval)))
		perror("setsockopt");

	if( setsockopt(sock2, SOL_SOCKET, SO_REUSEADDR, &sockoptval,
	    sizeof(sockoptval)))
		perror("setsockopt");

	backupserver.sin_family = AF_INET;

	bcopy((char *) hp->h_addr, (char *) &backupserver.sin_addr.s_addr,
		hp->h_length);

	backupserver.sin_port = htons(4321);
	length = sizeof(struct sockaddr_in);

	if(bind(sock2, (struct sockaddr *) &backupserver, length)) {
		perror("bind");
		sock2 = errno * (-1);
		return(sock2);
	}
	length = sizeof(backupserver);

	if(getsockname(sock2, (struct sockaddr *)&backupserver, &length)) {
		sock2 = errno * (-1);
		return(sock2);
	}
	(void) printf("OK: Socket has port # %d\n", ntohs(backupserver.sin_port));
	return(sock2);
}
-- 
Bradley Smith
Network & Technical Services @ Bradley University, Peoria, IL
brad@bradley.edu ---  309-677-2337

jik@athena.mit.edu (Jonathan I. Kamens) (05/30/91)

  You need to bzero the sockaddr_in structure (backupserver) before putting
anything into it.

  I compiled your program as-is (with a different host name) and it didn't
work.  I then added the line "bzero((char *) &backupserver,
sizeof(backupserver));" right before "backupserver.sin_family = AF_INET;" and
it worked fine.

-- 
Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8085			      Home: 617-782-0710

rd@zildjian.chorus.fr (Roland Dirlewanger) (05/30/91)

In article <1991May29.145535.23801@bradley.bradley.edu>
brad@bradley.bradley.edu (Bradley E. Smith) writes:

%% I am not sure why but the following program has problems.....
%% 
%% HARDWARE USED:
%% 
%% SUN 470 SunOS 4.1.1		- NO
%% SUN SLC SunOS 4.1.1		- NO
%% IBM RT BSD OS			- YES
%% AT&T 3B2 WIN TCP 3.2		- YES
%% AT&T 386 WIN TCP 3.0		- YES
%% 
%% What happens:  As the program is listed below (make sure you change
%% the host name if you are going to try it), 'bind(2)' fails on the
%% suns with EADDRNOTAVAIL.  The other machines work just fine.
%% 
%% If I change/remove the x(), and the '{' '}' so that the whole
%% program is in 1 function (ie I just delete a few lines everything
%% is in main()).  It works just fine.
%% 
%% [Source program deleted]

Implementations based on the BSD TCP/IP distribution (such as SunOS)
check that the last eight bytes (the sin_zero field) of a sockaddr_in
are set to 0. If not, they complain.

What happens, is that your "struct sockaddr_in backupserver" is
allocated in the stack, thus initialized to random data. In main(),
it happens to be initialized to 0, in x() it's not.

To fix your problem, you may either:

      - declare "struct sockaddr_in backupserver" to be a static
	variable (thus garantied to be zeroed):

	x () {
		...
		static struct sockaddr_in backupserver;
		...
	}

      - insert somewhere before the bind() the following line:

	bzero (backupserver.sin_zero, sizeof backupserver.sin_zero);

Hope this helped.

--
Roland Dirlewanger				E-mail:	rd@chorus.fr
Chorus systemes					Phone:	+33 1 30 64 82 85
6, Avenue Gustave Eiffel			Fax:	+33 1 30 57 00 66
F-78182 St Quentin en Yvelines Cedex

mouse@thunder.mcrcim.mcgill.edu (der Mouse) (06/02/91)

In article <1991May29.145535.23801@bradley.bradley.edu>, brad@bradley.bradley.edu (Bradley E. Smith) writes:

> I am not sure why but the following program has problems.....

[program deleted - problem with bind()]

> HARDWARE USED:

> SUN 470 SunOS 4.1.1		- NO
> SUN SLC SunOS 4.1.1		- NO
> IBM RT BSD OS			- YES
> AT&T 3B2 WIN TCP 3.2		- YES
> AT&T 386 WIN TCP 3.0		- YES

What you need to do is zero the supposedly-unused area of the struct
sockaddr_in before calling bind().  As far as I know SunOS is the only
system that imposes this requirement, but the range of systems I have
actually checked this on is fairly small - 4.3 BSD is the only one that
I'm sure doesn't require it.

Try doing a bzero((char *)&backupserver,sizeof(backupserver)) before
storing anything into it.  That generally does it for me.

The reason calling x() changes things is that backupserver (which is an
auto variable) is allocated at a slightly different place on the stack,
so the unused portion contains different stack trash.  The working way
places it so the unused portion contains zeros.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu