Single Server, Multiple Clients UDP Application in C (Winsock) - winapi

I have created single Server and Single Client echo application. It works fine for single server and single client. But now I want to make it more practical by handling multiple clients for a single Server. I came accross the idea of using listen() function at Server side to handle multiple client connections but then I came to know that listen is only used for TCP. Kindly help me with this. below is my functional code for single Server and Single Client. Help me with how can I modify it to make a Single Server Multiple Client application.
SERVER:
#define PORT 8888 //The port on which to listen for incoming data
int main()
{
SOCKET s;
struct sockaddr_in serverSocket, clientSocket;
char receiveBuffer[1000];
//int receiveBufferLength=1000;
int clientSocketLength;
int recv_len;
clientSocketLength = sizeof(clientSocket) ;
WSADATA wsa;
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Socket Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_DGRAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
serverSocket.sin_family = AF_INET;
serverSocket.sin_addr.s_addr = INADDR_ANY;
serverSocket.sin_port = htons( PORT );
//Bind
if( bind(s ,(struct sockaddr *)&serverSocket , sizeof(serverSocket)) == SOCKET_ERROR)
{
printf("\nBind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Bind done\n\n");
//keep listening for data
while(1)
{
printf("\n\t\t\tWaiting for data...\n");
fflush(stdout);
//receiveBuffer[2000]=NULL;
if((recv_len = recvfrom(s, receiveBuffer, 1000, 0, (struct sockaddr *) &clientSocket, &clientSocketLength)) == SOCKET_ERROR)
{
printf("\n\nrecvfrom() failed with error code : %d" , WSAGetLastError());
//exit(EXIT_FAILURE);
while(1);
}
//print details of the client/peer and the data received
printf("\n\nReceived packet from %s:%d\n", inet_ntoa(clientSocket.sin_addr), ntohs(clientSocket.sin_port));
printf("\nClient Says: " );
printf(receiveBuffer,recv_len);
//now reply the client with the same data
if (sendto(s, receiveBuffer, recv_len, 0, (struct sockaddr*) &clientSocket, clientSocketLength) == SOCKET_ERROR)
{
printf("\nsendto() failed with error code : %d" , WSAGetLastError());
// exit(EXIT_FAILURE);
while(1);
}
else
printf("\nMessage Sent Back to Client");
}
closesocket(s);
WSACleanup();
return 0;
}
CLIENT:
#define PORT 8888 //The port on which to listen for incoming data
#define SERVER "10.0.1.25" //ip address of udp server
//#define PORT 8888 //The port on which to listen for incoming data
int main(void)
{
struct sockaddr_in connectedSocket;
int s;
int length=sizeof(connectedSocket);
char receiveBuffer[1000];
char message[1000];
//clear the buffer by filling null, it might have previously received data
memset(receiveBuffer,'\0', 1000);
WSADATA wsa;
//Initialise winsock
printf("\nInitialising Winsock...\n");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("\nFailed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("\n.........Initialised.\n");
//create socket
if ( (s=socket(AF_INET, SOCK_DGRAM, 0)) == SOCKET_ERROR)
{
printf("\n\nsocket() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//setup address structure
memset((char *) &connectedSocket, 0, sizeof(connectedSocket));
connectedSocket.sin_family = AF_INET;
connectedSocket.sin_port = htons(PORT);
//connectedSocket.sin_port = INADDR_BROADCAST;
connectedSocket.sin_addr.S_un.S_addr = inet_addr(SERVER);
while(1)
{
printf("\n\n\nEnter message : ");
gets(message);
//send the message
if (sendto(s, message,sizeof(message) , 0 , (struct sockaddr *) &connectedSocket, sizeof(connectedSocket)) == SOCKET_ERROR)
{
printf("\nsendto() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("\nMessage Successfully sent to Server");
// fflush(stdout);
if (recvfrom(s, receiveBuffer, 1000, 0, (struct sockaddr *) &connectedSocket,&length) == SOCKET_ERROR)
{
printf("\nrecvfrom() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("\nServer Says : ");
printf(receiveBuffer,sizeof(receiveBuffer));
}
closesocket(s);
WSACleanup();
return 0;
}

Let me explain a few things for you that might be confusing.
First, in your server you need to set serverSocket.sin_addr.s_addr to INADDR_ANY even if you want to broadcast. You don't want to make it INADDR_BROADCAST. This is simply telling the server to bind on any IP address your computer has, cause a single computer can have more than 1 IP. Which you are doing correctly.
But how can you broadcast from the server? You need to use setsockopt with SO_BROADCAST parameter like this ...
int options = 1;
if ((setsockopt(s, SOL_SOCKET, SO_BROADCAST,(char *)&options,sizeof(options))) < 0){
printf("%d",WSAGetLastError());
}
This will make your server listens for broadcasts, but how can you send broadcasts? You need to set INADDR_BROADCAST in the s_addr field in the sockaddr structure before calling sendto function.
clientSocket.sin_addr.s_addr = INADDR_BROADCAST;
Then use sendto with clientSocket to boardcast your messsage back.
Second, in your client code, you have two options depending on your application.
If you want your clients to send message first to the server (direct without broadcast) then you are doing it right, by setting inet_addr(SERVER) so the client send the message to your server only.
But, if you want the client to broadcast the message, then you need to use setsockopt again in your client, same as in your server, and set the address in connectSocketstructure to INADDR_BROADCAST.
Finally, it would be better if you tell us what are you trying to accomplish here. If you want clients to connect to server first, then the server announce the client to other clients, then you might take TCP instead of UDP.

Related

select with other objects than sockets on windows

I'm facing an issue doing a select() call waiting on a socket + pipe.
I know there are already some topics on that but I have read lots of things and their opposite and I can't figure out what is the best solution for my problem.
The best for me would be to use WaitForMultipleObjects() listening on these two objects but when I try to call it only on the WSAEvent object, it fails and last error catch is code 6 (Invalid Handle).
WSAEVENT sockEvent = WSACreateEvent();
sockEvent = WSAEventSelect(fd, sockEvent, FD_WRITE);
HANDLE *pHandles = &sockEvent;
DWORD dwEvent = WaitForMultipleObjects(1, pHandles, FALSE, amqp_time_ms_until(deadline));
switch (dwEvent)
{
// ghEvents[0] was signaled
case WAIT_OBJECT_0 + 0:
// TODO: Perform tasks required by this event
return AMQP_STATUS_OK;
// ghEvents[1] was signaled
case WAIT_OBJECT_0 + 1:
// TODO: Perform tasks required by this event
return AMQP_STATUS_POLL_EXTERNAL_WAKE;
case WAIT_TIMEOUT:
return AMQP_STATUS_TIMEOUT;
// Return value is invalid.
default:
return AMQP_STATUS_SOCKET_ERROR;
}
So WaitForMultipleObjects doesn't seems to Work with WinSocks events, however I have already seen some examples on the net working with it.
And the of WSACreateEvent documentation (https://msdn.microsoft.com/en-us/library/windows/desktop/ms741561%28v=vs.85%29.aspx) says this :
Windows Sockets 2 event objects are system objects in Windows
environments. Therefore, if a Windows application wants to use an
auto-reset event rather than a manual-reset event, the application can
call the CreateEvent function directly.
This doesn't mean that WSAEvent are based on regular windows events ? If it's the case why it doesn't work with WaitForMultipleObjects ? The doc says it can handle regular events.
Thanks for helping.
This is your problem:
sockEvent = WSAEventSelect(fd, sockEvent, FD_WRITE);
You're overwriting the event handle! (As documented, the return value for WSAEventSelect is either 0 or SOCKET_ERROR. It is not a new event handle.)
Try something like
if (WSAEventSelect(fd, sockEvent, FD_WRITE) != 0) return SOCKET_ERROR;
Looking at the declaration of WSAEVENT revealed that WSAEVENT is simply an alias for HANDLE. This explains the note of the WSACreateEvent documentation you added to your post. So WSACreateEvent simply creates a manual reset event by calling CreateEvent(..., TRUE, FALSE, ...);.
Therefore an event returned by WSACreateEvent has to work along with WaitForMultipleObjects(..).
According to the code you've posted I cannot see any reason why WaitForMultipleObjects(..) should return "invalid handle" when supplied with an event returned by WSACreateEvent...
It may be though that pipes do not work with WaitForMultipleObjects(..). I remember having problems with that a long time ago but I cannot remember the details right now. But maybe it is another place to start digging...
Here is the code of my little test application which creates two threads (one event thread signalling a normal event and a simple TCP/IP server sending data). In the main loop a connection to the server is established and signalled events are processed.
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#pragma comment(lib, "Ws2_32.lib");
#define SERVER_PORT 5000
HANDLE hSomeEvent;
HANDLE hSocketEvent;
DWORD WINAPI eventThread(LPVOID pData)
{
while (1)
{
SleepEx(2250, FALSE);
SetEvent(hSomeEvent);
}
return (0);
}
DWORD WINAPI serverThread(LPVOID pData)
{
SOCKET listener;
struct sockaddr_in sockaddr;
int size;
SOCKET client;
listener = socket(AF_INET, SOCK_STREAM, 0);
if (listener == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = INADDR_ANY;
sockaddr.sin_port = htons(SERVER_PORT);
if (bind(listener, (struct sockaddr *)&sockaddr , sizeof(sockaddr)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
}
listen(listener, 1);
while (listener)
{
size = sizeof(struct sockaddr_in);
client = accept(listener, (struct sockaddr *)&sockaddr, &size);
printf("client connected\n");
while (client != INVALID_SOCKET)
{
SleepEx(5000, FALSE);
if (send(client, "hello\0", 6, 0) != 6)
{
closesocket(client);
shutdown(client, 2);
client = INVALID_SOCKET;
}
}
SetEvent(hSomeEvent);
}
return (0);
}
int main()
{
WSADATA wsaData;
HANDLE events[2];
DWORD result;
SOCKET s;
struct hostent *hp;
struct sockaddr_in sockaddr;
int len;
char buff[1024 * 16];
HANDLE *evtPtr;
WSAStartup(MAKEWORD(2, 2), &wsaData);
hSocketEvent = WSACreateEvent();
//hSocketEvent = CreateEvent(NULL, FALSE, FALSE, "socket_event");
hSomeEvent = CreateEvent(NULL, FALSE, FALSE, "some_event");
CreateThread(NULL, 0, eventThread, NULL, 0, &result);
CreateThread(NULL, 0, serverThread, NULL, 0, &result);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
hp = gethostbyname("127.0.0.1");
sockaddr.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(SERVER_PORT);
if (connect(s, (struct sockaddr*)&sockaddr, sizeof(sockaddr)))
{
closesocket(s);
printf("Could not connect socket : %d" , WSAGetLastError());
}
WSAEventSelect(s, hSocketEvent, FD_READ);
do
{
//events[0] = hSocketEvent;
//events[1] = hSomeEvent;
//result = WaitForMultipleObjects(2, events, FALSE, 1000);
evtPtr = &hSocketEvent;
result = WaitForMultipleObjects(1, evtPtr, FALSE, 1000);
switch (result)
{
case WAIT_OBJECT_0 + 0:
printf("hSocketEvent is signalled!\n");
len = recv(s, buff, sizeof(buff), 0);
printf(" %d bytes received\n", len);
WSAResetEvent(hSocketEvent);
break;
case WAIT_OBJECT_0 + 1:
printf("hSomeEvent is signalled!\n");
break;
case WAIT_TIMEOUT:
printf("timeout\n");
break;
default:
printf("error = %d\n", GetLastError());
break;
}
}
while (1);
printf("\n\nend.");
getch();
return (0);
}
Note that if you use WSACreateEvent you have to manually reset the event after readinng the data (otherwise WaitForMultipleObjects(..) will go nuts).

Windows 7 does not receive Encapsulated Security Payload (ESP) packet on RAW socket

I am trying to use recvfrom() function to receive Encapsulated Security Payload or ESP (IP protocol number = 50) packets on a raw socket. Unfortunately it is not working in windows 7. I would like to mention here that I can receive generic routing encapsulation (GRE) packets on a raw socket by just setting the IP protocol number to 47. And the socket smoothly works and receives GRE packets. But it fails on receiving ESP packets.
I should also mention that I have disabled my firewall services and windows' two default IPSec services viz. 1. IKE and AuthIP IPsec keying modules and 2. IPsec policy agent. I think by some reason windows is not sending the ESP packet to the upper layer.
Can anyone help me? Here is my program.
#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")
int main()
{
int iResult = 0;
WSADATA wsaData;
SOCKET RecvSocket;
sockaddr_in RecvAddr;
unsigned short Port = 27015;
char RecvBuf[1024];
int BufLen = 1024;
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof (SenderAddr);
//-----------------------------------------------
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
wprintf(L"WSAStartup failed with error %d\n", iResult);
return 1;
}
//-----------------------------------------------
// Create a receiver socket to receive datagrams
RecvSocket = socket(AF_INET, SOCK_RAW, 50);
if (RecvSocket == INVALID_SOCKET) {
wprintf(L"socket failed with error %d\n", WSAGetLastError());
return 1;
}
//-----------------------------------------------
// Bind the socket to any address and the specified port.
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Port);
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
iResult = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
if (iResult != 0) {
wprintf(L"bind failed with error %d\n", WSAGetLastError());
return 1;
}
//-----------------------------------------------
// Call the recvfrom function to receive datagrams
// on the bound socket.
wprintf(L"Receiving datagrams...\n");
iResult = recvfrom(RecvSocket,
RecvBuf, BufLen, 0, (SOCKADDR *) & SenderAddr, &SenderAddrSize);
if (iResult == SOCKET_ERROR) {
wprintf(L"recvfrom failed with error %d\n", WSAGetLastError());
}
//-----------------------------------------------
// Close the socket when finished receiving datagrams
printf("\n\nBufLen = %d\n\n", BufLen);
wprintf(L"Finished receiving. Closing socket.\n");
iResult = closesocket(RecvSocket);
if (iResult == SOCKET_ERROR) {
wprintf(L"closesocket failed with error %d\n", WSAGetLastError());
return 1;
}
//-----------------------------------------------
// Clean up and exit.
wprintf(L"Exiting.\n");
Sleep(60000);
WSACleanup();
return 0;
}

Client unable to receive messages from BROADCAST UDP Server. (Winsock)

I have developed a client server UDP application. The Server UDP socket is set to be a BROADCAST UDP Socket. The code of both sides does not generate any error, but the message sent from BROADCAST UDP SERVER Side is not Received at client side. Kindly have a look at my code, i know there is some blunder I can't figure out. I really need help:
SERVER:
#define PORT 8888 //The port on which to listen for incoming data
int main()
{
SOCKET s;
struct sockaddr_in serverSocket, clientSocket;
char receiveBuffer[1000];
//int receiveBufferLength=1000;
int clientSocketLength;
int recv_len;
clientSocketLength = sizeof(clientSocket) ;
WSADATA wsa;
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Socket Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_DGRAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
serverSocket.sin_family = AF_INET;
serverSocket.sin_addr.s_addr = INADDR_ANY;
serverSocket.sin_port = htons( PORT );
int broadcast =1;
if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char*) &broadcast, sizeof(broadcast)) < 0) {
//close(sock);
printf("Error in setting broadcast option");
}
//Bind
if( bind(s ,(struct sockaddr *)&serverSocket , sizeof(serverSocket)) == SOCKET_ERROR)
{
printf("\nBind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Bind done\n\n");
//keep listening for data
printf("\n\t\t\tWaiting for data...\n");
fflush(stdout);
//receiveBuffer[2000]=NULL;
if((recv_len = recvfrom(s, receiveBuffer, 1000, 0, (struct sockaddr *) &clientSocket, &clientSocketLength)) == SOCKET_ERROR)
{
printf("\n\nrecvfrom() failed with error code : %d" , WSAGetLastError());
//exit(EXIT_FAILURE);
while(1);
}
//print details of the client/peer and the data received
printf("\n\nReceived packet from %s:%d\n", inet_ntoa(clientSocket.sin_addr), ntohs(clientSocket.sin_port));
printf("\nClient Says: " );
printf(receiveBuffer,recv_len);
serverSocket.sin_addr.s_addr = INADDR_BROADCAST;
//now reply the client with the same data
if (sendto(s, receiveBuffer, recv_len, 0, (struct sockaddr*) &serverSocket, sizeof(serverSocket)) == SOCKET_ERROR)
{
printf("\nsendto() failed with error code : %d" , WSAGetLastError());
// exit(EXIT_FAILURE);
while(1);
}
else
printf("\nMessage Sent Back to Client");
while(1);
closesocket(s);
WSACleanup();
return 0;
}
CLIENT:
#define PORT 8888 //The port on which to listen for incoming data
#define SERVER "127.0.0.1" //ip address of udp server
//#define PORT 8888 //The port on which to listen for incoming data
int main(void)
{
struct sockaddr_in connectedSocket;
int s;
int length=sizeof(connectedSocket);
char receiveBuffer[1000];
char message[1000];
//clear the buffer by filling null, it might have previously received data
memset(receiveBuffer,'\0', 1000);
WSADATA wsa;
//Initialise winsock
printf("\nInitialising Winsock...\n");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("\nFailed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("\n.........Initialised.\n");
//create socket
if ( (s=socket(AF_INET, SOCK_DGRAM, 0)) == SOCKET_ERROR)
{
printf("\n\nsocket() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//setup address structure
memset((char *) &connectedSocket, 0, sizeof(connectedSocket));
connectedSocket.sin_family = AF_INET;
connectedSocket.sin_port = htons(PORT);
//connectedSocket.sin_port = INADDR_BROADCAST;
connectedSocket.sin_addr.S_un.S_addr = inet_addr(SERVER);
printf("\n\n\nEnter message : ");
gets(message);
//send the message
if (sendto(s, message,sizeof(message) , 0 , (struct sockaddr *) &connectedSocket, sizeof(connectedSocket)) == SOCKET_ERROR)
{
printf("\nsendto() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("\nMessage Successfully sent to Server");
// fflush(stdout);
if (recvfrom(s, receiveBuffer, 1000, 0, (struct sockaddr *) &connectedSocket,&length) == SOCKET_ERROR)
{
printf("\nrecvfrom() failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
while(1);
}
printf("\nServer Says : ");
printf(receiveBuffer,sizeof(receiveBuffer));
while(1);
closesocket(s);
WSACleanup();
return 0;
}
You are sending the reply back to the client on the serverSocket. You already have a clientsocket that you received the message on, use it to send the message back from the server to the client.
Remove ...
serverSocket.sin_addr.s_addr = INADDR_BROADCAST;
and change ...
if (sendto(s, receiveBuffer, recv_len, 0, (struct sockaddr*) &serverSocket, sizeof(serverSocket)) == SOCKET_ERROR)
to
if (sendto(s, receiveBuffer, recv_len, 0, (struct sockaddr*) &clientSocket, sizeof(clientSocket)) == SOCKET_ERROR)
It should work now.

Sockets - sending image

fp = fopen("image.jpg","rb");
if (!fp)
exit(1);
fseek(fp,0,SEEK_END);
len = ftell(fp);
fseek(fp,0,SEEK_SET);
buf = (char *)malloc(len);
fread(buf,len,1,fp);
fclose(fp);
if (WSAStartup(0x0202,&wsa) != 0)
{
printf("Error code : %d",WSAGetLastError());
return 1;
}
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Error code : %d" , WSAGetLastError());
WSACleanup();
exit(1);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Error code : %d" , WSAGetLastError());
closesocket(s);
WSACleanup();
exit(EXIT_FAILURE);
}
sprintf(str,"%d",len);
strcpy(message,"HTTP/1.1 200 OK\r\nContent-Length: ");
sprintf(message,"%s %s",message,str);
sprintf(message,"%s %s",message,"\r\nContent-Type: image/jpeg\r\n\r\n");
sprintf(message,"%s %s",message,buf);
sprintf(message,"%s %s",message,"\r\n");
listen(s , 100);
c = sizeof(struct sockaddr_in);
while( (new_socket = accept(s , (struct sockaddr *)&client, &c)) != INVALID_SOCKET )
{
memset(recvdata,'\0',sizeof(recvdata));
recv(new_socket,recvdata,2000,0);
send(new_socket , message , strlen(message) , 0);
}
if (new_socket == INVALID_SOCKET)
{
printf("Error code : %d" , WSAGetLastError());
closesocket(s);
WSACleanup();
return 1;
}
closesocket(s);
WSACleanup();
return 0;
}
I have a problem with sending image file. This is server side of communication and browser will be client side. When i try to connect to server, server accepts connection and everything is ok. Then i want to send image as response, and it should be showed in browser. Can anyone tell me what is a problem here?
Many issues. Just to start:
You are not checking return values of system calls (listen(), recv(), send(), etc.), so you don't know about errors, and how much data you sent or received.
Printing binary data like from image file here with printf() is a Bad IdeaTM - it will be truncated at the first zero byte, or it might overrun your memory with a lack of such.
You are assuming recv() consumes full HTTP request from a client. It might not, so you are breaking HTTP protocol.
You are not closing connected client socket in your loop. That is a resource leak.

Fail to open SSDP socket on Windows XP if already opened by other application

I want to listen to SSDP multicasts on port 1900. The port is already opened by Windows Discovery Service. I fail to bind my socket despite using SO_REUSEADDR socket option. I'm starting my application as administrator.
If I stop the service, start my application and then restart the service, then both get messages. What am I doing wrong?
static SOCKET CreateSocket(const char *ccAddress, unsigned short ulPort, struct IfPoolItem *item) {
struct sockaddr_in sAddr;
struct ip_mreq mc_req;
SOCKET sRet;
char cSockParam = TRUE;
/* create a socket */
if((sRet = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
return(INVALID_SOCKET);
}
item->s = sRet;
if (setsockopt(sRet, IPPROTO_IP, SO_REUSEADDR, &cSockParam, sizeof(cSockParam)) == -1) {
int iTmp = WSAGetLastError();
return (INVALID_SOCKET);
}
/* bind the socket to the given port */
memset(&sAddr, 0, sizeof(sAddr));
sAddr.sin_family = AF_INET;
sAddr.sin_addr.s_addr = inet_addr(item->szIP);
sAddr.sin_port = htons(ulPort);
if(bind(sRet, (struct sockaddr *)&sAddr, sizeof(sAddr)) == SOCKET_ERROR)
{
int iTmp = WSAGetLastError();
closesocket(sRet);
return(INVALID_SOCKET);
}
cSockParam = 4;
if (setsockopt(sRet, IPPROTO_IP, IP_MULTICAST_TTL, &cSockParam, sizeof(cSockParam)) == -1) {
int iTmp = WSAGetLastError();
return (INVALID_SOCKET);
}
/* Construct an IGMP join request structure */
mc_req.imr_multiaddr.s_addr = inet_addr(ccAddress);
mc_req.imr_interface.s_addr = inet_addr(item->szIP);
/* Send an ADD_MEMBERSHIP message via setsockopt */
if((setsockopt(sRet, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char FAR *) &mc_req, sizeof(mc_req))) == -1) {
int iTmp = WSAGetLastError();
return (INVALID_SOCKET);
}
/* Return the created socket. */
return(sRet);
}
I am not an expert with sockets but if you look at this msdn page it says that SO_REUSEADDR should be used with level = SOL_SOCKET parameter. So probably you call should be something like
setsockopt(sRet, SOL_SOCKET, SO_REUSEADDR,&cSockParam, sizeof(cSockParam))
Please try this and let meknow if it made any difference
I am not exactly sure if this is your problem, but the WDS may be using SO_EXCLUSIVEADDRUSE which is preventing your bind(). The docs in this link would seem to describe the behavior you are reporting.

Resources