Related
my goal:
I`m writing an application which writes a file to the serial port 128 bytes at a time (137 total, with ModBUS header and CRC) and waits for the reply. The writing I have managed to implement successfully. After sending a 137 byte packet I would like to wait on the serial com for a reply and process it, in case that modbus exception is thrown.
my problem:
The ReadFile function returns 170 which, from windows documentation, is 170 (0xAA) - The requested resource is in use. The only resource I am actually using is the serial port handle, which I doubt that it is this, the error is referring to.
Note -
- not using available ModBUS libraries because I use the address registers in a specific way, needing full control
- I am using overlapped I/O only because (according to WinApi doc) ReadFile never returns if no bytes come at the serial port; If timeouts are require overlapped access is a must (correct me if I`m wrong).
- I have a 2 sec max timeout (timeout for actually waiting for the reply) and 20 ms between bytes; if more than 20 ms between bytes pass I assume that no more bytes are coming;
Has anyone had any previous experience working with ReadFile and possibly Erro 170? Appreciate all the help I can get.
part of my code:
u8 WaitModBusReply(void)
{
u8 i = 0;
u8 ReplyStatus = 0xAA;
u8 ReplyBuff[ReplyBuffSize];
u8 * ptr = &ReplyBuff[0];
static u16 TotalRX_Bytes;
DWORD dwCommEvent;
DWORD dwBytesRead;
COMSTAT ComStatus;
DWORD comErrors = 0;
OVERLAPPED read_s = {0};
read_s.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
for (int z=0; z< ReplyBuffSize; z++)
ReplyBuff[z] = 0;
ClearCommError(ModBUS_Port, &comErrors, &ComStatus);
ResetEvent(read_s.hEvent);
if ( !WaitCommEvent(ModBUS_Port, &dwCommEvent, &read_s) )
{
//byte_timeout += MCU_Getms_TimeConsumption();
if ( (ReadFile(ModBUS_Port, ptr+TotalRX_Bytes, ReplyBuffSize-
TotalRX_Bytes, &dwBytesRead, NULL) )) //&dwBytesRead &modbus_reply
{
fprintf(stderr, "\n EXEC 3");
// ReadFile(PC_TestCenterPort, pBufPtr+TotalRX_Bytes, BufSize-
TotalRX_Bytes, &BytesRead, NULL);
TotalRX_Bytes += dwBytesRead;
i++;
ReplyStatus = Reply_Received;
}
}
else
printf("Error setting Com event mask:%d ", GetLastError());
if ( ReplyStatus == Reply_Received)
{
fprintf(stderr, "\nExit error3: %d\n", GetLastError() );
if ( (i == 4) ) // Exception returned. Parse it
{
if ( !ModBus_CRC16 (&ReplyBuff[0], i, READ) )
ReplyStatus = Reply_CRCError;
else
ReplyStatus = ReplyBuff[i-2];
}
else if ( (i == 7) ) // Reply returned
{
if ( !ModBus_CRC16 (&ReplyBuff[0], i, READ) )
ReplyStatus = Reply_CRCError;
else
ReplyStatus = Reply_OK;
}
}
/*
for ( int j=0; j<= 256; j++)
printf("\nReplyBuff[%d]: %X", j, ReplyBuff[j]); */
return ReplyStatus;
}
The logic for checking the reply array is not implemented so ignore that part.
This function is called by:
u8 SerialDataSend(void)
{
u8 t_status = BufferSent;
int write_status = -1;
int read_status = -1;
DWORD bytes_written = 0;
OVERLAPPED write_s;
memset(&write_s, 0, sizeof(write_s));
write_s.Internal = 0;
write_s.InternalHigh = 0;
write_s.Offset = 0;
write_s.OffsetHigh = 0;
write_s.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if ( !SerialInit() )
{
while (!t_status)
{
fprintf(stderr, "Starting transmission -\n");
while(packages_left > 0 && !t_status)
{
write_status = WriteFile(ModBUS_Port, ModBUS_Buffer(), 137,
&bytes_written, &write_s); //&write_s
fprintf(stderr,"\r ModBUS transaction - Packages left:%4d",
packages_left);
if( write_status ) // Return values for success and
overlapped access ongoing
{
fprintf(stderr, "Error :%d.\n", GetLastError());
t_status = BufferFailed;
CloseHandle(ModBUS_Port);
break;
}
//FlushFileBuffers(ModBUS_Port);
read_status = WaitModBusReply();
printf("READ STATUS: %d\n", read_status);
if ( !read_status && !write_status )
{
fprintf(stderr, "\n------------------------------------------------------------");
fprintf(stderr, "\n Exception occurred: %X\n",
read_status);
t_status = BufferFailed;
Sleep(1);
break;
}
packages_left--;
Sleep(200);
}
//printf("EXEC 1\n");
if (!t_status)
{
fprintf(stderr, "\n\nTransaction Complete. Bytes written :
%d\n", FileSize);
packages_left = 10;
}
break;
}
fclose(HMI_Program);
if ( t_status != BufferFailed )
{
fprintf(stderr, "Closing serial port - ");
if ( !CloseHandle(ModBUS_Port) )
fprintf(stderr, "Error :%d.\n", GetLastError());
else
fprintf(stderr, "OK.\n");
}
}
fflush(stdout);
fflush(stderr);
return t_status;
}
and the function which initializes the Serial port:
u8 SerialInit(void)
{
memset(&SerialSettings,0,sizeof(SerialSettings));
SerialSettings.DCBlength = sizeof(SerialSettings);
SerialSettings.BaudRate = CBR_115200;
SerialSettings.ByteSize = 8;
SerialSettings.StopBits = TWOSTOPBITS;
SerialSettings.Parity = NOPARITY;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
timeouts.ReadIntervalTimeout = 20;
timeouts.ReadTotalTimeoutConstant = 2000;
timeouts.ReadTotalTimeoutMultiplier = 1 ;
memset(&timeouts,0,sizeof(timeouts));
fprintf(stderr, "Opening serial port - ");
sprintf(COM_Port, "\\\\.\\COM%d", port_no);
ModBUS_Port = CreateFile(COM_Port, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
if (ModBUS_Port == INVALID_HANDLE_VALUE)
fprintf(stderr, "Error\n\n");
else
fprintf(stderr, "OK\n");
if ( !GetCommState(ModBUS_Port, &SerialSettings) )
{
fprintf(stderr, "Error getting device state.");
CloseHandle(ModBUS_Port);
}
else if( !SetCommState(ModBUS_Port, &SerialSettings) )
{
fprintf(stderr, "Error setting device parameters.");
CloseHandle(ModBUS_Port);
}
else if ( !SetCommTimeouts(ModBUS_Port, &timeouts) )
{
fprintf(stderr, "Error setting timeouts.");
CloseHandle(ModBUS_Port);
}
else if ( !SetCommMask(ModBUS_Port, EV_RXCHAR | EV_ERR ) )
{
fprintf(stderr, "\nError setting com mask.");
CloseHandle(ModBUS_Port);
}
return GetLastError();
}
Thanks.
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;
}
I am trying to get the DACL of service, and then get the SIDs. Here is my code:
PSECURITY_DESCRIPTOR psd = NULL;
DWORD dwSize = 0;
DWORD dwBytesNeeded = 0;
BOOL bDaclPresent = FALSE; // tu Trua mashin aq DACL
PACL pacl = NULL;
BOOL bDaclDefaulted = FALSE;
PEXPLICIT_ACCESS bevri = NULL;
ULONG aq = 0;
char ** gio = NULL;
serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
SC_HANDLE me = OpenService(serviceManager, serviceName, READ_CONTROL);
if (serviceManager == NULL)
{
fprintf(fp, "OpenService: fail %d\n.\n", GetLastError());
fflush(fp);
}
if (!QueryServiceObjectSecurity(me, DACL_SECURITY_INFORMATION, &psd, 0, &dwBytesNeeded))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
dwSize = dwBytesNeeded;
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
if (psd == NULL)
{
fprintf(fp, "HeapAlloc failed\n");
fflush(fp);
}
if (!QueryServiceObjectSecurity(me, DACL_SECURITY_INFORMATION, psd, dwSize, &dwBytesNeeded))
{
fprintf(fp, "QueryServiceObjectSecurity failed %d\n", (int)GetLastError());
fflush(fp);
}
}
else
{
fprintf(fp, "QueryServiceObjectSecurity failed %d\n", (int)GetLastError());
fflush(fp);
}
}
if (!GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl, &bDaclDefaulted))
{
fprintf(fp, "GetSecurityDescriptorDacl failed %d\n", (int)GetLastError());
fflush(fp);
}
if (GetExplicitEntriesFromAcl(pacl, &aq, &bevri) != ERROR_SUCCESS)
{
fprintf(fp, "GetExplicitEntriesFromAcl: failed %d.\n", (int)GetLastError());
fflush(fp);
}
for (ULONG i = 0; i < aq; i++)
{
if (ConvertSidToStringSid(&bevri->Trustee.ptstrName[GetTrusteeForm(&bevri->Trustee)], gio) == 0)
{
fprintf(fp, "ConvertSidToStringSid: failed %d.\n", (int)GetLastError());
fflush(fp);
}
for (int index = 0; gio[index] != NULL; index++)
{
char * myString = gio[index];
fprintf(fp, "Value: %s\n",myString);
}
}
I've read in documentation that GetTrusteeForm function would indicate if Trustee has SID or name, it returned 0s which in TRUSTEE_FORM indicates to TRUSTEE_IS_SID. My problem is that I have ConvertSidToStringSid: failed 87. which is The parameter is incorrect.. I can't figure out why am I getting this. P.S. I'm sorry I know that this part of code is not really helpful to reproduce the issue, but I thought someone might knew what would problem be. Any help would be appriciated. Thanks.
Can anyone please point out the error in my code?
I already have previous knowledge about socket programming in Linux using C. So, I tried writing a simple TCP echo server and client program using Visual C++ on Visual Studio 2017 in my Windows 8.1 machine.
I am able to send any message to the server or the client can send any message to any server using the send() function. But I cannot receive any message using the recv() method. On the server the recv() function returns the error code 10053 and the client returns an error code 10014. Below are the source codes of the programs.
tcpServer.cpp
#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>
#include<string.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char **argv) {
WSADATA wsa;
SOCKET s, cs;
struct sockaddr_in server_addr, client_addr;
unsigned short server_port = 4444;
char* server_ip = "192.168.2.5";
int client_addr_len;
char *message = "Hello World";
int r;
/*if (argc < 2) {
printf("usage: tcpServer.exe <your IP address>");
exit(1);
}
strcpy_s(server_ip, argv[1]);*/
//Display stuff
system("cls");
printf("\t\tTCP ECHO SERVER\n\n");
printf("Creating TCP echo server on the IP %s\n", server_ip);
//Initialise WinSock
printf("Initialising WinSock....\n");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("ERROR: Initialising failed with error Code : %d", WSAGetLastError());
exit(1);
}
printf("Successfully initialised.\n");
//Create socket
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("ERROR: Socket creating failed with error code: %d", WSAGetLastError());
exit(1);
}
printf("Socket created successfully.\n");
//Setting the struct sockaddr_in server_addr
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
//Binding
if (bind(s, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("ERROR: Could not bind to port with error code: %d", WSAGetLastError());
exit(1);
}
printf("Bound to port %d\n", server_port);
//Start listening for client
printf("\nListening for client connections on %s:%d\n", server_ip, server_port);
if (listen(s, 5) < 0) {
printf("ERROR: Cannot listen for client connections with error code: %d", WSAGetLastError());
exit(1);
}
//Accepting connections
client_addr_len = sizeof(struct sockaddr_in);
if ((cs = accept(s, (struct sockaddr*)&client_addr, &client_addr_len)) == INVALID_SOCKET) {
printf("ERROR: Cannot accept connections with error code: %d", WSAGetLastError());
exit(1);
}
printf("Connection accepted from %s\n", inet_ntoa(client_addr.sin_addr));
//No need of SOCKET s
closesocket(s);
//Receive messages
if ((r = recv(cs, message, 2000, 0)) < 0) {
printf("ERROR: Cannot receive messages with error code: %d", WSAGetLastError());
exit(1);
}
message = "Hello World";
printf("Message received: %s\n", message);
//Send back the message
send(cs, message, strlen(message), 0);
printf("Message echoed back to server: %s\n", message);
//Close and clearing
closesocket(cs);
WSACleanup();
}
tcpClient.cpp
#include<stdio.h>
#include<stdlib.h>
#include<winsock2.h>
#include<string.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char **argv) {
WSADATA wsa;
SOCKET s, cs;
struct sockaddr_in server_addr, client_addr;
unsigned short server_port = 4444;
char* server_ip = "192.168.2.5";
int client_addr_len;
char *message = "Hello World";
int r;
system("cls");
printf("\t\tTCP ECHO CLIENT\n\n");
printf("Connecting to TCP echo server on the IP %s\n", server_ip);
printf("Initialising WinSock....\n");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("ERROR: Initialising failed with error Code : %d", WSAGetLastError());
exit(1);
}
printf("Successfully initialised.\n");
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("ERROR: Socket creating failed with error code: %d", WSAGetLastError());
exit(1);
}
printf("Socket created successfully.\n");
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
if (connect(s, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("ERROR: Cannot connect to server %s", server_ip);
closesocket(s);
exit(1);
}
printf("Connected to server %s on port %d\n", server_ip, server_port);
if (send(s, message, strlen(message), 0) < 0) {
printf("ERROR: Message sending failed with error code %d", WSAGetLastError());
closesocket(s);
exit(1);
}
printf("Message sending was successful\n");
if (recv(s, message, 2000, 0) < 0) {
printf("ERROR: Message recieving failed with error code %d", WSAGetLastError());
closesocket(s);
exit(1);
}
printf("Message echoed back from server: %s\n", message);
getchar();
closesocket(s);
WSACleanup();
}
Outputs
On both sides, message is just a pointer, and you have it pointing at a read-only string literal. recv() is trying to read data into that literal's memory, which will fail. You need to change message to a fixed-sized array instead:
//char *message = "Hello World";
char message[2000];
On the server side, you are making a similar mistake with your server_ip value (if you uncomment the call to strcpy_n()).
Also, when calling recv(), you are ignoring its return value. You only check it for -1 (read error), but it can also return 0 (graceful disconnect) or > 0 (data received). The data is not null-terminated! You must take the actual number of bytes read into account when calling printf() afterwards. Don't use strlen(), unless you null-terminate the data manually.
Try something more like this instead:
Server
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char **argv) {
WSADATA wsa;
SOCKET s = INVALID_SOCKET, cs = INVALID_SOCKET;
struct sockaddr_in server_addr, client_addr;
unsigned short server_port = 4444;
char* server_ip;
int client_addr_len;
char message[2000];
int r, exitCode = 1;
/*if (argc < 2) {
printf("usage: tcpServer.exe <your IP address>");
exit(1);
}
server_ip = argv[1];
*/
server_ip = "192.168.2.5";
//Display stuff
system("cls");
printf("\t\tTCP ECHO SERVER\n\n");
printf("Creating TCP echo server on the IP %s\n", server_ip);
//Initialise WinSock
printf("Initialising WinSock....\n");
if ((r = WSAStartup(MAKEWORD(2, 2), &wsa)) != 0) {
printf("ERROR: Initialising failed with error Code : %d", r);
exit(1);
}
printf("Successfully initialised.\n");
//Create socket
if ((s = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
printf("ERROR: Socket creating failed with error code: %d", WSAGetLastError());
goto cleanup;
}
printf("Socket created successfully.\n");
//Setting the struct sockaddr_in server_addr
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
//Binding
if (bind(s, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
printf("ERROR: Could not bind to port with error code: %d", WSAGetLastError());
goto cleanup;
}
printf("Bound to port %d\n", server_port);
//Start listening for client
printf("\nListening for client connection on %s:%d\n", server_ip, server_port);
if (listen(s, 1) == SOCKET_ERROR) {
printf("ERROR: Cannot listen for client connection with error code: %d", WSAGetLastError());
goto cleanup;
}
//Accepting connection
client_addr_len = sizeof(client_addr);
if ((cs = accept(s, (struct sockaddr*)&client_addr, &client_addr_len)) == INVALID_SOCKET) {
printf("ERROR: Cannot accept connection with error code: %d", WSAGetLastError());
goto cleanup;
}
printf("Connection accepted from %s\n", inet_ntoa(client_addr.sin_addr));
//No need of SOCKET s anymore
closesocket(s);
s = INVALID_SOCKET;
//Receive messages
if ((r = recv(cs, message, 2000, 0)) == SOCKET_ERROR) {
printf("ERROR: Cannot receive message with error code: %d", WSAGetLastError());
goto cleanup;
}
if (r == 0) {
printf("Client disconnected");
goto cleanup;
}
printf("Message received: %.*s\n", r, message);
//Send back the message
if (send(cs, message, r, 0) == SOCKET_ERROR) {
printf("ERROR: Cannot send message with error code: %d", WSAGetLastError());
goto cleanup;
}
printf("Message echoed back to client: %.*s\n", r, message);
exitCode = 0;
cleanup:
//Close and clearing
if (cs != INVALID_SOCKET) closesocket(cs);
if (s != INVALID_SOCKET) closesocket(s);
WSACleanup();
return exitCode;
}
Client
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char **argv) {
WSADATA wsa;
SOCKET s = INVALID_SOCKET;
struct sockaddr_in server_addr, client_addr;
unsigned short server_port = 4444;
char* server_ip = "192.168.2.5";
int client_addr_len;
char message[2000];
int r, exitCode = 1;
system("cls");
printf("\t\tTCP ECHO CLIENT\n\n");
printf("Connecting to TCP echo server on the IP %s\n", server_ip);
printf("Initialising WinSock....\n");
if ((r = WSAStartup(MAKEWORD(2, 2), &wsa)) != 0) {
printf("ERROR: Initialising failed with error Code : %d", r);
exit(1);
}
printf("Successfully initialised.\n");
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
printf("ERROR: Socket creating failed with error code: %d", WSAGetLastError());
goto cleanup;
}
printf("Socket created successfully.\n");
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
if (connect(s, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("ERROR: Cannot connect to server %s", server_ip);
goto cleanup;
}
printf("Connected to server %s on port %d\n", server_ip, server_port);
strcpy_s(message, sizeof(message), "Hello World");
if (send(s, message, strlen(message), 0) == SOCKET_ERROR) {
printf("ERROR: Message sending failed with error code %d", WSAGetLastError());
goto cleanup;
}
printf("Message sending was successful\n");
if ((r = recv(s, message, sizeof(message), 0)) == SOCKET_ERROR) {
printf("ERROR: Message receiving failed with error code %d", WSAGetLastError());
goto cleanup;
}
if (r == 0) {
printf("Server disconnected");
goto cleanup;
}
printf("Message echoed back from server: %.*s\n", r, message);
getchar();
exitCode = 0;
cleanup:
if (s != INVALID_SOCKET) closesocket(s);
WSACleanup();
return exitCode;
}
That being said, on the server side, when calling listen(), there is no point in setting the backlog to 5 if you are only ever going to accept 1 client. If you really want to implement a useful server, you should be calling accept() in a loop instead for the lifetime of the server, using select() or worker threads to monitor connected clients.
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.