udp winsock programming - udp

I'm the beginner in socket programming. I want to receive udp packets continuously from the port. For that I created socket and using bind and recv calls I have done with my program. In a buffer I'm storing the udp packets. How to receive packet by packet. How to put condition for particular time interval? Thanks in advance.
static int recvData = 1;
sockID = socket(AF_INET, SOCK_DGRAM, 0);
if(sockID < 0)
{
printf("Socket creation error\n");
WSACleanup();
}
else
{
printf("Socket Created\n");
}
fepAddr.sin_family = AF_INET;
fepAddr.sin_port = htons(inputData.portNo);
fepAddr.sin_addr.s_addr = inet_addr(inputData.destIPAddr);
if (bind(sockID, (struct sockaddr *)&fepAddr, sizeof(fepAddr)) == SOCKET_ERROR)
{
printf("bind() failed: %ld.\n", WSAGetLastError());
closesocket(sockID);
return 0;
}
else
{
printf("bind() is OK!\n");
}
memset(udpBuf,sizeof(udpBuf),0);
while (recvData)
{
printf("receiving data\n");
recvResult = recvfrom( sockID, udpBuf, sizeof(udpBuf), 0,(struct sockaddr *)&fepAddr, &sock_len);
fprintf(udp, "%s", udpBuf);
//fwrite(udpBuf, sizeof(udpBuf), 1, udp);
recvData-- ;
}
exit:
if(udp)
{
fclose(udp);
udp = 0;
}
//shutdown socket
closesocket(sockID);
fclose(udp);

recvfrom() receives UDP data packet-by-packet. If a given packet is too large, recvfrom() will return an error. As for timing, you can use select() to know when the socket is readable.
Try something like this:
sockID = socket(AF_INET, SOCK_DGRAM, 0);
if (sockID == INVALID_SOCKET)
{
printf("Socket creation error\n");
goto exit;
}
printf("Socket Created\n");
memset(&fepAddr, 0, sizeof(fepAddr));
fepAddr.sin_family = AF_INET;
fepAddr.sin_port = htons(inputData.portNo);
fepAddr.sin_addr.s_addr = inet_addr(inputData.destIPAddr);
if (bind(sockID, (struct sockaddr *)&fepAddr, sizeof(fepAddr)) == SOCKET_ERROR)
{
printf("bind() failed: %ld.\n", WSAGetLastError());
goto exit;
}
printf("bind() is OK!\n");
memset(udpBuf, 0, sizeof(udpBuf));
printf("receiving data\n");
while (...)
{
printf(".");
recvResult = recvfrom(sockID, udpBuf, sizeof(udpBuf), 0, (struct sockaddr *)&fepAddr, &addr_len);
if (recvResult == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("\nrecvfrom() failed: %ld.\n", WSAGetLastError());
goto exit;
}
fd_set fd;
FD_ZERO(&fd);
FD_SET(sockID, &fd);
timeval t;
t.tv_sec = ...; // seconds
t.tv_usec = ...; // microseconds
selectResult = select(0, &fd, NULL, NULL, &t);
if (selectResult == SOCKET_ERROR)
{
printf("\nselect() failed: %ld.\n", WSAGetLastError());
goto exit;
}
if (selectResult == 0)
{
printf("\nsocket timed out.\n");
goto exit;
}
continue;
}
if (recvResult > 0)
fwrite(udpBuf, recvResult, 1, udp);
}
exit:
if (udp != 0)
{
fclose(udp);
udp = 0;
}
if (sockID != INVALID_SOCKET)
{
closesocket(sockID);
sockID = INVALID_SOCKET;
}

Related

UDP directed broadcast (WinSock2) failure

Let me start by saying this is my first foray into the world of C after 20+ years of assembly programming for PLCs and MicroControllers.
I'm trying to send a UDP datagram to the network broadcast address, in this particular case, 192.168.1.255.
The error I'm getting is a bind failure with error code 10049 (from WSAGetLastError()). As you can see from the attached code, I've created the socket, populated sockaddr_in, and setsockopt() to SO_BROADCAST.
For the life of me I can't figure out what I'm doing wrong and any pointers would be gratefully received.
iResult = WSAStartup(MAKEWORD(2, 2), &wsaTxData);
if (iResult != NO_ERROR)
{
WSAErrorString("WSAStartup for TX failed");
return(-1);
}
XPLMDebugString("UDP Server: WSAStartup TX complete.\n");
if ((BeaconSocket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
WSAErrorString("UDP Server: Could not create BECN socket");
return(-1);
}
// setup the sockaddr_in structure
//
si_beacon.sin_family = AF_INET;
si_beacon.sin_addr.s_addr = inet_addr("192.168.1.255");
si_beacon.sin_port = htons(_UDP_TX_PORT);
// setup to broadcast
//
char so_broadcast_enabled = '1';
if (setsockopt(BeaconSocket, SOL_SOCKET, SO_BROADCAST, &so_broadcast_enabled, sizeof(so_broadcast_enabled)) == SOCKET_ERROR) {
WSAErrorString("Error in setting Broadcast option");
closesocket(BeaconSocket);
return(-1);
}
// bind our socket
//
if (bind(BeaconSocket, (struct sockaddr *)&si_beacon, sizeof(si_beacon)) == SOCKET_ERROR)
{
char buf[256];
WSAErrorString("Bind to socket for UDP beacon failed");
sprintf(buf, "Port %u, address %s\n", ntohs(si_beacon.sin_port), inet_ntoa(si_beacon.sin_addr));
XPLMDebugString(buf);
return(-1);
}
// start the UDP beacon
//
udp_becn_thread_id = CreateThread(NULL, 0, BeaconThread, NULL, 0, NULL);
if (!udp_becn_thread_id) {
WSAErrorString("UDP Server: Error starting UDP Beacon");
return (-1);
}
XPLMDebugString("UDP Server: bind complete. beacon ACTIVE.\n");
return(0);
The issue is the IP address itself.
I copied the code to my computer (changed it a bit to get it to compile) and I got the error:
UDP Server: WSAStartup TX complete.
Bind to socket for UDP beacon failed
Port 47977, address 192.168.1.255
I then changed the line:
si_beacon.sin_addr.s_addr = inet_addr("192.168.1.255");
To
si_beacon.sin_addr.s_addr = inet_addr("192.168.0.127");
And when I ran it again, everything worked:
UDP Server: WSAStartup TX complete.
Done successfully
The issue is that the "bind" address needs to be your computers address on the local network. Not the remote client.
Another alternative is to use the address:
si_beacon.sin_addr.s_addr = inet_addr("0.0.0.0");
which binds to all network interfaces on the computer at once.
For reference, here's the version of the code that I used:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <WinSock2.h>
#include <WS2tcpip.h> // For inet_pton
#pragma comment(lib, "ws2_32.lib")
int main()
{
{
WSADATA wsaTxData;
memset(&wsaTxData, 0, sizeof(WSADATA));
const int iResult = WSAStartup(MAKEWORD(2, 2), &wsaTxData);
if (iResult != NO_ERROR)
{
printf("%s", "WSAStartup for TX failed.\n");
return -1;
}
printf("%s", "UDP Server: WSAStartup TX complete.\n");
}
SOCKET BeaconSocket;
memset(&BeaconSocket, 0, sizeof(SOCKET));
if ((BeaconSocket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
printf("%s", "UDP Server: Could not create BECN socket\n");
return -1;
}
// setup the sockaddr_in structure
//
sockaddr_in si_beacon;
memset(&si_beacon, 0, sizeof(sockaddr_in));
si_beacon.sin_family = AF_INET;
si_beacon.sin_addr.s_addr = inet_addr("0.0.0.0");
const unsigned short port_num = 0xbb69;
si_beacon.sin_port = htons(port_num);
// setup to broadcast
//
char so_broadcast_enabled = '1';
if (setsockopt(BeaconSocket, SOL_SOCKET, SO_BROADCAST, &so_broadcast_enabled, sizeof(so_broadcast_enabled)) == SOCKET_ERROR) {
printf("%s", "Error in setting Broadcast option\n");
closesocket(BeaconSocket);
return(-1);
}
// bind our socket
//
if (bind(BeaconSocket, (struct sockaddr*)&si_beacon, sizeof(si_beacon)) == SOCKET_ERROR)
{
char buf[256];
printf("%s", "Bind to socket for UDP beacon failed\n");
sprintf_s(buf, "Port %u, address %s\n", ntohs(si_beacon.sin_port), inet_ntoa(si_beacon.sin_addr));
printf("%s", buf);
return(-1);
}
printf("%s", "Done successfully");
return 0;
}

A bind socket request gives a EADDRNOTAVAIL

I have a small C program where I am trying to bind to a socket at a certain ip:port. Here it the program -
int main ()
{
int udp_fd = -1;
struct sockaddr_in sockaddr;
char *ip = (char *)"xx.yyy.zzz.aaa";
int port = 1234;
udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (udp_fd == -1) {
printf("Could not create socket\n");
return -1;
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(ip);
sockaddr.sin_port = htons(port);
if (bind(udp_fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1) {
printf("Could not bind to %s: %d: %d: %d\n", ip, port, errno, udp_fd);
return -1;
}
if (fcntl(udp_fd, F_SETFL, O_NONBLOCK | O_ASYNC) < 0) {
printf("Error setting socket as non-blocking \n");
return -1;
}
return 0;
}
This fails with EADDRNOTAVAIL
define EADDRNOTAVAIL 99 /* Cannot assign requested address */
I try to connect to the same server from another device that is on the same network as the other device that fails the bind and it is successful.
There are no firewalls enabled on the failing device.
You are trying to bind your socket to a non-local IP address.
You don't generally need to bind to a specific IP address at all. Change:
sockaddr.sin_addr.s_addr = inet_addr(ip);
to
sockaddr.sin_addr.s_addr = INADDR_ANY;

How to listen continuosly SSDP response after sending M-SEARCH

I would like to search Sat>IP servers on the network. Sat>IP servers advertise their presence to other Sat>IP servers and clients.
I must not continuosly send M-SEARCH messages but that instead it listens to server NOTIFY messages.
After initalizing network settings of my device, I'm sending M-SEARCH message and getting response if there is already any active Sat>IP server.
However, I couldn't get any response, If I opens Sat>IP server after sending M-SEARCH message.
Here's my code.
void SatIP::InitDiscoverThread()
{
if(INVALID_THREAD_CHK == DiscoverThreadChk)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE);
printf("InitDiscoverThread pthread_create\n");
DiscoverThreadChk = PTH_RET_CHK(pthread_create(&DiscoverThreadID, &attr, DiscoverThreadFunc, this));
if(DiscoverThreadChk != 0)
{
ASSERT(0);
}
}
}
void SatIP::FinalizeDiscoverThread()
{
if(INVALID_THREAD_CHK != DiscoverThreadChk)
{
printf("FinalizeDiscoverThread pthread_cancel\n");
pthread_cancel(DiscoverThreadID);
DiscoverThreadChk = INVALID_THREAD_CHK;
close(discoverSocket);
}
}
void *SatIP::DiscoverThreadFunc(void* arg)
{
SatIP* satip = (SatIP *)arg;
satip->ListenSSDPResponse();
pthread_exit(NULL);
}
bool SatIP::SendMSearchMessage()
{
vSatIPServers.clear();
FinalizeDiscoverThread();
const char *searchSatIPDevice = "M-SEARCH * HTTP/1.1\r\n" \
"HOST: 239.255.255.250:1900\r\n" \
"MAN: \"ssdp:discover\"\r\n" \
"MX: 2\r\n" \
"ST: urn:ses-com:device:SatIPServer:1\r\n\r\n";
struct sockaddr_in upnpControl, broadcast_addr;
discoverSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (discoverSocket == INVALID_SOCKET)
{
printf("socked failed INVALID_SOCKET\n");
return false;
}
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
if(setsockopt(discoverSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)) == SOCKET_ERROR)
{
printf("setsockopt timeout failed\n");
close(discoverSocket);
return false;
}
socklen_t ttl = 2;
if(setsockopt(discoverSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == SOCKET_ERROR)
{
printf("setsockopt TTL failed\n");
close(discoverSocket);
return false;
}
if(setsockopt(discoverSocket, SOL_SOCKET, SO_BROADCAST, searchSatIPDevice, sizeof(searchSatIPDevice)) == SOCKET_ERROR)
{
printf("setsockopt broadcast failed\n");
close(discoverSocket);
return false;
}
upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(discoverSocket, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
{
printf("bind failed\n");
close(discoverSocket);
return false;
}
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
for(int i = 0; i < 3; i++)
{
if(sendto(discoverSocket, searchSatIPDevice, strlen(searchSatIPDevice), 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR)
{
//printf("sendto failed\n");
close(discoverSocket);
return false;
}
else
{
usleep(10*100);
}
}
InitDiscoverThread();
return true;
}
void SatIP::ListenSSDPResponse()
{
while(1)
{
char buf[512];
memset(buf, 0, 512);
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");
int bcLen = sizeof(broadcast_addr);
//bool bRet = false;
while (recvfrom(discoverSocket, buf, 512, 0, (struct sockaddr*)&broadcast_addr, (socklen_t*)&bcLen) > 0)
{
printf("buf:%s\n",buf);
SATIP_SERVER_DESCRIPTION stServerDesc;
ostringstream ss;
if(strstr(buf, "device:SatIPServer"))
{
int i = 0;
char *deviceIp = strstr(buf, "LOCATION:") + 9; // get xml location including server description
while(deviceIp[i] == ' ') i++; // remove spaces from string
while(!isspace(deviceIp[i]))
{
ss << deviceIp[i];
++i;
}
stServerDesc.location = ss.str().c_str();
printf("location:%s\n",stServerDesc.location.c_str());
ss.str(""); // clear ss
i=0; // clear counter
deviceIp = strstr(buf, "http://") + 7; // get ip address
while(deviceIp[i] != ':')
{
ss << deviceIp[i];
++i;
}
stServerDesc.ipAddr = ss.str().c_str();
printf("ipAddr:%s\n", stServerDesc.ipAddr.c_str());
DownloadDeviceDescription(&stServerDesc);
stServerDesc.macAddr = GetMACAddressviaIP(stServerDesc.ipAddr);
printf("macAddr:%s\n", stServerDesc.macAddr.c_str());
if(IsServerProperToAdd(&stServerDesc))
vSatIPServers.push_back(stServerDesc);
printf("\n");
//bRet = true;
}
memset(buf, 0, 512);
}
}
}
How can I fix this issue? Any help would be appreciated.
Listening SSDP notify message is not related to sending M-SEARCH message. Devices like Sat>IP send NOTIFY message to 239.255.255.250 periodically even if you don't send M-SEARCH message. So, you should join a multicast group and receives from the group.
You can use the listener program in the following link by changing HELLO_PORT as 1900 and HELLO_GROUP as "239.255.255.250".
http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html
/*
* listener.c -- joins a multicast group and echoes all data it receives from
* the group to its stdout...
*
* Antony Courtney, 25/11/94
* Modified by: Frédéric Bastien (25/03/04)
* to compile without warning and work correctly
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define HELLO_PORT 1900
#define HELLO_GROUP "239.255.255.250"
#define MSGBUFSIZE 256
main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes,addrlen;
struct ip_mreq mreq;
char msgbuf[MSGBUFSIZE];
u_int yes=1; /*** MODIFICATION TO ORIGINAL */
/* create what looks like an ordinary UDP socket */
if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) {
perror("socket");
exit(1);
}
/**** MODIFICATION TO ORIGINAL */
/* allow multiple sockets to use the same PORT number */
if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) {
perror("Reusing ADDR failed");
exit(1);
}
/*** END OF MODIFICATION TO ORIGINAL */
/* set up destination address */
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */
addr.sin_port=htons(HELLO_PORT);
/* bind to receive address */
if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
/* use setsockopt() to request that the kernel join a multicast group */
mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP);
mreq.imr_interface.s_addr=htonl(INADDR_ANY);
if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) {
perror("setsockopt");
exit(1);
}
/* now just enter a read-print loop */
while (1) {
addrlen=sizeof(addr);
if ((nbytes=recvfrom(fd,msgbuf,MSGBUFSIZE,0,
(struct sockaddr *) &addr,&addrlen)) < 0) {
perror("recvfrom");
exit(1);
}
puts(msgbuf);
}
}

Unable to capture the IPv6 multicast traffic for Windows 8

Following is the function I wrote to capture IPv6 multicast data coming on multicast address ff02::1 and port 9154.
This code works fine on Windows Vista and Windows 7. But I am unable to capture the same traffic for Windows 8 (none of the winsock functions returns error for Win8).
Using netstat I am able to verify that my application is using this port.
Can any one help?
void func()
{
int multicastChannel = 0;
char multicastIP[] = "FF02::1";
char multicastPort[] = "9154";
ADDRINFO* multicastAddr = NULL;
ADDRINFO* localAddr = NULL;
ADDRINFO hints = { 0 };
struct ipv6_mreq multicastRequest6;
hints.ai_family = PF_UNSPEC;
hints.ai_flags = AI_NUMERICHOST;
if ( getaddrinfo(multicastIP, NULL, &hints, &multicastAddr) != 0 )
{
printf("getaddrinfo() failed");
return;
}
hints.ai_family = multicastAddr->ai_family;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if ( getaddrinfo(NULL, multicastPort, &hints, &localAddr) != 0 )
{
printf("getaddrinfo() failed");
return;
}
multicastChannel = socket(localAddr->ai_family, localAddr->ai_socktype, 0);
if ( bind(multicastChannel, localAddr->ai_addr, localAddr->ai_addrlen) != 0 )
{
printf("bind() failed");
return;
}
memcpy(&multicastRequest6.ipv6mr_multiaddr,
&((struct sockaddr_in6*)(multicastAddr->ai_addr))->sin6_addr,
sizeof(multicastRequest6.ipv6mr_multiaddr));
multicastRequest6.ipv6mr_interface = 0;
if ( setsockopt(multicastChannel,
IPPROTO_IPV6,
IPV6_ADD_MEMBERSHIP,
(char*) &multicastRequest6,
sizeof(multicastRequest6)) != 0 )
{
ERROR_ReportError("setsockopt() failed");
}
freeaddrinfo(localAddr);
freeaddrinfo(multicastAddr);
ioctlsocket(multicastChannel, FIONBIO, &arg);
sockaddr_in6 fromAddr;
while(1)
{
read = recvfrom(multicastChannel,
data,
1500,
0,
(struct sockaddr*)&fromAddr,
&sizeof(sockaddr_in6);
if (read > 0) {
function();
}
}
}

How to read Audio queue service bufer by byte?

I am recording sound from mic input using Audio queue service.
-(void)startRecording{
[self setupAudioFormat:&recordState.dataFormat];
recordState.currentPacket = 0;
OSStatus status;
status = AudioQueueNewInput(&recordState.dataFormat,
AudioInputCallback,
&recordState,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&recordState.queue);
if (status == 0)
{
// Prime recording buffers with empty data
for (int i = 0; i < NUM_BUFFERS; i++)
{
NSLog(#"buf in");
AudioQueueAllocateBuffer(recordState.queue, 16000, &recordState.buffers[i]);
AudioQueueEnqueueBuffer (recordState.queue, recordState.buffers[i], 0, NULL);
}
status = AudioFileCreateWithURL(fileURL,
kAudioFileAIFFType,
&recordState.dataFormat,
kAudioFileFlags_EraseFile,
&recordState.audioFile);
if (status == 0)
{
recordState.recording = true;
status = AudioQueueStart(recordState.queue, NULL);
if (status == 0)
{
NSLog(#"Recording");
}
}
}
if (status != 0)
{
//[self stopRecording];
NSLog(#"recording failed");
}
}
on callback:
void AudioInputCallback(void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp * inStartTime,
UInt32 inNumberPacketDescriptions,
const AudioStreamPacketDescription * inPacketDescs)
{
RecordState * recordState = (RecordState*)inUserData;
if (!recordState->recording)
{
printf("Not recording, returning\n");
}
// if (inNumberPacketDescriptions == 0 && recordState->dataFormat.mBytesPerPacket != 0)
// {
// inNumberPacketDescriptions = inBuffer->mAudioDataByteSize / recordState->dataFormat.mBytesPerPacket;
// }
/*
int sampleCount = recordState->buffers[0]->mAudioDataBytesCapacity / sizeof (AUDIO_DATA_TYPE_FORMAT);
NSLog(#"sample count = %i",sampleCount);
AUDIO_DATA_TYPE_FORMAT *p = (AUDIO_DATA_TYPE_FORMAT*)recordState->buffers[0]->mAudioData;
for (int i = 0; i < sampleCount; i++) {
if (p[i] > 1000) {
NSLog(#"%hd",p[i]);
}
}*/
printf("Writing buffer %lld\n", recordState->currentPacket);
OSStatus status = AudioFileWritePackets(recordState->audioFile,
false,
inBuffer->mAudioDataByteSize,
inPacketDescs,
recordState->currentPacket,
&inNumberPacketDescriptions,
inBuffer->mAudioData);
if (status == 0)
{
recordState->buffers[0] = nil;
recordState->currentPacket += inNumberPacketDescriptions;
}
AudioQueueEnqueueBuffer(recordState->queue, inBuffer, 0, NULL);
}
Here i want to read recorded buffer. is it possible to get something like this:
short[] buffer = ?;//here should an audio buffer converted to some structure (short[] just for example)
then i would like to read every element of this structure:
for (int i = 0; i < sizeOfBuffer; i++) {
bufferVal = buffer[i];
}
In short how to handle buffer when recording ?
Thanks.