accept() and getpeername() return 0.0.0.0

  • Follow


I think I'm dealing with a bug in a library or some weird problem.  The
following code compiles and works as I'd expect on Linux and cygwin, but on
the machine that matters (HP PA64, HPUX 11.11) it identifies the peer as
0.0.0.0 in both the accept() and getpeername() return vals, also identifies
the peer port as 0.  I'm using gcc 4.1.2, downloaded from HP's site,
compiling with 'gcc sockprob.c -o sockprob', then running it with
'./sockprob.c MY.I.P.ADD 7890', then connect to the server socket with
'telnet MY.I.P.ADD 7890'.  Cygwin and Linux show the ip and port of the
connector, but HPUX is showing 0.0.0.0.  I run a 'netstat -n' and it shows
the correct ip/port for the server and client.  I just don't get it.  Does
anyone have any advice?  Anyone seen stuff like this with gcc on PA64?

Thanks and sorry in advance.  I'm not a newsgroup frequent flyer - I just 
got flamed for posting the same question on comp.lang.c.  If you know of a 
good place to ask then please tell me.

-M

#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

char* ipstring;
int port1;

void parseargs(int, char**);

int main(int argc, char* args[])
{ struct sockaddr_in adr1;  /* address for the server */
  int ss1, as1;             /* file descriptors for server socket, active
socket */

  struct sockaddr_in from1; /* address for peer */
  socklen_t from1_len;

  parseargs(argc, args);

  if((ss1 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  { perror("socket failed");
    return 1;
  }

  memset(&adr1, 0, sizeof(adr1));
  adr1.sin_family = AF_INET;
  adr1.sin_port = htons(port1);

  if(!inet_aton(ipstring, (struct in_addr*)&(adr1.sin_addr)))
  { perror("inet_aton failed");
    return 1;
  }

  if(bind(ss1, (struct sockaddr*) &adr1, sizeof(adr1)))
  { perror("bind failed");
    return 1;
  }

  if(listen(ss1, 1) < 0)
  { perror("listen failed");
    return 1;
  }

  from1_len = sizeof(from1);
  memset(&from1, 0, sizeof(from1));
  from1.sin_family = AF_INET;

  if((as1 = accept(ss1, (struct sockaddr*) &from1, &from1_len)) == -1)
  { perror("Error accepting");
    return 1;
  }

  printf("peer address from accept() is %s %d\n",
          inet_ntoa(from1.sin_addr), ntohs(from1.sin_port));


  if(getpeername(as1, (struct sockaddr*) &from1, &from1_len))
  { perror("getpeername failed");
    return 1;
  }

  printf("peer add/port from getpeername() is %s %d\n",
          inet_ntoa(from1.sin_addr), ntohs(from1.sin_port));

  return 0;
}

void parseargs(int argc, char* args[])
{
  /* command line is sockprob ip port */
  ipstring = args[1];
  sscanf(args[2], "%d", &port1);
  return;
}




0
Reply Mike 2/27/2007 3:55:09 AM

Thanks for the reply - from1_len is 16 before and 16 after the accept() 
call.  I did a printf for each of the 16 bytes and it's all 0 except the 
second byte (socket family) which is 2, which is what the sys/socket.h 
header says for AF_INET.

Unfortunately, I don't have the full ansi cc product at my disposal, but if 
you think that's the solution then I'll pursue that.

Thanks,
Mike

"Vishwas Pai" <noman@noland.invalid> wrote in message 
news:Y0PEh.526$Gc5.402@news.cpqcorp.net...
>>
>>   from1_len = sizeof(from1);
>>   memset(&from1, 0, sizeof(from1));
>>   from1.sin_family = AF_INET;
>>
>>   if((as1 = accept(ss1, (struct sockaddr*) &from1, &from1_len)) == -1)
>>   { perror("Error accepting");
>>     return 1;
>>   }
>
> What is the value of "from1_len" after the accept call ^ ?
>
> Also, could you compile the same with HP C compiler
> and see if there is any difference ?
>
>>
>>   printf("peer address from accept() is %s %d\n",
>>           inet_ntoa(from1.sin_addr), ntohs(from1.sin_port));
>>
>
> If "from1_len" is zero (or invalid) above, you need to
> re-initialize it here.
>
>>
>>   if(getpeername(as1, (struct sockaddr*) &from1, &from1_len))
>>   { perror("getpeername failed");
>>     return 1;
>>   }
>
> --vishwas. 


0
Reply Mike 2/27/2007 4:35:27 AM


> 
>   from1_len = sizeof(from1);
>   memset(&from1, 0, sizeof(from1));
>   from1.sin_family = AF_INET;
> 
>   if((as1 = accept(ss1, (struct sockaddr*) &from1, &from1_len)) == -1)
>   { perror("Error accepting");
>     return 1;
>   }

What is the value of "from1_len" after the accept call ^ ?

Also, could you compile the same with HP C compiler
and see if there is any difference ?

> 
>   printf("peer address from accept() is %s %d\n",
>           inet_ntoa(from1.sin_addr), ntohs(from1.sin_port));
> 

If "from1_len" is zero (or invalid) above, you need to
re-initialize it here.

> 
>   if(getpeername(as1, (struct sockaddr*) &from1, &from1_len))
>   { perror("getpeername failed");
>     return 1;
>   }

--vishwas.
0
Reply Vishwas 2/27/2007 5:08:08 AM

Mike King wrote:
> Thanks for the reply - from1_len is 16 before and 16 after the accept() 
> call.  I did a printf for each of the 16 bytes and it's all 0 except the 
> second byte (socket family) which is 2, which is what the sys/socket.h 
> header says for AF_INET.
> 
> Unfortunately, I don't have the full ansi cc product at my disposal, but if 
> you think that's the solution then I'll pursue that.
> 

I don't think you need to test this with HP CC.

You can try installing the latest transport patches
(PHNE_35183 ,which has few dependencies, is the latest
transport patch for 11.11).

--vishwas.
0
Reply Vishwas 2/27/2007 9:23:37 AM

A 32-bit compilation of the program appears to work on my PA-RISC
11.11 system:

$ ./tryme 127.0.0.1 12345     
peer address from accept() is 127.0.0.1 55063
peer add/port from getpeername() is 127.0.0.1 55063

I do though get the following warnings in the compile:

cc -o tryme tryme.c
cc: "tryme.c", line 54: warning 604: Pointers are not assignment-compatible.
cc: "tryme.c", line 54: warning 563: Argument #3 is not the correct type.
cc: "tryme.c", line 63: warning 604: Pointers are not assignment-compatible.
cc: "tryme.c", line 63: warning 563: Argument #3 is not the correct type.


However a 64-bit compilation does not:

$ ./tryme 127.0.0.1 12345
peer address from accept() is 0.0.0.0 0
peer add/port from getpeername() is 0.0.0.0 0


The 64-bit compilation gave me the following warnings:

cc +DD64 -o tryme tryme.c
cc: "tryme.c", line 54: warning 728: Argument #3 converts long* to int*.
cc: "tryme.c", line 63: warning 728: Argument #3 converts long* to int*.

I believe this all stems from the use of socklen_t, which IMO HP-UX
11.11 has rather well and truly botched.  By default there is a
socklen_t available, but the "default" socket calls do not use it,
they use an int.  Only the XOPEN (IIRC) socket calls use the
socklen_t, and you only get those calls when setting the apropriate
XOPEN define.

That is all well and good save for the observation that socklen_t is
(IIRC) defined as a size_t, which is then defined as a long.  In
64-bit a long is 8 bytes and an int is 4 bytes (hence that warning -
64-bit HP-UX is "LP64" - Longs and Pointers 64-bit - Ints remain
32-bit) and the nature of the things (I'm guessing) is such that the
pointer is to the high-order bytes, which the call will take as the
int and so will believe that the value you are passing-in is actually
0 rather than 16.  So, it says you have no space for the from and so
it puts nothing there.

If in your source I replace "socklen_t" with "int" the 64-bit
compilation warnings go away:

cc +DD64 -o tryme tryme.c

and the code behaves correctly:

$ ./tryme 127.0.0.1 12345        
peer address from accept() is 127.0.0.1 55080
peer add/port from getpeername() is 127.0.0.1 55080

(the 32-bit compilation warnings go away too)

hth,

rick jones

PS - there is a bunch of backflipping in the netperf configure script
to decide on the "right" value to use for socklen_t to take care of
compilation warnings.  You might examine that for ideas if this code
is to be compiled on multiple platforms.  http://www.netperf.org/


-- 
web2.0 n, the dot.com reunion tour...
these opinions are mine, all mine; HP might not want them anyway... :)
feel free to post, OR email to rick.jones2 in hp.com but NOT BOTH...
0
Reply Rick 2/27/2007 7:42:43 PM

You nailed it.  I replaced socklen_t with int and it works.  Funny that with 
gcc it actually introduced a compile warning about passing int* when 
socklen_t* was expected.  So I changed it back to socklen_t, then put a

'from1_len = from1_len << 32;'

line in there to shift the value into the 4 high bytes.  It worked.

Thank you very much for your time - you and Vishwas both.  I'm also going to 
install the arpa patch at our next scheduled downtime.

Sincerely,
Mike

"Rick Jones" <rick.jones2@hp.com> wrote in message 
news:TQ%Eh.541$Xy5.505@news.cpqcorp.net...
>A 32-bit compilation of the program appears to work on my PA-RISC
> 11.11 system:
>
> $ ./tryme 127.0.0.1 12345
> peer address from accept() is 127.0.0.1 55063
> peer add/port from getpeername() is 127.0.0.1 55063
>
> I do though get the following warnings in the compile:
>
> cc -o tryme tryme.c
> cc: "tryme.c", line 54: warning 604: Pointers are not 
> assignment-compatible.
> cc: "tryme.c", line 54: warning 563: Argument #3 is not the correct type.
> cc: "tryme.c", line 63: warning 604: Pointers are not 
> assignment-compatible.
> cc: "tryme.c", line 63: warning 563: Argument #3 is not the correct type.
>
>
> However a 64-bit compilation does not:
>
> $ ./tryme 127.0.0.1 12345
> peer address from accept() is 0.0.0.0 0
> peer add/port from getpeername() is 0.0.0.0 0
>
>
> The 64-bit compilation gave me the following warnings:
>
> cc +DD64 -o tryme tryme.c
> cc: "tryme.c", line 54: warning 728: Argument #3 converts long* to int*.
> cc: "tryme.c", line 63: warning 728: Argument #3 converts long* to int*.
>
> I believe this all stems from the use of socklen_t, which IMO HP-UX
> 11.11 has rather well and truly botched.  By default there is a
> socklen_t available, but the "default" socket calls do not use it,
> they use an int.  Only the XOPEN (IIRC) socket calls use the
> socklen_t, and you only get those calls when setting the apropriate
> XOPEN define.
>
> That is all well and good save for the observation that socklen_t is
> (IIRC) defined as a size_t, which is then defined as a long.  In
> 64-bit a long is 8 bytes and an int is 4 bytes (hence that warning -
> 64-bit HP-UX is "LP64" - Longs and Pointers 64-bit - Ints remain
> 32-bit) and the nature of the things (I'm guessing) is such that the
> pointer is to the high-order bytes, which the call will take as the
> int and so will believe that the value you are passing-in is actually
> 0 rather than 16.  So, it says you have no space for the from and so
> it puts nothing there.
>
> If in your source I replace "socklen_t" with "int" the 64-bit
> compilation warnings go away:
>
> cc +DD64 -o tryme tryme.c
>
> and the code behaves correctly:
>
> $ ./tryme 127.0.0.1 12345
> peer address from accept() is 127.0.0.1 55080
> peer add/port from getpeername() is 127.0.0.1 55080
>
> (the 32-bit compilation warnings go away too)
>
> hth,
>
> rick jones
>
> PS - there is a bunch of backflipping in the netperf configure script
> to decide on the "right" value to use for socklen_t to take care of
> compilation warnings.  You might examine that for ideas if this code
> is to be compiled on multiple platforms.  http://www.netperf.org/
>
>
> -- 
> web2.0 n, the dot.com reunion tour...
> these opinions are mine, all mine; HP might not want them anyway... :)
> feel free to post, OR email to rick.jones2 in hp.com but NOT BOTH... 


0
Reply Mike 2/28/2007 1:24:47 AM

Don't worry, I'm not going to get creative with shifting - I just did that 
to confirm your theory.  I think gcc is using it's own headers that came 
with it because the man pages show that int* is expected as you say.  The 
gcc headers must have gratuitously changed the int* to socklen_t*, hence the 
compile warning.  I supposed that's what I get for using a non-native 
compiler.

Mike

"Rick Jones" <rick.jones2@hp.com> wrote in message 
news:Z86Fh.559$by5.196@news.cpqcorp.net...
> Mike King <wmk77@cox.net> wrote:
>> You nailed it.  I replaced socklen_t with int and it works.  Funny
>> that with gcc it actually introduced a compile warning about passing
>> int* when socklen_t* was expected.
>
> Odd - unless gcc was doing something funny, an int * should have been
> expected.
>
>> So I changed it back to socklen_t, then put a
>> 'from1_len = from1_len << 32;'
>
>> line in there to shift the value into the 4 high bytes.  It worked.
>
> Stick with using an int if you can - or switch to the XOPEN socket
> style.  I'd suggest staying far away from the shift experiment :)
>
> rick jones
> -- 
> oxymoron n, Hummer H2 with California Save Our Coasts and Oceans plates
> these opinions are mine, all mine; HP might not want them anyway... :)
> feel free to post, OR email to rick.jones2 in hp.com but NOT BOTH... 


0
Reply Mike 2/28/2007 2:29:17 AM

Mike King <wmk77@cox.net> wrote:
> You nailed it.  I replaced socklen_t with int and it works.  Funny
> that with gcc it actually introduced a compile warning about passing
> int* when socklen_t* was expected. 

Odd - unless gcc was doing something funny, an int * should have been
expected.

> So I changed it back to socklen_t, then put a
> 'from1_len = from1_len << 32;'

> line in there to shift the value into the 4 high bytes.  It worked.

Stick with using an int if you can - or switch to the XOPEN socket
style.  I'd suggest staying far away from the shift experiment :)

rick jones
-- 
oxymoron n, Hummer H2 with California Save Our Coasts and Oceans plates
these opinions are mine, all mine; HP might not want them anyway... :)
feel free to post, OR email to rick.jones2 in hp.com but NOT BOTH...
0
Reply Rick 2/28/2007 2:53:45 AM

7 Replies
311 Views

(page loaded in 0.795 seconds)

Similiar Articles:













7/29/2012 7:54:07 PM


Reply: