Multicast is not working on Windows Vista - c++

While I try to Multicast something to range of IP in win XP , it works fine but while I run the same application on Win VIsta I am unable to multicast. Do I need to configure or add a publisher info for Win Vitsa?
Edit:
struct sockaddr_in staddr;
memset(&staddr, 0, sizeof(struct sockaddr_in));
staddr.sin_family = AF_INET;
staddr.sin_port = htons(SSDP_PORT); // Use the first free port
staddr.sin_addr.s_addr=inet_addr(SSDP_MULTICAST_ADDRESS);
int socklen = sizeof(struct sockaddr_in);
Edit 2
Socket Creation
int ibindstatus =0 ;
try
{
//Initailize the WinSock
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
struct in_addr iaddr;
struct sockaddr_in staddr;
// set content of struct saddr and imreq to zero
memset(&staddr, 0, sizeof(struct sockaddr_in));
memset(&iaddr, 0, sizeof(struct in_addr));
// open a UDP socket
m_iSocket = socket(AF_INET, SOCK_DGRAM, 0);
if ( m_iSocket < 0 )
{
return SOCKET_NOT_AVAILABLE;
}
staddr.sin_family = AF_INET;
staddr.sin_port = htons(SSDP_PORT); // Use the first free port
staddr.sin_addr.s_addr = htonl(INADDR_ANY); // bind socket to any interface
ibindstatus = bind(m_iSocket, (struct sockaddr *)&staddr, sizeof(struct sockaddr_in));
if ( ibindstatus < 0 )
{
return SOCKET_BIND_ERROR;
}
//send the buffer
int iSendStatus = sendto(m_iSocket, cSendData, lSendDataLen, 0,
(struct sockaddr *)&staddr, socklen);
if(iSendStatus< 0)
{
return SEND_ERROR;
}

Well after lotz of experiments I was not able to figure out why Multi casting was not working, and found out suddenly this is because Network Discovery was off on my Vista.
So If here what I did , Go to Control Panel->SetUp File Sharing(Under Network and Internet) ->Sharing and Discovery and then switch on or off the network discovery
Well thatz what work for my application and the source code is what I have posted in my question. Hope fully this will save some of your time and frustation.

Related

How to Test and Run a Client Server Program in C++ using Eclipse

I am trying to get started with UDP and would like to test and debug some client server programs.
I am using an Eclipse IDE with cygwin64 as a compiler.
I have found some example client server programs from here: https://www.geeksforgeeks.org/udp-server-client-implementation-c/
I would like to be able to run the example to get me started on learning about UDP client servers.
The example code is as follows:
Server
// Server side implementation of UDP client-server model
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define PORT 8080
#define MAXLINE 1024
// Driver code
int main() {
int sockfd;
char buffer[MAXLINE];
char *hello = "Hello from server";
struct sockaddr_in servaddr, cliaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
memset(&cliaddr, 0, sizeof(cliaddr));
// Filling server information
servaddr.sin_family = AF_INET; // IPv4
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(PORT);
// Bind the socket with the server address
if ( bind(sockfd, (const struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0 )
{
perror("bind failed");
exit(EXIT_FAILURE);
}
int len, n;
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, ( struct sockaddr *) &cliaddr,
&len);
buffer[n] = '\0';
printf("Client : %s\n", buffer);
sendto(sockfd, (const char *)hello, strlen(hello),
0, (const struct sockaddr *) &cliaddr,
len);
printf("Hello message sent.\n");
return 0;
}
Client
// Client side implementation of UDP client-server model
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define PORT 8080
#define MAXLINE 1024
// Driver code
int main() {
int sockfd;
char buffer[MAXLINE];
char *hello = "Hello from client";
struct sockaddr_in servaddr;
// Creating socket file descriptor
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
int n, len;
sendto(sockfd, (const char *)hello, strlen(hello),
MSG_CONFIRM, (const struct sockaddr *) &servaddr,
sizeof(servaddr));
printf("Hello message sent.\n");
n = recvfrom(sockfd, (char *)buffer, MAXLINE,
MSG_WAITALL, (struct sockaddr *) &servaddr,
&len);
buffer[n] = '\0';
printf("Server : %s\n", buffer);
close(sockfd);
return 0;
}
I have tried opening up two different eclipse workbenches and running both the codes, but it is not running as expected and it is saying that the messages have been sent but I have not been able to receive them on the client or server.
I definitely would like to stick with c/c++ and try to get this working in eclipse if it's possible.
If anyone has any advice on how I can be able to see some results or anything that could get me started with this, it would be much appreciated. Thank you!
Problem
You have not set the address of the server correctly in the client code.
servaddr.sin_addr.s_addr = INADDR_ANY;
is meaningless when sending (Why would you want to send to any available address? You want to send to the server.) and is rejected by sendto. You would have seen this if you'd checked the return value. Always check the return value, even for UDP communications. Sure there are a million reasons why a packet won't arrive with UDP that you can't detect at the time of sendto, but it's good to know that the network stack actually accepted the message even if a grue subsequently devours the packet in one of the dark corners of the Internet. A sending error you can do something about, like perror and then fix the code accordingly. A grue, not so much. You'll have to make a protocol robust enough to retransmit or otherwise survive the loss of the packet.
Solution
Get the server's address structure with getaddrinfo.
Replace
// Filling server information
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = INADDR_ANY;
with something more like
struct addrinfo hints;
struct addrinfo *hostlist;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_UDP;
if (getaddrinfo("Server Name or Address Goes Here",
PORT, // this needs to be a char *, not an integer
&hints,
&hostlist))
{
// handle error
exit(EXIT_FAILURE);
}
PORT in this case needs to be a char *, so instead of
#define PORT 8080
use
constexpr char const * PORT = "8080";
You can leave out the constexpr if your compiler is old and doesn't support it.
Then when you go to send, iterate through the hostlist until you find a host that responds. Since you've probably narrowed the servers down to exactly one candidate, this is probably overkill, but you might as well get into practice doing things right. The alternative sucks when systems start getting complicated.
struct addrinfo *curhost;
for (curhost = hostlist; curhost != NULL; curhost = curhost->ai_next)
{
int rval = sendto(sockfd,
(const char *) hello,
strlen(hello),
0,
curhost->ai_addr,
curhost->ai_addrlen);
if (rval> 0) // always check return codes. Programmers are lazy.
// They wouldn't have gone to the effort of putting
// it there if it wasn't important.
{
if server responds
do protocol stuff to complete transaction
break;
}
}
freeaddrinfo(hostlist); // thou shalt not leak resources.
if (curhost == nullptr)
{
notify user that no server was willing to talk
}
Documentation for getaddrinfo.

How to detect if a port is already in use server side (in C++ on windows)?

It's certainly a common question, but not in this terms (windows, server side, accept multi connexion).
My goal is to accept to start a server listing on a port for multiple connections only if before that the port is detected "unused".
At the line where I put //HERE..., binddoesn't return a SOCKET_ERROR status as I expected.
Maybe I'm doing something wrong.
How to detect that my port is not in use by some other app?
Here is the status of the port before running (it is used)
netstat -an
TCP 127.0.0.1:2005 0.0.0.0:0 LISTENING
I hope this snippet is sufficent to explain what I'm doing, it's a merge of several steps.
WSADATA WSAData;
int err = WSAStartup(MAKEWORD(2, 2), &WSAData);
SOCKADDR_IN sin;
socklen_t recsize = sizeof(sin);
int one = 1;
SOCKADDR_IN* csin;
SOCKET csock = INVALID_SOCKET;
socklen_t crecsize = sizeof(SOCKADDR_IN);
int sock_err;
if (m_socket != INVALID_SOCKET)
{
memset(&sin, 0, recsize);
if(m_blocal)
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_family = AF_INET;
sin.sin_port = htons(m_iPort);
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(int));
sock_err = bind(m_socket, (SOCKADDR*)&sin, recsize);
//HERE I want to be sure no one else runs on this port
//rest of the code using: select(m_socket + 1, &rd, &wr, &er, &timeout);
}
closesocket(m_socket);
WSACleanup();
Don't set SO_REUSEADDR. Then bind() will fail if the address is already in use and WSAGetLastError() will return WSAEADDRINUSE.
Also note that two processen can still bind to the same port if the IP addresses are different, for example, one process binding to localhost and another process binding to the LAN network address.

Reading from UDP socket over WiFi always timeout

I have a piece of code that send a UDP broadcast to scan for device on our local network. It works fine when im plugged via ethernet, but it doesnt when im connected via WiFi.
Is there something different to do to connect in UDP when using WiFi?
You can find the code im using below. When using WiFi, select always return 0
struct sockaddr_in addr;
//Create socket
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
perror("socket");
exit(1);
}
/* set up destination address */
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(48620);
addr.sin_addr.s_addr = inet_addr("192.168.3.255");
//TRYING TO BIND, NOT WORKING
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
int a = WSAGetLastError(); //ERROR 10049
perror("bind"); //Says NO ERROR
}
//allow broadcast
int broadcast = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(broadcast)) == -1)
exit(1);
if (sendto(fd, (const char *)&request, sizeof(request), 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("sendto");
exit(1);
}
do
{
FD_ZERO(&rdFs);
FD_SET(fd, &rdFs);
lTimeout.tv_sec = 1;
lTimeout.tv_usec = 000000;
lSelRet = select(fd, (fd_set*)&rdFs, NULL, NULL, &lTimeout);
if (lSelRet > 0 && FD_ISSET(fd, &rdFs))
{
addrFromSize = sizeof(addrFrom);
lResult = recvfrom(fd, bufferIn, sizeof(bufferIn), 0, (struct sockaddr *) &addrFrom, &addrFromSize);
//Treat result
}
} while (lSelRet > 0);
Note : Even using WiFi, i can estalbish a TCP connection and communicate with the device, its just the UDP broadcast that doesnt work
Note2: currently testing on windows, but I will port it to Linux after
Edit : added the SO_BROADCAST as advised by Remy
Finally got it working, it was a code issue, not a router issue.
The issue was a misuse of the bind function, I needed to use my IP and not the broadcast IP.
/* set up destination address */
memset((char *)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(48620);
addr.sin_addr.s_addr = inet_addr("192.168.3.134"); //<== Windows : My IP, not the broadcast IP
addr.sin_addr.s_addr = INADDR_ANY; //Linux
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
perror("bind");
}
EDIT : strangely enough, in windows you must bind to the ip sending the request, and on linux you must bind to INADDR_ANY.

SQLBrowseConnect doesn't seem to enumerate servers on local domain

I am trying to enumerate local SQL instances using SQLBrowseConnect. Generally speaking, this is working fine, but we have one set up which results in an SQLExpress instance not being discovered. Here is the code in question:
SQLSetConnectAttr(hSQLHdbc,
SQL_COPT_SS_BROWSE_SERVER,
_T("(local)"),
SQL_NTS);
CString inputParam = _T("Driver={SQL Server}");
SQLBrowseConnect(hSQLHdbc,
inputParam,
SQL_NTS,
szConnStrOut,
MAX_RET_LENGTH,
&sConnStrOut);
In the failed instance, the code is running on a domain controller. The missing local instance of SQL is an SQLExpress instance (version 9). However, the puzzling thing is that running sqlcmd -L shows the missing instance without any problems.
Am I missing something really silly? Please remember that on other systems and set ups there is no issue.
After much investigation, I couldn't really find out what the problem was specifically. This one machine just would not discover its own instances of SQL using SQLBrowseConnect. I therefore decided to write my own version. Discovering SQL instances turns out to be pretty easy. You just send a broadcast UDP packet to port 1434 containing the payload 0x02 (1 byte) and wait for SQL servers to respond. They respond with one packet per server which details all the instances on that machine. The code required to do this is shown below:
// to enumerate sql instances we simple send 0x02 as a broadcast to port 1434.
// Any SQL servers will then respond with a packet containing all the information
// about installed instances. In this case we only send to the loopback address
// initialise
WSADATA WsaData;
WSAStartup( MAKEWORD(2,2), &WsaData );
SOCKET udpSocket;
struct sockaddr_in serverAddress;
if ((udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
return;
}
// set up the address
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
serverAddress.sin_port = htons(1434);
// the payload
char payload = 0x02;
// config the port for broadcast (not totally necessary right now but maybe in the future)
BOOL broadcast = TRUE;
setsockopt(udpSocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char*>(&broadcast), sizeof(BOOL));
// receive address info
sockaddr_in RecvAddr;
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof (SenderAddr);
// bind the socket to the receive address info
int iResult = bind(udpSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
if (iResult != 0)
{
int a = WSAGetLastError();
return;
}
if (sendto(udpSocket, &payload, 1, 0, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
{
int a = WSAGetLastError();
return;
}
// set up a select so that if we don't get a timely response we just bomb out.
fd_set fds ;
int n ;
struct timeval tv ;
// Set up the file descriptor set.
FD_ZERO(&fds) ;
FD_SET(udpSocket, &fds) ;
// Set up the struct timeval for the timeout.
tv.tv_sec = 5 ;
tv.tv_usec = 0 ;
// Wait until timeout or data received.
n = select ( (int)udpSocket, &fds, NULL, NULL, &tv ) ;
if ( n == 0)
{
// timeout
return;
}
else if( n == -1 )
{
// error
return;
}
// receive buffer
char RecvBuf[1024];
int BufLen = 1024;
memset(RecvBuf, 0, BufLen);
iResult = recvfrom(udpSocket,
RecvBuf,
BufLen,
0,
(SOCKADDR *) & SenderAddr,
&SenderAddrSize);
if (iResult == SOCKET_ERROR)
{
int a = WSAGetLastError();
return;
}
// we have received some data. However we need to parse it to get the info we require
if (iResult > 0)
{
// parse the string as required here. However, note that in my tests, I noticed
// that the first 3 bytes always seem to be junk values and will mess with string
// manipulation functions if not removed. Perhaps this is why SQLBrowseConnect
// was having problems for me???
}

How to set up a Winsock UDP socket?

I want to create a Winsock UDP socket that only sends data to a client. I want the kernel to choose an available port for me. On the other hand, I want to indicate which local IP to use, since I'm running a few nics.
I've tried combing through the maze of socket options, as well as binding with the port in the socket address set to 0 to no avail.
My code is in Win32 C++.
Please excuse the lack of error checking:
char pkt[...];
size_t pkt_length = ...;
sockaddr_in dest;
sockaddr_in local;
WSAData data;
WSAStartup( MAKEWORD( 2, 2 ), &data );
local.sin_family = AF_INET;
local.sin_addr.s_addr = inet_addr( <source IP address> );
local.sin_port = 0; // choose any
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr( <destination IP address> );
dest.sin_port = htons( <destination port number> );
// create the socket
SOCKET s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
// bind to the local address
bind( s, (sockaddr *)&local, sizeof(local) );
// send the pkt
int ret = sendto( s, pkt, pkt_length, 0, (sockaddr *)&dest, sizeof(dest) );
The answer of Graeme Perrow doesn't work anymore because inet_addr is deprecated.
Use inet_pton instead like this:
#include <string>
#include <WinSock2.h>
#include <Ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main() {
const char* pkt = "Message to be sent";
const char* srcIP = < source IP address >;
const char* destIP = < destination IP address >;
sockaddr_in dest;
sockaddr_in local;
WSAData data;
WSAStartup(MAKEWORD(2, 2), &data);
local.sin_family = AF_INET;
inet_pton(AF_INET, srcIP, &local.sin_addr.s_addr);
local.sin_port = htons(0);
dest.sin_family = AF_INET;
inet_pton(AF_INET, destIP, &dest.sin_addr.s_addr);
dest.sin_port = htons(< destination port number >);
SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(s, (sockaddr *)&local, sizeof(local));
sendto(s, pkt, strlen(pkt), 0, (sockaddr *)&dest, sizeof(dest));
closesocket(s);
WSACleanup();
return 0;
}
Not a direct "HowTo", but I have been using an open source library called "ACE (Adaptive Communication Environment" for all my TCP and UDP socket programming and found it very useful and powerful. It takes a "software pattens" approach to providing building blocks to solve your particular problem.
I was able to use their UDP encapsulation to connect to a given port and have replies sent to a free port chosen by the system. Alternatively you can specify the return port if you wish.
ACE is available here:
ACE Homepage
When you say "I want to indicate which local IP to use, since I'm running a few nics", do you mean that you want to specify the ip address, or do you want to specify the nic and use the associated ip address?
If you are trying to specify the nic, this question should be relevant.