I am currently learning C++ and trying to understand sockets. I've done sockets before in high level languages in C# and Java but having problems in C++.
I've gone through the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx.
The code I have is pretty much working except there's one thing I'm not sure of. When I've written other socket apps, I don't usually receive the response until after a new line character is received.
I thought maybe C++ add 1 character received at a time and adds to the buffer, so then when I close the socket, the buffer would contain everything that was received, but it seems to be a hex value, but the hex in an ascii converter seems to print gibberish instead of the socket data.
Below is my code
const int DEFAULT_BUF_LEN = 525;
InitialiseLibrary initLibrary("tunnel.conf");
if (initLibrary.initialise(0))
{
cout << "Failed to initialise library" << endl;
}
BitsLibrary bitsLibrary;
StaticSettings staticSettings(&bitsLibrary, "tunnel.conf");
//Open a socket connection
WSAData wsaData;
int iResult;
SOCKET listenSocket = INVALID_SOCKET;
SOCKET clientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvBuf[DEFAULT_BUF_LEN];
int recBufLen = DEFAULT_BUF_LEN;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
cout << "WSAStartup Failed with error: " << iResult << endl;
return EXIT_FAILURE;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
iResult = getaddrinfo(NULL, "500", &hints, &result);
if (iResult != 0)
{
cout << "getaddrinfo failed with error: " << iResult << endl;
return EXIT_FAILURE;
}
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (listenSocket == INVALID_SOCKET)
{
cout << "Socket failed with error: " << WSAGetLastError() << endl;
freeaddrinfo(result);
WSACleanup();
return EXIT_FAILURE;
}
iResult = ::bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult != 0)
{
cout << "bind failed with error: " << iResult << endl;
FreeAddrInfo(result);
closesocket(listenSocket);
WSACleanup();
return EXIT_FAILURE;
}
freeaddrinfo(result);
iResult = listen(listenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR)
{
cout << "Listen failed with error: " << WSAGetLastError() << endl;
closesocket(listenSocket);
WSACleanup();
return EXIT_SUCCESS;
}
sockaddr_in clientAddr;
socklen_t sin_size = sizeof(struct sockaddr_in);
clientSocket = accept(listenSocket, (struct sockaddr*)&clientAddr, &sin_size);
send(clientSocket, "welcome", string("welcome").length(),0);
if (clientSocket == INVALID_SOCKET)
{
cout << "accept failed with error: " << WSAGetLastError() << endl;
closesocket(listenSocket);
WSACleanup();
return EXIT_FAILURE;
}
closesocket(listenSocket);
do {
iResult = recv(clientSocket, recvBuf, recBufLen, 0);
if (iResult > 0)
{
cout << "Bytes received: " << iResult << endl;
cout << "Received: " << recvBuf << endl;
iSendResult = send(clientSocket, recvBuf, iResult, 0);
if (iSendResult == SOCKET_ERROR)
{
cout << "send failed with error: " << WSAGetLastError() << endl;
closesocket(clientSocket);
WSACleanup();
return EXIT_FAILURE;
}
cout << "Bytes sent " << iSendResult << endl;
}
else if (iResult == 0)
{
cout << "Connection closing" << endl;
}
else
{
cout << "Recv failed with error: " << WSAGetLastError() << endl;
closesocket(clientSocket);
WSACleanup();
return EXIT_FAILURE;
}
} while (iResult > 0);
iResult = shutdown(clientSocket, SD_SEND);
if (iResult == SOCKET_ERROR)
{
cout << "shutdown failed with error: " << WSAGetLastError() << endl;
closesocket(clientSocket);
WSACleanup();
return EXIT_FAILURE;
}
closesocket(clientSocket);
WSACleanup();
cout << "Message was: " << recvBuf << endl;
return EXIT_SUCCESS;
If I'm not mistaken, if I was doing this in C# and connect via telnet to my socket I could send Hello but the app wouldn't do anything until I sent \r\n or the buffer was full.
However, in my C++ app, as soon as I enter H my app immediately responds prints out the recvBuf which just contains H plus a load of blank characters (shows as squares in cmd) which I'm assuming is the blank parts of the array buffer, and sends the reply.
Sockets don't care about newlines or nulls. Only higher-level streaming APIs do that. The important thing is the return value of recv(). That tells you exactly how many bytes were received. Nothing in the buffer beyond that count is valid.
In a streaming protocol, it is useful to establish a protocol for determining the content length.
For example, a client could send the content-length followed by data and the server would first read the content length and then read the socket in a loop and buffer the data until content-length number of bytes have been received.
Related
I'm new to C++ Socket and my Server can't send message to its client. The send() function return -1 always and it seems to have a problem with accpSocket. However Client can do that smoothly and I don't know what's wrong. Please help me thank you so much!
Server
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<iostream>
#include<sdkddkver.h>
#include<winsock.h>
using namespace std;
int main() {
SOCKET serverSocket, acceptSocket = INVALID_SOCKET;
int port = 2403;
WSADATA wsaData;
int wsaerr;
//Step 1: Set up dll
WORD versionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(versionRequested, &wsaData);
if (wsaerr)
cout << "The winsock dll not found";
else {
cout << "The winsock dll found\n";
cout << "Winsock dll status: " << wsaData.szSystemStatus << endl;
}
//Step 2: Set up server socket
serverSocket = INVALID_SOCKET;
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
cout << "Error at socket: " << WSAGetLastError();
WSACleanup();
return 0;
}
else
cout << "Server socket successfull!\n";
//Step 3: Binding socket
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.S_un.S_addr = INADDR_ANY;
service.sin_port = htons(port);
if (bind(serverSocket, (sockaddr*)&service, sizeof(service)) == SOCKET_ERROR) {
cout << "Binding failed! " << WSAGetLastError();
return 0;
}
else
cout << "Binding complete!\n";
// Step 4: Listen to the connections
if (listen(serverSocket, 1) == SOCKET_ERROR) {
cout << "Listen failed! " << WSAGetLastError();
return 0;
}
else
cout << "Waiting for connections ...";
SOCKET accpSocket = accept(serverSocket, NULL, NULL);
if (accpSocket == INVALID_SOCKET) {
cout << "Accepting failed! " << WSAGetLastError();
WSACleanup();
return -1;
}
else
cout << "Accept connection!\n";
char recvMess[2000];
char sendMess[2000];
int byterecv = recv(accpSocket, recvMess, sizeof(recvMess), 0);
cout << "Client: " << recvMess << endl;
cout << "Server: ";
cin.getline(sendMess, 2000);
int bytesend = send(acceptSocket, sendMess, 2000, 0);
if (bytesend <= 0)
cout << "Unsent";
return 0;
}
Client
#include<iostream>
#include<WinSock2.h>
#include<WS2tcpip.h>
using namespace std;
int main() {
int port = 2403;
WSADATA wsaData;
int wsaerr;
SOCKET clientSocket;
WORD versionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(versionRequested, &wsaData);
if (wsaerr)
cout << "Winsock dll not found!";
else {
cout << "Winsock dll is ok!\n";
cout << "Status: " << wsaData.szSystemStatus << endl;
}
clientSocket = INVALID_SOCKET;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET) {
cout << "Set up client socket failed" << WSAGetLastError();
WSACleanup();
return 0;
}
else
cout << "Set up complete!\n";
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_port = htons(port);
if (inet_pton(clientService.sin_family, "127.0.0.1", &clientService.sin_addr) <= 0) {
cout << "Invalid address!";
return -1;
}
if ((connect(clientSocket, (SOCKADDR*)&clientService, sizeof(clientService))) == SOCKET_ERROR) {
cout << "Connection failed!\n";
WSACleanup();
return 0;
}
else
cout << "Connection complete!\n";
char sendMess[2000];
char recvMess[2000];
cout << "Client: ";
cin.getline(sendMess, 2000);
int bytesend = send(clientSocket, sendMess, 2000, 0);
int byterecv = recv(clientSocket, recvMess, 2000, 0);
if (byterecv <= 0)
cout << "Nothing";
else
cout << "Server" << recvMess << endl;
return 0;
}
int bytesend = send(acceptSocket, sendMess, 2000, 0);
is not sending to a connected socket. acceptSocket was defined at the top of main and then ignored up until the call to send
As a general rule of thumb, keep variable definition close to first use.
In the server at
SOCKET serverSocket, acceptSocket = INVALID_SOCKET;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Killlllll meeeeee!!!!
remove acceptSocket to prevent future mistakes and in
int bytesend = send(acceptSocket, sendMess, 2000, 0);
replace acceptSocket with the socket that was actually accepted, accpSocket.
Side notes:
Never ignore the return codes.
int byterecv = recv(accpSocket, recvMess, sizeof(recvMess), 0);
could fail and return -1 or return 0 if the socket was disconnected, yet the program will still
cout << "Client: " << recvMess << endl;
And worse, there's no guarantee that recvMess will be null-terminated, recv on a streaming socket gives you what the socket has available or becomes available up to the maximum number of bytes requested, so if there is any data read, make sure byterecv is a valid index in recvMess by only reading sizeof(recvMess) - 1 bytes and then forcing termination with recvMess[byterecv] = '\0'; before printing.
send(acceptSocket, sendMess, 2000, 0); sends all 2000 bytes of sendMess regardless of how many bytes were read with cin.getline(sendMess, 2000);. Use
send(acceptSocket, sendMess, cin.gcount(), 0);
instead. Add on an extra byte (cin.gcount() + 1) if you want to send the null terminator.
I'm trying to create a server client that once its working I can pass a vector into it and send it to a client program through ssh like putty. The issue is whenever I try to connect raw or ssh with putty on 127.0.0.1:45000 the program terminates once it connects.
Here is my code:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
// Initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Intitialze winsock! Quiting" << endl;
return;
}
// Create a socket to bind
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
}
// Bind the socket to an ip address to the port
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(45000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // could also use inet_pton
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell winsock the socket is for listening
listen(listening, SOMAXCONN);
// Wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
char host[NI_MAXHOST]; //Clients remote name
char service[NI_MAXHOST]; // Service (port) the client is on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXHOST); // use mem set of linux
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << " connected on port " << service << endl;
return;
}
else
{
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on port " <<
ntohs(client.sin_port) << endl;
return;
}
// Close listening socket
closesocket(listening);
// while loop; accept and echo message back to client
char buf[4096];
while (true)
{
ZeroMemory(buf, 4096);
// wait for client to send data
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == SOCKET_ERROR)
{
cerr << "Error in recv(). Quitting" << endl;
break;
}
if (bytesReceived == 0)
{
cout << "Client Disconnected, bytes 0" << endl;
break;
}
// echo message back to client
send(clientSocket, buf, bytesReceived + 1, 0);
// Close the socket
}
closesocket(clientSocket);
// Shutdown winsock
WSACleanup();
}
I'm writing it and compiling in Visual Studio 2019.
Here's the message I get from Putty when trying to connect with the ssh option or raw.
If anyone can help it would be greatly appreciated. Thanks!
When calling getnameinfo(), you are return'ing from main() immediately, without calling closesocket() first, regardless of whether getnameinfo() is successful or fails. This is the root of your Putty error. You are explicitly exiting your app whenever a client connects, without informing the client that the connection is being closed.
More generally, if accept() is successful (and socket(), too), you should always call closesocket() on the returned SOCKET, regardless of anything else happening in your code (same with WSACleanup() if WSAStartup() is successful).
There are several other mistakes in your code:
It is illegal for main() to have a non-int return type (though some compilers allow this, as a non-standard extension. Don't rely on this!).
You are missing a return from main() if socket() fails.
You are not checking for errors on bind(), listen(), accept(), or send().
There is no point in setting the backlog to SOMAXCONN if you are only going to accept() 1 client ever.
you have a potential buffer overflow when calling send(). Imagine if recv() returned exactly 4096 bytes received. Sending bytesReceived + 1 number of bytes back to the client would go out of bounds of your buf array.
With that said, try something more like this:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main()
{
// Initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int errCode = WSAStartup(ver, &wsData);
if (errCode != 0)
{
cerr << "Can't initialize winsock! Error " << errCode << ". Quitting" << endl;
return 0;
}
// Create a socket to bind
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
errCode = WSAGetLastError();
cerr << "Can't create listening socket! Error " << errCode << ". Quitting" << endl;
WSACleanup();
return 0;
}
// Bind the socket to an ip address to the port
sockaddr_in hint = {};
hint.sin_family = AF_INET;
hint.sin_port = htons(45000);
hint.sin_addr.s_addr = INADDR_ANY; // could also use inet_pton
if (bind(listening, (sockaddr*)&hint, sizeof(hint)) == SOCKET_ERROR)
{
errCode = WSAGetLastError();
cerr << "Can't bind listening socket! Error " << errCode << ". Quitting" << endl;
closesocket(listening);
WSACleanup();
return 0;
}
// Tell winsock the socket is for listening
if (listen(listening, 1) == SOCKET_ERROR)
{
errCode = WSAGetLastError();
cerr << "Can't open listening socket! Error " << errCode << ". Quitting" << endl;
closesocket(listening);
WSACleanup();
return 0;
}
// Wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
if (clientSocket == INVALID_SOCKET)
{
errCode = WSAGetLastError();
cerr << "Can't accept a client! Error " << errCode << ". Quitting" << endl;
closesocket(listening);
WSACleanup();
return 0;
}
char host[NI_MAXHOST]; //Clients remote name
char service[NI_MAXHOST]; // Service (port) the client is on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXHOST); // use mem set of linux
if (getnameinfo((sockaddr*)&client, clientSize, host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << " connected on port " << service << endl;
}
else
{
inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
cout << host << " connected on port " << ntohs(client.sin_port) << endl;
}
// Close listening socket
closesocket(listening);
listening = INVALID_SOCKET;
// while loop; accept and echo message back to client
char buf[4096];
while (true)
{
// wait for client to send data
int bytesReceived = recv(clientSocket, buf, sizeof(buf), 0);
if (bytesReceived == SOCKET_ERROR)
{
errCode = WSAGetLastError();
cerr << "Error reading from client: " << errCode << ". Quitting" << endl;
break;
}
if (bytesReceived == 0)
{
cout << "Client Disconnected" << endl;
break;
}
// echo message back to client
char *ptr = buf;
int bytesToSend = bytesReceived;
do
{
int bytesSent = send(clientSocket, ptr, bytesToSend, 0);
if (bytesSent == SOCKET_ERROR)
break;
ptr += bytesSent;
bytesToSend -= bytesSent;
}
while (bytesToSend > 0);
if (bytesToSend != 0)
{
errCode = WSAGetLastError();
cerr << "Error writing to client: " << errCode << ". Quitting" << endl;
break;
}
}
// Close the client socket
closesocket(clientSocket);
// Shutdown winsock
WSACleanup();
return 0;
}
I have a program, that needs to communicate with a server through a HTTP POST request and then receive the answer from the server. The send and receive code is in a loop and should be executed as fast as possible. My problem is, that the recv()-function needs about 500ms until it finishes. The length of the answer i receive is unknown.
if (send(m_socket, buffer, strlen(buffer), 0) != strlen(buffer))
{
cout << "HTTP: Error sending:" << WSAGetLastError() << endl;
return "0";
}
const int buflen = 322;
char buffer2[buflen];
recv(m_socket, buffer2, buflen, 0);
What can i change to decrease the time of the recv()-function to a few ms?
Here's the complete code:
WSADATA wsaData;
SOCKET m_socket;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult)
cout << "Error" << endl;
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET)
cout << "Invalid Socket : " << WSAGetLastError() <<endl;
setsockopt(m_socket, IPPROTO_TCP, TCP_NODELAY, "1", 1);
sockaddr_in clientService;
clientService.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &clientService.sin_addr.s_addr);
clientService.sin_port = htons(80);
if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
cout << "Connection Failure"<<WSAGetLastError()<<endl;
WSACleanup();
return 0;
}
while(alpha)
{
if (send(m_socket, buffer, strlen(buffer), 0) != strlen(buffer))
{
cout << "HTTP: Error sending:" << WSAGetLastError() << endl;
return "0";
}
const int lang = 322;
char buffer2[lang];
recv(m_socket, buffer2, lang, 0);
cout<<buffer2<<endl;
}
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.
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.