I have a linux machine and a Windows machine I have a C++ program witch acts as a server on the linux machine and a Qt application witch acts as a client on windows machine. I use the socket as a encryption key (basic xor encryption)
The problem is when I hit multiple times connect I get bogus strings. I think the problem is in qt application here is my code. I have tried to put a global flag busy to prevent the user from hitting the connect button manny times but this flag never gets triggered.
Why? Should I use a mutex? If yes how?
void MainWindow::performRead()
{
QTcpSocket * sock = static_cast<QTcpSocket*>(this->sender());
if (key == 0)
{
busy = true;
QString recv(sock->readLine());
key = recv.toInt();
qDebug() << "Cheia este " << key;
char * response = enc_dec("#AUTH|admin|admin",strlen("#AUTH|admin|admin"),key);
sock->write(response);
}
else
{
busy = true;
while (sock->bytesAvailable() > 0)
{
unsigned short word;
sock->read((char*)(&word),2);
qDebug()<<word;
QByteArray bts = sock->read(word);
char * decodat = enc_dec((char*)bts.data(),bts.length() - 2,key);
char testx[2];
sock->peek(&testx[0],2);
qDebug() << decodat;
}
}
busy = false;
}
void MainWindow::on_pushButton_clicked()
{
if (!busy)
{
key = 0;
QTcpSocket * sock = new QTcpSocket();
connect(sock,SIGNAL(readyRead()),this,SLOT(performRead()));
sock->connectToHost("194.110.212.46",6550);
}
else qDebug()<<"Can't you see I am busy??" << endl;
}
char * enc_dec(char * str,int len, int key)
{
unsigned char keys[2];
keys[0] = (unsigned char)key;
keys[1] = keys[0] ^ 255;
char * nou = new char[len + 1];
nou[len] = '\0';
for (int i = 0; i < len; i++)
{
char tmpy = str[i] ^ keys[i % 2];
nou[i] = tmpy;
}
return nou;
}
Your code is pretty messed up, here are my suggestions:
Do not connect the socket on every button hit - you are overwriting what you had before, and do unnecessary work - TCP connection establishment is expensive,
Maybe have a "Connect" and "Disconnect" buttons, and only allow reading from socket when connection is established,
Try making sure everything works without your "encryption" first,
Use real encryption after that.
Related
I am trying to establisch a serial port connection to my Aviator 7000 weighing scale using Qt c++. The expected result would be a succesfull communication through the use of a byte command.
Sadly I don't receive any bytes back from the scale. below you can find what I tried so far:
const int Max_attempts = 5;
const int Max_sleep = 125;
int attemps;
attemps = 0;
while (true)
{
int enq {5};
QByteArray bytes;
bytes.setNum(enq);
m_serial->write(bytes);
m_serial->waitForReadyRead(Max_sleep);
if (m_serial->bytesAvailable() !=0)
{
qDebug() << m_serial->bytesAvailable() ;
qDebug() << "connected" << m_serial->readAll();
break;
}
attemps += 1;
if (attemps == Max_attempts)
{
qDebug() << "no connection established";
break;
}
}
Kind regards,
Tibo
According to this manual you are supposed to send a byte 0x05 but you are sending 0x35 (the character "5").
Use
bytes.append('\X05');
I've got a C++ server that communicates with multiple clients. It uses a vector to store the handles to the sockets for those clients (playerSockets in the code below). At the end of the "game" I want the server to loop through that vector and write the same string to each client. However, sometimes the data that the client reads (and then displays) is "corrupted" as you can see in the screenshot, but this doesn't happen for the first client, only the second. I can't figure out why this is happening! I use this same technique (looping and writing) earlier in the program and it always works fine in that instance.
Here is what it is supposed to be shown:
Here and here's what I get:
Here is the server code that writes:
std::string announcement = "";
if (playerWon) {
...
}
} else {
announcement = "?No one won the game!\nGAME BOARD: " + cn.getGameBoard();
for (int player : gameData->playerSockets) {
write(player, announcement.c_str(), announcement.size() + 1);
}
}
And here's the client code that reads. Keep in mind that more than one client is running and connected to the server, and this issue only happens with a client OTHER THAN the first client in the server's loop:
static bool readMyTurn(int clientSd) {
...
char buf[BUFSIZE];
read(clientSd, buf, BUFSIZE);
string myTurn(buf);
cout << "MYMYMYMY: " << myTurn << endl;
myTurn.erase(0, 1);
cout << myTurn << endl;
...
}
UPDATE
Here is my current code to read until encountering the null-terminator character.
string readOneStringFromServer(int clientSd, string &leftovers) {
ssize_t nullTerminatorPosition = 0;
std::string stringToReturn = "";
do {
char buf[BUFSIZE];
ssize_t bytesRead = read(clientSd, buf, BUFSIZE);
nullTerminatorPosition = findPositionOfNullTerminator(buf, bytesRead);
// found a null terminator
if (nullTerminatorPosition != -1) {
// create a buffer to hold all of the chars from buf1 up to and including the null terminator
char upToNullTerminator[nullTerminatorPosition + 1];
// get those chars from buf1 and put them into buf2 (including the null terminator)
for (int i = 0; i < nullTerminatorPosition + 1; ++i) {
upToNullTerminator[i] = buf[i];
}
// use buf2 to create a string
stringToReturn += upToNullTerminator;
// check if there are leftover bytes after the null terminator
int leftoverBytes = bytesRead - nullTerminatorPosition - 1;
if (leftoverBytes != 0) {
// if there are, create a char array of that size
char leftoverChars[leftoverBytes];
// loop through buf1 and add the leftover chars to buf3
for (int i = nullTerminatorPosition + 1; i < bytesRead; ++i) {
leftoverChars[i - (nullTerminatorPosition + 1)] = buf[i];
}
// make a string out of those leftover chars
leftovers = leftoverChars;
} else {
// if there are no leftover bytes, then we want to "erase" what is currently held in leftovers so that
// it doesn't get passed to the next function call
leftovers = "";
}
// didn't find one
} else {
stringToReturn += buf;
}
} while (nullTerminatorPosition == -1);
return stringToReturn;
}
I have quite a lot of debugging monitoring all over my program so whenever something undesired happens a message appears in XCode with "std::cout" showing what happended, where it happened, and so on.
While I was testing the app on an iPhone or iPad connected to my computer, this worked as well (as I always had XCode open to show the fault).
But now I installed the app on devices of several beta-testers and they do not see these messages...
Rewriting the code to route all the "cout" to a string would cost a lot of time as they appear everywhere in several classes and sub classes, etc...
is there a possibility of simply reading out the last line of the output console or detecting the event of writing to the console and then copying it over to a separate string?
This is something I've done on some android projects to forward stdout and stderr to logcat. You could use this same approach to forwards the stdout/stderr to anywhere you want:
struct stream {
const char *name;
int fd[2];
FILE *src;
};
static void*
log_thread(void *arg)
{
struct stream *stream = arg;
char buf[4000], *off = buf, *nl; // Can't be too big or android stops logging
for (ssize_t r = 0;;off += r, r = 0) {
if (off - buf < sizeof(buf) - 1) {
errno = 0;
r = read(stream->fd[0], off, (sizeof(buf) - 1) - (off - buf));
if (r <= 0) { if (errno == EINTR) continue; else break; }
off[r] = 0;
}
if ((nl = strrchr(off, '\n'))) {
*nl = 0; ++nl;
__android_log_write(ANDROID_LOG_INFO, stream->name, buf);
r = (off + r) - nl;
memcpy((off = buf), nl, r);
} else if (off - buf >= sizeof(buf)) {
__android_log_write(ANDROID_LOG_INFO, stream->name, buf);
r = 0; off = buf;
}
}
close(stream->fd[0]);
close(stream->fd[1]);
return NULL;
}
__attribute__((constructor)) static void
log_init(void) {
static struct stream stream[] = { { .name = "stdout" }, { .name = "stderr" } };
stream[0].src = stdout; stream[1].src = stderr;
for (size_t i = 0; i < sizeof(stream) / sizeof(stream[0]); ++i) {
setvbuf(stream[i].src, NULL, _IOLBF, BUFSIZ);
pipe(stream[i].fd);
dup2(stream[i].fd[1], fileno(stream[i].src));
pthread_t thread;
pthread_create(&thread, 0, log_thread, &stream[i]);
pthread_detach(thread);
}
}
I have a dll which hooks recv function of a network application. The code works just fine (it makes everything its suppossed to do), but if i add output logs to a file, the connection closes after some time working (the server side application throws the error "An existing connection was forcibly closed by the remote host").
That time isnt even always the same, sometimes it closes almost when initializing connection, other times i can use the connection for few secs before it gets closed. It does not give any error or warning message. If i remove the log code, the application runs fine. Any idea why is that happening? I run it in windows 8 x64
Also, even erasing the log code, the connection keeps being closed in windows xp x32.
Here is the recv hook code:
int __stdcall NewRecv(SOCKET socket, char *data, int datalen, int flags) {
int result = 0;
if(!IsLoginServerPacket(&socket)) {
INT size = 0,opcode = 0,temp = 0,writer = 0,second_op = 0;
do {
size = 0;
second_op = 0;
temp = 0;
writer = 0;
while(temp < 2) {
temp += recvPacket(socket,recv_gs_buffer+writer,2 - temp,flags);
writer += temp;
}
size = (*(SHORT*)recv_gs_buffer) & 0xffff;
// THIS IS THE LOG CODE
FILE *f = fopen("debug.txt", "a");
fprintf(f, "datalen=%d, size=%d\n", datalen, size);
fclose(f);
while(temp < size) {
temp += recvPacket(socket,recv_gs_buffer+writer,size - temp,flags);
writer += temp;
}
Decrypt(&gs_crypt,recv_gs_buffer+2,size-2);
opcode = (*(recv_gs_buffer+2) & 0xff);
if(opcode == EXTENDED_PROTOCOL) {
second_op = *(SHORT*)(recv_gs_buffer + 3);
second_op &= 0xffff;
HandleGameServerPacket(second_op,recv_gs_buffer+2,size-2);
}
} while(second_op == 0x8a || second_op == 0x8b);
if(opcode == 0x00) {
SetKey(recv_gs_buffer+4,&gs_crypt);
SetKey(recv_gs_buffer+4,&client_crypt);
} else
Crypt(&client_crypt,recv_gs_buffer+2,size-2);
int i = 0;
while(i < size) {
data[i] = recv_gs_buffer[i];
i++;
}
//memcpy(data,recv_gs_buffer,size);
result = size;
} else
result = recvPacket(socket,data,datalen,flags);
return result;
}
I just found the problem and its solution.
The injected app was configuring sockets on non blocking mode. Any little delay was making it throwing WSAEWOULDBLOCK (10035 error code). All i had to do to fix it was to retry the recv request if i get any error
INT val = 0;
while(temp < 2) {
val = recvPacket(socket,recv_gs_buffer+writer,2 - temp,flags);
if(val > 0) {
temp += val;
writer += temp;
}
}
And
val = 0;
while(temp < size) {
val = recvPacket(socket,recv_gs_buffer+writer,size - temp,flags);
if(val > 0) {
temp += val;
writer += temp;
}
}
I have 1 server that's built with C++ and c sockets in Unix. The client is using QT and the socket api that comes with it.
The server sends 345 bytes of data to the client.
Sending message from server:
void Moderator::testSynch(){
int type = (int) SYNCRHONIZE_M;
//Update all connected clients with info about other clients
for(int i = 0; i<nrOfClients_; i++){
const TcpSocket &clientSocket = clients_[i].getSocket();
int clientID = clients_[i].getID();
int tempType = htonl(type);
int tempClientID = htonl(clientID);
int tempNrOfClients = htonl(funNrOfClients);
clientSocket.writeData((const char*) &tempType, sizeof(tempType));
clientSocket.writeData((const char*) &tempClientID, sizeof(tempClientID));
clientSocket.writeData((const char*) &tempNrOfClients, sizeof(tempNrOfClients));
for(int j = 0; j<nrOfClients; j++){ //Send info about connectecd clients
int tempLength = (int) clients_[j].getName().length();
int tempID = clients_[j].getID();
string tempName = clients_[j].getName();
tempID = htonl(tempID);
tempLength = htonl(tempLength);
clientSocket.writeData((const char*) &tempID, sizeof(tempID));
clientSocket.writeData((const char*) &tempLength, sizeof(tempLength));
clientSocket.writeData(tempName.c_str(), (int)tempName.length());
}
}
}
bool TcpSocket::writeData(const char* buffer, int length)const{
size_t bytesLeft = length;
ssize_t bytesWritten = 0;
while((bytesWritten = write(socketFD_, buffer, bytesLeft)) > 0){
bytesLeft -= bytesWritten;
buffer += bytesWritten;
}
return bytesLeft == 0;
}
Reading message in client:
void ChatClient::readMessage(Message &message){
if(socket_->readData((char*) &type, sizeof(type))){
if(type == SYNCRHONIZE_M){
int nrOfUsers = 0;
socket_->readData((char*) &ID_, sizeof(ID_)); //Set the client ID that server gave us
socket_->readData((char*) &nrOfUsers, sizeof(nrOfUsers));
ID_ = ntohl(ID_);
nrOfUsers = ntohl(nrOfUsers);
qDebug("%s=%d", "nrOfUsers", nrOfUsers);
message.setMessageType(SYNCRHONIZE_M);
messageOK = true;
for(int i = 0; i<nrOfUsers; i++){ //Update client with all connected users to server
int userID = 0;
int nameLength = 0;
socket_->readData((char*) &userID, sizeof(userID));
socket_->readData((char*) &nameLength, sizeof(nameLength));
userID = ntohl(userID);
nameLength = ntohl(nameLength);
if(nameLength > 0){
qDebug("%s=%d", "nameLength", nameLength);
buffer = new char[nameLength];
socket_->readData(buffer, nameLength);
message.addUser(ConnectedUser(buffer, nameLength, userID));
delete [] buffer;
}
}
}
}
}
bool TcpSocket::readData(char* buffer, int length){
int bytesLeft = length;
int bytesRead = 0;
while((bytesRead = qSocket_->read(buffer, bytesLeft)) > 0){
bytesLeft -= bytesRead;
buffer += bytesRead;
}
return bytesLeft == 0;
}
The problem i'm having is sometimes the entire message from server is not available at once.
For example, first 45 bytes is available in the client. The client then tries to read the entire message (345 bytes) which results in weird behavior. Immediately after the client is done reading the next 300 bytes becomes available.
What is the best way to send messages between sockets? Also, how can I determine if the entire message have been received?
You have some notion of a "message" that exists only in your head. Nothing in your code reflects that. If you have an application protocol that involves a "message" that is sent, then you need to write code to send a message and code to receive a message based on your protocol's definition of a message. TCP only provides streams of bytes and doesn't glue them together for the application into anything bigger than one byte.