I'm learning Windows Registered I/O, I found a sample project from the website "https://github.com/zeliard/RIOEchoServer", It does well on my computer.
However, if I change this code from the listening server side to the actively sending client side, I find that connect + RIOSend works fine, but RIOSendEx will definitely give an error code of 10022!
#include <WinSock2.h>
#include <MSWsock.h>
#include <WS2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char * argv[])
{
static const wchar_t SERVER[] = L"127.0.0.1";
static const unsigned short PORTNUM = 54321;
static const DWORD RIO_PENDING_RECVS = 1;
static const DWORD RIO_PENDING_SENDS = 1;
static const DWORD RECV_BUFFER_SIZE = 1024;
static const DWORD SEND_BUFFER_SIZE = 1024;
static const DWORD ADDR_BUFFER_SIZE = 64;
static const DWORD RIO_MAX_RESULTS = 1;
WSADATA wsadata;
if (0 != ::WSAStartup(0x202, &wsadata))
{
printf_s("WSAStartup Error: %d\n", GetLastError());
exit(0);
}
/// RIO socket
SOCKET socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_REGISTERED_IO);
if (socket == INVALID_SOCKET)
{
printf_s("WSASocket Error: %d\n", GetLastError());
exit(0);
}
/// RIO function table
GUID functionTableId = WSAID_MULTIPLE_RIO;
DWORD dwBytes = 0;
RIO_EXTENSION_FUNCTION_TABLE rio;
if (NULL != WSAIoctl(socket, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &functionTableId, sizeof(GUID), (void**)&rio, sizeof(rio), &dwBytes, NULL, NULL))
{
printf_s("WSAIoctl Error: %d\n", GetLastError());
exit(0);
}
/// rio's completion manner: iocp
HANDLE hIOCP = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
if (NULL == hIOCP)
{
printf_s("CreateIoCompletionPort Error: %d\n", GetLastError());
exit(0);
}
OVERLAPPED overlapped;
RIO_NOTIFICATION_COMPLETION completionType;
completionType.Type = RIO_IOCP_COMPLETION;
completionType.Iocp.IocpHandle = hIOCP;
completionType.Iocp.CompletionKey = NULL;
completionType.Iocp.Overlapped = &overlapped;
/// creating RIO CQ, which is bigger than (or equal to) RQ size
RIO_CQ completionQueue = rio.RIOCreateCompletionQueue(RIO_PENDING_RECVS + RIO_PENDING_SENDS, &completionType);
if (completionQueue == RIO_INVALID_CQ)
{
printf_s("RIOCreateCompletionQueue Error: %d\n", GetLastError());
exit(0);
}
/// creating RIO RQ
/// SEND and RECV within one CQ (you can do with two CQs, seperately)
RIO_RQ requestQueue = rio.RIOCreateRequestQueue(socket, RIO_PENDING_RECVS, 1, RIO_PENDING_SENDS, 1, completionQueue, completionQueue, NULL);
if (requestQueue == RIO_INVALID_RQ)
{
printf_s("RIOCreateRequestQueue Error: %d\n", GetLastError());
exit(0);
}
/// registering RIO buffers for SEND
char sendBuffer[SEND_BUFFER_SIZE];
RIO_BUFFERID sendRioBufferId = rio.RIORegisterBuffer(sendBuffer, static_cast<DWORD>(sizeof(sendBuffer)));
if (sendRioBufferId == RIO_INVALID_BUFFERID)
{
printf_s("RIORegisterBuffer Error: %d\n", GetLastError());
exit(0);
}
RIO_BUF sendRioBuffer;
sendRioBuffer.BufferId = sendRioBufferId;
sendRioBuffer.Offset = 0;
sendRioBuffer.Length = SEND_BUFFER_SIZE;
/// registering RIO buffers for ADDR
char addrBuffer[ADDR_BUFFER_SIZE];
RIO_BUFFERID addrRioBufferId = rio.RIORegisterBuffer(addrBuffer, static_cast<DWORD>(sizeof(addrBuffer)));
if (addrRioBufferId == RIO_INVALID_BUFFERID)
{
printf_s("RIORegisterBuffer Error: %d\n", GetLastError());
exit(0);
}
RIO_BUF addrRioBuffer;
addrRioBuffer.BufferId = addrRioBufferId;
addrRioBuffer.Offset = 0;
addrRioBuffer.Length = ADDR_BUFFER_SIZE;
/// registering RIO buffers for RECV and then, post pre-RECV
char recvBuffer[RECV_BUFFER_SIZE];
RIO_BUFFERID recvRioBufferId = rio.RIORegisterBuffer(recvBuffer, static_cast<DWORD>(sizeof(recvBuffer)));
if (recvRioBufferId == RIO_INVALID_BUFFERID)
{
printf_s("RIORegisterBuffer Error: %d\n", GetLastError());
exit(0);
}
RIO_BUF recvRioBuffer;
recvRioBuffer.BufferId = recvRioBufferId;
recvRioBuffer.Offset = 0;
recvRioBuffer.Length = RECV_BUFFER_SIZE;
/// posting pre RECVs
if (!rio.RIOReceiveEx(requestQueue, &recvRioBuffer, 1, NULL, &addrRioBuffer, NULL, 0, 0, &recvRioBuffer))
{
printf_s("RIOReceive Error: %d\n", GetLastError());
exit(0);
}
//////////////////////////////////////////////////////////////////////////
// active send code begin ...
//////////////////////////////////////////////////////////////////////////
sendRioBuffer.Length = 5;
memcpy_s(sendBuffer, RECV_BUFFER_SIZE, "hello", sendRioBuffer.Length);
sockaddr_in * address = reinterpret_cast<sockaddr_in *>(addrBuffer);
memset(address, 0x0, ADDR_BUFFER_SIZE);
address->sin_family = AF_INET;
address->sin_port = htons(PORTNUM);
if (::InetPton(AF_INET, SERVER, &address->sin_addr) <= 0)
{
printf_s("inet_pton Error: %d\n", GetLastError());
exit(0);
}
#if 0 // connect + RIOSend is OK
if (SOCKET_ERROR == ::connect(socket, reinterpret_cast<struct sockaddr *>(address), sizeof(*address)))
{
printf_s("Connect Error: %d\n", GetLastError());
exit(0);
}
if (!rio.RIOSend(requestQueue, &sendRioBuffer, 1, 0, &sendRioBuffer))
{
printf_s("RIOSend Error: %d\n", GetLastError());
exit(0);
}
#else // RIOSendEx not work
if (!rio.RIOSendEx(requestQueue, &sendRioBuffer, 1, NULL, &addrRioBuffer, NULL, NULL, 0, &sendRioBuffer))
{
printf_s("RIOSendEx Error: %d\n", GetLastError());
exit(0);
}
#endif // 0
INT notifyResult = rio.RIONotify(completionQueue);
if (notifyResult != ERROR_SUCCESS)
{
printf_s("RIONotify Error: %d\n", GetLastError());
exit(0);
}
DWORD numberOfBytes = 0;
ULONG_PTR completionKey = 0;
OVERLAPPED* pOverlapped = 0;
RIORESULT results[RIO_MAX_RESULTS];
if (!::GetQueuedCompletionStatus(hIOCP, &numberOfBytes, &completionKey, &pOverlapped, INFINITE))
{
printf_s("GetQueuedCompletionStatus Error: %d\n", GetLastError());
exit(0);
}
memset(results, 0, sizeof(results));
ULONG numResults = rio.RIODequeueCompletion(completionQueue, results, RIO_MAX_RESULTS);
if (0 == numResults || RIO_CORRUPT_CQ == numResults)
{
printf_s("RIODequeueCompletion Error: %d\n", GetLastError());
exit(0);
}
const RIORESULT & res = results[0];
if (0 != res.Status)
{
printf_s("RIOSend(Ex) Error: %d\n", res.Status);
exit(0);
}
printf_s("RIOSend(Ex) OK\n");
//////////////////////////////////////////////////////////////////////////
// active send code end ...
//////////////////////////////////////////////////////////////////////////
if (SOCKET_ERROR == ::closesocket(socket))
{
printf_s("closesocket Error: %d\n", GetLastError());
}
rio.RIOCloseCompletionQueue(completionQueue);
rio.RIODeregisterBuffer(sendRioBufferId);
rio.RIODeregisterBuffer(recvRioBufferId);
rio.RIODeregisterBuffer(addrRioBufferId);
return 0;
}
wish your help, Thanks!
yanrk
From RIOSendEx documentation:
sends network data on ... a bound ... UDP socket
Your example will work if you add those lines before calling RIOSendEx:
sockaddr_in addr{}; // zero-initialized
addr.sin_family = AF_INET;
if (SOCKET_ERROR == ::bind(socket, (struct sockaddr *)&addr, sizeof(addr)))
{
printf("bind failed\n");
exit(0);
}
if (!rio.RIOSendEx(requestQueue ...
You can bind to some particular port (not recommended):
addr.sin_port = htons(5001);
Or leave it zero for OS to choose.
Aparently, RIOSendEx do not perform an implicit bind (unlike WSASendTo).
The reason for this might be that bind is a complicated process that might involve waiting and APC and all kinds of stuff, while whole idea of RIO is to pay upfront.
connect + RIOSendEx doesn't make sense. Since you specified remote address with connect function you can't send data through that socket anywhere else. RIOSendEx is supposed to be used with datagrams.
You have not set the Destination IP-Address in the RioSendEx-Function:
Copy the content of your address-Buffer into the associated Buffer of addrRioBuffer.
e.g.:
memcpy_s(addrBuffer, ADDR_BUFFER_SIZE, address, sizeof(sockaddr_in));
if (!rio.RIOSendEx(requestQueue, &sendRioBuffer, 1, NULL, &addrRioBuffer, NULL, NULL, 0, &sendRioBuffer))
{
printf_s("RIOSendEx Error: %d\n", GetLastError());
exit(0);
}
// […]
I will post a working exampel in the next day´s.
http://www.thbweb.eu
Related
Recently I've migrated my program to OpenSSL due to multiple problems with built-in SSL support in the older versions of Windows. Everything works perfectly despite the site specified in the title, I constantly get error:00000001:lib(0):func(0):reason(1).
If I uncomment lines that set non-blocking mode for a socket, I just get another error message. Any help is desperately appreciated. I tested that issue using OpenSSL 1.1.1j under Windows 10 64-bits (but it seems not to be dependent on the OS version)
I thought that the problem may be caused by missing certificates, so I added Microsoft.pem to the context - nothing changed (you can grab this file from https://github.com/drwetter/testssl.sh/blob/3.1dev/etc/Microsoft.pem
That is the code that emulates my program:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#define HOST "free.currencyconverterapi.com"
int main()
{
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
SSL_library_init();
SSL_load_error_strings();
const SSL_METHOD *meth = TLS_client_method();
if (!meth) {
fprintf(stderr, "SSL setup failure: client method");
return 1;
}
SSL_CTX *g_ctx = SSL_CTX_new(meth);
if (!g_ctx) {
fprintf(stderr, "SSL setup failure: context");
return 2;
}
SSL_CTX_load_verify_locations(g_ctx, "microsoft.pem", NULL);
SSL_CTX_ctrl(g_ctx, SSL_CTRL_MODE, SSL_MODE_AUTO_RETRY, nullptr);
RAND_screen();
addrinfo *air = nullptr, hints = { 0 };
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (GetAddrInfoA(HOST, "443", &hints, &air)) {
fprintf(stderr, "AddrInfo for host %s failed (%u)", HOST, WSAGetLastError());
return 3;
}
int rc = 1;
SOCKET s = INVALID_SOCKET;
for (auto *ai = air; ai; ai = ai->ai_next) {
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (s == INVALID_SOCKET) {
FreeAddrInfoA(air);
return 4;
}
if (connect(s, ai->ai_addr, (int)ai->ai_addrlen) == 0) {
rc = 0;
break;
}
if (WSAGetLastError() != WSAEWOULDBLOCK) {
rc = WSAGetLastError();
closesocket(s);
s = INVALID_SOCKET;
continue;
}
}
if (rc) {
fprintf(stderr, "connection failed: %d", rc);
return 6;
}
FreeAddrInfoA(air);
// uncomment that lines to obtain another error code
// u_long notblocking = 0;
// if (ioctlsocket(s, FIONBIO, ¬blocking) != 0) {
// FreeAddrInfoA(air);
// return 5;
// }
SSL *session = SSL_new(g_ctx);
if (!session) {
fprintf(stderr, "SSL setup failure: session");
return 7;
}
SSL_set_fd(session, s);
int err = SSL_connect(session);
if (err != 1) {
err = SSL_get_error(session, err);
char buf[100];
ERR_error_string_n(err, buf, sizeof(buf));
fprintf(stderr, "SSL negotiation failure: %s (%d)", buf, err);
return 8;
}
fprintf(stderr, "Connection succeeded");
return 0;
}
--
WMBR, George Hazan
Using winsock, I got a client and a server, when connect is done and i send a message the first time i can recv it in the server but after that when I do a time loop i can not show them on the screen. the send message inside the time loop does not return an error. I know this is a weird problem but if you take a look at timerCb that's where the send function is, it does not return an error but in my server i cannot print it. I have also tried making a new while loop with a parameter of recv it still did not work.
This is my client,
char receivingMessage[1000];
char messageInitiation[90] = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
//main
SetTimer(NULL, 0, 3600, timerCb);
if(WSAStartup(MAKEWORD(2, 2), &ws) != 0){
printf("WSA err %d \n", GetLastError());
}else{
}
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET){
printf("Invalid Socket \n");
}else{
printf("socket binded \n");
}
rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
rmtServer.sin_port = htons(4743);
rmtServer.sin_family = AF_INET;
if((connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in))) != 0){
printf("\n err %d", GetLastError());
}else{
printf("\n connected");
send(s, messageInitiation, strlen(messageInitiation), 0);
recv(s, receivingMessage, 1000, 0);
printf("\n %s", receivingMessage);
int liop;
liop = strcmp(receivingMessage, "I got you!!");
if(liop == 0){
connectedYet = TRUE;
}
printf("\n is it true: ? %d\n", connectedYet);
}
while(GetMessage(&message, NULL, 0, 0) > 0){
TranslateMessage(&message);
DispatchMessage(&message);
}
//outside main
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
char *msgg = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
printf("\n%s\n", "timing");
if(send(s, msgg, strlen(msgg), 0) == SOCKET_ERROR){
printf("err :%d\n", GetLastError());
}
}
And this is my server
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow) {
MSG message;
WSADATA ws;
SOCKET s, incomingSocket;
struct sockaddr_in server, client;
char incomingMessage[1800];
int recvState;
WSAStartup(MAKEWORD(2, 2), &ws);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
server.sin_port = htons(4743);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
bind(s, (struct sockaddr *)&server, sizeof(server));
listen(s, 1300);
int g = sizeof(struct sockaddr_in);
while((incomingSocket = accept(s, (struct sockaddr *)&client, &g)) != INVALID_SOCKET){
printf("%s\n", inet_ntoa(client.sin_addr));
printf("conn\n");
if((recvState = recv(incomingSocket, incomingMessage, 2500, 0)) == SOCKET_ERROR){
}else{
int as;
if((as = strcmp(incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89")) == 0){
printf("\n identical");
send(incomingSocket, "I got you!!", 11, 0);
}
printf("\n :%s\n", incomingMessage);
}
}
if(incomingSocket == INVALID_SOCKET){
printf("invalid socket");
}
return 0;
}
UPDATE
I have added this in my server code, before return 0 it does not display anything at all.
while((recvState = recv(incomingSocket, incomingMessage, 50, 0)) > 0) {
printf("\n new msg %s\n", incomingMessage);
}
TCP is a byte stream, not message-oriented like you are expecting.
recv() is not guaranteed to return complete messages. It could return as little as 1 byte, or it could return partial bytes from a message, or even bytes from multiple messages. You have to handle buffering and message framing in your code logic. And pay attention to its return value so you know how much it actually read. If you are expecting more data than is read, you have to call recv() again to read the rest, potentially many times. So use a loop.
So, either:
Have the sender send a string's length as a fixed-length value before then sending the actual characters. Then have the receiver read the length to know how many characters to read.
Have the sender send a unique terminator after each string, like a nul character or even a CRLF, then the receiver can keep reading until it encounters the terminator.
As for send(), it is not guaranteed to send complete data, either. It could send as few as 1 byte, or at least less than what you requested. So you have to pay attention to its return value, too, to know how much it actually sent. If it doesn't send everything in one go, you have to call it again to send any remaining data, potentially many times. So use a loop.
For example, try something more like this:
Client:
const char messageInitiation* = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
char* readStr(SOCKET s)
{
char *str = NULL;
char buffer[100], ch;
int buf_len = 0, str_len = 0, ret;
do
{
ret = recv(s, &ch, 1, 0);
if (ret == SOCKET_ERROR)
{
printf("recv err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
if (ch == '\0')
break;
if (buf_len == sizeof(buffer))
{
char *newstr = (char*) realloc(str, str_len + buf_len + 1);
if (!newstr)
{
printf("memory err\n");
free(str);
return NULL;
}
str = newstr;
memcpy(str + str_len, buffer, buf_len);
str_len += buf_len;
buf_len = 0;
}
buffer[buf_len++] = ch;
}
while (true);
if (buf_len > 0)
{
char *newstr = (char*) realloc(str, str_len + buf_len + 1);
if (!newstr)
{
printf("memory err\n");
free(str);
return NULL;
}
str = newstr;
memcpy(str, buffer, buf_len);
str_len += buf_len;
}
str[str_len] = '\0';
return str;
}
int sendStr(SOCKET s, const char *str)
{
const unsigned char *pstr = (const unsigned char*) str;
int len = strlen(str) + 1, ret;
do
{
ret = send(s, pstr, len, 0);
if (ret == SOCKET_ERROR)
{
printf("send err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pstr += ret;
len -= ret;
}
while (len > 0);
return 0;
}
/* alternatively:
int readAll(SOCKET s, void *data, int len)
{
unsigned char *pdata = (unsigned char *) data;
int ret;
while (len > 0)
{
ret = recv(s, pdata, len, 0);
if (ret == SOCKET_ERROR)
{
printf("recv err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pdata += ret;
len -= ret;
}
return 0;
}
int readStr(SOCKET s)
{
int32_t len = 0;
if (readAll(s, &len, sizeof(len)) == SOCKET_ERROR)
return NULL;
char *str = (char*) malloc(len + 1);
if (!str)
{
printf("memory err\n");
return NULL;
}
if (readAll(s, str, len) == SOCKET_ERROR)
{
free(str);
return NULL;
}
str[len] = '\0';
return str;
}
int sendAll(SOCKET s, const void *data, int len)
{
const unsigned char *pdata = (const unsigned char*) data;
int ret;
while (len > 0)
{
ret = send(s, pdata, len, 0);
if (ret == SOCKET_ERROR)
{
printf("send err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pdata += ret;
len -= ret;
}
return 0;
}
int sendStr(SOCKET s, const char *str)
{
int32_t len = strlen(str) + 1;
int ret = sendAll(s, &len, sizeof(len));
if (ret == 0)
ret = sendAll(s, str, len);
return ret;
}
*/
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
printf("\n%s\n", "timing");
if (!sendStr(s, messageInitiation))
PostQuitMessage(0);
}
int main()
{
WSADATA ws;
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
if (ret != 0)
{
printf("WSA err %d\n", ret);
return -1;
}
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("socket err %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("socket created\n");
struct sockaddr_in rmtServer = {};
rmtServer.sin_family = AF_INET;
rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
rmtServer.sin_port = htons(4743);
if (connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
printf("connect err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
printf("connected\n");
if (sendStr(s, messageInitiation) != 0)
{
closesocket(s);
WSACleanup();
return -1;
}
char *receivingMessage = recvStr(s);
if (!receivingMessage)
{
closesocket(s);
WSACleanup();
return -1;
}
printf("%s\n", receivingMessage);
BOOL connectedYet = (strcmp(receivingMessage, "I got you!!") == 0);
printf("is it true: ? %d\n", connectedYet);
free(receivingMessage);
SetTimer(NULL, 0, 3600, timerCb);
MSG message;
while (GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
closesocket(s);
WSACleanup();
return 0;
}
Server:
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// see client code above
char* readStr(SOCKET s);
int sendStr(SOCKET s, const char *str);
int main()
{
struct sockaddr_in server = {0}, client;
WSADATA ws;
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
if (ret != 0)
{
printf("WSA err %d\n", ret);
return -1;
}
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("socket err %d\n", WSAGetLasatError());
WSACleanup();
return -1;
}
struct sockaddr_in server = {};
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons(4743);
ret = bind(s, (struct sockaddr *)&server, sizeof(server));
if (ret == SOCKET_ERROR)
{
printf("bind err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
if (listen(s, 10) == SOCKET_ERROR)
{
printf("listen err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
int g, iResult;
struct sockaddr_in client;
do
{
g = sizeof(client);
SOCKET incomingSocket = accept(s, (struct sockaddr *)&client, &g);
if (incomingSocket == INVALID_SOCKET)
{
printf("accept err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
printf("%s conn\n", inet_ntoa(client.sin_addr));
char *incomingMessage = recvStr(incomingSocket);
if (incomingMessage)
{
printf("%s\n", incomingMessage);
if (incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89") == 0)
{
printf("identical\n");
sendStr(incomingSocket, "I got you!!");
}
}
closesocket(incomingSocket);
}
while (true);
return 0;
}
Hey there wonderful community!
I'm back with a question regarding a console server application I've made with winsock. It's finally reaching a stage where I would need a to add a GUI, and to do so, I need it to be using the Windows subsystem.
And so I started the migration.
Yet I'm hitting a stack overflow somewhere in my application, and for the life of me I can't figure out where. Perhaps it has to do with WIN being a non-blocking subsystem (hope I used my vocab correctly).
Anyway, I hope to enlist you all as helpers. Many thanks :)
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <conio.h>
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
int minitialize();
int msend(char msendbuf[512]);
char* mrecv(bool show);
int mshutdown();
void GoToXY(int column, int line);
int scroll(void);
int printm(char *inp);
int printm(char *inp, DWORD color);
int mexit();
char *vir = "true";
int clientnumber=0;
int currentclient=0;
int lastclient=0;
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "10150"
struct _client
{
bool con;
sockaddr_in addr; //Client info like ip address
SOCKET cs; //Client socket
fd_set set; //used to check if there is data in the socket
std::string ip;
std::string name;
int i; //any piece of additional info
} client[100];
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
DWORD WINAPI recvfunc(LPVOID randparam)
{
while (true) {
ClientSocket=client[currentclient].cs;
if (mrecv(true)=="1") {
client[currentclient].con=false;
ClientSocket=client[lastclient].cs;
break;
}
}
return 0;
}
DWORD WINAPI headerfunc(LPVOID randparam)
{
Sleep(500);
while (true) {
CONSOLE_SCREEN_BUFFER_INFO SBInfo;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hOut, &SBInfo);
int xx = SBInfo.dwCursorPosition.X;
int yy = SBInfo.dwCursorPosition.Y;
GoToXY(0,0);
HANDLE hHeaderColor;
hHeaderColor = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hHeaderColor, FOREGROUND_GREEN);
std::cout<<"Server Started. Current Client:"<<currentclient<<" Clients connected: "<<clientnumber<<" ("<<xx<<","<<yy<<") "<<lastclient;
SetConsoleTextAttribute(hHeaderColor, 0 |
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE);
GoToXY(xx,yy);
Sleep(2000);
}
return 0;
}
DWORD WINAPI sendfunc(LPVOID randparam)
{
while (true) {
char mmessage[512];
std::cin.getline(mmessage, 512);
if (strlen(mmessage)<2) {
GoToXY(0,23);
sendfunc("1");
}
char msendbuf[512]="Server> ";
strcat(msendbuf,mmessage);
if (msend(msendbuf)==1) {
"Client must have disconnected. Please select a new client.";
sendfunc("1");
}
if ((strncmp(msendbuf,"Server> /",9)) != 0) {
printm(msendbuf,FOREGROUND_INTENSITY);
}
GoToXY(0,23);
for (int sp=0; sp<72; sp++) {
std::cout<<" ";
}
GoToXY(0,23);
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
minitialize();
HANDLE hRecvThread;
HANDLE hSendThread;
HANDLE hHeaderThread;
DWORD dwRecvThreadId;
DWORD dwSendThreadId;
DWORD dwHeaderThreadId;
hHeaderThread = CreateThread(NULL,0,headerfunc,"1",0,&dwHeaderThreadId);
for (int mf=2; mf<25; mf++) {
std::cout<<"\n";
}
hSendThread = CreateThread(NULL,0,sendfunc,"1",0,&dwSendThreadId);
// Accept a client socket
for (int sock=1; sock<100; sock++) {
ClientSocket = accept(ListenSocket, NULL, NULL);
char sockprint[80];
char sockchar[4];
itoa(sock,sockchar,10);
strcpy(sockprint,"Client ");
strcat(sockprint,sockchar);
strcat(sockprint," connected.");
printm(sockprint);
GoToXY(0,23);
if (ClientSocket == INVALID_SOCKET) {
printm("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
client[sock].cs=ClientSocket;
client[sock].con=true;
lastclient=clientnumber;
clientnumber++;
currentclient=clientnumber;
hRecvThread = CreateThread(NULL,0,recvfunc,"1",0,&dwRecvThreadId);
}
// shutdown the connection since we're done
mshutdown();
std::cin.ignore();
return 0;
}
int printm(char *inp, DWORD color) {
HANDLE hOut;
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hOut,
color);
printm(inp);
SetConsoleTextAttribute(hOut, 0 |
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE);
return 0;
}
int printm(char *inp) {
CONSOLE_SCREEN_BUFFER_INFO SBInfo;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hOut, &SBInfo);
int xx = SBInfo.dwCursorPosition.X;
int yy = SBInfo.dwCursorPosition.Y;
GoToXY(0,22);
std::cout<<inp<<"\n";
scroll();
GoToXY(xx,yy);
return 1;
}
int msend(char msendbuf[512]) // Send a message
{
if (strncmp(msendbuf,"Server> /exit",(strlen(msendbuf))) == 0) {
mexit();
}
if (strncmp(msendbuf,"Server> /set_client",19) == 0) {
int nm=atoi(&msendbuf[20]);
currentclient=nm;
ClientSocket=client[nm].cs;
char sockchar[4];
itoa(ClientSocket,sockchar,10);
char sockprint[80];
strcpy(sockprint,"New Socket: ");
strcat(sockprint,sockchar);
printm(sockprint);
char clientprint[80];
strcpy(clientprint,"Client: ");
strcat(clientprint,&msendbuf[20]);
printm(clientprint);
}
if (strncmp(msendbuf,"Server> /list_clients",(strlen(msendbuf))) == 0) {
printm("Clients:",FOREGROUND_RED);
for (int cm=1; cm < 100; cm++) {
int cn=client[cm].cs;
if (cn>0) {
char cli[80];
char cmchar[4];
char cnchar[80];
itoa(cn,cnchar,10);
itoa(cm,cmchar,10);
strcpy(cli,cmchar);
strcat(cli," ");
strcat(cli,cnchar);
strcat(cli," ");
strcat(cli,client[cm].ip.c_str());
strcat(cli," ");
strcat(cli,client[cm].name.c_str());
printm(cli,FOREGROUND_RED);
}
else {
break;
}
}
}
if (strncmp(msendbuf,"Server> /test",(strlen(msendbuf))) == 0) {
char ipcon[500];
*ipcon=(system("ipconfig"));
}
if (strncmp(msendbuf,"Server> /help",(strlen(msendbuf))) == 0) {
printm("Type /help for help or:");
printm("/set_client [client number]");
printm("/list_clients");
}
int iResult3 = send( ClientSocket, msendbuf, 512, 0 );
if (iResult3 == SOCKET_ERROR) {
printm("send failed with error: %d\n", WSAGetLastError());
return 1;
}
}
char* mrecv(bool show) //Recieve a message
{
int iResult2 = recv(ClientSocket, recvbuf, 512, 0);
if (iResult2 > 0) {
if ((strncmp(recvbuf,"/",1)) != 0) {
printm(recvbuf);
}
if (strncmp(recvbuf,"/ip",3) == 0) {
client[clientnumber].ip=&recvbuf[4];
char prin[80];
strcpy(prin,"client[clientnumber].ip: ");
strcat(prin,client[clientnumber].ip.c_str());
printm(prin,FOREGROUND_BLUE);
}
if (strncmp(recvbuf,"/name",5) == 0) {
client[clientnumber].name=&recvbuf[6];
char prin2[80];
strcpy(prin2,"client[clientnumber].name: ");
strcat(prin2,client[clientnumber].name.c_str());
printm(prin2,FOREGROUND_GREEN | FOREGROUND_BLUE);
}
if (strncmp(recvbuf,"/alert",5) == 0) {
char *message=&recvbuf[7];
char prin2[80];
strcpy(prin2,client[clientnumber].name.c_str());
strcat(prin2,": ");
strcat(prin2, message);
printm(prin2,FOREGROUND_RED);
}
if (strncmp(recvbuf,"Client> /alert",14) == 0) {
char *message=&recvbuf[15];
char prin2[80];
strcpy(prin2,client[clientnumber].name.c_str());
strcat(prin2,": ");
strcat(prin2, message);
printm(prin2,FOREGROUND_RED);
}
}
else if (iResult2 == 0) {
printf("Connection closing...\n");
closesocket(ClientSocket);
WSACleanup();
return "1";
}
else {
printm("recv failed with error: %d\n", WSAGetLastError());
printm("Client must have disconnected. Please select a new client.");
return "1";
}
return recvbuf;
}
int minitialize() //initialize the winsock server
{
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printm("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printm("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printm("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printm("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printm("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
unsigned long b=1;
ioctlsocket(ClientSocket,FIONBIO,&b);
}
int mshutdown() //shutdown the server
{
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printm("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
void GoToXY(int column, int line)
{
// Create a COORD structure and fill in its members.
// This specifies the new position of the cursor that we will set.
COORD coord;
coord.X = column;
coord.Y = line;
// Obtain a handle to the console screen buffer.
// (You're just using the standard console, so you can use STD_OUTPUT_HANDLE
// in conjunction with the GetStdHandle() to retrieve the handle.)
// Note that because it is a standard handle, we don't need to close it.
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Finally, call the SetConsoleCursorPosition function.
if (!SetConsoleCursorPosition(hConsole, coord))
{
// Uh-oh! The function call failed, so you need to handle the error.
// You can call GetLastError() to get a more specific error code.
// ...
return;
}
}
int scroll( void )
{
HANDLE hStdout;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
SMALL_RECT srctScrollRect, srctClipRect;
CHAR_INFO chiFill;
COORD coordDest;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdout == INVALID_HANDLE_VALUE)
{
printf("GetStdHandle failed with %d\n", GetLastError());
return 1;
}
// Get the screen buffer size.
if (!GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
{
printf("GetConsoleScreenBufferInfo failed %d\n", GetLastError());
return 1;
}
// The scrolling rectangle
srctScrollRect.Top = 1;
srctScrollRect.Bottom = 22;
srctScrollRect.Left = 0;
srctScrollRect.Right = csbiInfo.dwSize.X - 1;
// The destination for the scroll rectangle is one row up.
coordDest.X = 0;
coordDest.Y = 0;
// The clipping rectangle
srctClipRect.Top = 2;
srctClipRect.Bottom = 22;
srctClipRect.Left = 0;
srctClipRect.Right = csbiInfo.dwSize.X - 1;
// Fill the bottom row with blanks.
chiFill.Attributes = FOREGROUND_RED;
chiFill.Char.AsciiChar = (char)' ';
// Scroll up one line.
if(!ScrollConsoleScreenBuffer(
hStdout, // screen buffer handle
&srctScrollRect, // scrolling rectangle
&srctClipRect, // clipping rectangle
coordDest, // top left destination cell
&chiFill)) // fill character and color
{
printf("ScrollConsoleScreenBuffer failed %d\n", GetLastError());
return 1;
}
return 0;
}
int mexit()
{
msend("/server_closed");
mshutdown();
exit(0);
}
Turns out it was the recursive calling in my "sendfunc" thread that tripped me up.
Specifically,
if (msend(msendbuf)==1) {
"Client must have disconnected. Please select a new client.";
sendfunc("1");
}
Because I continued to call "sendfunc" from itself, it caused the stack overflow.
So, for anyone else having these problems, watch for overkill recursive function calls.
I simply removed my sending function and I was good to go.
I have implemented a c++ winsock (win 32) with intention of crashing using an strcpy command. The socket itself is instantiated inside a thread. However, when I put the strcpy inside the recv loop, it does not seem to crash.
I know there is nothing wrong with the compiler since writing one with just strcpy crashes, I am thinking it is related to recv since it initiates a block on the process.
Here is the full code below for the sever, the crash I am trying to implement is in the form of strcpy(a, "AAAA..."); in regular circumstances it should crash, but here it does not. I would like to know why.
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#include<winsock2.h>
#include<stdlib.h>
#include<stdio.h>
#include<ws2tcpip.h>
#include <iostream.h>
#include <conio.h>
#define DEFAULT_PORT "1133"
#define DEFAULT_BUFLEN 512
struct thread_data
{
int m_id;
thread_data(int id) : m_id(id){}
};
char a[10];
DWORD WINAPI ServerThread (LPVOID pParam){
WSADATA wsaData;
struct addrinfo *result =NULL;
struct addrinfo hints;
SOCKET ListenSocket = INVALID_SOCKET;
do{
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
int iResult;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
iResult = getaddrinfo(NULL,DEFAULT_PORT,&hints, &result);
if (iResult != 0 ){
printf("get addrinfo failed with error %d\n", iResult);
WSACleanup();
return 1;
} //end if
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket ==0){
printf("socket creation failed with error %d\n", WSAGetLastError());
}
//bind socket
iResult= bind( ListenSocket , result->ai_addr, (int)result->ai_addrlen);
if(iResult == SOCKET_ERROR){
printf("bind failed with error %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf ("initializing socket\n ");
iResult= listen(ListenSocket,SOMAXCONN);
if (iResult== SOCKET_ERROR){
printf("listen failed with %d\n",WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
SOCKET client ;
sockaddr_in from;
int fromlen=sizeof(from);
char temp[1024];
char temp_to_send[1024];
char temp_to_send_vuln[512];
printf("accepting client request\n");
client=accept(ListenSocket, (struct sockaddr*) &from, &fromlen);
printf("accepted socket\n");
iResult =1;
int iSendResult =1;
char c;
//start receiving from client
while( (iResult = recv(client,temp,1024,0 )) > 0 ){
c = temp[0];
temp[iResult] = '\0';
if(c!=13)
strcat(temp_to_send,temp);
//if enter is hit echo sent data to client
if(c ==13 ){
printf("sending %s \n",temp_to_send);
//I WANT TO CRASH THE PGORAM HERE!!
strcpy(a,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
strcat(temp_to_send_vuln,temp_to_send);
strcat(temp_to_send_vuln,"\r\n");
iSendResult = send(client,temp_to_send,strlen(temp_to_send),0);
//if user types "exit" the client socket would terminate
if (strcmp(temp_to_send,"exit") ==0){
printf("exit entered\n");
closesocket(client);
WSACleanup();
break;
}
re-initialize variables for next input
temp[0] = '\0';
temp_to_send[0] = '\0';
}//end if(ch ==13)
}//end recv
printf("termination of socket with error %d and buffer length is ", WSAGetLastError());
printf("client said %s\n", temp) ;
if (iResult == SOCKET_ERROR){
printf("receiving failed with error %d",WSAGetLastError());
}
if (iSendResult == SOCKET_ERROR){
printf("seding failed with error %d", WSAGetLastError());
closesocket(client);
WSACleanup();
exit(1);
}
} while(1);
closesocket(ListenSocket);
WSACleanup();
printf("program ended\n");
return 0;
}
//the main function that calls the thread
int main(void)
{
//create thread here
CreateThread(NULL, 0 ,ServerThread, new thread_data(0), 0,0);
//terminate program when escape character is hit
while(_getch()!=27);
return 0;
}
Your strcpy() call is just trashing a and then whatever else happens to be after it in global memory; it's undefined whether it'll crash or not. If you really want to crash out, just call strcpy( NULL, "whatever" ).
The ConnectEx function requires an "unconnected, previously bound socket". Indeed, if I omit the bind step in my example (see below), ConnectEx fails with WSAEINVAL.
Here's my current understanding: before calling ConnectEx, bind the socket to INADDR_ANY and port 0 (unless it is already bound):
struct sockaddr_in addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = 0;
rc = bind(sock, (SOCKADDR*) &addr, sizeof(addr));
if (rc != 0) { ... bind failed; call WSAGetLastError to see why ... }
Or for an IPv6 socket:
struct sockaddr_in6 addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_any;
addr.sin6_port = 0;
rc = bind(sock, (SOCKADDR*) &addr, sizeof(addr));
if (rc != 0) { ... bind failed; call WSAGetLastError to see why ... }
This lets the operating system assign a local address to our socket (as opposed to the remote address we are connecting to). connect does this step automatically, but ConnectEx does not.
My questions are:
Is my assessment correct?
Is there a way to do this automatic bind that is agnostic to the address family, or will I have to handle each of AF_INET, AF_INET6, AF_BTH (Bluetooth), etc. manually?
Working ConnectEx example (also on Gist: https://gist.github.com/4158972):
#include <stdio.h>
#include <WinSock2.h>
#include <MSWSock.h>
#include <WS2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
struct mswsock_s {
LPFN_CONNECTEX ConnectEx;
} mswsock;
static BOOL load_mswsock(void)
{
SOCKET sock;
DWORD dwBytes;
int rc;
/* Dummy socket needed for WSAIoctl */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
return FALSE;
{
GUID guid = WSAID_CONNECTEX;
rc = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid, sizeof(guid),
&mswsock.ConnectEx, sizeof(mswsock.ConnectEx),
&dwBytes, NULL, NULL);
if (rc != 0)
return FALSE;
}
rc = closesocket(sock);
if (rc != 0)
return FALSE;
return TRUE;
}
int main(int argc, char *argv[])
{
int rc;
BOOL ok;
WSADATA wsaData;
SOCKET sock;
rc = WSAStartup(MAKEWORD(2,2), &wsaData);
if (rc != 0) {
printf("WSAStartup failed: %d\n", rc);
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("Your computer is from the wrong millenium.\n");
WSACleanup();
return 1;
}
if (!load_mswsock()) {
printf("Error loading mswsock functions: %d\n", WSAGetLastError());
return 1;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
printf("socket: %d\n", WSAGetLastError());
return 1;
}
/* ConnectEx requires the socket to be initially bound. */
{
struct sockaddr_in addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = 0;
rc = bind(sock, (SOCKADDR*) &addr, sizeof(addr));
if (rc != 0) {
printf("bind failed: %d\n", WSAGetLastError());
return 1;
}
}
/* Issue ConnectEx and wait for the operation to complete. */
{
OVERLAPPED ol;
ZeroMemory(&ol, sizeof(ol));
sockaddr_in addr;
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("173.194.37.36"); // google.com
addr.sin_port = htons(80);
ok = mswsock.ConnectEx(sock, (SOCKADDR*) &addr, sizeof(addr), NULL, 0, NULL, &ol);
if (ok) {
printf("ConnectEx succeeded immediately\n");
} else if (WSAGetLastError() == ERROR_IO_PENDING) {
printf("ConnectEx pending\n");
DWORD numBytes;
ok = GetOverlappedResult((HANDLE) sock, &ol, &numBytes, TRUE);
if (ok)
printf("ConnectEx succeeded\n");
else
printf("ConnectEx failed: %d\n", WSAGetLastError());
} else {
printf("ConnectEx failed: %d\n", WSAGetLastError());
return 1;
}
}
/* Make the socket more well-behaved. */
rc = setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
if (rc != 0) {
printf("SO_UPDATE_CONNECT_CONTEXT failed: %d\n", WSAGetLastError());
return 1;
}
/* This will fail if SO_UPDATE_CONNECT_CONTEXT was not performed. */
rc = shutdown(sock, SD_BOTH);
if (rc != 0) {
printf("shutdown failed: %d\n", WSAGetLastError());
return 1;
}
printf("Done\n");
return 0;
}
connect does this step automatically, but ConnectEx does not.
Correct.
Is my assessment correct?
Yes.
Is there a way to do this automatic bind that is agnostic to the address family, or will I have to handle each of AF_INET, AF_INET6, AF_BTH (Bluetooth), etc. manually?
I believe that INADDR_ANY is a bunch of zeros in all address families, so you could just try using the memset() and omitting the assignment to addr.sin_addr.s_addr completely. Whether this is kosher, portable, politically correct etc. is another question into which I will not enter.
It seems pretty curious that Microsoft didn't manage to have ConnectEx() call bind() internally, considering that saving system calls is the motivation for its existence, and also considering that most programs never bind an outbound socket at all.
It is possible to get the bind address for ConnectEx in an address family independent way.
Solution 1
Call getaddrinfo with the following options:
pServiceName = "0"
hints.ai_flags = AI_PASSIVE
hints.ai_family = address family of the socket
Then use the first result of the returned address list.
To get the address family of the socket you can use getsockopt with SO_PROTOCOL_INFOW.
Solution 2
Use SOCKADDR_STORAGE for the address structure and call INETADDR_SETANY which is defined in MSTcpIP.h. It supports AF_INET and AF_INET6.