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.
Related
I have created a UDP socket, and am trying to send some data over it using WSASendTo. This works sometimes, but fails sporadically (with WSAEFAULT) and I can't seem to track it down.
First, I setup Winsock2 and create my UDP socket:
const char* host = "127.0.0.1";
int port = 10000;
WSADATA wsd = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
return 1;
}
int socktype = SOCK_DGRAM;
int family = AF_INET;
int protocol = IPPROTO_UDP;
SOCKET sock = WSASocketW(family,
socktype,
protocol,
NULL,
0,
WSA_FLAG_OVERLAPPED);
Then I get the addr structure setup with my IP and port:
struct sockaddr_in addr;
int addr_size = sizeof(addr);
addr.sin_family = AF_INET;
inet_pton(AF_INET, host, (void*)addr.sin_addr);
addr.sin_port = htons((u_short)port);
Finally, I send my data using WSASendTo:
// `overlapped` and `buf` are both declared at a higher scope so
// that they are available in the completion routine.
WSAOVERLAPPED overlapped = { 0 }
WSABUF buf;
buf.buf = data;
buf.len = size;
char* data = "Hello, World!";
int size = strlen(data);
// Returns -1 here, with WSAGetLastError() == 10014.
ret = WSASendTo(sock,
&buf,
1,
&bytes_sent,
flags,
(SOCKADDR*)&addr,
&addr_size,
&overlapped,
SendCompletion);
At this point ret equals -1 and a call to WSAGetLastError returns either 997 (WSA_IO_PENDING, which I would expect) or, about half the time, 10014 (WSAEFAULT).
According to the documentation, this means that:
The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small.
I've gone through and verified that these things appear to be correct. That is, the addresses seem to be reasonable and the size of things like lpTo are correct.
Any idea why this would sometimes fail?
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.
I have an odd problem with a UDP server I'm working on. The very first udp packet received has no information on the source of the packet. Subsequent udp packets all appear to be fine and correctly display the ip address from which the packet was received. I have no clue what is causing this behavior, probably some stupid mistake, or some obscure bug. I'm using on a Linux machine running Debian.
fd_set master;
fd_set read_fds;
int fdmax;
int i;
int bytes_sent;
int bytes_recv;
socklen_t addr_len;
struct sockaddr_storage their_addr;
// provides users information needed to connect
serv_info *server_info;
server_info = (serv_info*) serv_config;
// Create UDP listener socket
int info_sock = createDGRAMSocket(NULL, server_info->port, 1);
char buffer[1024];
int len;
int send_response;
FD_SET(info_sock, &master);
fdmax = info_sock;
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("Info started \n");
while (running) {
read_fds = master;
select(fdmax+1, &read_fds, NULL, NULL, NULL);
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("length %u: %s\n", bytes_recv, buffer);
send_response = 0;
switch (buffer[0]) {
// Handle different packet types
}
struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;
unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
if (send_response) {
bytes_sent = sendto(info_sock, buffer, len, 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr_storage));
if (bytes_sent < 0) {
printf("[ERROR] Packet Send Failed %d (%s) %d\n", bytes_sent, buffer, len);
}
}
}
}
};
close(info_sock);
You need to initialize addr_len to sizeof(their_addr). According to the man page:
The argument addrlen is a value-result argument, which the caller should initialize
before the call to the size of the buffer associated with src_addr, and
modified on return to indicate the actual size of the source address. The returned
address is truncated if the buffer provided is too small; in this case, addrlen will
return a value greater than was supplied to the call.
Since you aren't initializing addr_len it seems to be taking on a value of 0 (this is highly undefined behavior). In this case, recvfrom() will not fill in the their_addr buffer, but as the man page indicates addr_len will return a value greater than was supplied to the call. So after the first call addr_len is taking on a value that is allowing the next calls to recvfrom() to properly fill in the their_addr buffer. Relying on this is unsafe though.
I am new in Unix/Linux networking programming, so I have written server-client program in below.In this code there is one socket between client and server, client requests to server, then server responses from 1 to 100 numbers to client. So my question is how can we do this process with 3 socket( tcp connection) without using thread? ( e.g. First socket runs then second runs then third runs then first again. ) Do you have any suggestion?
Client.c
int main()
{
int sock;
struct sockaddr_in sa;
int ret;
char buf[1024];
int x;
sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(SERVER_PORT);
inet_pton (AF_INET, SERVER_IP, &sa.sin_addr);
ret = connect (sock,
(const struct sockaddr *) &sa,sizeof (sa));
if (ret != 0) {
printf ("connect failed\n");
exit (0);
}
x = 0;
while (x != -1) {
read (sock, buf , sizeof(int));
x = ntohl(*((int *)buf));
if (x != -1)
printf ("int rcvd = %d\n", x);
}
close (sock);
exit (0);
}
Server.c
int main()
{
int list_sock;
int conn_sock;
struct sockaddr_in sa, ca;
socklen_t ca_len;
char buf[1024];
int i;
char ipaddrstr[IPSTRLEN];
list_sock = socket (AF_INET, SOCK_STREAM, 0);
bzero (&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(SERVER_PORT);
bind (list_sock,(struct sockaddr *) &sa,sizeof(sa));
listen (list_sock, 5);
while (1){
bzero (&ca, sizeof(ca));
ca_len = sizeof(ca); // important to initialize
conn_sock = accept (list_sock,(struct sockaddr *) &ca,&ca_len);
printf ("connection from: ip=%s port=%d \n",inet_ntop(AF_INET, &(ca.sin_addr),
ipaddrstr, IPSTRLEN),ntohs(ca.sin_port));
for (i=0; i<100; ++i){
*((int *)buf) = htonl(i+20);
// we using converting to network byte order
write (conn_sock, buf, sizeof(int));
}
* ((int *)buf) = htonl(-1);
write (conn_sock, buf, sizeof(int));
close (conn_sock);
printf ("server closed connection to client\n");
}
}
I think it best to look at the excellent resource Beej's Guide to Netwokr Programming which goes into detail about this. He also has some good examples which you can use as a starting point and he covers all the major platforms including windows.
Basically you do:
socket()
bind()
listen()
accept()
accept() returns a socket connected to a unique client. Then you'd use select, poll or epoll to determine when data is available on those sockets. I suggest you can look at the man pages for these API's and Beej's guide. It's where I first learned network programming.
Looking at your code, your inner loop is wrong. When you accept a connection, you need to add it to a list or something. Currently, you overwrite it and loose it. You should use (e)poll or select to tell you which has data. You can write to any of them at any time. Again, look at the examples in Beej's guide, they are most helpful.
Maybe it's not exactly what you want,but I think you could try epoll,There is a simple example
typedef struct event_loop
{
int max_event;
int epfd;
}event_loop;
event_loop* create_event_loop()
{
event_loop *ep = malloc(sizeof(event_loop));
ep->max_event = 512;
ep->epfd = epoll_create(512);
return ep;
}
int add_event(event_loop *ep, int fd)
{
epoll_event ee;
ee.data.fd = fd;
ee.event = EPOLLIN | EPOLLPRI;
epoll_ctl(ep->epfd, EPOLL_CTL_ADD, fd, &ee);
}
void event_main(event_loop *ep, int listenfd)
{
epoll_event events[512];
int nfds, i, newfd;
while(1)
{
if(nfds = epoll_wait(ep->epfd, events, 512, -1) == -1)
exit(1);
for(i = 0; i < nfds; i++)
{
if(events[nfds].data.fd == listenfd)
{
newfd = accept(listenfd, NULL, NULL);
add_event(ep, newfd);
}
else
{
//do what you want
}
}
}
}
epoll is a high-efficiency solution,just man epoll get more information
I am always getting no bytes sent, with an errno of 22 (EINVAL, Invalid Argument) with this code. The destination_host is set elsewhere and known to be valid, so I really don't see what is going on. MAXMSGSIZE is 1000. No errors, or warnings. I am compiling with -Wall -Werror -pedantic
char *data_rec;
u_int data_len;
int sockfd;
uint16_t *ns;
struct sockaddr_in address;
struct sockaddr *addr;
char *ip;
int i;
int errno;
int bytes_sent;
data_len = MAXMSGSIZE;
data_rec = malloc(sizeof(char)*MAXMSGSIZE);
ns = malloc(MAXMSGSIZE*sizeof(uint16_t));
ip = malloc(MAXMSGSIZE*sizeof(char));
data_rec = "some random test stuff";
sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd<0) {
printf("socket() failed\n");
}
inet_ntop(AF_INET,destination_host->h_addr,ip,MAXMSGSIZE);
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(theirPort);
address.sin_addr.s_addr = (unsigned long)ip;
addr = (struct sockaddr*)&address;
bind(sockfd,addr,sizeof(address));
/*Convert the message to uint16_t*/
for(i=0; i<MAXMSGSIZE; i++) {
ns[i] = htons(data_rec[i]);
}
/* send the message */
bytes_sent = sendto(sockfd, ns, data_len, MSG_DONTWAIT, addr, sizeof(addr));
if(bytes_sent == -1) {
printf("Error sending: %i\n",errno);
}
You're giving the wrong size for the address. addr is really a struct sockaddr_in, not a struct sockaddr.
Change the last parameter of sendto to sizeof(address)
inet_ntop probably isn't what you want - it converts from network (i.e. wire) format into presentation format (i.e. "1.2.3.4"). Try:
address.sin_addr.s_addr = *((unsigned long *)destination_host->h_addr);
You have:
bytes_sent = sendto(sockfd, ns, data_len, MSG_DONTWAIT, addr, sizeof(addr));
Because sizeof(addr) == 4 (or 8), use sizeof(*addr).