This is a discussion on accept() and getpeername() return 0.0.0.0 within the HP-UX Operating System forums, part of the Unix Operating Systems category; --> I think I'm dealing with a bug in a library or some weird problem. The following code compiles and ...
| |||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| 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; } |
| |||
| > > 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. |
| |||
| 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. |
| |||
| 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. |
| |||
| 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... |
| |||
| 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... |
| |||
| 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... |
| ||||
| 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... |