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.
Related
We receive multicast data to two machines- Prod and Dev. The below code worked on Prod, but has never worked on Dev (even though the boxes should be set up identically). However, when I run
tshark -i <interface> -c 50
on Dev packets are being received from the same multicast address and port as Prod.
I have posted the code below. The program reaches the log line "Listening for packets" but then appears to simply block on recvfrom().
I would like to clarify I am not doing anything daft. Is there anything else I can check to see what's happening with the packets? I cannot speak with our vendor yet because they will simply run tshark and say the problem must be with our code.
std::string address("1.2.3.4"); // Not real address
const char *group = address.c_str();
int port = 26477;
_sock = socket(AF_INET, SOCK_DGRAM, 0);
assert(_sock >= 0);
u_int yes = 1;
int result = setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
assert(result >= 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
result = bind(_sock, (struct sockaddr *)&addr, sizeof(addr));
assert(result >= 0);
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(group);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
result = setsockopt(_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
assert(result >= 0);
LOG("Listening for packets...."); // CODE REACHES HERE
while (1)
{
socklen_t addrlen = sizeof(addr);
const size_t maxNumBytesToRead = MSGBUFSIZE - 1;
// I think code is just blocking here, waiting for packets
const int nbytes = recvfrom(_sock, msgbuf, maxNumBytesToRead, 0, (struct sockaddr *)&addr, &addrlen);
}
You're specifying INADDR_ANY as the interface to join the multicast group on. This means the system will choose a default interface. If your system has more than one active interface, it might not be the one you intended.
What's probably happening here is that your PROD machine happens to be joining on the desired interface, while the DEV machine is joining on a different interface.
Change mreq.imr_interface to contain the IP address of the network interface you want to bind to.
I'm trying to build a c client that sends an html request message to a website, and then reads the response. Unfortunately, my connect() statement does not return.
Yes, I have seen this answer: connect() does not return
However, I do not want to set the socket to non-blocking, and then keep doing select() until I get a response, as I am only dealing with one request at a time.
int main() {
struct hostent *hp;
struct sockaddr_in serveraddr;
mySocket = socket(AF_INET, SOCK_STREAM, 0);
hp = gethostbyname("firefox.com"));
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
bcopy((char *)hp->h_addr_list[0], (char *)&serveraddr.sin_addr.s_addr, hp->h_length);
serveraddr.sin_port = htons(8080); // works up till here
connect(mySocket, (SA *) &serveraddr, sizeof(serveraddr)); // never returns
return 0;
}
Am I connecting correctly? I've gotten rid of the error checking in the above code.
Here is the output of "lsof -Pnl +M -i4" in terminal
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
proxy 8321 1000 3u IPv4 51542 0t0 TCP 10.0.2.15:42708->63.245.213.17:8080 (SYN_SENT)
Could this be a firewall issue? If so, how do I resolve it?
I should've been on port 80, not 8080, in the line:
serveraddr.sin_port = htons(8080); // no
serveraddr.sin_port = htons(80); // yes
Thanks for your help guys.
I'm writing an application that listens for UDP packets over a unix domain socket. Consider the following code block.
int sockfd;
struct sockaddr_un servaddr;
sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
if(sockfd < 0)
{
perror("socket() failed");
}
unlink(port);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, port);
if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind() failed");
close(sockfd);
}
int n;
struct sockaddr_un cliaddr;
socklen_t len = sizeof(cliaddr);
discovery_msgs client_message;
bzero(&client_message, sizeof(client_message));
// Wait for a message to be received
n = recvfrom(sock_fd, &client_message, sizeof(client_message), 0,
(struct sockaddr *) &cliaddr, &len);
// At this point n = 560, client_message is filled with the expected data
//len = 0 and cliaddr has no information about the client that sent the data
Now the type of client_message isn't really important, I'm receiving a UDP packet and client_message contains all of the data I expect. The problem begins when I look at cliaddr and len after calling recvfrom. cliaddr is not modified by recvfrom like it normally is with normal network TCP/UDP and len is set to 0 after the call(which means recvfrom wrote no data to &cliaddr). I need the information in cliaddr to be populated with the unix domain path so I can send a response.
What am I doing wrong?
The solution is binding the socket on the client side when using Unix domain sockets. Otherwise the transient pathname created for sending the UDP packet immediately disappears after sendto(), which explains why the client's address information is not available on the server side.
See Stevens Network Programming page 419 or see this for an example client implementation that solves this issue: libpix.org/unp/unixdgcli01_8c_source.html
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_un cliaddr, servaddr;
sockfd = Socket(AF_LOCAL, SOCK_DGRAM, 0);
bzero(&cliaddr, sizeof(cliaddr)); /* bind an address for us */
cliaddr.sun_family = AF_LOCAL;
strcpy(cliaddr.sun_path, tmpnam(NULL));
Bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
bzero(&servaddr, sizeof(servaddr)); /* fill in server's address */
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, UNIXDG_PATH);
dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));
exit(0);
}
Note: unp.h defines Bind() which is simply bind() with some error checking(commonly used throughout Stevens Network Programming). In the same manner, (SA *) is the equivalent to (struct sockaddr *).
Hi I have programmed linux daemon who sends files in udp packets.
problem is that in string "abc\0asdf" it sends only abc not null character and asdf (all characters after null symbol),
there is udp client code, which send packets:
int sock;
struct sockaddr_in server_addr;
struct hostent *host;
host= (struct hostent *) gethostbyname((char *)ip);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
perror("socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
memset(server_addr.sin_zero,0,8);
and code which send buffer:
if (sendto(sock, buf, sizeof buf, 0, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))==-1)
in serverside I need to receive binary buffer:
defining socket code:
int sock;
int addr_len, bytes_read;
struct sockaddr_in server_addr , client_addr;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Socket");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
//bzero(&(server_addr.sin_zero),8);
memset(server_addr.sin_zero,0,8);
if (bind(sock,(struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1){
perror("Bind");
exit(1);
}
addr_len = sizeof(struct sockaddr);
diep("sendto()");
and receive buffer (in big loop):
bytes_read = recvfrom(sock,buf,sizeof (buf),0,
(struct sockaddr *)&client_addr, &addr_len);
does anyone know why I didn't receive full buffer?
By looking at the comments, the error is most likely that you treat the received buffer as a string.
If you want to print/output the buffer, you need to convert the null character into something else first.
You should use a for loop to print your received buffer instead of printf:
for (int i=0; i<bytes_read; i++)
printf("%c",buf[i]);
This is incorrect (formatting changed so it fits on a screen for me):
if (sendto(sock,
buf,
sizeof buf,
0,
(struct sockaddr *)&server_addr,
sizeof(struct sockaddr))==-1)
You want sizeof(server_addr) as the length. This will be larger than sizeof(struct sockaddr).
Also, from the manpage:
Return Value
On success, these calls return the number of characters sent. On error, -1 is returned, and errno is set appropriately.
You haven't accounted for the case where it returns some value less than sizeof(buf). Not sure how that can happen but it seems to be something to handle.
My comment on the overall approach is similar to what #jgauffin says. buf is just bytes. It's only a convention for C strings that '\0' terminates them, not a requirement. Typically when using binary byte buffers you also track the size. You're just assuming that all of sizeof(buf) will be used which doesn't make sense. (Suggestion: Perhaps part of your sendto payload should include the size of the message that follows?)
I have a network server application written in C, the listener is bound using INADDR_ANY so it can accept connections via any of the IP addresses of the host on which it is installed.
I need to determine which of the server's IP addresses the client used when establishing its connection - actually I just need to know whether they connected via the loopback address 127.0.0.1 or not.
Partial code sample as follows (I can post the whole thing if it helps):
static struct sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = INADDR_ANY;
serverAddress.sin_port = htons(port);
bind(listener, (struct sockaddr *) &serverAddress, sizeof(serverAddress));
listen(listener, CONNECTION_BACKLOG);
SOCKET socketfd;
static struct sockaddr_in clientAddress;
...
socketfd = accept(listener, (struct sockaddr *) &clientAddress, &length);
The solution to my specific problem (thanks to zildjohn01) in case anyone needs it, is shown below:
int isLocalConnection(int socket){
struct sockaddr_in sa;
int sa_len = sizeof(sa);
if (getsockname(socket, &sa, &sa_len) == -1) {
return 0;
}
// Local access means any IP in the 127.x.x.x range
return (sa.sin_addr.s_addr & 0xff) == 127;
}
You can use the getsockname function.
The getsockname() function retrieves the locally-bound name of the specified socket
From your code
socketfd = accept(listener, (struct sockaddr *) &clientAddress, &length);
Analyse the returned clientAddress. This is what you need.