can a windows service run a TCP server? - c++

I created 2 programs in c++ using visual studio 2008: a windows service based on this service which i added tcp server code to and a client program using MFC, which has a listbox that displays the ip address and hostname of the computer thats running the service. The user then chooses a server and clicks a connect button. Since there will be many servers running, I used some PHP script on a web host site. The service sends its ip address and host name to the web host, the web host puts the information into a list and the client then accesses this list.
all this works fine with the server code but when i put the server code into the windows service, the client program freezes and doesn't respond when the connect button is clicked. The ip address and host name still appear in the client listbox, i just can't connect to the server i select.
is the windows service stopping the server code from working?
here is the cpp file that contains the server code in the service program:
char* WebPost(char Website[], char Webpage[], char Request[], int RetLen)
{
// Sends an HTTP Post request with POST Data...
SOCKET WebSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *WebHost;
WebHost = gethostbyname(Website);
if (WebHost == NULL)
{
if (WSAGetLastError() == WSANOTINITIALISED)
printf("Error Not Connected!");
else
printf("Error: %d", WSAGetLastError());
Sleep(1000);
exit(0);
}
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)WebHost->h_addr);
connect(WebSocket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr));
char PostRequest[1024];
sprintf(PostRequest,
"POST %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Content-Length: %hu\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\nD=%s\0",
Webpage, Website,
strlen(Request)+2, Request
);
send(WebSocket, PostRequest, strlen(PostRequest), 0);
// Get return data
char* Data = new char[RetLen];
recv(WebSocket, Data, 4, 0);
for (;;)
{ // Skip HTTP headers
Data[0] = Data[1];
Data[1] = Data[2];
Data[2] = Data[3];
recv(WebSocket, &Data[3], 1, 0);
if (Data[0] == '\r' && Data[1] == '\n'
&& Data[2] == '\r' && Data[3] == '\n')
break;
}
int DataLen = recv(WebSocket, Data, RetLen, 0);
Data[DataLen] = '\0'; // Return the data
shutdown(WebSocket, 2);
closesocket(WebSocket);
return Data;
}
void ServStart()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
{
printf("WSAStartup failed with error %ld.\n", WSAGetLastError());
exit(0);
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion));
WSACleanup();
exit(0);
}
//Start listening
ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListeningSocket == INVALID_SOCKET)
{
printf("Error at socket, error code: %ld.\n", WSAGetLastError());
WSACleanup();
exit(0);
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port);
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
{
printf("bind failed. Error code: %ld.\n", WSAGetLastError());
closesocket(ListeningSocket);
WSACleanup();
exit(0);
}
if (listen(ListeningSocket, 5) == SOCKET_ERROR)
{
printf("listen: Error listening on socket %ld.\n", WSAGetLastError());
closesocket(ListeningSocket);
WSACleanup();
exit(0);
}
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
printf("Error when getting local host name: ", WSAGetLastError());
exit(0);
}
struct hostent *phe = gethostbyname(ac);
if (phe == 0)
{
printf("Error: ", WSAGetLastError());
exit(0);
}
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr)); // use the first ip-address
printf("IP used by Server: %s\n", inet_ntoa(addr)); // inet_ntoa(addr) provides the local address.
MyIP = inet_ntoa(addr);
char SendBuf[32];
// * is used as a separator, because it's not allowed in the hostname.
//So it won't interfere with it.
sprintf(SendBuf, "%hhu|%s*%s", cAddIP, MyIP, ac); // Send the server the IP and host name
WebPost(WEBSITE, WEBPAGE, SendBuf, 0);
printf("listening for connections...\n\n");
}
void ShutDown() // Shut down the server (tells the web server I am offline)
{
char SendBuf[32]; // Remove my IP from the list of online servers...
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR)
{
printf("Error when getting local host name: ", WSAGetLastError());
exit(0);
}
sprintf(SendBuf, "%hhu|%s*%s", cRemIP, MyIP,ac);
WebPost(WEBSITE, WEBPAGE, SendBuf, 0);
printf("Successful shutdown\n");
Sleep(1000);
WSACleanup();
}
void ServLoop()
{
SOCKADDR_IN SenderInfo;
SOCKET NewConnection;
int ByteReceived, nlen;
char recvbuff[1024];
for (;;)
{
//Main program loop
NewConnection = SOCKET_ERROR;
while(NewConnection == SOCKET_ERROR)
{
NewConnection = accept(ListeningSocket, NULL, NULL); // this is a blocking function
printf("New client got connected, ready to receive and send data...\n\n");
ByteReceived = recv(NewConnection, recvbuff, sizeof(recvbuff), 0);
if (ByteReceived > 0)
{
getsockname(ListeningSocket, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr));
memset(&SenderInfo, 0, sizeof(SenderInfo));
nlen = sizeof(SenderInfo);
getpeername(NewConnection, (SOCKADDR *)&SenderInfo, &nlen);
}
}
if (shutdown(NewConnection, 2) != 0)
printf("there is something wrong with the shutdown. The error code: %ld\n", WSAGetLastError());
else
printf("shutdown is working...\n");
}
}
// --------------------------------------------
BOOL ConsoleProc(DWORD Msg)
{
switch (Msg)
{
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
ShutDown();
return false;
}
return false;
}
// -----------------------------------------------------
CSampleService::CSampleService(PWSTR pszServiceName,
BOOL fCanStop,
BOOL fCanShutdown,
BOOL fCanPauseContinue) :
CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue),
m_dwTimeout(10 * 1000)
{
// Create a manual-reset event that is not signaled at first to indicate
// the service is stopping.
m_hStoppingEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
// Create a manual-reset event that is not signaled at first to indicate
// the stopped signal of the service.
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
}
CSampleService::~CSampleService(void)
{
if (m_hStoppedEvent)
{
CloseHandle(m_hStoppedEvent);
m_hStoppedEvent = NULL;
}
if (m_hStoppingEvent)
{
CloseHandle(m_hStoppingEvent);
m_hStoppingEvent = NULL;
}
}
void CSampleService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv)
{
WriteErrorLogEntry(L"CSampleService::Start: function entry");
// Log a service start message to the Application log.
WriteEventLogEntry(L"CppWindowsService in OnStart", EVENTLOG_INFORMATION_TYPE);
// Queue the main service function for execution in a worker thread.
CThreadPool::QueueUserWorkItem(&CSampleService::ServiceWorkerThread, this);
WriteErrorLogEntry(L"CSampleService::Start: function exit");
}
void CSampleService::ServiceWorkerThread(void)
{
WriteErrorLogEntry(L"CSampleService::ServiceWorkerThread: running");
// Periodically check if the service is stopping.
while (WaitForSingleObject(m_hStoppingEvent, m_dwTimeout) == WAIT_TIMEOUT)
{
// Perform main service function here...
// Handle console events
SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleProc, TRUE);
ServStart(); // Main loop is in another thread
ServLoop(); // The never returning server loop
}
// Signal the stopped event.
SetEvent(m_hStoppedEvent);
WriteErrorLogEntry(L"CSampleService::ServiceWorkerThread: done");
}
void CSampleService::OnStop()
{
ShutDown(); //shut down server
SetServiceStatus(SERVICE_STOP_PENDING, ERROR_SUCCESS, 30 * 1000);
WriteErrorLogEntry(L"CSampleService::Stop: function entry");
// Log a service stop message to the Application log.
WriteEventLogEntry(L"CppWindowsService in OnStop", EVENTLOG_INFORMATION_TYPE);
// Indicate that the service is stopping and wait for the finish of the
// main service function (ServiceWorkerThread).
SetEvent(m_hStoppingEvent);
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
{
SetServiceStatus(SERVICE_STOP_PENDING, ERROR_INVALID_DATA, 30 * 1000);
WriteErrorLogEntry(L"OnStop: Service Start", GetLastError());
throw GetLastError();
}
WriteErrorLogEntry(L"CSampleService::Stop: function exit");
}

The answer to your specific question is, yes, a windows service can run a TCP server.
The answer to why yours does not work is not clear. At first glance the service code looks reasonable. It's possible connections to your service are being blocked by your OS firewall (i.e. your console one is in the accept list but your service one is not). You might convert some of your error printf logic into something that prints to a file instead (e.g. fprintf?) so you can take a look at what's going on...

Sure, of course it can. Why would it not be possible?

Related

How to handle 10093(WSANOTINITIALISED) error when invoke accept method

Recently my code meet some issue. My programme work as server and listen to ONE client to connect, then send some commands to my programme. Then I will handle this command and return the value to client side.
But now I got the issue accept() method will get 10093(WSANOTINITIALISED) error and seems accept() method didn't block there.
It is not always happened. I tested the programme. Sometimes it works very well. Client side connected to my programme and send first command. Then my programme handle the command and send back return value. Then stopped the connection(closesocket(sClient);). Then Client side connected to my programme again and send second command...While time to time it happened accept() get 10093(WSANOTINITIALISED) error and client side will fail to connect to my programme any more. and the while loop(while (true && !m_bExitThread)) also didn't block.
My questions are:
Why did it happen? did someone meet the same issue? I believe my code should be correct, otherwise why most of time it works well.
If this 10093 error comes, how should I handle it? Do I need to closesocket and wait for Client side connect again? or do I need to WSACleanup(); and try to start this socket Thread totally again?
Below is the code. it is a thread I start it when my programme start up and stop it when programme stopped.
UINT CMainFrame::RunSocketThread()
{
m_bExitThread = false;
WORD wSockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(wSockVersion, &wsaData) != 0) // Here always success, no problem
{
LOGL(ILoggingSink::LogLevel::Error, _T("WSAStartup error !"));
return 0;
}
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET)
{
LOGL(ILoggingSink::LogLevel::Error, _T("socket error !"));
return 0;
}
sockaddr_in stSocketAddr;
stSocketAddr.sin_family = AF_INET;
stSocketAddr.sin_port = htons(7700);
stSocketAddr.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(slisten, (LPSOCKADDR)&stSocketAddr, sizeof(stSocketAddr)) == SOCKET_ERROR)
{
LOGL(ILoggingSink::LogLevel::Error, _T("bind error !"));
return 0;
}
if (listen(slisten, 5) == SOCKET_ERROR)
{
LOGL(ILoggingSink::LogLevel::Error, _T("listen error !"));
return 0;
}
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
while (true && !m_bExitThread)
{
// Waiting for connection
sClient = accept(slisten, (SOCKADDR*)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET) // Here I can get error code 10093(WSANOTINITIALISED)
{
LOGL(ILoggingSink::LogLevel::Error, _T("accept error %d!"), WSAGetLastError());
continue;
}
// revice data
int ret = recv(sClient, revData, 255, 0);
if (ret > 0)
{
revData[ret] = 0x00;
ParseJsonCommand(revData);
}
// send data
// Here I wait for programme finished handling the income command and return a value, otherwise just sleep and wait
while (CmdLineInfo::m_eReturn == ReturnTypeEnum::kNull)
{
Sleep(100);
}
const char* sendData;
CString strData;
strData = "{\"Command\":\"";
strData += CmdLineInfo::s_sLFODCommandName;
strData += "\", \"ReturnValue\":\"";
if(CmdLineInfo::m_eReturn == ReturnTypeEnum::kSuccess)
strData +="1\"} ";
else
strData += "0\"} ";
CStringA strAData(strData);
sendData = strAData;
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
return 0;
}

Problems intercommunicating processes in c++ using winsock2

I am having terrible trouble intercommunicating processes, using UNIX sockets. My server is written in c++, but I can't get past calling the bind method.
c++ code.
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));
WCHAR strbuf[256];
WSADATA wsaData;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
wsprintfW(strbuf, L"My Sample Service : WSAStartup failed with error: %d", iResult);
OutputDebugString(strbuf);
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
return 1;
}
int opt = TRUE;
int master_socket, addrlen, new_socket, client_socket[30],
max_clients = 30, activity, i, valread, sd;
int max_sd;
struct sockaddr_in address;
char buffer[1025]; //data buffer of 1K
//set of socket descriptors
fd_set readfds;
TIMEVAL tv = { 2, 0 };
//a message
char *message = "ECHO Daemon v1.0 \r\n";
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
/*struct addrinfo *result = NULL;
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNIX;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_PASSIVE;
iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
wsprintfW(strbuf, L"My Sample Service : getaddrinfo failed with error: %d", iResult);
OutputDebugString(strbuf);
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit 2"));
WSACleanup();
return 1;
}*/
//create a master socket
if ((master_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == 0)
{
OutputDebugString(_T("My Sample Service : socket failed with error"));
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
return 1;
}
//set master socket to allow multiple connections ,
//this is just a good habit, it will work without this
if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0)
{
OutputDebugString(_T("My Sample Service : setsockopt failed with error"));
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
return 1;
}
//type of socket created
address.sin_family = AF_UNIX;
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //I really don't know what to put here
//address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
////bind the socket to localhost port 8000
//if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
//{
// wsprintfW(strbuf, L"My Sample Service : bind failed with error: %d", WSAGetLastError());
// OutputDebugString(strbuf);
// OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit 2"));
// closesocket(master_socket);
// WSACleanup();
// return 1;
//}
// Setup the TCP listening socket
iResult = bind(master_socket, (struct sockaddr *)&address, sizeof(address));
if (iResult == SOCKET_ERROR) {
wsprintfW(strbuf, L"My Sample Service : bind failed with error: %d", WSAGetLastError());
OutputDebugString(strbuf);
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
closesocket(master_socket);
WSACleanup();
return 1;
}
//freeaddrinfo(result);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
wsprintfW(strbuf, L"My Sample Service : listen failed with error: %d\n", WSAGetLastError());
OutputDebugString(strbuf);
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
closesocket(master_socket);
WSACleanup();
return 1;
}
addrlen = sizeof(address);
//accept the incoming connection
wsprintfW(strbuf, L"My Sample Service : Listener on port %d", PORT);
OutputDebugString(strbuf);
OutputDebugString(_T("My Sample Service: Waiting for connections ..."));
// Periodically check if the servC:\Users\Administrator\Desktopice has been requested to stop
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
/*
* Perform main service function here
*/
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for (i = 0; i < max_clients; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if (sd > 0)
FD_SET(sd, &readfds);
//highest file descriptor number, need it for the select function
if (sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
activity = select(max_sd + 1, &readfds, NULL, NULL, &tv);
if ((activity < 0) && (errno != EINTR))
{
OutputDebugString(_T("My Sample Service: select failed with error"));
}
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
wsprintfW(strbuf, L"My Sample Service : accept failed with error: %d", WSAGetLastError());
OutputDebugString(strbuf);
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
closesocket(master_socket);
WSACleanup();
return 1;
}
//inform user of socket number - used in send and receive commands
wsprintfW(strbuf, L"My Sample Service : New connection , socket fd is %d , ip is : %s , port : %d" , new_socket , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
OutputDebugString(strbuf);
//send new connection greeting message
if (send(new_socket, message, strlen(message), 0) != strlen(message))
{
OutputDebugString(_T("My Sample Service: Welcome message sent failed with error"));
}
else
{
OutputDebugString(_T("My Sample Service: Welcome message sent successfully"));
}
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if (client_socket[i] == 0)
{
client_socket[i] = new_socket;
wsprintfW(strbuf, L"My Sample Service: Adding to list of sockets as %d", i);
OutputDebugString(strbuf);
break;
}
}
}
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET(sd, &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = recv(sd, buffer, 1024, 0)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd, (struct sockaddr*)&address, \
(socklen_t*)&addrlen);
wsprintfW(strbuf, L"My Sample Service: Host disconnected , ip %s , port %d",
inet_ntoa(address.sin_addr), ntohs(address.sin_port));
OutputDebugString(strbuf);
//Close the socket and mark as 0 in list for reuse
closesocket(sd);
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//set the string terminating NULL byte on the end
//of the data read
buffer[valread] = '\0';
send(sd, buffer, strlen(buffer), 0);
}
}
}
}
The error returned by the bind method is 10022. I only want to accept connections from my own machine. The commented part of the code is because somewhere, I read that for UNIX sockets, getaddrinfo should not be done. Can someone help me to solve my problem??
I can't find any complete example project of process intercommunication using winsock either, if you point me to one it would also be very helpful.
THANK
EDIT
I am trying to intercommunicate two processes in windows. The link left by #Hans_Passant in the comments, points out that for this I must Download the Windows Insiders SDK for the Windows build 17061, but it is not available to everyone, it says: "To access this page, you need to be a member of the Windows Insider Program". so how can I do it?
Unix sockets are already local, you must put nothing but the address family in the address:
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sun_family = AF_UNIX;
Example (source: doc):
int sfd, cfd;
struct sockaddr_un my_addr, peer_addr;
socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
handle_error("socket");
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, MY_SOCK_PATH,
sizeof(my_addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &my_addr,
sizeof(my_addr)) == -1)
handle_error("bind");
if (listen(sfd, LISTEN_BACKLOG) == -1)
handle_error("listen");
/* Now we can accept incoming connections one
at a time using accept(2). */
peer_addr_size = sizeof(peer_addr);
cfd = accept(sfd, (struct sockaddr *) &peer_addr,
&peer_addr_size);
Update: I would recommend you to stick to TCP sockets:
master_socket = socket(AF_INET, SOCK_STREAM, 0)
and then:
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_LOOPBACK;
address.sin_port = htons(PORT);
Listening in the loopback interface ensures that no connections from the outside world will ever reach the socket.

C++ TCP Server (Winsock) Connecting (invalid client) Instantly Then Closes

Edit: Working on a solution - turns out googling 204.204.204.204 gets me further than more descriptive requests.
Honestly. Wits end. I have no idea how I can spend an entire day doing something that took 10 minutes in Flask (Server) and Javascript (client). I need this to run in C++ and allow a client to connect via BlueStacks' port on the same machine. The client is unimportant because I can't even get that far.
I've tried WinSocks, I've tried WxWidget's networking implementation, I've even tried some random C++ wrapper thing. All of them failed (typically within the EXAMPLE! As in, copy paste and errors everywhere). So I ultimately went back to WinSockets and followed a tutorial on YouTube.
int ServerStuff() {
WSADATA WsData;
WORD ver = MAKEWORD(2, 2);
int wsOK = WSAStartup(ver, &WsData);
if (wsOK != 0) {
wxLogMessage("Can't initialize Winsock! Quitting");
return false;
}
//Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
wxLogMessage("Can't create a socket! Quitting");
return false;
}
//Bind the ip and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
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 a connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
//if (clientSocket == INVALID_SOCKET) {
// wxLogMessage("Client Invalid Socket");
// return false;
//}
char host[NI_MAXHOST]; //Client's remote name
char service[NI_MAXHOST]; //Service (port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXHOST);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
wxLogMessage("Can't initialize Winsock! Quitting");
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
wxLogMessage(host);
int wut = client.sin_port;
wxString mystring = wxString::Format(wxT("%i"), wut);
wxLogMessage("Connected on port");
wxLogMessage(mystring);
//wxLogMessage(to_string(ntohs(client.sin_port)));
}
wxLogMessage("Got this far somehow");
//Close listening socket - we don't need it anymore - later on we'll learn how to accept multiple client
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) {
//wxLogMessage("ERROR in recv");
break;
}
if (bytesReceived == 0) {
wxLogMessage("Client Disconnected");
break;
}
//Echo back to client
send(clientSocket, buf, bytesReceived + 1, 0);
//Close the socket
closesocket(clientSocket);
//Cleanup winsock
WSACleanup();
wxLogMessage("Welp");
}
}
// event handlers
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
// true is to force the frame to close
ServerStuff();
//Close(true);
}
On the YouTube video ("Creating a TCP Server in C++" - not allowed to post links) this works! The command window opens, is blank infinitely until he connects a client and then the client sends a message and the server replies with the same exact message in return.
Not mine. Mine just rushes through everything and then closes. My log used to immediately quit on the commented code where it states the client socket is invalid so I commented it out. Now my output is:
204.204.204.204
Connected on port
52428
Got this far somehow
I don't know what to do. I'm just trying to send data over a same-machine TCP connection. I'm baffled as to how this is so difficult. It seems like some random process is immediately trying to connect as a client to my server ? But why is it allowed to connect on port 52428 when I'm explicitly hosting on 54000?
My goal:
Start Server
Connect to Server using a Java App within BlueStacks
Send data from Server to Client
It makes more sense for the computer to be the server because there will be multiple BlueStacks instances and I'd prefer to not have to "spawn" multiple programs / servers for what I'm doing.
I see a few mistakes in your socket code.
not calling WSACleanup() if WSAStartup() is successful and then something goes wrong afterwards.
not calling closesocket() if socket() is successful and then something goes wrong afterwards.
not zeroing out the sockaddr_in that you pass to bind(). Random bytes in the struct can cause bind() to fail.
ignoring the return values of bind(), listen(), accept(), and send().
not treating the return value of getnameinfo() correctly. It returns 0 on success, not failure.
sending +1 extra byte back to the client than you received from the client. If the client sends fewer bytes than your buffer can hold, that extra byte would be 0x00 due to your ZeroMemory() call. But if the client actually sends enough bytes to completely fill your buffer, then you would send an extra byte from memory that you do not own. If you really want to send a null terminator after everything you echo, do so explicitly. Otherwise, a true echo server should only send back exactly what it receives, no more, no less.
Try something more like this:
void ServerStuff() {
WSADATA WsData;
int ret = WSAStartup(MAKEWORD(2, 2), &WsData);
if (ret != 0) {
wxLogMessage("Can't initialize Winsock! Error: %d", ret);
return;
}
//Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listening == INVALID_SOCKET) {
wxLogMessage("Can't create a socket! Error: %d", WSAGetLastError());
WSACleanup();
return;
}
//Bind the ip and port to a socket
sockaddr_in hint = {};
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.s_addr = INADDR_ANY; //Could also use inet_pton
ret = bind(listening, (sockaddr*)&hint, sizeof(hint));
if (ret == SOCKET_ERROR) {
wxLogMessage("Can't bind socket! Error: %d", WSAGetLastError());
closesocket(listening);
WSACleanup();
return;
}
//Tell winsock the socket is for listening
ret = listen(listening, SOMAXCONN);
if (ret == SOCKET_ERROR) {
wxLogMessage("Can't listen on socket! Error: %d", WSAGetLastError());
closesocket(listening);
WSACleanup();
return;
}
//Wait for a connection
sockaddr_in client = {};
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
if (clientSocket == INVALID_SOCKET) {
wxLogMessage("Can't accept a client! Error: %d", WSAGetLastError());
closesocket(listening);
WSACleanup();
return;
}
char host[NI_MAXHOST] = {}; //Client's remote name
ret = getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, NULL, 0, 0);
if (ret != 0) {
wxLogMessage("Can't get client name info! Error: %d", ret);
inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
}
wxLogMessage("Client: %s, Connected on port: %hu", host, ntohs(client.sin_port));
//Close listening socket - we don't need it anymore - later on we'll learn how to accept multiple client
closesocket(listening);
//while loop: accept and echo message back to client
char buf[4096];
int bytesReceived;
while (true)
{
//Wait for client to send data
bytesReceived = recv(clientSocket, buf, sizeof(buf), 0);
if (bytesReceived == SOCKET_ERROR) {
wxLogMessage("Can't read from client! Error: ", WSAGetLastError());
break;
}
if (bytesReceived == 0) {
wxLogMessage("Client Disconnected");
break;
}
//Echo back to client
ret = send(clientSocket, buf, bytesReceived, 0);
if (ret == SOCKET_ERROR) {
wxLogMessage("Can't send to client! Error: ", WSAGetLastError());
break;
}
}
//Close the socket
closesocket(clientSocket);
//Cleanup winsock
WSACleanup();
wxLogMessage("Welp");
}

SOCKET connection problems in a service on Windows Server 2012

I inherited a C++/Windows project where we have an SNMP extension agent (loaded by SNMP service). Inside the agent, we are creating a simple TCP server to which our client applications connect and provide it with data for SNMP queries/traps etc. This all seems to work fine on Windows Server 2008. However, on Windows Server 2012, the client can no longer connect to the server running inside the agent (in SNMP service). The connect() fails with error 10013.
My server code looks something like this:
fd_set master_set;
fd_set readfds;
SOCKET listener;
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
OutputDebugStringA("WSAStartup failed\n");
return -1;
}
FD_ZERO(&master_set);
FD_ZERO(&readfds);
//----------------------
// Create a SOCKET for listening for
// incoming connection requests.
listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listener == INVALID_SOCKET) {
OutputDebugStringA("socket failed with error:\n");
return -1;
}
int reuse_addr = 1;
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse_addr, sizeof(reuse_addr));
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service = { 0 };
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(27015);
if (bind(listener, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR)
{
printf("bind failed with error: %d \n", WSAGetLastError());
closesocket(listener);
return -1;
}
if (listen(listener, 5) == SOCKET_ERROR)
{
OutputDebugStringA("listen failed with error\n");
closesocket(listener);
return -1;
}
u_long NonBlock = 1;
if (ioctlsocket(listener, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
OutputDebugStringA("ioctlsocket() failed with error\n");
return -1;
}
FD_SET(listener, &master_set);
timeval timeout;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
printf("Started Server on port %d\n", 27015);
for (;;)
{
readfds = master_set;
int ret = select(0, &readfds, NULL, NULL, &timeout);
if (ret == 0)
{
// Time out // Check if we need to shutdown
continue;
}
if (ret < 0)
{
printf("Error in Socket select\n");
return -1;
}
for (int i = 0; i < readfds.fd_count; i++)
{
SOCKET xfd = readfds.fd_array[i];
if (xfd == listener)
{
// New Connection.
SOCKET new_fd = HandleNewConnection(listener);
if (new_fd == -1)
{
printf("Error Accepting new connection");
continue;
}
FD_SET(new_fd, &master_set);
printf("Accepted new Connection\n");
continue;
}
else
{
if (!HandleIncomingData(xfd))
{
closesocket(xfd);
FD_CLR(xfd, &master_set);
continue;
}
}
}
}
SOCKET HandleNewConnection(SOCKET listener)
{
SOCKET newfd = accept(listener, (sockaddr*)NULL, (int*)NULL);
u_long NonBlock = 1;
ioctlsocket(newfd, FIONBIO, &NonBlock);
return newfd;
}
bool HandleIncomingData(SOCKET fd)
{
char buffer[16] = { 0 };
int recv_bytes = -1;
if ((recv_bytes = recv(fd, buffer, 16, 0)) <= 0)
{
printf("Connection Closed/ Error in Recieving");
return false;
}
printf("recieved %d bytes\n", recv_bytes);
return true;
}
The select continues to timeout every 3 seconds without any connection getting accepted.
Here's all that I have tried (none worked):
Tried to run the service in a specific user account.
The server is run in a separate thread, I provided a SECURITY_ATTRIBUTE with NULL DACL to see if it's a security problem.
Tried different ports.
Tried same server code in a separate normal application. The client can connect to this application.
Sample server application when launched from the agent, the client cannot connect to it.
Windows firewall is turned off and I don't have any anti virus software installed which would block such connections.
Checked connection from outside and observed in Wireshark that the TCP SYN packet does arrive but there's no response to it.
Observed in Process Explorer TCP/IP properties that the SNMP service does have a TCP socket listening on 127.0.0.1:27015.
For quick tests I am just doing telnet to port 27015.
Is there something obviously wrong with the server code which I am missing?
Is there some security restriction in Windows Server 2012 which don't allow a service to accept such TCP connections?
Any other hints, comments, inputs?
I solved the problem. The issue was due to Windows Service Hardening which did not allow any TCP communication from snmp service (and extensions). This is enforced even if the firewall is turned off.
https://support.microsoft.com/en-us/kb/2771908
I could solve it following these steps (found in http://www-01.ibm.com/support/docview.wss?uid=nas7ba16117761f1f93b86257f73000cff77)
Log on the system as Administrator and open Registry by issuing regedit in the command prompt.
Navigate to [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\Static\System].
Find the values which meet the following points:
a. “Name” string starts with “SNMP-”.
b. “Data” string contains “syswow64\snmp.exe”.
c. “Data” string contains “Action=Block”.
Change the “Action=Block” to “Action=Allow” of those entries.
Restart the “Windows Firewall” service by issuing net stop MPSSVC and net start MPSSVC .
Restart the “SNMP Service” service by using net stop SNMP and net start SNMP .

First client is laggy in multi-socket winsock server

I have a WinSock server setup, which is properly accepting clients and relaying the appropriate information. The server takes two clients, receives a fixed size buffer of 256 bytes, stores it, and then relays the other buffer to the client. (Ie. client1 sends its buffer, server saves it, then sends client1 the buffer for client2).
Anytime client1 changes its buffer, it takes roughly 4 seconds for client2 to receive the changes. If client2 makes a change, client1 receives the update almost instantly (less than 0.1s).
Nagle's algorithm is disabled and I've tried changing the order which the server processes the requests, but client1 always lags. The data always shows up intact, but takes too long. Below is the loop the server uses to process the data:
for(;;)
{
// check if more clients can join
if (numClients < MAX_CLIENTS)
{
theClients[numClients] = accept(listeningSocket, NULL, NULL);
if (theClients[numClients] == INVALID_SOCKET)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "server accept()");
closesocket(listeningSocket);
WSACleanup();
exit(0);
}
// disable Nagle's algorithm
int flag = 1;
int result = setsockopt(theClients[numClients], IPPROTO_TCP, TCP_NODELAY,
(char *) &flag, sizeof(int));
if (result < 0)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client connect()");
closesocket(theClients[numClients]);
WSACleanup();
}
// make the socket non-blocking
u_long iMode = 1;
ioctlsocket(theClients[numClients],FIONBIO, &iMode);
cout << "Client # " << numClients << " connected." << endl;
numClients++;
started = true;
}
else
{
// we've received all the connections, so close the listening socket
closesocket(listeningSocket);
}
// process client2
if (theClients[1] != INVALID_SOCKET)
{
memset(keys2, 0, 255);
// receive the updated buffer
nBytes = recv(theClients[1], keys2, sizeof(keys2), 0);
receiveResult = WSAGetLastError();
if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
{
JBS::reportSocketError(receiveResult, "server receive keys2()");
shutdown(theClients[1],2);
closesocket(theClients[1]);
WSACleanup();
exit(0);
break;
}
// send client1's buffer to client2
send(theClients[1],keys1,sizeof(keys1),0);
sendResult = WSAGetLastError();
if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
{
JBS::reportSocketError(sendResult, "server send keys1()");
shutdown(theClients[1],2);
closesocket(theClients[1]);
WSACleanup();
exit(0);
break;
}
}
// process client1
if (theClients[0] != INVALID_SOCKET)
{
memset(keys1, 0, 255);
// receive the updated buffer
nBytes = recv(theClients[0], keys1, sizeof(keys1), 0);
receiveResult = WSAGetLastError();
if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
{
JBS::reportSocketError(receiveResult, "server receive keys1()");
shutdown(theClients[0],2);
closesocket(theClients[0]);
WSACleanup();
exit(0);
break;
}
// send client2's buffer to client1
send(theClients[0],keys2,sizeof(keys2),0);
sendResult = WSAGetLastError();
if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
{
JBS::reportSocketError(sendResult, "server send keys2()");
shutdown(theClients[0],2);
closesocket(theClients[0]);
WSACleanup();
exit(0);
break;
}
}
Sleep((float)(1000.0f / 30.0f));
}
Client sending code:
int nError, sendResult;
sendResult = send(theSocket, keys, sizeof(keys),0);
nError=WSAGetLastError();
if((nError != WSAEWOULDBLOCK) && (nError != 0))
{
JBS::reportSocketError(sendResult, "client send()");
shutdown(theSocket,2);
closesocket(theSocket);
WSACleanup();
}
I've pasted your code below, with some inline comments in it, mostly because I can't fit it all reaonsably in a comment. How are you determining that it's taking four seconds for changes to get from client1 to client2? Visual inspection? Does this mean that Client1 & Client2 are running on the same machine (no different network latency issues to worry about)?
I've highlighted some blocks that look wrong. They may not be, it may be because you've tried to simplify the code that you've posted and you've missed some bits. I've also made some suggestions for where you might want to add some logging. If the sockets are really non-blocking you should be coming back from all of the calls very quickly and failing to read data, unless the client has sent it. If you've got a 4 second delay, then the problem could be:
the client hasn't sent it... is Nagle disabled on the client? If this were the case, I'd expect successive calls to recv to happen, with no data.
The recv call is taking too long... is the socket really in non-blocking mode?
The send call is taking too long... is the socket in non-blocking mode, is it buffered, is the client trying to receive the data?
Having the times each section of code takes will help to track down where your problem is.
You can get the time, using something like this (borrowed from the web):
struct timeval tv;
struct timezone tz;
struct tm *tm;
gettimeofday(&tv, &tz);
tm=localtime(&tv.tv_sec);
printf(" %d:%02d:%02d %d \n", tm->tm_hour, tm->tm_min,
m->tm_sec, tv.tv_usec);
Your code:
for(;;)
{
/* This block of code is checking the server socket and accepting
* connections, until two? (MAX_CLIENTS isn't defined in visible code)
* connections have been made. After this, it is attempting to close
* the server socket everytime around the loop. This may have side
* effects (although probably not), so I'd clean it up, just in case
*/
/* LOG TIME 1 */
// check if more clients can join
if (numClients < MAX_CLIENTS)
{
theClients[numClients] = accept(listeningSocket, NULL, NULL);
if (theClients[numClients] == INVALID_SOCKET)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "server accept()");
closesocket(listeningSocket);
WSACleanup();
exit(0);
}
// disable Nagle's algorithm
int flag = 1;
int result = setsockopt(theClients[numClients], IPPROTO_TCP, TCP_NODELAY,
(char *) &flag, sizeof(int));
if (result < 0)
{
nret = WSAGetLastError();
JBS::reportSocketError(nret, "client connect()");
closesocket(theClients[numClients]);
WSACleanup();
}
// make the socket non-blocking
u_long iMode = 1;
ioctlsocket(theClients[numClients],FIONBIO, &iMode);
cout << "Client # " << numClients << " connected." << endl;
numClients++;
/* This started variable isn't used, is it supposed to be wrapping
* this server code in an if statement?
*/
started = true;
}
else
{
// we've received all the connections, so close the listening socket
closesocket(listeningSocket);
}
/* LOG TIME 2 */
// process client2
if (theClients[1] != INVALID_SOCKET)
{
memset(keys2, 0, 255);
// receive the updated buffer
/* LOG TIME 3 */
nBytes = recv(theClients[1], keys2, sizeof(keys2), 0);
/* LOG TIME 4 */
receiveResult = WSAGetLastError();
if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
{
JBS::reportSocketError(receiveResult, "server receive keys2()");
shutdown(theClients[1],2);
closesocket(theClients[1]);
WSACleanup();
exit(0);
break;
}
// send client1's buffer to client2
/* LOG TIME 5 */
send(theClients[1],keys1,sizeof(keys1),0);
/* LOG TIME 6 */
sendResult = WSAGetLastError();
if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
{
JBS::reportSocketError(sendResult, "server send keys1()");
shutdown(theClients[1],2);
closesocket(theClients[1]);
WSACleanup();
exit(0);
break;
}
}
// process client1
/* If the client has been accepted (note that because this
* is part of the same block of code, and there's no protection
* around it, the first connection will process it's first
* receive/send combination before the second socket has been accepted)
*/
if (theClients[0] != INVALID_SOCKET)
{
memset(keys1, 0, 255);
// receive the updated buffer
/* You're trying a receive against a non-blocking socket. I would expect this
* to fail with WSAEWOULDBLOCK, if nothing has been sent by the client, but
* this block of data will still be sent to the client
*/
/* LOG TIME 7 */
nBytes = recv(theClients[0], keys1, sizeof(keys1), 0);
/* LOG TIME 8 */
receiveResult = WSAGetLastError();
if ((receiveResult != WSAEWOULDBLOCK) && (receiveResult != 0))
{
JBS::reportSocketError(receiveResult, "server receive keys1()");
shutdown(theClients[0],2);
closesocket(theClients[0]);
WSACleanup();
exit(0);
break;
}
// send client2's buffer to client1
/* The first time around the loop, you're sending the buffer to the
* first connected client, even though the second client hasn't connected yet.
* This will continue 30 times a second, until the second client connects. Does
* the client handle this correctly?
*/
/* LOG TIME 9 */
send(theClients[0],keys2,sizeof(keys2),0);
/* LOG TIME 10 */
sendResult = WSAGetLastError();
if((sendResult != WSAEWOULDBLOCK) && (sendResult != 0))
{
JBS::reportSocketError(sendResult, "server send keys2()");
shutdown(theClients[0],2);
closesocket(theClients[0]);
WSACleanup();
exit(0);
break;
}
}
Sleep((float)(1000.0f / 30.0f));
}
Client sending code:
int nError, sendResult;
/* There's no recv / loop in this section
*/
sendResult = send(theSocket, keys, sizeof(keys),0);
nError=WSAGetLastError();
if((nError != WSAEWOULDBLOCK) && (nError != 0))
{
JBS::reportSocketError(sendResult, "client send()");
shutdown(theSocket,2);
closesocket(theSocket);
WSACleanup();
}