I have an application written in C that is a server and a client at the same time. What I do is the following:
sock = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&server, length);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(MYPORT);
char broadcast = '1';
int broadcastlen = sizeof(broadcast);
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, &broadcastlen) < 0) {
close(sock);
error("Error in setting broadcast option");
}
if (bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0) {
close(sock);
error("Error in BINDING");
}
bzero(&sender, length);
bcast.sin_family = AF_INET;
bcast.sin_addr.s_addr = NBCAST; // NBCAST is the broadcast address of the subnet
bcast.sin_port = htons(MYPORT);
if (sendto(sock, dateQuery, strlen(dateQuery) + 1, 0, (struct sockaddr*)&bcast, sizeof(bcast)) < 0) {
close(sock);
error("ERROR in sending");
}
Up to this point everything works well. But I start a thread with the sock parameter to listen to, and do the following:
int len = sizeof(struct sockaddr_in);
struct sockaddr_in sender_addr;
recfrom(sock, recvbuff, recvbufflen, 0, (struct sockaddr*) &sender_addr, &len);
And it blocks there forever. I tried to make it work from different PCs, but it doesn't seem to work, because the thread is blocked due to recvfrom(). Can anyone tell me what is wrong with my code?
Thanks
EDIT: if my code is broken, could you please suggest a way to solve this? So, my task is to implement an application in C that is a server and a client at the same time. I send a broadcast message every 3 seconds, and I have to answer to that broadcast message with the system time.
So far this is the idea I came up with, of course I did not answer to that broadcast message since I couldn't even read it.
I just solved the problem. The code works perfectly, I just had to disable the firewall. But I don't know exactly how did this help me. Any way, thanks for the answers and comments.
Perhaps, you have to make the socket non-blocking?
Try:
u_long iMode = 1;
ioctlsocket(sock, FIONBIO, &iMode);
Related
I am using sockets in order to synchronize several remote processes.
The idea is that a process creates a pthread which manages the server side, just like that:
void *listener(void * in) {
int sockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n = *((int *) in);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
int option = 1;
setsockopt(sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char*) &option, sizeof (option));
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("ERROR on binding");
if (listen(sockfd, n) < 0)
error("ERROR when listening");
clilen = sizeof (cli_addr);
int cnt = 0;
while (cnt < n) {
int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
error("ERROR on accept");
}
cnt++;
}
close(sockfd);
return 0;
}
Meanwhile, the other processes would execute:
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(_managementHost); //managementHost);
if (server == NULL)
error("ERROR, no such host\n");
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(PORT);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("ERROR connection");
close(sockfd);
Now, the problem I have is when I have a lot of processes trying to connect at the same time to the server, some of them are throwing connection refused errors.
I guess that is because the accepts may not be ready... In fact, I have read that it could happen, but I have not found my specific case.
Could anyone shed light on the matter?
A possible solution that occurs to me, is to create a thread for each accept, but I would prefer to avoid it.
Thank you.
EDIT: corrected double initialization of socket in the server. Thanks to #Remy Lebeau.
Now, the problem I have is when I have a lot of processes trying to connect at the same time to the server, some of them are throwing connection refused errors.
A listening TCP socket has a backlog of pending connections. The 2nd parameter of listen() specifies how many connections are allowed to be in the backlog queue before they are accepted. If a new client tries to connect when the backlog is full, the client is refused. There is nothing the client or server can do about that. It is the client's responsibility to detect the error and re-connect at a later time.
Your listener() is accepting clients until it reaches a designated number of connections, but you are also using that same number for the listen backlog queue size. The number of active connections and the number of pending connections are two different things. If you are expecting a lot of clients to connect at the same time, you need a large backlog size to avoid the refusal errors. But that backlog should be sized proportional to the traffic you are expecting. If you have 1000 clients, but they connect only 20 at a time, you would set the backlog to, say, 25, not 1000.
Your listener() has some other logic bugs. It is calling socket() twice and saving the two sockets to the same sockfd variable, so it is leaking the first socket. You need to remove the second call to socket() (the one just before setsockopt()). You are also leaking the sockets that accept() returns. You need to close() an accepted socket after you are doing using it.
Just make your server concurrent by calling fork to spawn a child for each client. Easiest way to do it, IMO. Avoids threading and will stop the connection refused errors.
EDIT: You could also look into pre-forking your server. You'd have to research how you want to handle locking around accept, though (if you're locking at all).
I'm learning C by writing a small application that sends a DNS query to a specified server. Here is an example of the network code:
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
This works fine as the query is succesfully sent, and a reply is recieved. However, by sniffing the traffic with Wireshark I can see the message: Destination unreachable (Port unreachable).
I found out that I can avoid this by calling bind() before sendto():
int send_query()
{
int sockfd;
struct sockaddr_in server;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("cannot create socket\n");
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(53);
inet_pton(AF_INET, "8.8.8.8", &(server.sin_addr));
if(bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind failed\n");
}
sendto(sockfd, const void *buffer, size_t length, 0, (struct sockaddr *) &server, sizeof(server));
}
Now the Destination unreachable (Port unreachable) message is gone, but the application has to be run with root privileges as it will bind to port 53.
Is it possible to modify the code so a random non-privileged source port is used instead?
Problem solved
The problem occured because of a stupid mistake. I had simply commented out recvfrom(). As I was sniffing the traffic while testing the application, I could see the response and error arrving at my computer, and mistakenly confused this as the application was receving. Because I don't know what the hell I'm doing, I started to mess around with bind() etc. and this avalanche of failure started.
For brevity I did not post all the code, but the issue had probably been solved instantly if had did that instead.
You can bind to port 0 to let the OS randomly pick one available for you (just like INADDR_ANY is 0). See https://stackoverflow.com/a/1077305/3543692
Also, binding to port 53 makes no sense. The 53 port is the port of the DNS server, not the DNS client. Think if all the DNS clients on your computer use 53 for DNS client port, then only one DNS request to a server can be proceeded concurrently. Typically, all clients (both TCP/UDP) use random unused ports assigned by OS.
I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.
I have a socket server running on multiple machines. It works like a charm besides on one machine.
The server binds correctly but returns an error (EFAULT) when the client attempts to connect.
Perhaps someone has an idea what the source of the problem might be. Thanks a lot in advance!
Some information about the machine:
Linux version 2.6.18.3
gcc version 3.3.5 (Debian 1:3.3.5-13)
The socket server source is pretty straight forward.
...
...
struct sockaddr_in server_addr;
struct sockaddr* client;
socklen_t alen;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
...
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0){
...
}
if(listen(sockfd,BACKLOG) == -1){
...
}
alen = sizeof(client);
new_fd = accept(sockfd, client, &alen);
if (new_fd == -1) {
/*
* this part of the code is executed
* errno is set to 14
*/
}
Thank you for pointing me in the right direction.
Use this:
struct sockaddr_in client;
...
alen = sizeof(client);
new_fd = accept(sockfd, (struct sockaddr *) &client, &alen);
accept expects a pointer to an existing buffer which it'll fill in. You have two errors, you set alen to the size of a pointer, and you pass an uninitialized pointer to accept.
From the accept(2) man page:
EFAULT The addr argument is not in a writable part of the user address
space.
Check to make sure that you've allocated client appropriately.
I have used wireshark to see the DHCP packet structure. Now I have created a DHCPDISCOVER request and stored it in 'message'. I then broadcast it on the network.
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST, &on,sizeof(on));
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR, &on,sizeof(on));
bzero(&cliaddr, sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliaddr.sin_port = htons(68);
if (bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0) {
perror("bind");
exit(1);
}
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("255.255.255.255");
addr.sin_port = htons(67);
cnt = sendto(sockfd, message, sizeof(message), 0,(struct sockaddr *) &addr, sizeof(addr));
if (cnt < 0) {
perror("sendto");
exit(1);
}
addrlen = sizeof(servaddr);
cnt = recvfrom(sockfd, reply, sizeof(reply), 0,(struct sockaddr *) &servaddr, &addrlen);
if (cnt < 0) {
perror("recvfrom");
exit(1);
}
printf("\nReply Received\n");
I run this program and analyze the packets sent and received using wireshark. I see that a DHCPDISCOVER packet is sent on port 67 and a DHCPOffer packet is received on port 68 in the wireshark window. My client sends the packet fine but does not receive this packet and it blocks on recvfrom call. What is going wrong?
You need to put your receive out before you send the packet request, or else the response probably comes back before you are ready to receive it.
Also, is the response broadcast? If not, and you don't currently have an IP address assigned to your machine, then you're going to have some trouble receiving it because your host will filter received packets by IP address won't know that the response is destined for it (even though the link layer address matches), so it'll not deliver it.
But my guess is it's the first problem. You'll have to either use threads or do a non-blocking receive, or else your receive will block and thus you'll never getting around to sending the request.
Well i disagree with the above answer.. recvfrom should be able receive both the packets.
Here problem lies because ,port no is within the range of 1000. typically , these packets are filtered by linux kernel(iptables) and not sent to. user application.
https://bugzilla.redhat.com/show_bug.cgi?id=983672