Discussion:
Recv on a socket
(too old to reply)
coardump
2005-03-15 10:32:56 UTC
Permalink
Hi all, I was wondering if someone could look over the attached code
and tell me what I have done wrong, no doubt several things.

-bash-2.05b$ ./d 192.168.1.2 22 aaaaa


Connected!! Reading from the socket....!
Snarfed:
Data aaaaa

Size 6

Sending buffer....
Sent [5] bytes to [192.168.1.2]
Data sent -> [aaaaa]

Snarfed:
Data aaaaa

Size 6
-bash-2.05b$


As you can see, when I send 5 bytes, the code will recv 6 bytes, I
guess it's a NULL byte but I can't think of a way to remove it other
than hard coding the buffer limit, which sadly has to be dynamic as the
data being recv()'d is unknown in size. Can csomeone suggest how I can

a) sort this code to recv() correctly, by that I mean if I sent 5 'a's
it should show 5 'a's AND total '5' in the Sent area.

b) any other issues that glare at you?

Once I fix this issue I will malloc my storage areas too.


Appreciated,
coardump.


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


#define MAX_RECV_BUF 1000
#define ERR 1

int banner(int argc, char **argv);
int socksnarf(int bytes, int sockfd, char *buf);
int socksend(int bytes, int sockfd, char *data, struct sockaddr_in
addr);
int main(int argc, char **argv);


int
banner(int argc, char **argv)
{
fprintf(stderr,
"\n+------------------------------------------");
fprintf(stderr, "\nSends data bulks to a remote TCP socket");
fprintf(stderr, "\nUsage: %s <ip> <port> <data>", argv[0]);
fprintf(stderr,
"\n+------------------------------------------");
fprintf(stderr, "\nExample:\n\t %s 192.168.1.1 23 `perl -e
'print \"A\" x 5000'`\n\n", argv[0]);

return(1);
}


int
socksnarf(int bytes, int sockfd, char *buf)
{

if((bytes = recv(sockfd, buf, MAX_RECV_BUF - 1, 0)) < 0) {
perror("recv");
_exit(ERR);
}

buf[bytes] = '\0';

fprintf(stderr, "Snarfed:\nData %s \nSize %d\n", buf, bytes);

return(0);
}


int
socksend(int bytes, int sockfd, char *data, struct sockaddr_in addr)
{

fprintf(stderr, "\nSending buffer....");

if((bytes = send(sockfd, data, strlen(data), 0)) == NULL) {
perror("send");
_exit(ERR);
}

printf("\nSent [%d] bytes to [%s]\n", strlen(data),
inet_ntoa(addr.sin_addr));
printf("Data sent -> [%s]\n\n", data);

return(0);
}


int
main(int argc, char **argv)
{
char *data = NULL;
char buf[1024];

int bytes, port, sockfd;

struct sockaddr_in addr;
struct hostent *host;


if(argc < 4) {
banner(argc, argv);
}

port = atoi(argv[2]);
if(!port) {
fprintf(stderr, "um, port seems to be NULL :/!\n");
_exit(ERR);
}

data = argv[3]; /* Did malloc data but removed it incase it
caused my issue, seems not */
if(!data) {
fprintf(stderr, "um, data pointer is NULL :/!\n");
_exit(ERR);
}

if((host = gethostbyname(argv[1])) == NULL) {
perror("gethostbyname");
exit(ERR);
}

bzero((char *)&addr, sizeof(addr));

addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr((char*)argv[1]);

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
_exit(ERR);
}

if(connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("\nconnect");
_exit(ERR);
}else{
printf("\n\nConnected!! Reading from the
socket....!\n");
}

socksnarf(bytes, sockfd, buf);
if(!socksnarf) {
perror("socksnarf");
_exit(ERR);
}

sleep(2);

socksend(bytes, sockfd, data, addr);
if(!socksnarf) {
perror("socksnarf");
_exit(ERR);
}

sleep(2);

socksnarf(bytes, sockfd, buf);
if(!socksnarf) {
perror("socksnarf");
_exit(ERR);
}

close(sockfd);
if(!sockfd) {
perror("close");
_exit(ERR);
}

return(0);
}
Rainer Temme
2005-03-15 12:49:40 UTC
Permalink
Hi coardump (a real name would certainly be preferred ...

Besides some constructions that are completely senseless
as you use them (and which are common for folks who came from pascal)
Post by coardump
socksnarf(bytes, sockfd, buf);
if(!socksnarf) {
perror("socksnarf");
_exit(ERR);
}
Since socksnarf is a function the "if (!socksnarf)"
would only be executed if the pointer were NULL ...
in this case the program would non even have compiled.
Yes, I know that pascal is different ... but this is C.

as said, besides this ...
... your code and the output is consistent !!! ... (amazed???)
Post by coardump
Data aaaaa
Size 6
comes from this fprintf()
Post by coardump
fprintf(stderr, "Snarfed:\nData %s \nSize %d\n", buf, bytes);
Sent [5] bytes to [192.168.1.2]
Data sent -> [aaaaa]
comes from these printf's
Post by coardump
printf("\nSent [%d] bytes to [%s]\n", strlen(data),
inet_ntoa(addr.sin_addr));
printf("Data sent -> [%s]\n\n", data);
It is not overly easy to see, but nevertheless still visible,
that "aaaaa" + "\n" was displayed in the "snarf" output ...
the newline in the data is where the additional Newline comes from
that is not in the fprintf-format. So, the length of 6 is ok.


Your code didn't show the server-side at all ...
I wouldn't be amazed is "I don't know you, go away" would have been
the string snarfed.


Regards ... Rainer
coardump
2005-03-15 17:12:54 UTC
Permalink
Hey Rainer, thanks for the reply!!
Post by Rainer Temme
Hi coardump (a real name would certainly be preferred ...
:-)
Post by Rainer Temme
Post by coardump
socksnarf(bytes, sockfd, buf);
if(!socksnarf) {
perror("socksnarf");
_exit(ERR);
}
Since socksnarf is a function the "if (!socksnarf)"
would only be executed if the pointer were NULL ...
in this case the program would non even have compiled.
Yes, I know that pascal is different ... but this is C.
Over zealous debugging :-) I only code c, so I have bad habbit's
already huh.
Post by Rainer Temme
Post by coardump
Data aaaaa
Size 6
It is not overly easy to see, but nevertheless still visible,
that "aaaaa" + "\n" was displayed in the "snarf" output ...
the newline in the data is where the additional Newline comes from
that is not in the fprintf-format. So, the length of 6 is ok.
OK, what I want is NOT to count the \n so that I get output as such:

Snarfed:
Data aaaaa
Size 5

meaning I do not count the \n as output and I also loose the space
between Data and Size seen in my example. Basically stripping the new
line recieved from the server.

Only way I can think of doing it, keeping in mind I need to retain the
dynamic effect would be to use strstr() to find any instances and
remove it manually before passing it to fprintf. Any better methods to
achieve what I want?
Post by Rainer Temme
Your code didn't show the server-side at all ...
I wouldn't be amazed is "I don't know you, go away" would have been
the string snarfed.
I'm running the code agains a netcat listener on port 22 on my
workstation, that's all.


thanks
coardump.
Måns Rullgård
2005-03-15 17:58:26 UTC
Permalink
Post by coardump
Post by Rainer Temme
Post by coardump
Data aaaaa
Size 6
It is not overly easy to see, but nevertheless still visible,
that "aaaaa" + "\n" was displayed in the "snarf" output ...
the newline in the data is where the additional Newline comes from
that is not in the fprintf-format. So, the length of 6 is ok.
Data aaaaa
Size 5
meaning I do not count the \n as output and I also loose the space
between Data and Size seen in my example. Basically stripping the new
line recieved from the server.
Only way I can think of doing it, keeping in mind I need to retain the
dynamic effect would be to use strstr() to find any instances and
remove it manually before passing it to fprintf. Any better methods to
achieve what I want?
Figure out why the newline is getting sent in the first place.
Post by coardump
Post by Rainer Temme
Your code didn't show the server-side at all ...
I wouldn't be amazed is "I don't know you, go away" would have been
the string snarfed.
I'm running the code agains a netcat listener on port 22 on my
workstation, that's all.
OK, so you're typing from the keyboard? Guess which character is
always at the end a line typed in the terminal.
--
Måns Rullgård
***@inprovide.com
coardump
2005-03-15 21:26:54 UTC
Permalink
Post by Måns Rullgård
Figure out why the newline is getting sent in the first place.
The newline is being sent from nc input as well as a pop3 service I
tried it against. In the end I hope to automate pop3 retrieval. I can
see the newline if I do an x/x buf in GDB so I understand why it's
being sent.
Post by Måns Rullgård
OK, so you're typing from the keyboard? Guess which character is
always at the end a line typed in the terminal.
Yeah, what i would like to know is how to remove that line. It was a
misunderstanding on how recv was snarfing the data. So, I guess I now
know that I am getting the data correctly and will now manually remove
the newline manually before formatting the data with frpintf, which
seems the best option.

In general is my code ok, other than the comment regarding my error
checking on my functions? I'm not an experienced coder and hope to base
my future artform on the knowledge I have already gained.

All your experienced guidance is very much appreciated.

coardump.
David Schwartz
2005-03-15 21:34:25 UTC
Permalink
Post by coardump
In general is my code ok, other than the comment regarding my error
checking on my functions? I'm not an experienced coder and hope to base
my future artform on the knowledge I have already gained.
No, your code is not okay. The purpose of the newline is to let you know
when you've received a complete line, and you must use it for that purpose
before you remove it.

DS
coardump
2005-03-15 21:43:41 UTC
Permalink
Post by David Schwartz
No, your code is not okay. The purpose of the newline is to let you know
when you've received a complete line, and you must use it for that purpose
before you remove it.
So as it stands now, my code is not ok? or do you mean my suggestion to
recv all the data, inclusive of the \n and then remove it before using
fprintf is bad?

coardump.
David Schwartz
2005-03-15 21:47:57 UTC
Permalink
Post by David Schwartz
Post by David Schwartz
No, your code is not okay. The purpose of the newline is to let
you know
Post by David Schwartz
when you've received a complete line, and you must use it for that
purpose
Post by David Schwartz
before you remove it.
So as it stands now, my code is not ok? or do you mean my suggestion to
recv all the data, inclusive of the \n and then remove it before using
fprintf is bad?
I don't think I'm quite getting through. It's receipt of the newline
that indicates to you that you *have* received all the data for a single
line.

A single call to 'recv' might return part of a line, all of a line, or a
full line and part of the next one or more lines. You have to look at the
data you received and see if it contains a newline. If so, all the data
before the newline is one line, and any data after it is part of the next
lines.

You seem to think you can receive "all of the data" and then look at it
later. But it's looking at the data that tells you if you've received all of
it.

DS
coardump
2005-03-15 21:38:30 UTC
Permalink
Reading my reply back to you Mans, it comes across rather arrogant,
which is not intentional - I appreciate your comments. They are what
motivated me to think for myself rather than be a lazybones and use GDB
to see what the heck was going on. Thanks, it is now clear - sometimes
a subtle prod with a sharp stick helps lol :-)

Any other comments welcome though!!!

coardump.
Måns Rullgård
2005-03-15 21:59:29 UTC
Permalink
Post by coardump
Reading my reply back to you Mans, it comes across rather arrogant,
which is not intentional - I appreciate your comments. They are what
No offense taken.
Post by coardump
motivated me to think for myself rather than be a lazybones and use GDB
to see what the heck was going on. Thanks, it is now clear - sometimes
a subtle prod with a sharp stick helps lol :-)
Any other comments welcome though!!!
Get a good book, read it, and understand it. The books by Stevens are
highly regarded around here.
--
Måns Rullgård
***@inprovide.com
coardump
2005-03-15 22:11:01 UTC
Permalink
Post by Måns Rullgård
Get a good book, read it, and understand it. The books by Stevens are
highly regarded around here.
I got UNIX Network Programming Volume 2 which is really good. I guess I
just need to read man pages a little harder and play with more
examples.

Regarding using another pop3 client, I thought of that but decided it
was cheating lol twisted perhaps but it defeats the purpose of trying
to write my own, or so I thought. Obviously asking you guys also does
that *blushes* and hobbles off to the corner :-)

.coardump
Måns Rullgård
2005-03-15 22:23:37 UTC
Permalink
Post by coardump
Post by Måns Rullgård
Get a good book, read it, and understand it. The books by Stevens are
highly regarded around here.
I got UNIX Network Programming Volume 2 which is really good. I
guess I just need to read man pages a little harder and play with
more examples.
Nothing beats experimenting.
Post by coardump
Regarding using another pop3 client, I thought of that but decided it
was cheating lol twisted perhaps but it defeats the purpose of trying
to write my own, or so I thought. Obviously asking you guys also does
that *blushes* and hobbles off to the corner :-)
Well, it all depends on whether you goal is learning, or getting a
specific task done.
--
Måns Rullgård
***@inprovide.com
coardump
2005-03-15 22:46:30 UTC
Permalink
Post by Måns Rullgård
Well, it all depends on whether you goal is learning, or getting a
specific task done.
Mans my only goal is to learn, and then hopefully help others do the
same :-)

cheers for all the comments!!

coardump.
Måns Rullgård
2005-03-15 22:50:55 UTC
Permalink
Post by coardump
Post by Måns Rullgård
Well, it all depends on whether you goal is learning, or getting a
specific task done.
Mans my only goal is to learn, and then hopefully help others do the
same :-)
In that case you are doing exactly the right thing, i.e. experimenting,
and figuring out why things behave the way they do.
--
Måns Rullgård
***@inprovide.com
Måns Rullgård
2005-03-15 21:57:41 UTC
Permalink
Post by coardump
Post by Måns Rullgård
Figure out why the newline is getting sent in the first place.
The newline is being sent from nc input as well as a pop3 service I
tried it against. In the end I hope to automate pop3 retrieval.
Why not just use fetchmail or something similar, at least as a base
for further hacking?
--
Måns Rullgård
***@inprovide.com
James Antill
2005-03-16 00:28:02 UTC
Permalink
Post by coardump
Post by Måns Rullgård
Figure out why the newline is getting sent in the first place.
The newline is being sent from nc input as well as a pop3 service I
tried it against. In the end I hope to automate pop3 retrieval. I can
see the newline if I do an x/x buf in GDB so I understand why it's
being sent.
Post by Måns Rullgård
OK, so you're typing from the keyboard? Guess which character is
always at the end a line typed in the terminal.
Yeah, what i would like to know is how to remove that line. It was a
misunderstanding on how recv was snarfing the data. So, I guess I now
know that I am getting the data correctly and will now manually remove
the newline manually before formatting the data with frpintf, which
seems the best option.
In general is my code ok, other than the comment regarding my error
checking on my functions? I'm not an experienced coder and hope to base
my future artform on the knowledge I have already gained.
Apart from the message that David is trying to convey (Ie. TCP doesn't
deliver messages[1]), I'd specifically recommend against doing things like...

#define MAX_RECV_BUF 1000
[...]
int
socksnarf(int bytes, int sockfd, char *buf)
[...]
char buf[1024];
[...]
socksnarf(bytes, sockfd, buf);

...doing this kind of thing in C is just asking to be hurt. You want to
pass the length of available space into socksnarf() ... and you want them
to be together[2]. Ie. You probably want a minimum of:

struct Network_buf
{
size_t sz;
size_t len;
char buf[];
};

/* inside a function ... */
struct Network_buf *data = malloc(sizeof(struct Network_buf) + 1024);
if (!data) errno = ENOMEM, err(EXIT_FAILURE, "network_buf");

data->sz = 1024;
data->len = 0;
/* this ADT can now also be resized using realloc() */


[1] You might want to look at: http://www.and.org/texts/network_io.html

[2] Also don't create functions that look a lot like recv() but have the
arguments in a different order, that's just more mental paid for no gain.
--
James Antill -- ***@and.org
Need an efficient and powerful string library for C?
http://www.and.org/vstr/
Loading...