WSASendTo Periodically Fails With 10014 - c

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?

Related

Reading UDP packets with several clients

I have an application installed locally (not developed by me), which broadcasts UDP packets every second.
Reading the packets from my application (developed in C++ in Windows) which also is locally installed, works fine.
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOK = WSAStartup(version, &data);
SOCKET serverIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = INADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(UDP_RECEIVE_PORT);
bind(serverIn, (sockaddr*)&serverHint, sizeof(serverHint));
sockaddr_in client;
int clientSize = sizeof(client);
int RECIEVE_BUFFER_SIZE = 65507;
char* recieveBuffer = new char[RECIEVE_BUFFER_SIZE];
while(updating)
{
int bytesIn = recvfrom(serverIn, recieveBuffer, RECIEVE_BUFFER_SIZE, 0, (sockaddr*)&client, &clientSize);
}
closesocket(serverIn);
WSACleanup();
But I recently noticed while I was testing some code, while my app was running, that the bind(...)
function returned an error code of 10048 (WSAEADDRINUSE). Hence, it seems the first client bound to listen for the UDP packets is the only one who can listen, and the other clients is unable to read the broadcasted UDP packets.
So then I added the SO_REUSEADDR option before calling the bind(...) function to be able to bind successfully to the socket:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
setsockopt((SOCKET)serverIn, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen);
That works, but the recvfrom(...) function then does not recieve any data at all! I guess it waits for the other client to close its socket.
Next solution is to initialize the socket with SOCK_RAW instead.
The above option SO_REUSEADDR is now not needed, and remove it:
SOCKET serverIn = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
This works, I can read the data now! Though, Windows now requires the adminstrator rights for my application. Also I do recieve the UDP information in the data which I do not need.
Is there any better method to do this without requiring administrator rights, any possibility to discard the header information in the buffer?
Below is a little program I wrote to demonstrate that IPv4 UDP broadcast can and does work as expected under Windows (i.e. without requiring raw-sockets or Administrator privileges).
Run it with the command line argument "server" and it will send out one broadcast UDP packet per second.
Then also run several more instances of the same program, with no command line arguments, to receive the UDP packets and print a line of text to stdout whenever they do. The expected behavior should look like this:
As for why it's not working for you -- one possible guess is that your UDP-packet-sending program is actually sending out unicast UDP packets rather than broadcast. If that's the case, then I would expect that only one client program would receive packets (even if multiple clients are bound to the same port). A network trace tool like Wireshark might be able to help you determine if the UDP packets being sent are broadcast or unicast.
Anyway, here's the code:
#include <stdio.h>
#include <ws2tcpip.h>
#pragma comment(lib,"WS2_32")
static int BindUDPSocket(SOCKET sock, unsigned short port, bool allowPortSharing)
{
if (sock == INVALID_SOCKET) return -1;
if (allowPortSharing)
{
const BOOL trueValue = true;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &trueValue, sizeof(trueValue)) < 0) return -1;
}
struct sockaddr_in bindAddr; memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.sin_family = AF_INET;
bindAddr.sin_addr.s_addr = INADDR_ANY; // aka 0.0.0.0
bindAddr.sin_port = htons(port);
return bind(sock, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
}
int main(int argc, char ** argv)
{
WSADATA data;
WORD version = MAKEWORD(2, 2);
(void) WSAStartup(version, &data);
const unsigned short TEST_PORT = 12345;
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock<0) {printf("socket() failed\n"); exit(10);}
if ((argc > 1)&&(strcmp(argv[1], "server") == 0))
{
if (BindUDPSocket(sock, 0, false)<0) {printf("BindUDPSocket() failed for server\n"); exit(10);}
const BOOL allowBroadcast = true;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &allowBroadcast, sizeof(allowBroadcast)) < 0)
{
printf("setsockopt(SO_BROADCAST) failed\n");
exit(10);
}
const char buf[] = {0x01, 0x02, 0x03, 0x04}; // dummy data
struct sockaddr_in toAddr; memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = INADDR_BROADCAST; // aka 255.255.255.255
toAddr.sin_port = htons(TEST_PORT);
printf("Sending outgoing broadcast UDP sockets on port %u, once per second\n", TEST_PORT);
while(true)
{
if (sendto(sock, buf, sizeof(buf), 0, (const sockaddr *) &toAddr, sizeof(toAddr)) == sizeof(buf))
{
printf("Sent %zu bytes of broadcast UDP data\n", sizeof(buf));
}
else printf("sendto() failed!\n");
Sleep(1000); // wait 1 second
}
}
else
{
if (BindUDPSocket(sock, TEST_PORT, true)<0) {printf("BindUDPSocket() failed for client\n"); exit(10);}
printf("Waiting to receive incoming broadcast UDP sockets on port %u\n", TEST_PORT);
while(true)
{
char buf[1024];
const int ret = recv(sock, buf, sizeof(buf), 0L);
printf("Received %i bytes of incoming UDP data\n", ret);
}
}
}

Client program in c for ipv6 connect is not working?

/client.c/
void main()
{
static int s = 0;
char url_or_ip[130] = {0};
int port = 0;
ip_type_or_dns_enum ip_dns_type = -1;
char *sptr = ext_sio_recv_buff;
char *ip_str = NULL;
char ip_buf[128] = {0};
int isipv6 = 0;
char buff[NWY_UART_RECV_SINGLE_MAX + 1] = {0};
int on = 1;
int opt = 1, ret = 0, send_len;
uint64_t start;
ip6_addr_t addr;
struct sockaddr_in6 sa;
struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&sa;
port = 8000;
addr.addr[0] = 0x25035959;
addr.addr[1] = 0x87493683;
addr.addr[2] = 0x2abf3de2;
addr.addr[3] = 0x1ab43f8e;
/*socket creation*/
s = socket_open(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
sa.sin6_len = sizeof(struct sockaddr_in6);
sa.sin6_family = AF_INET6;
sa.sin6_port = htons(port);
/*assigning the address for ipv6*/
sa.sin6_addr.un.u32_addr[0] = htonl(addr.addr[0]);
sa.sin6_addr.un.u32_addr[1] = htonl(addr.addr[1]);
sa.sin6_addr.un.u32_addr[2] = htonl(addr.addr[2]);
sa.sin6_addr.un.u32_addr[3] = htonl(addr.addr[3]);
socket_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&on,sizeof(on));
socket_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt));
/*connect to the particular server*/
int ret = socket_connect(s, (struct sockaddr *)&sa, sizeof(sa));
if(ret >0)
{
socket_send(s, uart_rec_buffer, uart_length, 0);
socket_shutdown(s, SHUT_RD);
socket_close(s);
s=0;
}
}
here i am trying to make ipv6 client connection to the ipv6 server, but in the connect system call it is failing . i tried to change the ip and checked still same issue. But the code fails in connect system call and returning -1 and showing invalid argument. Any suggestions. And the API's i am using are similar to the socket programming api's and the socket_open is similar to the socket creation and the socket_connect is similar to the connect system call and assinging the values to the ipv6 predefined structures, the socket is created successfully but socket_connect is failed, why? and it is showing invalid argument passed to the connect call..

UNIX domain datagram socket blocks on recvfrom() with select()

I am using UNIX domain datagram sockets to send records from multiple clients to a single server in a multithreaded program. Everything is done within one process; I'm sending records from multiple threads to a single thread that acts as the server. All threads are assigned to separate cores using their affinity masks.
My problem is when I use select() to retrieve records from client sockets that have records in the socket buffer. I am using the same basic setup I used with a single client socket (and it worked in that context), but now it hangs (apparently it blocks) when I call recvfrom. That's surprising because the select() function has already identified the socket as available for reading.
int select_clientsockets(int64_t srvrfd, int64_t * claddr, int fds_array[], int fd_count, void * recvbuf){
int fds_ready;
int abc;
int64_t cli_addr;
FD_ZERO(&fdset);
FD_SET(0,&fdset);
socklen_t * len = (socklen_t * ) sizeof(struct sockaddr_un);
fds_ready = select(3, &fdset, NULL, NULL, 0);
for (int i = 0; i < fd_count; i++){
fds_array[i] = 0;
if (FD_ISSET(i, &fdset)) {
fds_array[i] = 1;
cli_addr = claddr[i];
server_receive(srvrfd, recvbuf, 720, cli_addr);}
}
return 0;
}
The select function calls server_receive on clients where select says data are available:
int64_t server_receive(int64_t sfd, void * buf, int64_t msgLen, int64_t claddr)
{
socklen_t * len = (socklen_t * ) sizeof(struct sockaddr_un);
int numBytes = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) claddr, len);
if (numBytes == -1)
return 0;
return numBytes;
}
The client socket address is taken from the 3-element array "claddr" (for 3 client sockets) where the corresponding position for each client socket is filled in when the socket is created. At socket creation I also call FD_SET to set the client address into the fd_set. I think I should get the client socket address from fd_set instead, BUT they're both the same pointer value so I don't know why that would make a difference. For internet domain datagram sockets we can use getpeername() but I don't know if there is an analogous function for UNIX domain sockets -- or even if that's the problem.
Thanks very much for any help with this.
UPDATE:
Client fds are added to the global fdset struct on socket creation:
int64_t * create_socket_client(struct sockaddr_un claddr, int64_t retvals[])
{
int sfd, j;
size_t msgLen;
ssize_t numBytes;
char resp[BUF_SIZE];
retvals[0] = 0;
retvals[1] = 0;
sfd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (sfd == -1)
return retvals;
memset(&claddr, 0, sizeof(struct sockaddr_un));
claddr.sun_family = AF_UNIX;
snprintf(claddr.sun_path, sizeof(claddr.sun_path), "/tmp/ud_ucase_cl.%ld", (long) getpid());
FD_SET(sfd,&fdset);
retvals[0] = sfd;
retvals[1] = (int64_t)&claddr;
return retvals;
}
FD_ZERO(&fdset);
FD_SET(0,&fdset);
socklen_t * len = (socklen_t * ) sizeof(struct sockaddr_un);
fds_ready = select(3, &fdset, NULL, NULL, 0);
for (int i = 0; i < fd_count; i++){
fds_array[i] = 0;
if (FD_ISSET(i, &fdset)) {
Your code empties fdset then adds only 0 to fdset. So when you call select and pass it fdset, you are asking it only to check socket 0 for readiness.
You later check if sockets 0 to one less than fd_count are in fdset, but only zero could possibly be because it's the only one you asked about.
Where is the list of sockets you want to check for readiness?

C submit command to server from client

I have a client-server application which runs on UDP ( I need it UDP not tcp ).
A client can send a message to server and it's working fine and vice versa.
I want the client to be able to pass a message as "_connect game1 10" and trigger a function on the server correspondingly which is called _connect(char *name, int num).
How can this be performed to analyse each command to trigger what command ? and is serialisation is a solution and how to implement it.
You can do something on the lines of the following steps
1. Create a message structure
typedef struct info
{
char clientReq[MAX_LENGTH];
char sub[MAX_LENGTH];
u_int32_t value;
u_int16_t end; //Set for the packet which closes the connection
}messageInfo;
On Client
Create socket and bind locally //and connect to server socket(optionally)
fd = socket( family, SOCK_DGRAM, 0 );
//handle error
struct sockaddr_in peerV4;
struct sockaddr_in clientV4;
rc = bind(fd,(struct sockaddr *) &clientV4,
sizeof clientV4);
//error handling
Send the packet data to server.
//update peer(server) socket info here
peerV4.sin_family = AF_INET;
peerV4.sin_port = htons(serverPort);
peerV4.sin_addr.s_addr = "x.x.x.x";
uint8_t *tBuf = (uint8_t *)malloc(sizeof (info)); //memset to zero
info *pHeader = (info *)tBuf;
pHeader->value = htonl(10); //local value to send
pHeader->end = htons(0);
pHeader->clientReq = "connect";
pheader->sub = "game1";
sendto(serverSock, tBuf, sizeof(info),0
,(struct sockaddr *) &peerV4,
sizeof(peerV4));
Send last packet and close local socket.
pHeader->end = htons(1); // so the server closes the socket
//send packet
close(fd);
On Server
1. Create a UDP socket, bind to a local address wait for client to send you the data and use recvfrom
fd = socket( family, SOCK_DGRAM, 0 );
//bind socket
uint8_t *recvBuf = (uint8_t *)malloc(sizeof(info));
info *pheader = (info *)recvBuf;
int currLen = recvfrom( fd, recvBuf,
mBufLen),0,(struct sockaddr *)&peerV4,
&sockaddrLen);
//error handling
if(currLen > 0)
{
if(htons(pheader->end) == 1)
//close socket
char *localSub = pheader->sub;
char *localRecv = pheader->clientReq;
//do something with the values on the server like
if (strcasecmp(localRecv,"connect") == 0) //pseudo
connect(sub,pheader->value)
}

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