There are zillions of these questions I know, but none of them were similar to my issue, so I figured I'd ask. I have a server set up that validates clients that connect to it by receiving username/password combinations and checking them using a SQL query. I wrote the system, and it worked perfectly fine during the first couple of requests.
http://puu.sh/d9mss/384b4df9f0.png
However, I found that if I wait about 5 minutes and then try to connect, this happens.
http://puu.sh/d9mx7/192cbb2cfc.png
This is the code that I am running to perform that task.
bool CNetDatabase::AuthUser(std::string username, const unsigned char* passwordhash)
{
RoughSanitizeString(username); //this doesn't do anything
/* Turn password hash into string */
std::ostringstream password;
password.fill('0');
password << std::hex;
for (int i = 0; i < 20; i++)
{
password << std::setw(2) << (unsigned int)passwordhash[i];
}
/* Make request */
MYSQL_RES* result = nullptr;
if (mysql_query(sql_con, tools::string::format(
"SELECT COUNT(`index`) FROM `Users` WHERE `username` = '%s' AND `password` = '%s'",
username.c_str(), password.str().c_str()).c_str()))
{
fprintf(
stderr,
"ERROR: mysql_query failed: %s [%d]\n",
mysql_error(sql_con), mysql_errno(sql_con));
return false;
}
/* Get and return result */
result = mysql_store_result(sql_con);
MYSQL_ROW row = mysql_fetch_row(result);
mysql_free_result(result);
return row[0][0] == '1' ? true : false;
}
Any ideas on what could be going wrong?
Check MySQL manual. There are session timeouts on both client and server side.
Anyway it is a good practice to expect that connection to external resources may become unavailable and try to reconnect (for instance database server could be physically rebooted). You can try to set reconnect flag when creating connection to enable automatic reconnects but those might not always work depending on your environment.
Upon further investigation, I think it's safe to conclude that it is my host's problem, not my code. I registered an account with a site that offered the ability to make free MySQL databases, and my server has been throwing SQL queries at it without issue all night. For posterity, if you are using your website's SQL server and are hosting with Hostgator, they might be causing the issue.
Related
I'm currently running a FileZilla FTP server on a network. My issue is that on seemingly random machines, when the user navigates to a directory (which they are able to do) and attempts to ls (i.e. data transfer) their end hangs waiting for a response, while the server reports this 425: Can't open data connection for transfer mentioned above. This result varies depending on the client machine used, where some (either local or remote) are able to proceed and others stuck here. I understand that this is because simple FTP commands like CWDing operate on the 20/21 ports, whereas FTP data transfer operate on some other port number, which in turn may be blocked by a firewall somewhere along the chain. My question is, how do I account for these varying ports (if this truly is the issue), as as best I know they could be anything above 1024?
My end goal with this project is to implement a very simple FTP solution, ideally using WinINet, however, so far I've run into the same problem:
BOOL CWebFileFinder::FindFile(const CString& URL)
{
CString ServerName;
CString strObject;
INTERNET_PORT nPort;
DWORD dwServiceType = AFX_INET_SERVICE_FTP;
if (AfxParseURL(URL, dwServiceType, ServerName, strObject, nPort))
{
m_Connection = m_Session.GetFtpConnection(ServerName, m_Username, m_Password, nPort/*, true*/); // results in findfile still failing
if (m_Connection)
{
m_Connection->SetCurrentDirectory("sms"); // CDs into this dir
m_Finder = new CFtpFileFind(m_Connection);
if (m_Finder)
{
More = m_Finder->FindFile(_T("*.*")); // hangs here
}
}
}
catch (CException* pEx)
{
CString str;
LPTSTR error = str.GetBuffer(255);
pEx->GetErrorMessage(error, 255);
pEx->Delete();
str.ReleaseBuffer();
}
return More;
}
As far as I can see, either I need to call to open this data port prior to the LIST, or find the firewalls blocking these ports and create a rule to prevent that (What ports does Wininet listen on for Active FTP data connection?). Of course I could also be just completely off-base – Any insights at all would be greatly appreciated!
Your FTP server seems to require an encrypted connection (TLS/SSL).
WinInet does not support encrypted FTP.
See C++/Win32 The basics of FTP security and using SSL.
I want to check using sockets whether a client is still connected to the server. I saw that the revc function gives me the status of the client but it is not working as I expect (sometines client did not disconnect and the revc function thought he was).
I got this code:
if (recv(client->getSocket(), rcmsg, 1024, 0) <= 0)
{
bool found = false;
for (i = 0; i < this->clients.size(); i++)
{
if (*(this->clients[i]) == *client)
{
found = true;
break;
}
}
if (found)
this->clients.erase(this->clients.begin() + i);
closesocket(client->getSocket());
std::cout << "disconected: socket = " << client->getSocket() << ", ip = " << inet_ntoa(addr.sin_addr) << endl;
There is another solution?
Thanks in advance.
It's important to remember where TCP/IP came from.
It's a communications protocol stack that's designed to withstand an all-out nuclear war.
That means, telegraph poles being vapourised, radio links intermittent or no longer there, telephone exchanges no longer being there... and it still had to work.
In this context, define "connected".
A TCP "connection" is merely two distinct hosts believing that they're connected, and somehow packets are routed to the hosts eventually by the remaining routers on the network.
This is why there is a whole host of protocols we never even think about, for example RIP (Routing Information Protocol) who's job is to discover the remaining links after the bombardment.
There is really no such thing as "connected". There is simply the time elapsed since you received a packet from the remote host. That's it.
I'm not usually the type to post a question, and more to search why something doesn't work first, but this time I did everything I could, and I just can't figure out what is wrong.
So here's the thing:
I'm currently programming an IRC Bot, and I'm using libircclient, a small C library to handle IRC connections. It's working pretty great, it does the job and is kinda easy to use, but ...
I'm connecting to two different servers, and so I'm using the custom networking loop, which uses the select function. On my personal computer, there's no problem with this loop, and everything works great.
But (Here's the problem), on my remote server, where the bot will be hosted, I can connect to one server but not the other.
I tried to debug everything I could. I even went to examine the sources of libircclient, to see how it worked, and put some printfs where I could, and I could see where does it comes from, but I don't understand why it does this.
So here's the code for the server (The irc_session_t objects are encapsulated, but it's normally kinda easy to understand. Feel free to ask for more informations if you want to):
// Connect the first session
first.connect();
// Connect the osu! session
second.connect();
// Initialize sockets sets
fd_set sockets, out_sockets;
// Initialize sockets count
int sockets_count;
// Initialize timeout struct
struct timeval timeout;
// Set running as true
running = true;
// While the server is running (Which means always)
while (running)
{
// First session has disconnected
if (!first.connected())
// Reconnect it
first.connect();
// Second session has disconnected
if (!second.connected())
// Reconnect it
second.connect();
// Reset timeout values
timeout.tv_sec = 1;
timeout.tv_usec = 0;
// Reset sockets count
sockets_count = 0;
// Reset sockets and out sockets
FD_ZERO(&sockets);
FD_ZERO(&out_sockets);
// Add sessions descriptors
irc_add_select_descriptors(first.session(), &sockets, &out_sockets, &sockets_count);
irc_add_select_descriptors(second.session(), &sockets, &out_sockets, &sockets_count);
// Select something. If it went wrong
int available = select(sockets_count + 1, &sockets, &out_sockets, NULL, &timeout);
// Error
if (available < 0)
// Error
Utils::throw_error("Server", "run", "Something went wrong when selecting a socket");
// We have a socket
if (available > 0)
{
// If there was something wrong when processing the first session
if (irc_process_select_descriptors(first.session(), &sockets, &out_sockets))
// Error
Utils::throw_error("Server", "run", Utils::string_format("Error with the first session: %s", first.get_error()));
// If there was something wrong when processing the second session
if (irc_process_select_descriptors(second.session(), &sockets, &out_sockets))
// Error
Utils::throw_error("Server", "run", Utils::string_format("Error with the second session: %s", second.get_error()));
}
The problem in this code is that this line:
irc_process_select_descriptors(second.session(), &sockets, &out_sockets)
Always return an error the first time it's called, and only for one server. The weird thing is that on my Windows computer, it works perfectly, while on the Ubuntu server, it just doesn't want to, and I just can't understand why.
I did some in-depth debug, and I saw that libircclient does this:
if (session->state == LIBIRC_STATE_CONNECTING && FD_ISSET(session->sock, out_set))
And this is where everything goes wrong. The session state is correctly set to LIBIRC_STATE_CONNECTING, but the second thing, FD_ISSET(session->sock, out_set) always return false. It returns true for the first session, but for the second session, never.
The two servers are irc.twitch.tv:6667 and irc.ppy.sh:6667. The servers are correctly set, and the server passwords are correct too, since everything works fine on my personal computer.
Sorry for the very long post.
Thanks in advance !
Alright, after some hours of debug, I finally got the problem.
So when a session is connected, it will enter in the LIBIRC_STATE_CONNECTING state, and then when calling irc_process_select_descriptors, it will check this:
if (session->state == LIBIRC_STATE_CONNECTING && FD_ISSET(session->sock, out_set))
The problem is that select() will alter the sockets sets, and will remove all the sets that are not relevant.
So if the server didn't send any messages before calling the irc_process_select_descriptors, FD_ISSET will return 0, because select() thought that this socket is not relevant.
I fixed it by just writing
if (session->state == LIBIRC_STATE_CONNECTING)
{
if(!FD_ISSET(session->sock, out_set))
return 0;
...
}
So it will make the program wait until the server has sent us anything.
Sorry for not having checked everything !
Right now I have a C++ client application that uses mysql.h to connect to a MYSQL database and have to preform some logic in case there is a disconnect. I'm wondering if this is the best way to reconnect to a MYSQL database in a situation where my client gets disconnected.
bool MYSQL::Reconnect(const char *host, const char *user, const char *passwd, const char *db)
{
bool out = false;
pid_t command_pid = fork();
if (command_pid == 0)
{
while(1)
{
sleep(1);
if (mysql_real_connect(&m_mysql, host, user, passwd, db, 0, NULL, 0) == NULL )
{
fprintf(stderr, "Failed to connect to database: Error: %s\n",
mysql_error(&m_mysql));
}
else
{
m_connected = true;
out = true;
break;
}
}
exit(0);
}
if (command_pid < 0)
fprintf(stderr, "Could not fork process[reconnect]: %s\n", mysql_error(&m_mysql));
return out;
}
Right now i take in all my parameters and preform a fork. the child process attempts to reconnect every second with a sleep() statement. Is this a good way to do this? Thanks
Sorry, but your code doesn't do what you think it does, Kaiser Wilhelm.
In essence, you're trying to treat a fork like a thread, which it is not.
When you fork a child, the parent process is completely cloned, including file and socket descriptors, which is how your program is connected to the MySQL database server. That is, both the parent and the child end up with their own copy of the same connection to the database server when you fork. I assume the parent only calls this Reconnect() method when it sees the connection drop, and stops using its copy of the now-defunct MySQL connection object, m_mysql. If so, the parent's copy of the connection is just as useless as the client's when you start the reconnect operation.
The thing is, the reverse is not also true: once the child manages to reconnect to the database server, the parent's connection object remains defunct. Nothing the child does propagates back up to the parent. After the fork, the two processes are completely independent, except insofar as they might try to access some I/O resource they initially shared. For example, if you called this Reconnect() while the connection was up and continued using the connection in the parent, the child's attempts to talk to the DB server on the same connection would confuse either mysqld or libmysqlclient, likely causing data corruption or a crash.
As hinted above, one solution to this is to use threads instead of forking. Beware, however, of the many problems with using threads with the MySQL C API.
Given a choice, I'd rather use asynchronous I/O to do the background connection attempt within the application's main thread, but the MySQL C API doesn't allow that.
It seems you're trying to avoid blocking your main application thread while attempting the DB server reconnection. It may be that you can get away with doing it synchronously anyway by setting the connect timeout to 1 second, which is fine when the MySQL server is on the same machine or same LAN as the client. If you could tolerate your main thread blocking for up to a second for connection attempts to fail — worst case happening when the server is on a separate machine and it's physically disconnected or firewalled — this would probably be a cleaner solution than threads. The connection attempt can fail much quicker if the server machine is still running and the port isn't firewalled, such as when it is rebooting and the TCP/IP stack is [still] up.
As far as I can tell, this doesn't do what you intended.
Logical issues
Reconnect doesn't "perform some logic in case there is a disconnect" at all.
It attempts to connect over and over again until it succeeds, then stops. That's it. The state of the connection is never checked again. If the connection drops, this code knows nothing about it.
Technical issues
Also pay close attention to the technical issues that Warren raises.
Sure, it's perfectly OK. You might want to think about replacing the while ( 1 ) loop with something like
while ( NULL == mysql_real_connect( ... )) {
sleep( 1 );
...
}
which is the kind of idiom that one learns by practice, but your code works just fine as far as I can see. Don't forget to put a counter inside the while loop.
Greetings, I have a C++ script that runs indefinitely. Sometimes (rarely), the MySQL connection is lost, so I'd like to implement some logic to reconnect if that ever happens. I know this is easy, but I just want to ensure that it's correct as I'm new to C++.
This is how the connection is established:
const char* mysql_server = argv[argcounter++];
const char* mysql_database = argv[argcounter++];
const char* mysql_user = argv[argcounter++];
const char* mysql_password = argv[argcounter++];
mysql_conn = mysql_init(NULL);
// connect to database
if (!mysql_real_connect(mysql_conn, mysql_server,
mysql_user, mysql_password, mysql_database, 0, NULL, 0))
{
fprintf(stderr, "%s\n", mysql_error(mysql_conn));
exit(1);
}
I'm wondering how to check if the connection no longer exists. The loop runs every 1500 seconds.
Thank you
Why not use the MYSQL reconnection option to mysql_options?
From http://dev.mysql.com/doc/refman/5.0/en/mysql-options.html) :-
"MYSQL_OPT_RECONNECT (argument type: my_bool *)
Enable or disable automatic reconnection to the server if the connection is found to have been lost. Reconnect has been off by default since MySQL 5.0.3; this option is new in 5.0.13 and provides a way to set reconnection behavior explicitly."