SFML TCP packets being changed - c++

After failing to get any help in the SFML forums, I've decided to see if anyone here can be of any help. I have an application which updates itself through a TCP connection to a server application. This works perfectly fine, except for one specific packet transmission, in which the packet is somehow changed. The server sends a packet containing the number 1:
pack << sf::Uint8(1);
ClientSocket.Send(pack);
(Where pack is of type sf::Packet and ClientSocket is of type sf::SocketTCP)
Stepping through with my debugger does in fact confirm that these lines are executed, and that the next Receive call in my client is the next few lines:
sock.Receive(pack);
sf::Uint8 conf;
pack >> conf;
(Where pack is once again an sf::Packet, and sock is a SocketTCP)
However, somehow in my client, conf is showing up as having a value of zero (my debugger confirms this) and it acts as so (the next line switches depending on the value). I am running both applications on the same machine, and they are both reading each other as "127.0.0.1", so the packets (if I understand correctly) aren't going through my router, or really ever leaving my machine. Any ideas on why my packets are being corrupted?
For the record, in case it's any help, I'm using SFML 1.6 and my application in being run on a Debian Squeeze Linux machine.
EDIT: Per request, here is some more code from my application.
First, the portion of my client specifically relating to this updater:
cout << "Connecting to update server." << endl;
sf::IpAddress server = sf::IpAddress::LocalHost;
sf::TcpSocket sock;
if (sock.connect(server, PORT, sf::seconds(20.0f)) != sf::Socket::Done)
return false;
cout << "Connected. Searching for updates for updater." << endl;
sf::Packet pack;
std::string lastUpdate = getLastUpdate();
#ifdef __WXGTK__
pack << "uupdate" << lastUpdate << sf::Uint8(1);
#elif defined(__WXMSW__)
pack << "uupdate" << lastUpdate << sf::Uint8(2);
#elif defined(__WXOSX__)
pack << "uupdate" << lastUpdate << sf::Uint8(3);
#endif
sock.send(pack);
pack.clear();
sock.receive(pack); //THIS IS THE PART WHERE IT BREAKS
sf::Int32 conf;
pack >> conf;
if (conf == 1) { //There is an update!
cout << "Update found!" << endl;
pack << "begin" << sf::Uint32(512);
sock.send(pack);
pack.clear();
sock.receive(pack);
pack >> conf;
if (conf == 0) { //No errors
wxFileOutputStream* out = new wxFileOutputStream(wxString(UPDATER, StrConv).append(".temp"));
char* data = new char[512];
while (data != chara("done") && data != chara("error")) {
sock.receive(pack);
sf::Int32 size;
pack >> size;
data = const_cast<char*>((const char*)pack.getData());
out->Write(data, size);
}
out->Close();
if (data == chara("done"))
wxCopyFile(wxString(UPDATER, StrConv).append(".temp"), wxString(UPDATER, StrConv));
wxRemoveFile(wxString(UPDATER, StrConv).append(".temp"));
}
}
cout << "Updater is up-to-date. Executing updater." << endl;
sock.disconnect();
bool success;
if (wxTheApp->argc == 1)
success = wxExecute(wxT(UPDATER));
else
success = wxExecute(wxString(UPDATER, StrConv).append(wxTheApp->argv[1]));
return success;
And then the portion of the server relating to these updates:
//ClientSocket has already been initalised by way of a TcpListener
cout << "Checking for updater patches for client at " << ClientAddress.toString() << endl;
std::string lastUpdate;
pack >> lastUpdate;
sf::Uint8 os;
pack >> os;
//Check last time updater was changed
struct tm* clock;
struct stat attribs;
if (os == 1)
stat("Linux/Updater", &attribs);
else if (os == 2)
stat("Windows/Updater.exe", &attribs);
else if (os == 3)
stat("Mac/Updater", &attribs);
clock = gmtime(&(attribs.st_mtime));
time_t lastWrite = mktime(clock);
time_t clientUpdate = stringToNumber<time_t>(lastUpdate.c_str());
if (lastWrite > clientUpdate) {
cout << "Found updater patches for client at " << ClientAddress.toString() << endl;
pack << sf::Int32(1);
ClientSocket->send(pack); //THIS IS THE PART WHERE IT BREAKS
pack.clear();
ClientSocket->receive(pack);
std::string mes;
pack >> mes;
if (mes != "begin") {
cerr << "Client at " << ClientAddress.toString() << " sent unrecognised message: " << mes << ". Ending conversation." << endl;
ClientSocket->disconnect();
return false;
}
sf::Uint32 size;
pack >> size;
cout << "Beginning to send updater patch to " << ClientAddress.toString() << endl;
ifstream in;
if (os == 1)
in.open(chara("Linux/Updater"), ios_base::in | ios_base::binary);
else if (os == 2)
in.open(chara("Windows/Updater.exe"), ios_base::in | ios_base::binary);
else if (os == 3)
in.open(chara("Mac/Updater"), ios_base::in | ios_base::binary);
if (in.fail()) {
pack << sf::Uint8(1);
ClientSocket->send(pack);
cerr << "Failed to open updater at request of " << ClientAddress.toString() << ". Closing connection." << endl;
ClientSocket->disconnect();
return false;
}
pack << sf::Uint8(0);
ClientSocket->send(pack);
pack.clear();
//Get length of file
in.seekg(0, ios::end);
int length = in.tellg();
in.seekg(0, ios::end);
char* buf = new char[size];
for (unsigned int i = 0; i < length / size; i++) { //Read and send every `size`-sized block we can
in.read(buf, size);
pack << sf::Int32(size) << buf;
ClientSocket->send(pack);
}
in.read(buf, length % size);
pack << sf::Int32(length % size) << buf;
ClientSocket->send(pack);
pack.clear();
pack << "done";
ClientSocket->send(pack);
pack.clear();
} else {
pack << sf::Int8(0);
ClientSocket->send(pack);
}
EDIT: I know it's been almost a month since there have been any posts on here, but I'm still having issues with this. I'm at wit's end on how to solve this.

This is not really an answer but I can't add a comment on the question so...
SFML 1.6 is not maintained and if there is an issue with SFML itself it might already be solved in version 2.0. You can download the RC here.

So, turns out the problem was rather simple. You know how I added lots of pack.clear() lines in? Turns out I forgot to add one between receiving the original data and sending the original data on the server. So my packet still had data left over from the first call to sock.receive(pack) (which was a few lines above the start of the code from the server posted above). It took me this long to see that. Put in a call to pack.clear() and the problem went away.

Related

C++ WinSock sending files

Recently, i've been assigned a client/server project, which is basically a chat room, where files can be sent and recieved, and we can use webcams.
I'm currently working on the file transfer part, and after looking at some online tutorials, i've noticed most of them use offsets to write into their buffers, then they write the whole buffer into their new file.
To replicate that kind of code, i've set up 2 buffers, one on the client side, the other on the server side. On the server side, i read 8192 bytes from my file, into the buffer, then i send it into the client side, which recieves it, and adds it to my buffer. Problem is, after the second file transfer, every single transfer it does, it's a SOCKET_ERROR, which probably means something's not quite right.
server:
std::ifstream readFile;
readFile.open(FileName, std::ios::binary | std::ios::ate);
if (!readFile)
{
std::cout << "unable to open file" << std::endl;
}
int FileSize = readFile.tellg();
readFile.seekg(0);
int remainingBytes = 0;
uint32_t FileSize32t = (uint32_t)FileSize;
FileSize32t = htonl(FileSize32t);
send(connections[ID], (char*)&FileSize32t, sizeof(uint32_t), 0);
int sent_bytes = 0;
int offset = 0;
char data[8192];
remainingBytes = FileSize;
int i = 0;
while (i<6)
{
readFile.read(data, 8192);
if (remainingBytes < 8192)
{
sent_bytes = send(connections[ID], data+offset, remainingBytes, 0);
remainingBytes -= sent_bytes;
offset += sent_bytes;
}
else
{
sent_bytes = send(connections[ID], data+offset, 8192, 0);
if (sent_bytes == SOCKET_ERROR)
{
std::cout << "erro" << std::endl;
}
remainingBytes -= sent_bytes;
offset += sent_bytes;
std::cout <<"offset: "<< offset << std::endl;
std::cout << "Sent bytes: " << sent_bytes << std::endl;
std::cout << "remaining bytes: " << remainingBytes << std::endl;
}
i++;
}
Client:
char data[8192];
std::ofstream writeFile;
writeFile.open("Putin.jpg", std::ios::binary);
int bytesReceieved = 0;
int totalBytesReceieved = 0;
int i = 0;
while (i<6)
{
if (recvFileSize - totalBytesReceieved < 8192)
{
bytesReceieved = recv(connection, data+totalBytesReceieved, recvFileSize - totalBytesReceieved, 0);
totalBytesReceieved += bytesReceieved;
}
else
{
bytesReceieved = recv(connection, data + totalBytesReceieved, 8192, 0);
totalBytesReceieved += bytesReceieved;
std::cout << totalBytesReceieved << std::endl;
}
i++;
}
writeFile.write(data, totalBytesReceieved);
std::cout << "transferĂȘncia terminada, bytes recebidos: " << totalBytesReceieved << std::endl;
writeFile.close();
Do note that this is just a test program, and it's preety much one of my first interactions with C++. I've been told this probably isn't the best way to start off with C++, but i need this assignment done until the 15th of september, so i need to finish it regardless. If you find any errors or problems besides my original issue do feel free to point them out and if you can, explain me why it's wrong.
Thank you very much for your help.

libarchive returns error on some entries while 7z can extract normally

I'm having trouble with libarchive version 3.3.2. I wrote a program to read selected entries in 7z archives, that look like:
file.7z
|__ file.xml
|__ file.fog
|__ file_1.fog
However, the program failed to read file_1.fog for most of my archives, and failed to read file.fog for some. I tried to use archive_error_string() to see what happens, and the errors were either corrupted archive or truncated RAR archive or Decompressing internal error.
Here's the trouble code:
void list_archive(string name) {
struct archive *a;
struct archive_entry *entry;
// create new archive struct for the file
a = archive_read_new();
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
// open 7z file
int r = archive_read_open_filename(a, name.c_str(), 1024);
if (r != ARCHIVE_OK) {
cout << "cannot read file: " << name << endl;
cout << "read error: " << archive_error_string(a) << endl;
}
// looping through entries
for (;;) {
int status = archive_read_next_header(a, &entry);
// if there's no more header
if (status != ARCHIVE_OK) break;
// print some status messages to stdout
string pathname(archive_entry_pathname(entry));
cout << "working on: " << pathname << endl;
size_t entry_size = archive_entry_size(entry);
// load the entry's content
char * content;
content = (char*)malloc(entry_size);
r = archive_read_data(a, content, entry_size);
// check if archive_read_data was successful
if (r > 0) {
cout << "read " << r << " of " << entry_size << " bytes successfully\n";
// we are interested in .fog file only
if (pathname.back() == 'g') {
// do something with the .fog file
}
}
else // usually the error happens here
if (archive_errno(a) != ARCHIVE_OK) cout << "read error: " << archive_error_string(a) << endl;
// free the content and clear the entry
archive_read_data_skip(a);
free(content);
archive_entry_clear(entry);
cout << "-----" << endl;
}
// we are done with the current archive, free it
r = archive_read_free(a);
if (r != ARCHIVE_OK) {
cout << "Failed to free archive object. Error: " << archive_error_string(a) << endl;
exit(1);
}
}
I found the troublemaker and answer here if future users have the same problem.
int r = archive_read_open_filename(a, name.c_str(), 1024);
Apparently 1024 is too small for a buffer size. I increased it to 102400 and was able to read/extract all my archives.
Be aware, technically buffer size should not break functionality, it's OK to reduce speed but it's not acceptable to break the operation, therefore I think the way it's processing archives is not that reliable.

Serial Port communication - PuTTY emulation

I am writing a simple user interface to communicate with an In-Circuit Serial Programmer. The intention is to remove the need for the end-user to type over a dozen cryptic commands via PuTTY, and in fact to remove the need for typing altogether as the user is inevitably wearing keyboard-unfriendly gloves. The process requires interaction with the user, so a simple batch script is not feasible.
I can find the correct COM port and successfully open it. I can send data, but the response is only ever the equivalent of "unknown command".
I shall refrain from posting the whole code as nobody will be able to recreate my circumstances. However, I can always add everything if necessary.
I open comms using CreateFile() and use WriteFile() or ReadFile() to communicate. For example:
if (!WriteFile(hSerial, "r rc.all\r\n", 10, &bytesRead, NULL))
cout << "Error sending message (" << GetLastError() << ")" << endl;
if (!ReadFile(hSerial, msgBuffer, 15, &bytesRead, NULL))
cout << "No message received" << endl
else
{
cout << "Bytes rcvd = " << bytesRead << endl;
for (int x=0; x<bytesRead; x++)
cout << (unsigned int) msgBuffer[x] << " ";
}
No matter what message I send (either "r rc.all" or "foobar") I always get the same response:
Bytes rcvd = 3
62 13 10
Which is >\r\n. I have tried slowing down the sending of characters to simulate them being typed, but this invokes the same response from the ICSP:
bool serialSend(LPCSTR MESSAGE, PHANDLE hSERIAL)
{
DWORD bytesWritten;
char writeBuff[2];
writeBuff[1] = '\0';
for (UINT x = 0; x <= strnlen(MESSAGE, 64); x++)
{
cout << MESSAGE[x];
writeBuff[0] = MESSAGE[x];
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character '" << MESSAGE[x] << "', error " << GetLastError() << ")" << endl;
Sleep(100);
}
writeBuff[0] = '\n';
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character 'LF', error " << GetLastError() << ")" << endl;
Sleep(100);
writeBuff[0] = '\r';
if (!WriteFile(*hSERIAL, writeBuff, 1, &bytesWritten, NULL))
cout << "\t\tERROR! (character 'CR', error " << GetLastError() << ")" << endl;
cout << endl;
return true;
}
I have set the parameters of the serial connection to match the settings in PuTTY - Byte length, stop bit, parity, flow control, etc. The fact that I get a response at all suggests the connections is not at fault.
What is wrong?
The problem turned out to be the \r\n combination sent at the end of the message.
Sending just \r or just \n does not work. However, sending (char) 13 does - even though that should be the same as \r.
There also needs to be a pause between the sending of each character; 1ms is sufficient.

Interpretation of homework requirements, involving client/server communication

I've been working on an assignment that asks us to implement some code provided to us that allows the creation of a server and client that can communicate. I was to fork a process in main, and then test the various request options available, and then measure the difference in time it took to do this via the child process, or locally using a function. I'm unsure if I've interpretated the requirements correctly though. On top of this, all the timing functions return 0 seconds. Not sure if this is correct or not. I'll post a small portion of the code.
Homework statement (only a small portion):
Measure the invocation delay of a request (i.e. the time between the
invocation of a request until the response comes back.) Compare that
with the time to submit the same request string to a function that
takes a request and returns a reply (as compared to a separate process
that does the same). Submit a report that compares the two.
The function declared before main:
string myfunc(string request){
//string myreq = request;
RequestChannel my_func_channel("control", RequestChannel::CLIENT_SIDE);
string reply1 = my_func_channel.send_request(request);
return reply1;
}
And how I interpreted the directions in code:
int main(int argc, char * argv[]) {
//time variables
time_t start, end;
double time_req_1, time_req_func;
cout << "client.C Starting...\n" << flush;
cout << "Forking new process...\n " << flush;
pid_t childpid = fork();
if(childpid == -1)
cout << "Failed to fork.\n" << flush;
else if(childpid == 0){
cout << "***Loading Dataserver...\n" << flush;
//Load dataserver
RequestChannel my_channel("control", RequestChannel::CLIENT_SIDE);
cout << "***Dataserver Loaded.\n" << flush;
time(&start);
string reply1 = my_channel.send_request("hello");
cout << "***Reply to request 'hello' is '" << reply1 << "'\n" << flush;
time(&end);
time_req_1 = difftime(end,start);
cout <<"\n\nRequest 1 took : "<< time_req_1 << flush;
}
else{//parent
time(&start);
string s = myfunc("hello");
time(&end);
time_req_func = difftime(end,start);
cout <<"\nmyfunc Request took: "<< time_req_func << "\n" << flush;
}
usleep(1000000);
}
This is an abbreviated version of my code, but contains everything you should need to figure out whats going on. Have I done what the directions stated? Also, is it likely that my 0 seconds results are correct?
The time it takes to do it once may be (probably is) too small to measure, so time how long it takes to do it many times and then work out how long each one took.

Http upload with progress info, in C++ (Poco/Boost)

I'm trying to upload a big file to my http server.
And i need to show a upload progress.
How can i get HOW MANY BYTES are sent during the upload?
Need send events to my GUI.
In poco, i don't know where to put the callback.
_session.sendRequest(_request)
_session.receiveResponse(_response)
Any ideas? or links, Thanks!!
This was 'partially' discussed in 08. Ironically I am looking for exactly the same thing.
http://sourceforge.net/mailarchive/message.php?msg_id=20619477
EDIT: 02/14/12
This is not the best, but it works... probably would best to write 1k blocks at a time.
I'd like to see your suggestions.
std::string szMessage;
.... /* fill your szMessage such as with a Form.write() */ ..
CountingOutputStream _cos( _session.sendRequest(_request) )
std::streamsize len = 0;
string::iterator it;
for ( it=szMessage.begin() ; it < szMessage.end(); it++ ) {
len ++;
_cos.put(*it);
if(len %4096 ==0)
cout << "len: " << len << endl;
}
cout << "Chars printed: " << len << endl;
std::istream& rsout = _session.receiveResponse(_response)
std::ostringstream ostr;
StreamCopier::copyStream(rsout, ostr);
// Retrieve response is not necessary if we have the resp code
std::cout << endl; response.write(cout);
std::cout << ostr.str();
int code = response.getStatus();
if (code != nRespCode) {
stringstream s;
s << "HTTP Error(*): " << code;
throw Poco::IOException(s.str());
}