Receive raw JSON string through TCP C++ - c++

So I need to receive a raw JSON string through a TCP connection.
I programmed a console application to receive the string. I tested the connection with telnet by sending text and it works fine. But when someone is sending me raw JSON strings I do not seem to receive anything. Is this because of the recv function?
Here is my code for receiving:
if ((new_socket = accept(s, (struct sockaddr *)&client, &c)) != INVALID_SOCKET)
{
puts("Connection accepted");
// Receive until the peer closes the connection
do {
iResult = recv(new_socket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
string input(recvbuf,iResult);
cout << input;
log << input;
}
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);
}
I convert the input (recvbuf) to a string and print it to my console and to a log file. But when I use telnet it works fine, but if someone sends me raw JSON strings I seem to get no data. Is this a problem on my side (recv the wrong function or something?) or theirs? I tried using the read function but it creates a Assertion failed error.

Related

Winsock program causing port exhaustion

Going off a different post that helped explain the source of the symptoms of my issue: https://superuser.com/questions/1348102/windows-10-ephemeral-port-exhaustion-but-netstat-says-otherwise
I am having a very similar issue - except the problem is the program eating up all the ports is one I created myself.
See the top 2 results
See the top 2 results - 6072 ports used by one instance and 545 by the other - if I understand that result set correctly.
There are 2 instances listed as there are 2 instances running - this is a program that connects to a machine every 60 seconds, asks if it has information, retrieves it if it does, and then closes the connection.
It was written in C++ using winsock TCP connections.
Is there anything someone could suggest I modify to prevent this from happening?
Currently, after about a month and a half of the program running, we run into the issue of not being able to RDC into the server "due to a time and date difference" even though the time and date are perfectly in sync with the NTP server and the rest of the computers, and of course it will seize being able to connect to anything.
We can still connect to the server directly through IP address, but not hostname.
I haven't yet found any solutions to this other than rebooting the server.
The mechanism for connecting is a simple and primitive:
void Connect(string ipA)
{
// Initialize Winsock
Debug("Connecting to socket...");
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
Debug("Client: Error at WSAStartup().");
}
else
{
Debug("Client: WSAStartup() is OK.");
}
// Create a SOCKET for connecting to server
u_long mode = (u_long)0;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
GPT_ATTRIBUTE_NO_BLOCK_IO_PROTOCOL;
if (ConnectSocket == INVALID_SOCKET)
{
printf("Client: Error at socket(): %ld.\n", WSAGetLastError());
WSACleanup();
return;
}
iResult = ioctlsocket(ConnectSocket, FIONBIO, &mode);
if (iResult != NO_ERROR)
printf("ioctlsocket failed with error: %ld\n", iResult);
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(ipA.c_str());
clientService.sin_port = htons(port);
// Connect to server.
if (connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
Debug("Connection failed...");
WSACleanup();
return;
}
else
Debug("Connection successful.");
}
This method is called with the IP address supplied as a parameter and results in a successful connection.
After that, several request-response packets are sent using these:
void SendPacket(int iResult, SOCKET ConnectSocket, const char* a)
{
Debug("Sending message to CW: " + (string)a);
iResult = send(ConnectSocket, a, strlen(a), 0);
if (iResult == SOCKET_ERROR) {
Debug("Send failed");
closesocket(ConnectSocket);
WSACleanup();
}
else
Debug("Send successful.");
}
And
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
And once we're done with the particular session, we close the connection:
void ShutDown(int iResult, SOCKET ConnectSocket)
{
iResult = shutdown(ConnectSocket, SD_SEND);
Debug("Shutting down socket...");
if (iResult == SOCKET_ERROR) {
Debug("Shutdown failed");
closesocket(ConnectSocket);
WSACleanup();
}
else
Debug("Shutdown successful.");
}
There are a couple hundred lines of code that handles the data received, but those won't be relevant as they don't deal with any sort of network connection.
To say I have no experience with C++ would be an understatement, I simply slapped this together using basic MS templates until it worked exactly as we needed it and haven't touched it since.
So if there is anything someone can point out that I could change to avoid port exhaustion, I would be very grateful.
Just to add a bit of clarity - the program will ALWAYS connect to the machine on the same port. I have tried to bind the outgoing connection (from Windows) port to the same one also, but I have been unsuccessful - wasted many hours trying to get this 1 simple thing right, but I presume that would resolve my issues.
I see that you are calling shutdown when you are done with a connection and if we consult the documentation for that we see:
The shutdown function does not close the socket. Any resources attached to the socket will not be freed until closesocket is invoked.
Which I take to mean that any ports associated with the socket remain in use.
Further down that page, we also read:
An application should not rely on being able to reuse a socket after it has been shut down. In particular, a Windows Sockets provider is not required to support the use of connect on a socket that has been shut down.
So, all-in-all, I would call closesocket instead of shutdown and then request a new socket from Winsock when you need one.

Getting undocumented error code from recvfrom

When attempting to read UDP packets using recvfrom the function returns -1 indicating an error. I of course then call WSAGetLastError to find out what the problem is. The reported error number is 183. I cant seem to find any reference as to what that number means.
Edit:
while (bytesRecv != SOCKET_ERROR)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
logError("Bytes recieved: ", bytesRecv);
// if data was recieved from the server
if (bytesRecv > 0)
{
//Data packet processing code
}
else
{
if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
}
}
}
Edit:
void logError(const std::string &text, int errorCode)
{
std::ofstream log_file("error_log_file.txt", std::ios_base::out | std::ios_base::app);
log_file << text << errorCode << "\n";
}
The problem is not with WSAGetLastError() itself. The real problem is that you are calling logError() before calling WSAGetLastError(), and logError() ends up resetting the last error code to 183.
logError() uses a std::ofstream to open a file for appending. On Windows, that operation will ultimately call CreateFile() with the OPEN_ALWAYS flag, for which its documentation states:
Opens a file, always.
If the specified file exists, the function succeeds and the last-error code is set to ERROR_ALREADY_EXISTS (183).
If the specified file does not exist and is a valid path to a writable location, the function creates a file and the last-error code is set to zero.
...
If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.
Internally, WSAGetLastError() simply maps to GetLastError() (a well-known but undocumented implementation detail). So, no matter whether the CreateFile() succeeds or fails in opening the file, the error code reported by WSAGetLastError() will get reset to the result of the open operation.
Your call to logError() is in the wrong place. It needs to be moved inside of your if (bytesRecv > 0) block (BTW, UDP supports 0-length datagrams, so you should be using >= instead of >):
while (true)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
// if data was received from the server
if (bytesRecv >= 0)
{
logError("Bytes received: ", bytesRecv); // <-- moved here!!!
//Data packet processing code
}
else // if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
break;
}
}
Alternatively:
while (true)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
// if data was received from the server
if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
break;
}
logError("Bytes received: ", bytesRecv); // <-- moved here!!!
//Data packet processing code
}

sql server has gone away error because of WSACleanup

I would like to ask for help since I don't know what to do anymore. I have a simulator created in c++, where it accepts an id input from a user and checks if it is in the database (created in mysql workbench) which is only in the localhost.
sqlQuery = "SELECT staffaccess.card_number FROM proxycardsim.staffaccess WHERE staffaccess.card_number = "
+ inputID;
if(mysql_ping(theInstance.connects))
{
}
int queryState = mysql_query(theInstance.connects, sqlQuery);
resultSet = mysql_store_result(theInstance.connects);
rowNum = mysql_num_rows(theInstance.resultSet);
if (rowNum == NULL)
{
mysql_free_result(theInstance.resultSet);
return false;
}
else
{
mysql_free_result(theInstance.resultSet);
return true;
}
The thing is that the simulator is connected to another computer that serves as a server (connected through winsock). If the server is up, it works ok or if all the inputs are wrong, but if the server is down(my code will try to connect again to the server pc so I have to call WSACleanup) after inputting one correct value and I input another mysql_query returns an error that mysql server has gone away. Then the program will break when it goes to mysql_num_rows.
I have this code in another function and when I commented them out one by one, I found out that the error is because of WSACleanup(). If the WSACleanup line is not there my query runs ok.
if ( false == theInstance.compareID(m_IDEntry))
{
addData(ConsoleLog,rec,0,0);
}
else
{
// Send an initial buffer
iResult = send( connectSocket, sendBuf, (int)strlen(sendBuf), 0 );
if(false == theInstance.addToLog(m_IDEntry))
{
addData(ConsoleLog,rec,0,3);
}
if (iResult == SOCKET_ERROR) {
closesocket(connectSocket);
WSACleanup();
serverConnect();
iResult = send( connectSocket, sendBuf, (int)strlen(sendBuf), 0 );
}
if (iResult != SOCKET_ERROR) {
addData(ConsoleLog,rec,0,1);
}
iResultRcv = recv(connectSocket, recvbuf, recvbuflen, 0);
if ( iResultRcv <= 0 )
{
addData(ConsoleLog,rec,0,7);
}
}
I hope someone can help me out.
Don't call WSACleanup. WSACleanup is intended to be used when you no longer want to do any socket communication. That's not the case for you.

sending whole data at once using socket

I'm trying to send a file from client to server using winsock2 lib.
After converting the file into char array, i'm sending this array using the send() command.
The problem: the data sent separately.
For e.g: I have file of size: 144429.
It does not send it at once, the data is split into many portions, like:
first send: 1460
second send: 21544
third send: 57136
etc..
until to whole data is sent.
so my question is: what causes it to send it by parts and not by once????
Solution I found working but not making any sense:
If i'm adding
cout << "bla bla bla";
before the send() function, it does work and send the whole 144429 by once. (but if the string given to cout is shorter, no change, send by parts)
CODE:
CLIENT SIDE
int Client::sendData(char *sendbuf, int length)
{
int iResult;
// if I remove those next few lines (until and including the cout line)
// the send will split.
char tmp[1];
// sent 1 dummy byte
iResult = send( _connectSocket, tmp, 1, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "SENDING DATA..." << endl;
// THIS IS THE RELEVANT AND ACTUAL DATA I WANT TO SEND
// send the data
iResult = send( _connectSocket, sendbuf, length, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "Data sent (" << iResult << " Bytes)" << endl;
return 0;
}
SERVER SIDE:
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
int iResult = 0;
int totalBytesRead = 0;
// Receive until the peer shuts down the connection
do {
totalBytesRead += iResult;
iResult = recv(_clientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("RECEIVED DATA\n");
printf("Bytes received: %d\n", iResult);
} else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed: %d\n", WSAGetLastError());
closesocket(_clientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// store data into file
FileTransfer::binaryToFile(recvbuf, "doch.docx", totalBytesRead-1);
return 0;
}
There is no way to guarantee that send transmits some data as one unit - it just doesn't work that way. You have to add some extra information to tell the system that "Here's this much data to come" and/or "I'm done now". Even if you could convince your sending side to send of everything in one packet, assuming the receiving side isn't connected DIRECTLY with just a simple cable to the sender, you can't guarantee that the packet isn't broken up during it's passing through the network.
You just have to accept that if you are sending more than a single byte in a packet, you may have to call send multiple times. To simplify it, write a function that takes a an arbitrary size "whole packet" and calls send as many times as necessary... If you have a protocol that indicates the size of the data sent [such as in the first few bytes], you could have a receive function that does the same thing.
Depending on the socket type you are using there might be a limitation of data size in the underlying transport protocol.
In case you are using a network socket the size is limited by the maximum transfer unit (see: http://en.wikipedia.org/wiki/Maximum_transmission_unit).
If your data doesn't fit this size you will have to iterate in a loop sending portions of your data until either an error occurs or all data has been sent.

How do I receive data in a C++ client's main loop without closing the server socket?

I was reading this winsock example.
I am trying to conceptualize how you would create a C++ client program that has a persistent TCP/IP connection to a C# .NET server.
The problem I see is that in order for the C++ client to leave the receive loop, the server must close its socket connection to the client.
In my case the server will send to the client every couple seconds. I need to be able to receive one packet from the server and restart the main program loop so the client can perform the rest of its functionality.
If this receive code is in the C++ client's main loop, the client will never stop receiving if the server never closes the connection to the client:
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0 )
printf("Bytes received: %d\n", iResult);
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
The example program that you have chosen to work from is designed to send a single request and receive a single response. It uses the state of the connection to indicate the end of the request, and the end of the response.
You might want to work from a different example program. Search for "winsock chat example" on google.
On the other hand, to modify this program as you have asked, you could replace the do-while loop with this:
// Assume that the OP's protocol sends 100-byte packets.
// Each while iteration attempts to receive one such packet.
// The while exits when the other side closes its connection.
while(1) {
// Receive 100-byte packet
int receivedBytes;
for(receivedBytes = 0; receivedBytes < 100; ) {
int iResult = recv(ConnectSocket,
recvbuf+receivedBytes,
recvbuflen-receivedBytes, 0);
if ( iResult > 0 ) {
receivedBytes += iResult;
printf("Bytes received: %d\n", iResult);
} else if ( iResult == 0 ) {
printf("Connection closed\n");
break;
} else {
printf("recv failed with error: %d\n", WSAGetLastError());
break;
}
}
if(receivedBytes == 100) {
// ... process packet here
} else {
break;
}
}
The problem here is that you have no way to know at what point recv() is going to return. There are five workarounds:
Make the socket non-blocking. (Not recommendable)
Use select() with a timeout.
Use async sockets. This is probably the fastest way, but more complex.
Use a thread.
BSD kqueue