TCP sockets in c - c

I'm attempting to write a TCP socket interface for my program and I'm pulling my hair out with an accept() error (I think). For this I've created some boiled down test code.
First I do a little set up
int server_socket = 0;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
int accepted_connection = 0;
struct sockaddr_in server_address;
server_address.sin_port = htons(9001);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
struct sockaddr_in client_address;
client_address.sin_port = 0;
client_address.sin_family = AF_INET;
char * server_socket_read_buffer[100] = {0};
int server_socket_read_length = 0;
All pretty simple stuff. Just allocate some variables. Next I bind and listen
if (bind(server_socket,(struct sockaddr *)&server_address, sizeof(server_address)) < 0)
{
perror("Bind() on server_socket has failed\n");
}
if (listen(server_socket, 10) < 0)
{
perror("Listen() on server_socket has failed\n");
}
Next is the part where I believe I have my problem
printf("Attempting accept!\n");
if (accepted_connection = accept(server_socket, (struct sockaddr *)NULL, NULL) < 0)
{
perror("Accept failed\n");
}
sleep(10);
if (server_socket_read_length = read(accepted_connection, &server_socket_read_buffer, server_socket_read_length) < 0)
{
perror("Read failed\n");
}
printf("Read %d bytes from socket\n", server_socket_read_length);
for (int i = 0; i<server_socket_read_length;i++)
{
printf("%x\n",server_socket_read_buffer[i]);
}
This compiles and runs. When I use nc with the command 'nc 127.0.0.1 9001' I get a connection, but no data is read. In particular I get 0 bytes of data. I thought this might be due to the NULLs in the accept line, but changing those to a proper struct and length prevent my code from compiling.
If anyone can shed some light on what I'm doing wrong I would be very grateful.

There are a couple of errors:
INADDR_ANY is in host byte order and needs to be converted to network one like htonl(INADDR_ANY). But it does not matter since constant INADDR_ANY is defined as 0.
This
char * server_socket_read_buffer[100]
should be
char server_socket_read_buffer[100]
This
read(accepted_connection, &server_socket_read_buffer, server_socket_read_length)
should be
read(accepted_connection, server_socket_read_buffer, sizeof server_socket_read_buffer)

You are passing in server_socket_read_length = 0 which causes a maximum read length of zero. Pass the buffer size. The declaration of server_socket_read_buffer is incorrect as well. Probably you should allocate a bigger buffer (like 4KB) on the heap.
Also remove the sleep.
The rest is probably working because nc obtains a connection and you are able to accept and read without error.

So after more struggle I found my final answer. The block
if (accepted_connection = accept(server_socket, (struct sockaddr *)NULL, NULL) < 0)
{
//code
}
Doesn't work. My read later on was blocking because accepted_connection wasn't a valid socket. Changing to
(accepted_connection = accept(server_socket, (struct sockaddr *)NULL, NULL);
if accepted_connection < 0)
{
//code
}
resolved my issue. As far as I can gather the file descriptor wasn't being created inline with the if() and reading data from an integer isn't very helpful.
Thanks for the input everyone.

Related

Why my socket doesn't receive any message?

In my code, I have this snippet:
char temp_buff[2048] = "";
strcpy(temp_buff, json_object_to_json_string(hb));
printf("%s\n", temp_buff);
char *str;
int fd = 0;
struct sockaddr_in demoserverAddr, cliaddr;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
debug_level > 0 && printf("[SKT]\tError creating socket\n");
}
else
{
demoserverAddr.sin_family = AF_INET;
demoserverAddr.sin_port = htons(9100);
demoserverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(demoserverAddr.sin_zero, '\0', sizeof(demoserverAddr.sin_zero));
}
memset(&cliaddr, 0, sizeof(cliaddr));
int len=sizeof(cliaddr);
sendto(fd, temp_buff, strlen(temp_buff),MSG_CONFIRM, (const struct sockaddr *)&cliaddr, len);
On the other side, I write netcat -u -l 9100 in a terminal to see the incoming message, but nothing happens. Why?
You have two issues here.
First, by using SOCK_STREAM in the call to socket you're creating a TCP socket, but you're using sendto to and your netcat call is using the -u option indicating that you want to use UDP. So use SOCK_DGRAM instead.
Second, you're specifying cliaddr as the address to send to, but that variable was zero'ed out by memset. The demoserverAddr variable contains the IP and port of the remote server, so pass that to sendto. Also, be sure to check the return value.
int len=sizeof(demoserverAddr);
int rval = sendto(fd, temp_buff, strlen(temp_buff),MSG_CONFIRM,
(const struct sockaddr *)&demoserverAddr, len);
if (rval < 0) perror("sendto failed");

User buffer size to receive multicast packets?

The below code is from Git. It joins a multicast group and receives packets.
Here we loop and receive the data in a buffer called msgbuf:
while (1)
{
char msgbuf[MSGBUFSIZE];
const int addrlen = sizeof(addr);
const int nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *) &addr, &addrlen);
How do I choose the size for the buffer msgBuf? Does it just have to be the max packet size? Or do I need to store multiple packets whilst I process the first?
Full code:
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Command line args should be multicast group and port\n");
printf("(e.g. for SSDP, `listener 239.255.255.250 1900`)\n");
return 1;
}
char* group = argv[1]; // e.g. 239.255.255.250 for SSDP
int port = atoi(argv[2]); // 0 if error, which is an invalid port
if(port <= 0)
{
perror("Invalid port");
return 1;
}
// create what looks like an ordinary UDP socket
//
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
perror("socket");
return 1;
}
// allow multiple sockets to use the same PORT number
//
u_int yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &yes, sizeof(yes)) < 0)
{
perror("Reusing ADDR failed");
return 1;
}
// set up destination address
//
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); // differs from sender
addr.sin_port = htons(port);
// bind to receive address
//
if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
{
perror("bind");
return 1;
}
// use setsockopt() to request that the kernel join a multicast group
//
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mreq, sizeof(mreq)) < 0)
{
perror("setsockopt");
return 1;
}
// now just enter a read-print loop
//
while (1)
{
char msgbuf[MSGBUFSIZE];
const int addrlen = sizeof(addr);
const int nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0, (struct sockaddr *) &addr, &addrlen);
if (nbytes < 0)
{
perror("recvfrom");
return 1;
}
msgbuf[nbytes] = '\0';
puts(msgbuf);
}
return 0;
}
Unlike TCP which combines packets into a stream, UDP respects packet boundaries so recvfrom only gets one packet at a time.
So MSGBUFSIZE only needs to be as big as a single packet. If you're not using jumbo packets that would be 1500, otherwise it would be 9000.
as noted by #Ingo, in this code you should be using:
char msgbuf[MSGBUFSIZE + 1];
the + 1 is because recvfrom can write upto MSGBUFSIZE bytes into the array, and you then write another NUL byte at the end.
as far as choosing a value for MSGBUFSIZE, that would depend on the protocol specification. given that most physical networks would struggle to send more than 1500 bytes without fragmentation something like 2048 might be a reasonable value. you could also check for nbytes == MSGBUFSIZE (maybe also using MSG_TRUNC) and report a "packet truncated" warning, but this basically wouldn't happen for packets routed over the public internet
in response to:
do I need to store multiple packets whilst I process the first?
you'd normally let the network stack take care of that. recv maintains packet/datagram boundaries and hence will always start writing the next packet at the supplied buffer address. again it depends on the protocol how you detect and handle errors, e.g. missing or out-of-order packets, and timeouts

C / binding multiple sockets [on differnet ports]

I want to bind 4 sockets on different ports. Somehow I get always the : Address already in use error. For the first loop, the case PORT1 it is working, but when coming to the second run I get the above mentioned error. It would be nice, if someone could take a closer look at my code.
The output looks like that:
thread 0 started, pc_packet_receiver
sock_fd[8]
sock_fd[8], fdmax[8]
sock_fd[9]
error: could not bind UDP socket, port2
: Address already in use
As you can see, the first printf in the loop is processed twice and when bind is called for PORT2 the program crashes.
sock_fd is an array of file descriptors
sock_addr_port[1..4] are four different struct sock_addr
the values PORT1/PORT2/PORT3/PORT4 are defined in an enum [1..4]
in the end I want to add all sock_fd[i] into a FD_SET to processing them with select
thank you very much in advance for your help.
for(i = 0; i < 4; i++) {
if((sock_fd[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("error: could not open UDP socket\n");
exit(EXIT_FAILURE);
}
printf("\tsock_fd[%d]\n", sock_fd[i]);
switch (i+1) {
case PORT1:
bzero(&sock_addr_port1, sock_len_port1);
sock_addr_port1.sin_family = AF_INET;
sock_addr_port1.sin_port = htons(ETH_PORT1);
sock_addr_port1.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock_fd[i], (struct sockaddr *) &sock_addr_port1, sock_len_port1) < 0) {
perror("error: could not bind UDP socket, port1\n");
exit(EXIT_FAILURE);
}
break;
case PORT2:
bzero(&sock_addr_port2, sock_len_port2);
sock_addr_port2.sin_family = AF_INET;
sock_addr_port2.sin_port = htons(ETH_PORT2);
sock_addr_port2.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock_fd[i], (struct sockaddr *) &sock_addr_port2, sock_len_port2) < 0) {
perror("error: could not bind UDP socket, port2\n");
exit(EXIT_FAILURE);
}
break;
case PORT3:
bzero(&sock_addr_port3, sock_len_port3);
sock_addr_port3.sin_family = AF_INET;
sock_addr_port3.sin_port = htons(ETH_PORT3);
sock_addr_port3.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock_fd[i], (struct sockaddr *) &sock_addr_port3, sock_len_port3) < 0) {
perror("error: could not bind UDP socket, port3\n");
exit(EXIT_FAILURE);
}
break;
case PORT4:
bzero(&sock_addr_port4, sock_len_port4);
sock_addr_port4.sin_family = AF_INET;
sock_addr_port4.sin_port = htons(ETH_PORT4);
sock_addr_port4.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock_fd[i], (struct sockaddr *) &sock_addr_port4, sock_len_port4) < 0) {
perror("error: could not bind UDP socket, port4\n");
exit(EXIT_FAILURE);
}
break;
default:
break;
}
FD_SET(sock_fd[i], &read_fds);
fdmax = sock_fd[i];
printf("sock_fd[%d], fdmax[%d]\n", sock_fd[i], fdmax);
}
There is another process running which uses ETH_PORT2 right now. You should be able to see this when you run netstat -tan (-tn on Windows) on the command line.
Google for "which process uses which port" to see how you can find out the process.

Passive socket not accepting ftp

I'm making an ftp server, and when i'm trying to connect to it with filezilla, the server is not accepting the connection on the passive socket. It hangs at the accept call.
Here's a part of my code :
if ((server->pasv_sock = accept(server->sockt, (struct sockaddr*)&sin_clt,
(socklen_t*)&size_sin) == -1))
My socket is bind to a specific port and the client tries to connect with this one. Telnet is not connecting either.
If you can help me find what's wrong, thank you :)
Did you remember to call listen before accept?
Remember: socket -> bind -> listen -> accept.
Edit: Here's some commentary on your code.
struct protoent *pe;
struct sockaddr_in sin;
int sock;
struct sockaddr_in sin_clt;
int size_sin;
if ((pe = getprotobyname("TCP")) == NULL)
perro("getprotobyname");
sock = xsocket(AF_INET, SOCK_STREAM, pe->p_proto);
Using getprotobyname is unnecessary, since the name is hard-coded and there's only one IP stream protocol anyway. Use 0 instead of pe->p_proto, and don't bother calling getprotobyname.
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
You don't initialize sin.sin_port. That's an error.
while (bind(sock, (const struct sockaddr*)&sin,
(socklen_t)sizeof(sin)) == -1 && server->port2 <= 65535)
sin.sin_port = htons(server->port2++);
This loop is a bit of a mess. It might be mostly correct, but it's hard to tell. Let's rewrite it so it's obviously correct rather than not obviously incorrect.
if (listen(sock, 1) == -1)
perror("listen");
size_sin = sizeof(sin_clt);
if ((server->pasv_sock = accept(sock, (struct sockaddr*)&sin_clt,
(socklen_t*)&size_sin) == -1))
This definitely doesn't do what you want.
Discussion: I'll add parentheses to the last line to show you what it actually does.
if ((server->pasv_sock = accept(...) == -1))
is the same as
if ((server->pasv_sock = (accept(...) == -1)))
I'm guessing that you got a compiler warning that complained about the assignment, which suggested adding parentheses... but the parentheses you added were in the wrong place. The reason the compiler was warning you was because this is a common source of errors, and it's impossible for the compiler to know what you actually mean by that statement. You mean something more like this:
if ((server->pasv_sock = accept(...)) == -1)
But I don't recommend that. Easier to read and more fool-proof is to pull assignments out of if predicates,
server->pasv_sock = accept(...);
if (server->pasv_sock == -1)
And no, there's no difference in the resulting assembly code; so there's no performance difference.
There's another problem with this line, but it's somewhat pedantic. You shouldn't cast (socklen_t *) &size_sin. Instead, you should change the declaration of size_sin to have the socklen_t type to begin with. The only reason it works is because socklen_t is typedefed to int, but pretend you don't know that and use the right type to begin with.
Sample code:
int port, sock, r, csock;
struct sockaddr_in saddr, caddr;
socklen_t caddrlen;
// This is a simpler way to get a TCP socket
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) abort();
// Loop over available ports, and bind to one
// (I'm not sure if this is the best way to do this)
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
for (port = 10000; port < 65536; ++port) {
saddr.sin_port = htons(port);
r = bind(sock, (struct sockaddr *) &saddr, (socklen_t) sizeof(saddr));
if (!r)
break;
}
if (r) abort();
// Listen and accept a connection
r = listen(sock, 1);
if (r < 0) abort();
caddrlen = (socklen_t) sizeof(caddr);
csock = accept(sock, (struct sockaddr *) &caddr, &caddrlen);
if (csock < 0) abort();
// You don't want to listen for more connections
close(sock);
Reccomendations: For now, try to stay away from putting side effects (accept, bind, assignments, etc.) in conditionals. I'm not saying that it's never okay to do this, but it looks like that's where your problems are and it's very easy to just move the side effects to a separate line of code, then only do the final comparison in the if condition or while condition.
// Both of these are correct.
// The bottom one is obviously correct.
// Correctness is not always good enough.
// Being obviously correct is important!
if ((p->x = func()) == NULL)
...
p->x = func();
if (p->x == NULL)
...

Simple messaging application...getting errno 14: bad address

I am writing a simple messaging application in C using sockets. When I use function recvfrom, it returns -1 and sets errno = 14 which is Bad address (which I am printing at the end).
The strange thing is that it still reads from the socket and gets the correct message. That is, the application is working perfectly and as expected except for that error.
My question is this: Why do you think I am getting this error? I cannot think of any reason. I was using inet_pton to set peer->sin_addr but I was getting the same error.
// socket file descriptor to send data through
int recv_sock_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
// fill in the peer's address, loopback in this case
struct sockaddr_in *peer = malloc(sizeof(struct sockaddr_in));
peer->sin_family = AF_INET;
peer->sin_port = htons(11110);
char *new = &(peer->sin_addr);
new[0] = 127;
new[1] = 0;
new[2] = 0;
new[3] = 1;
for (int i = 0; i < 8; i++) {
peer->sin_zero[i] = NULL;
}
bind(recv_sock_fd, peer, sizeof(struct sockaddr_in));
// check to see if the socket has any data...code removed
char buff[32] = {0};
errno = 0;
int bytes_received = recvfrom(recv_sock_fd, buff, sizeof(buff), NULL, (struct sockaddr *)peer, sizeof(struct sockaddr_in));
printf("Bytes recieved: %d: %d : %s\n", bytes_received, errno, strerror(errno));
Look at the signature of recvfrom(2):
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
Last argument is an address, while you are giving it a plain integer.
Then you're building of the IP address is wrong. Do use inet_pton(3), that's what it's for. Also check the return value of the bind(2), it's surely failing now.

Resources