Winsock Error 10022 on Listen - c++

i'm making a small IRC server, but I've come across a problem; upon trying to listen to the socket, i get error 10022 (Invalid Argument).
The error also appears on accept(), but this is because the socket isn't listening (the problem i'm posting about).
I didn't include the accept function because i feel it isn't necessary and would be adding pointless code.
#include <iostream>
#include <ws2tcpip.h>
#include <winsock2.h>
#include <thread>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
#define maxConnections 10
class Server
{
struct sockaddr_storage their_addr;
struct addrinfo hints, *res;
struct addrinfo *servinfo;
int status;
SOCKET sock;
public:
void Start(const char *port);
};
void Server::Start(const char *port)
{
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 0), &WSAData) != 0)
{
std::cout << "[ERROR]: " << GetLastError() << ".\n";
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
status = getaddrinfo(NULL, port, &hints, &res);
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == SOCKET_ERROR)
{
std::cout << "[ERROR]: " << WSAGetLastError() << "Bad Socket.\n";
}
bind(sock, res->ai_addr, res->ai_addrlen);
Error:
if (listen(sock, maxConnections) == SOCKET_ERROR)
{
std::cout << "[ERROR]: " << WSAGetLastError() << " Listening Failed.\n";
}
The code above details the socket creation and binding, all of which are successful (though not necessarily right). The socket creation including 'NULL' might be the issue.
Thanks :)

WSAStartup() and getaddrinfo() do not use (WSA)GetLastError(), they directly return the actual error code instead. You are not accounting for that in your error messages.
socket() returns INVALID_SOCKET on failure, not SOCKET_ERROR.
When using getaddrinfo() to create a listening socket, you should specify AI_PASSIVE in the addrinfo.ai_flags field of the hints parameter. That will fill the output addrinfo with data that is suitable to pass to bind().
Try something more like this:
class Server
{
private:
bool winsockStarted;
SOCKET sock;
...
public:
Server();
~Server();
bool Start(const char *port);
void Stop();
...
};
Server::Server()
: sock(INVALID_SOCKET), winsockStarted(false)
{
WSADATA WSAData = {0};
int status = WSAStartup(MAKEWORD(2, 0), &WSAData);
if (status != 0)
std::cout << "[ERROR]: " << status << " Unable to start Winsock." << std::endl;
else
winsockStarted = true;
}
Server::~Server()
{
Stop();
if (winsockStarted)
WSACleanup();
}
bool Server::Start(const char *port)
{
Stop();
struct addrinfo hints = {0};
struct addrinfo *res = NULL;
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int status = getaddrinfo(NULL, port, &hints, &res);
if (status != 0)
{
std::cout << "[ERROR]: " << status << " Unable to get address info for Port " << port << "." << std::endl;
return false;
}
SOCKET newsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (newsock == INVALID_SOCKET)
{
std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to create Socket." << std::endl;
freeaddrinfo(res);
return false;
}
if (bind(newsock, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR)
{
std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to bind Socket." << std::endl;
freeaddrinfo(res);
closesocket(newsock);
return false;
}
freeaddrinfo(res);
if (listen(newsock, maxConnections) == SOCKET_ERROR)
{
std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to Listen on Port " << port << "." << std::endl;
closesocket(newsock);
return false;
}
sock = newsock;
return true;
}
void Server::Stop()
{
if (sock != INVALID_SOCKET)
{
closesocket(sock);
sock = INVALID_SOCKET;
}
}

I reread my code and realized that i need to add a check here
status = getaddrinfo(NULL, port, &hints, &res);
I changed it to
if (status = getaddrinfo(NULL, port, &hints, &res) != 0)
{
std::cout << "[ERROR]: " << WSAGetLastError() << "Get Address Info failed.\n";
}
and startup was successful.
If someone could explain why, i'll improve my answer.

Related

How to handle broadcast messages?

I created a client that sends broadcast messages over my local network:
#define SERVER_PORT "7777"
int main(int argc, char** argv)
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
if (argc != 3) {
fprintf(stderr,"usage: client ip message\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], SERVER_PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
for(p = servinfo; p != NULL; p = p->ai_next)
{
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
perror("talker: socket");
continue;
}
break;
}
int broadcast = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) == -1)
{
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return 2;
}
std::cout << "type any number to start: ";
int temp = 0;
std::cin >> temp;
while(1)
{
if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, p->ai_addr, p->ai_addrlen)) == -1)
{
std::cout << "[ERROR] sendto error: " << errno << std::endl;
continue;
}
std::cout << "[INFO] sended: " << numbytes << " bytes!" << std::endl;
sleep(5);
}
freeaddrinfo(servinfo);
close(sockfd);
return 0;
}
Yes I'm using while(1) loop without a chance for exit (that's doesn't matter).
This client successfully sends broadcast messages. But how to handle them from the server side? I tried to do it next way (server was written as a class. Here is to main methods):
virtual void Init() override
{
addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
int iRes = -1;
if((iRes = getaddrinfo(m_sIpAddress.c_str(), std::to_string(m_iPort).c_str(), &hints, &m_pAddr)) != 0)
{
std::cout << "getaddrinfo error: " << gai_strerror(iRes) << std::endl;
exit(-1);
}
std::cout << "getaddrinfo success!" << std::endl;
m_iSocket = socket(AF_INET, SOCK_DGRAM, 0);
if(m_iSocket == -1)
{
std::cout << "socket error: " << errno << std::endl;
exit(-1);
}
std::cout << "socket created!" << std::endl;
if((iRes = bind(m_iSocket, m_pAddr->ai_addr, m_pAddr->ai_addrlen)) == -1)
{
std::cout << "bind error: " << errno << std::endl;
exit(-1);
}
std::cout << "binded successfully!" << std::endl;
}
virtual void Listen() override
{
int iNumOfReadBytes = -1;
std::string msg;
msg.resize(1024);
sockaddr_in clientAddr;
socklen_t addrLen = sizeof(sockaddr);
while(true)
{
if((iNumOfReadBytes = recvfrom(m_iSocket, const_cast<char*>(msg.c_str()), 1024-1, 0, reinterpret_cast<sockaddr*>(&clientAddr), &addrLen)) == -1)
{
std::cout << "recvfrom error: " << errno << std::endl;
continue;
}
char ip[16]; //string for ip
inet_ntop(AF_INET, &(clientAddr.sin_addr), ip, 16);
std::cout << "[";
for (int i = 0; i < 16; i++)
{
std::cout << ip[i];
}
std::cout << "]";
std::cout << msg << std::endl;
}
}
Init method is responsible for initializing of the socket and Listen method for handling broadcast messages.
Lets imagine that server has 192.168.88.123 ip address while client sends broadcast messages on 192.168.88.255 ip.Server should get messages from client, I suppose, but it never actually receives them.
I also tried to configure client to send messages to the 255.255.255.255 ip. Messages were sent, but server didn't get them.
So is it code's fault? Or something with IPs (if it is so, that's very weird)?
P.S. I read the Beej's networking guide. There was a broadcast example, but only from client side. But I'm interesting in handling of such messages from server side.
Thanks!
The code looks fine (though, there are some things I would suggest tweaking, like specifying the IPPROTO_UDP protocol when calling getaddrinfo(), and including the AI_PASSIVE flag on the server side).
Not all network routers allow UDP broadcasts by default. So check your router configuration, as well as your OS firewall. Use a packet sniffer, like WireShark, to make sure the packets are actually leaving the sender's NIC and arriving on the receiver's NIC, that they are not being blocked during transit.
Also, double check to make sure your client socket and server socket are bound to the same subnet, and that the client is sending to the correct broadcast IP for that subnet. Given the server IP of 192.168.88.123, the broadcast IP would be 192.168.88.255 only if the subnet mask is 255.255.255.0, is that the case in your environment?
Also, check if you have the same problem if your server binds to 0.0.0.0 (listens on all local NICs) instead of binds to 192.168.88.123 (listens on just 1 NIC).

Simple non-blocking multi-threaded tcp server

I'm studying C++, and this weekend I started to play around with sockets and threads. Bellow is a simple multi threaded server that I'm making based on some tutorials.
The issue that I'm facing is that when I'm connecting with 2 telnet clients only the keystrokes form the first connection appear on the server. Any keystroke sent from the second telnet connection appears suddenly once the first telnet connection closes. Could someone explain to me what have I done wrong here?
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
void clientSocketHandler(SOCKET clientSocket, std::string client_ip) {
char buf[4096];
std::thread::id thread_id = std::this_thread::get_id();
std::cout << thread_id << " - " << client_ip << ": connected" << std::endl;
while (true)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == 0)
{
std::cout << thread_id << " - " << client_ip << ": disconnected" << std::endl;
break;
}
if (bytesReceived > 0)
{
std::cout << thread_id << " - " << client_ip << ": " << std::string(buf, 0, bytesReceived) << std::endl;
//send(clientSocket, buf, bytesReceived + 1, 0);
}
}
std::cout << thread_id << " - " << client_ip << ": closing client socket & exiting thread..." << std::endl;
closesocket(clientSocket);
}
void waitForConnections(SOCKET serverSocket) {
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(1337);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(serverSocket, (sockaddr*)&hint, sizeof(hint));
listen(serverSocket, SOMAXCONN);
while (true) {
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&client, &clientSize);
if (clientSocket != INVALID_SOCKET)
{
char host[NI_MAXHOST]; // Client's remote name
ZeroMemory(host, NI_MAXHOST); // same as memset(host, 0, NI_MAXHOST);
std::string client_ip = inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::thread t(clientSocketHandler, clientSocket, client_ip);
t.join();
}
Sleep(100);
}
}
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
std::cerr << "Can't Initialize winsock! Quitting..." << std::endl;
return 1;
}
// Create a socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Can't create a socket! Quitting..." << std::endl;
return 1;
}
// If serverSocketMode = 0, blocking is enabled;
// If serverSocketMode != 0, non-blocking mode is enabled.
u_long serverSocketMode = 1;
if (ioctlsocket(serverSocket, FIONBIO, &serverSocketMode) != NO_ERROR)
{
WSACleanup();
std::cerr << "Can't set socket to non-blocking mode! Quitting..." << std::endl;
return 1;
}
// Disables the Nagle algorithm for send coalescing.
// This socket option is included for backward
// compatibility with Windows Sockets 1.1
BOOL flag = TRUE;
if (setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&flag, sizeof(flag)) != NO_ERROR)
{
WSACleanup();
std::cerr << "Can't set socket NO_DELAY option! Quitting..." << std::endl;
return 1;
}
// Start listening for connections
waitForConnections(serverSocket);
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}
This should work. I removed pointless things like setting the socket to non-blocking and disabling the Nagle algorithm. The latter should only be done for things that need low-millisecond interactivity.
But, the substantial change that should fix your problem is changing join to detach. Using join causes your program to wait for the thread to finish before continuing. Using detach says "This thread is going to run in the background doing things, and I don't care about learning its fate later.".
If you don't use one of the two, and the ::std::thread object is destroyed, the system throws an exception because you're destroying the only means you have of getting information about whether or not a thread exited with an error of some kind with saying that either you don't care about such information, or explicitly asking for it.
I don't have Windows, so I can't test it:
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
void clientSocketHandler(SOCKET clientSocket, std::string client_ip)
{
char buf[4096];
std::thread::id thread_id = std::this_thread::get_id();
std::cout << thread_id << " - " << client_ip << ": connected" << std::endl;
while (true)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == 0)
{
std::cout << thread_id << " - " << client_ip << ": disconnected" << std::endl;
break;
}
if (bytesReceived > 0)
{
std::cout << thread_id << " - " << client_ip << ": " << std::string(buf, 0, bytesReceived) << std::endl;
//send(clientSocket, buf, bytesReceived + 1, 0);
}
}
std::cout << thread_id << " - " << client_ip << ": closing client socket & exiting thread..." << std::endl;
closesocket(clientSocket);
}
void waitForConnections(SOCKET serverSocket)
{
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(1337);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(serverSocket, (sockaddr*)&hint, sizeof(hint));
listen(serverSocket, SOMAXCONN);
while (true) {
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&client, &clientSize);
if (clientSocket != INVALID_SOCKET)
{
char host[NI_MAXHOST]; // Client's remote name
ZeroMemory(host, NI_MAXHOST); // same as memset(host, 0, NI_MAXHOST);
std::string client_ip = inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::thread t(clientSocketHandler, clientSocket, client_ip);
t.detach();
}
Sleep(100);
}
}
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
std::cerr << "Can't Initialize winsock! Quitting..." << std::endl;
return 1;
}
// Create a socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Can't create a socket! Quitting..." << std::endl;
return 1;
}
// Start listening for connections
waitForConnections(serverSocket);
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}

Issues with UDP client to UDP server with 10057 error

I have an issues of connecting to my UDP server. On VS it showed no errors except when I do an error checking it give me a Error 10057.
UDP Client:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
#define ZeroMemory
using namespace std;
WSADATA wsadata;
SOCKET Client;
SOCKADDR_IN Server;
unsigned int Port = 5020;
int ret;
char buf[4096];
int len, tolen, fromlen, namelen;
int main(int argc, char * argv[])
{
// Initialize Winsocket
ret = WSAStartup(MAKEWORD(2, 2), &wsadata);
// CHECKS THE SOCKET STATUS
if (ret == SOCKET_ERROR)
{
printf("Client: Winstock Status is: %s ", wsadata.szSystemStatus);
WSACleanup();
cout << endl;
}
else
{
printf("Client: Winstock Status is: %s ", wsadata.szSystemStatus);
cout << endl;
}
// Client Address
Server.sin_family = AF_INET;
Server.sin_port = htons(Port);
inet_pton(AF_INET, "127.0.0.1", &Server.sin_addr);
// Create Socket
ret = Client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// CHECKS IF SOCKET IS CREATED
if (Client == INVALID_SOCKET)
{
cout << "Client: Can't Create Socket! ERROR: %s " << WSAGetLastError();
WSACleanup();
cout << endl;
}
// Bind Socket
ret = bind(Client, (sockaddr*)& Server,sizeof(Server));
// CHECKS IF SOCKET IS BINDED
if (ret == INVALID_SOCKET)
{
cout << "Client: Failed to bind socket" << WSAGetLastError(); ;
cout << endl;
}
string s(argv[1]);
// SendTo()
ret = sendto
(
Client,
s.c_str(),
s.size() + 1,
0,
(sockaddr*) & Server,
sizeof(Server)
);
if (ret == SOCKET_ERROR);
{
cout << "That did not work! Error Code: " << WSAGetLastError();
cout << endl;
}
// CloseSocket
closesocket(Client);
// CleanUp Winsocket
WSACleanup();
return 0;
}
UDP Server:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
WSADATA wsadata;
SOCKET ServerSocket;
SOCKADDR_IN ServerAddress, Client;
unsigned int Port = 5020;
char buf[4096];
int ret;
int len, tolen, fromlen, namelen;
int main()
{
// Initializing Socket
ret = WSAStartup(MAKEWORD(2, 2), &wsadata);
if (ret == SOCKET_ERROR)
{
cout << "Server: Failed to initialized socket. Error: " << wsadata.szSystemStatus;
cout << endl;
}
else
{
cout << "Server: Successfully initialized socket." << wsadata.szSystemStatus;
cout << endl;
}
// Sever Address
ServerAddress.sin_family = AF_INET;
ServerAddress.sin_port = htons(Port);
inet_pton(AF_INET, "127.0.0.1", &ServerAddress.sin_addr);
// Create Socket
ret = ServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ret == -1)
{
cout << "Server: Failed to create socket. Error: " << WSAGetLastError();
cout << endl;
}
else
{
cout << "Server: Socket has been created ";
cout << endl;
}
// Bind Socket
ret = bind(ServerSocket, (sockaddr*)& ServerAddress, sizeof(ServerAddress));
if (ret == -1)
{
cout << "Server: Failed to bind socket. Error: " << WSAGetLastError();
cout << endl;
}
else
{
cout << "Server: Socket is binded to address ";
cout << endl;
}
int ClientLength = sizeof(Client);
while(true)
{
// receivefrom
ret = recvfrom
(
ServerSocket,
buf,
len,
0,
(sockaddr*)& Client,
&ClientLength
);
if (ret == SOCKET_ERROR)
{
cout << "Error receiving from client" << WSAGetLastError();
}
// display message
char ClientIP[256];
inet_ntop(AF_INET, &Client.sin_addr, ClientIP, 256);
cout << "message recieve from: " << ClientIP << " : " << buf << endl;
}
// Close Socket
closesocket(ServerSocket);
// Cleanup Winsocket
WSACleanup();
return 0;
}
I have executed the client first, no issues, executed server then client that's when it showed the issue.
// SendTo()
ret = sendto
(
Client,
s.c_str(),
s.size() + 1,
0,
(sockaddr*) & Server,
sizeof(Server)
);
if (ret == SOCKET_ERROR);
{
cout << "That did not work! Error Code: " << WSAGetLastError();
cout << endl;
}
Two mistakes:
ret = Client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
If you are writing a UDP client, you need to create a UDP socket, not a TCP socket:
ret = Client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ret = bind(Client, (sockaddr*)& Server,sizeof(Server));
This is on the client side. Why are you trying to bind() to the server's endpoint? You use bind() to set the local address of the socket, not the remote address. Use connect() for the remote address (which you don't need to do when using sendto()).

Send Email with C++ WINSOCK (TCP, SSL)

I've been trying for days to send a short, plain-text email to myself with C++. I'm using Visual Studio Express 2015. I'm eventually hoping to email automatic alerts to myself. I am using a Gmail account. I can't seem to manage to get this to work. I can send data, but can't receive. The server is closing my connection with Error 10054. (You can read about what that error means on this page.)
Here is the history: I have cobbled all this together from lots of S.O. posts and MSDN articles. I used to have a functional WSASetSocketSecurity section in this code, but for whatever reason, my connection attempts were timing out, so I omitted it. At this point, I will settle for the server not severing my connection when I send EHLO or HELO.
I'm really at a loss for how to proceed. Days of exploration, dozens of read articles, hundreds of dead ends. I hope that you'll forgive the few bits of junk code and that S.O. removed my hand alignments. Please take a look, let me know what I am doing wrong, let me know of any improper style, or anything else that offends your good-coder sensibilities. Many thanks.
#include "stdafx.h"
#include <exception>
#include <string>
#include <iostream> // In-out stream objects for development
#include <stdio.h> // Standard in-out for development
#include <winsock2.h> // For making socket connection to email server
#include <Mstcpip.h>
#include <Ws2tcpip.h> // Enhanced protocols to assist winsock2.h
#pragma comment(lib, "Ws2_32.lib") // Library for winsock2.h
#pragma comment(lib, "Fwpuclnt.lib") // Library for winsock2.h
#define BUFFER_SIZE 512
using namespace std;
void cleanup(SOCKET ConnectSocket, struct addrinfo *result) {
if (ConnectSocket != INVALID_SOCKET) {
closesocket(ConnectSocket);
}
freeaddrinfo(result);
WSACleanup();
cout << "socket closed" << endl;
cin.get(); // Development only
}
int _tmain(int argc, char* argv[]) {
// Initialize email parameters
char bccAddresses[64] = "";
char fromAddress[64] = "my_email#host.com";
char msg[512] = "Hello world!";
char port[12] = "465";
char serverName[64] = "smtp.host.com";
char toAddresses[64] = "my_email#host.com";
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
WSADATA wsaData;
try {
// Initialize Winsock
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult == SOCKET_ERROR) {
cout << "Error " << iResult << endl;
throw std::exception("WSAStartup failed\n");
}
cout << "WSAStartup successful: " << iResult << endl;
// Set up the hints socket address structure
ZeroMemory(&hints, sizeof(hints));
hints.ai_flags = AI_SECURE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo(serverName, port, &hints, &result);
if (iResult == SOCKET_ERROR) {
cout << "Error " << WSAGetLastError() << endl;
throw std::exception("getaddrinfo failed\n");
}
cout << "getaddrinfo successful: " << iResult << endl;
// Connect to the socket
ptr = result;
ConnectSocket = WSASocket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol, NULL, 0, 0);
if (ConnectSocket == INVALID_SOCKET) {
cout << "Error " << WSAGetLastError() << endl;
throw std::exception("Error at socket\n");
}
cout << "WSASocket successful: " << iResult << endl;
// Connect via the socket
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
cout << "Error " << WSAGetLastError() << endl;
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
throw std::exception("Unable to connect to server!\n");
}
cout << "connect successful: " << iResult << endl;
// Send message
char sendBuffer[BUFFER_SIZE] = "What is your malfunction";
char recvBuffer[BUFFER_SIZE];
sprintf_s(sendBuffer, BUFFER_SIZE, "EHLO %s%s", serverName, "\r\n");
iResult = send(ConnectSocket, sendBuffer, BUFFER_SIZE, 0);
if (iResult == SOCKET_ERROR) {
cout << "Error " << WSAGetLastError() << endl;
throw std::exception("WINSOCK send failed\n");
}
cout << "Sent:\n" << sendBuffer << "Byte count: " << iResult << endl;
iResult = recv(ConnectSocket, recvBuffer, BUFFER_SIZE, 0);
if (iResult == SOCKET_ERROR) {
cout << "Error " << WSAGetLastError() << endl;
throw std::exception("WINSOCK recv failed\n");
}
cout << "EHLO response: " << iResult << endl;
sprintf_s(sendBuffer, BUFFER_SIZE, "QUIT%s", "\r\n");
iResult = send(ConnectSocket, sendBuffer, BUFFER_SIZE, 0);
if (iResult == SOCKET_ERROR) {
cout << "Error " << WSAGetLastError() << endl;
throw std::exception("WINSOCK send failed\n");
}
cout << "Sent:\n" << sendBuffer << "Byte count: " << iResult << endl;
iResult = recv(ConnectSocket, recvBuffer, BUFFER_SIZE, 0);
if (iResult < 0) {
cout << "Error " << WSAGetLastError() << endl;
throw std::exception("WINSOCK recv failed\n");
}
cout << "Quit response: " << iResult << endl;
// Shutdown the connection
iResult = shutdown(ConnectSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
cout << "Error " << WSAGetLastError() << endl;
throw std::exception("shutdown failed\n");
}
// Clean up
cleanup(ConnectSocket, result);
return 0;
}
catch (std::exception err) {
printf(err.what());
cleanup(ConnectSocket, result);
return 1;
}
catch (...) {
printf("Unknown error\n");
cleanup(ConnectSocket, result);
return 2;
}
}
Three parts to this answer.
MIME Encode the username and password.
ACTUALLY send the username and password! :)
Some servers are skeptical and want you to say HELO or EHLO twice.
I will post full code soon. Although I feel I was about 40% of the way there, I owe my success to this site: http://www.coastrd.com/smtps.

hostname not translated into an IP address using Winsock

getaddrinfo() does not translate a hostname into an IP address and consequently does not connect() to the server. Is something wrong with my implementation - compiles with no warning messages?
Is this function call to connect correct?
connect(client, result->ai_addr, result->ai_addrlen)
Full implementation listed below:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>
#include <iostream>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
int main (
int argc,
char* argv[])
{
if (argc != 3)
{
cerr << "Usage: " << argv[0] << " [hostname] [port number]\n";
exit(EXIT_FAILURE);
}
WSADATA wsaData;
WORD wVersionRequested;
int wError;
wVersionRequested = MAKEWORD(2, 2);
wError = WSAStartup(wVersionRequested, &wsaData);
if (wError != 0)
{
cerr << "WSAStartup failed with error: " << wError << endl;
exit (EXIT_FAILURE);
}
/*
* Confirm that the WinSock DLL supports 2.2.
* Note that if the DLL supports versions greater
* than 2.2 in addition to 2.2, it will still return
* 2.2 in wVersion since that is the version we
* requested.
*/
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
cerr << "Could not find a usable version of Winsock.dll." << endl;
WSACleanup();
exit(EXIT_FAILURE);
} else {
cout << "The Winsock 2.2 dll was found." << endl;
}
SOCKET client;
if ((client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
{
cerr << "Error: socket() return value == SOCKET_ERROR" << endl;
WSACleanup();
exit (EXIT_FAILURE);
}
cout << "Created a socket." << endl;
struct addrinfo *result = NULL;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if ((wError = getaddrinfo(
argv[1],
argv[2],
&hints,
&result)) !=0 )
{
freeaddrinfo(result);
WSACleanup();
if (wError == 11001)
{
cerr << "Error: occurred: getaddrinfo() failed "
<< wError << " - Host not found." << endl;
exit(EXIT_FAILURE);
}
cerr << "Error: occurred: getaddrinfo() failed "
<< wError << endl;
exit(EXIT_FAILURE);
}
/*
* Attempt to connect to the Server
*
*/
switch (wError = connect(client, result->ai_addr, result->ai_addrlen)) {
case 0:
cerr << "Resolved hostname." << endl;
break;
case SOCKET_ERROR:
wError = WSAGetLastError();
cerr << "Error: connet() failed "
"Details: " << wError << endl;
closesocket(client);
freeaddrinfo(result);
WSACleanup();
exit(EXIT_FAILURE);
break;
default:
cerr << "Fatal connect() error: unexpected "
"return value." << endl;
closesocket(client);
freeaddrinfo(result);
WSACleanup();
exit(EXIT_FAILURE);
break;
}
cout << "Connected to server." << endl;
closesocket(client);
freeaddrinfo(result);
WSACleanup();
exit(EXIT_SUCCESS);
}
getaddrinfo may be giving you an IPv6 address, or perhaps the machine has more than one IP address and you're trying to connect to the wrong one.
Also, if your server is listening on 127.0.0.1 and you try to connect to the real IP address, the connection will fail. Similarly, if the server is listening on the real IP address and you try to connect using 127.0.0.1, the connection will fail. If the server listens on 0.0.0.0, both addresses should work.
To listen on 0.0.0.0, you would have code similar to this:
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port=htons( port_num );
bind( s, (sockaddr *)&sin, sizeof( sin ) );
Try setting the hint.ai_family to AF_UNSPEC instead of AF_INET, I believe that when AF_INET is specfied the getaddrinfo functions excepts IPv4-like address.