sql server has gone away error because of WSACleanup - c++

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.

Related

bind() fails occasionally with Address already in use even after setting SO_REUSEADDR and SO_REUSEPORT

We have a streaming server implemented using live555 library. This server is deployed on CentOS instance.
Recently we wanted to modify the server socket options, so that it can accept the requests immediately after re-starting the process (either after crash or manual restart).
I have referred to man pages and few web links and set the socket options (SO_REUSEADDR and SO_REUSEPORT) before bind() call.
int setupStreamSocket(UsageEnvironment& env,
Port port, Boolean makeNonBlocking) {
int newSocket = createSocket(SOCK_STREAM);
if (newSocket < 0) {
socketErr(env, "unable to create stream socket: ");
return newSocket;
}
int reuseFlag = 1;
fprintf(stderr,"reuseFlag : %d\n",reuseFlag);
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {
socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
closeSocket(newSocket);
return -1;
}
if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
(const char*)&reuseFlag, sizeof reuseFlag) < 0) {
socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
closeSocket(newSocket);
return -1;
}
int flag = 1;
setsockopt( newSocket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag) );
if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());
int reuse_addr_val, reuse_port_val;
socklen_t reuse_addr_len = sizeof(reuse_addr_val);
socklen_t reuse_port_len = sizeof(reuse_port_val);
getsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr_val, &reuse_addr_len);
getsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, &reuse_port_val, &reuse_port_len);
fprintf(stderr,"reuse_addr_val = %d, reuse_port_val = %d\n", reuse_addr_val, reuse_port_val);
if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
char tmpBuffer[100];
sprintf(tmpBuffer, "bind() error (port number: %d): ",
ntohs(port.num()));
socketErr(env, tmpBuffer);
closeSocket(newSocket);
return -1;
}
}
if (makeNonBlocking) {
if (!makeSocketNonBlocking(newSocket)) {
socketErr(env, "failed to make non-blocking: ");
closeSocket(newSocket);
return -1;
}
}
return newSocket;
}
This code works as expected (binding to the address even when a socket is in TIME_WAIT state) if I restart the server with above options.
If I replace previous build (without socket options) with the build created with above code then I have noticed that occasionally bind() is failing with Address already in use error.
When the bind() failed the port/address is in TIME_WAIT state. So the server should able to bind the socket to the address.
tcp 0 0 10.0.1.24:8554 10.0.1.89:27085 TIME_WAIT -
And the getsockopt() of my code printed the flag value (corresponding to SO_REUSEADDR and SO_REUSEPORT) as 1.
reuse_addr_val = 1, reuse_port_val = 1
bind() error (port number: 8554): Address already in use
So I'm wondering why it's failing only few times. Did I miss something in my code ? or is this an expected behavior ?

Receive raw JSON string through TCP 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.

C++ Server reply properly

I want to make a Server that reply to my Sockets.
I have a code like this:
#define DEFAULT_BUFLEN 512
/*...*/
int iResult;
int iSendResult;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
/*...*/
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (recvbuf == "hello"){
iSendResult = send(ClientSocket, "Hi Client", sizeof("Hi Client"), 0);
}else {printf("[ERROR]Unexpected Socket.\n"); }
Now, it doesn't work. and I don't now why. I try to searck something online (whit poor results).
How can I make it works? I'm willing to change all the code.
You can't compare C-style strings with ==. You're comparing the address of the buffer with the address of a static string literal, which will always be unequal.
You also need to deal with the fact that each read from a stream socket (assuming that's what this is) might give more or less data than you're expecting.
A more correct comparison might be
if (iResult < 0) {
// Some kind of read error, check errno for details
} else if (iResult == 0) {
// Socket was closed
} else if (iResult < 5) {
// Not enough input: read some more or give up
} else if (std::equal(recvbuf, recvbuf+5, "hello")) {
// Expected input: there might be more data to process
} else {
// Unexpected input
}

C++ Custom Client Handler

Below is the code that accepts a client... I just added a bit to add it to a pool which is a list<Client>. Client is my own class that is defined by (SOCKET, Char*) socket and ip address. The addclient2pool() function just adds to the list. Then I iterate through the list and send data via the stored socket in Client.
while(true) {
ClientSocket = accept(ListenSocket, (struct sockaddr *) &n, &len);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return;
}
addClient2Pool(Client(ListenSocket, inet_ntoa(n.sin_addr)));
}
The socket seems to have closed so I can't send messages... 10057. I am pretty sure there's something fundamentally wrong with the way I am storing the socket into Client class but I am new to C++.
void messageHandler() {
int iSend;
char* charB = "hello!";
while(true) {
for(ClientPool::iterator it = mainClientPool.begin(); it != mainClientPool.end(); ++it) {
Client c = *it;
SOCKET sock = c.getSocket();
iSend = send(sock, charB, sizeof(charB),0);
if (iSend == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
}
}
Sleep(2000);
}
}
I used std::thread nameofthread(void) and nameofthread.join();
I see several issues with your code.
You are passing ListenSocket to Client() when you should be passing ClientSocket instead:
addClient2Pool(Client(ClientSocket, inet_ntoa(n.sin_addr)));
If you need to shut down the server for any reason, you should close any active client sockets first. In your example, if accept() fails, you are calling closesocket(ListenSocket) and WSACleanup() without clearing mainClientPool first (I assume your ~Client() deconstructor calls closesocket() on the client socket):
mainClientPool.clear(); // <-- add this
closesocket(ListenSocket);
WSACleanup();
When looping through your list, you need to use a Client& reference when deferencing the iterator so you are not making temporary copies of your Client objects that invoke their destructors when they go out of scope (thus closing your client sockets):
Client &c = *it; // <-- add '&'
You are misusing sizeof(). Since charB is a char* and not a char[], you need to use strlen() instead:
iSend = send(sock, charB, strlen(charB), 0);
Lastly, when send() (or any other socket operation) fails, you should close the failed client socket and remove it from your list. Which means changing your for() loop into a while() loop so you can modify the list while you are looping through it:
void messageHandler() {
...
while(true) {
...
ClientPool::iterator it = mainClientPool.begin();
while (it != mainClientPool.end()) {
...
if (iSend == SOCKET_ERROR) {
...
it = mainClientPool.erase(it);
} else {
++it;
}
}
...
}
...
}

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