Currently, I use libevent to send and receive messages. The issue I am currently encountering is that I do not receive all messages on the server; and only receive the first message I sent.
Client Code:
for (int i=0; i < 10 ; i++)
{
bufferevent_write(bev, data, strlen(data) + 1);
}
Server Code:
static void read_cb(struct bufferevent* bev, void* arg)
{
char buf[2048] = {};
bufferevent_read(bev, buf, sizeof(buf));
//do something
}
I have modified the client like this:
for (int i=0; i < 10 ; i++)
{
bufferevent_write(bev, data, strlen(data) + 1);
sleep(1)
}
When I add a sleep(1),I can receive all messages.
I would like to avoid using sleep(1). What needs to be added / changed in code, such that all messages can be received, and sleep is not used.
This situation seems to be a bit like a spacket splicing problem, you can try this
static void read_cb(struct bufferevent* bev, void* arg)
{
char bufs[2048];
struct evbuffer *input = bufferevent_get_input(bev);
size_t lens = evbuffer_get_length(input);
char * rline = bufs;
while( lens > 0){
char buf [1024]
memcpy(buf, rline, strlen(data));
rline = rline + strlen(data);
lens = lens -strlen(data);
// use buf do something else
}
}
Related
I have this function which prints the hmac of a string:
char *print_bits(unsigned char *bits, size_t len)
{
int i;
char buf[64], *put = buf;
for(i = 0; i < len; i++){
put += snprintf(put, 64, "%02x", bits[i]);
}
return put;
}
I want to use the result of printf and it send to my client app:
char buffer[64]
len = strlen(buffer);
if(len < BUFFERSIZE)
{
gen_hmac_sha256(global_eid, (unsigned char *) buffer, len + 1);
get_hmac_sha256(global_eid, hmac_sha256_out, HMAC_SHA256_LEN);
printf("App.cpp: hmac sha256 hash: ");
char *buffer2 = print_bits(hmac_sha256_out, 32);
printf("\n");
send(new_sock, buffer2, 64, 0);
}
However, send is not sending the result to the client. Thanks in advance for your help.
In your function print_bits, you are returning address to local variable/array. This will lead to undefined behaviour as you will be pointing to a memory region that you no longer have ownership and some other function/code can modify it.
Since, you are using C++, you can write the same code using std::string.
std::string get_bits_str(unsigned char *bits, size_t len)
{
std::stringstream stream;
for(i = 0; i < len; i++){
stream << std::hex << bits[i] << " ";
return stream.str();
}
std::string buf = print_bits(hmac_sha256_out, 32);
printf("\n");
send(new_sock, buf.c_str(), 64, 0);
Create a buffer to hold the hmac string gotten from the print_bits function using snprintf as shown below:
char buf [64];
char *print_bits(unsigned char *bits, size_t len)
{
int i;
for(i = 0; i < len; i++){
snprintf(buf+i*2, 3, "%02x", bits[i]);
}
return buf;
}
Then in the main function, use the send() system call as shown below to send from server to the client.
len = strlen(buffer);
if(len < BUFFERSIZE)
{
gen_hmac_sha256(global_eid, (unsigned char *) buffer, len + 1);
get_hmac_sha256(global_eid, hmac_sha256_out, HMAC_SHA256_LEN);
printf("App.cpp: hmac sha256 hash: ");
send(new_sock, print_bits(hmac_sha256_out, 32), 64, 0);
}
Note that the hmac algorithm itself is executed inside Intel SGX and has not been shown.
right now, I am currently trying to output the contents of buf.mtext so I can make sure take the correct input before moving on with my program. Everything seems to work fine, except one thing; msgrcv() puts garbage characters into the buffer, and the reciever process outputs garbage characters.
Here is my sender process:
int main (void)
{
int i; // loop counter
int status_01; // result status
int msqid_01; // message queue ID (#1)
key_t msgkey_01; // message-queue key (#1)
unsigned int rand_num;
float temp_rand;
unsigned char eight_bit_num;
unsigned char counter = 0;
unsigned char even_counter = 0;
unsigned char odd_counter = 0;
srand(time(0));
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf_01;
msgkey_01 = MSG_key_01; // defined at top of file
msqid_01 = msgget(msgkey_01, 0666 | IPC_CREAT)
if ((msqid_01 <= -1) { exit(1); }
/* wait for a key stroke at the keyboard ---- */
eight_bit_num = getchar();
buf_01.mtype = 1;
/* send one eight-bit number, one at a time ------------ */
for (i = 0; i < NUM_REPEATS; i++)
{
temp_rand = ((float)rand()/(float)RAND_MAX)*255.0;
rand_num = (int)temp_rand;
eight_bit_num = (unsigned char)rand_num;
if ((eight_bit_num % 2) == 0)
{
printf("Even number: %d\n", eight_bit_num);
even_counter = even_counter + eight_bit_num;
}
else
{
printf("Odd number: %d\n", eight_bit_num);
odd_counter = odd_counter + eight_bit_num;
}
/* update the counters ------------------------------ */
counter = counter + eight_bit_num;
if((eight_bit_num % 2) == 0) { even_counter = even_counter + eight_bit_num; }
else { odd_counter = odd_counter + eight_bit_num; }
buf_01.mtext[0] = eight_bit_num; // copy the 8-bit number
buf_01.mtext[1] = '\0'; // null-terminate it
status_01 = msgsnd(msqid_01, (struct msgbuf *)&buf_01, sizeof(buf_01.mtext), 0);
status_01 = msgctl(msqid_01, IPC_RMID, NULL);
}
Here is my receiver process:
int main() {
struct message {
long mtype;
char mtext[BUFFER_SIZE];
} buf;
int msqid;
key_t msgkey;
msgkey = MSG_key_01;
msqid = msgget(msgkey, 0666); // connect to message queue
if (msqid < 0) {
printf("Failed\n");
exit(1);
}
else {
printf("Connected\n");
}
if (msgrcv(msqid, &buf, BUFFER_SIZE, 0, 0) < 0) { // read message into buf
perror("msgrcv");
exit(1);
}
printf("Data received is: %s \n", buf.mtext);
printf("Done receiving messages.\n");
return 0;
}
The output is usually something like as follows:
Data received is: ▒
Done receiving messages.
I have made sure to clear my message queues each time after running the sender and receiver processes, as well, since I have come to find out this can cause issues. Thanks in advance for your help.
Turns out neither of the suggested solutions were the issue, as I suspected; the sender process actually works just fine. The problem was that I was trying to print buf.mtext instead of buf.mtext[0] which isn't an actual integer value. I fixed the issue by just doing this:
int temp_num = buf.mtext[0];
printf("Data recieved is %d \n", temp_num);
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 am trying to send large amounts of data over a socket, sometimes when I call send (on Windows) it won't send all the data I requested, as expected. So, I wrote a little function that should have solved my problems- but it's causing problems where the data isn't being sent correctly and causing the images to be corrupted. I'm making a simple chat room where you can send images (screenshots) to each other.
Why is my function not working?
How can I make it work?
void _internal_SendFile_alignment_512(SOCKET sock, BYTE *data, DWORD datasize)
{
Sock::Packet packet;
packet.DataSize = datasize;
packet.PacketType = PACKET_FILETRANSFER_INITIATE;
DWORD until = datasize / 512;
send(sock, (const char*)&packet, sizeof(packet), 0);
unsigned int pos = 0;
while( pos != datasize )
{
pos += send(sock, (char *)(data + pos), datasize - pos, 0);
}
}
My receive side is:
public override void OnReceiveData(TcpLib.ConnectionState state)
{
if (state.fileTransfer == true && state.waitingFor > 0)
{
byte[] buffer = new byte[state.AvailableData];
int readBytes = state.Read(buffer, 0, state.AvailableData);
state.waitingFor -= readBytes;
state.bw.Write(buffer);
state.bw.Flush();
if (state.waitingFor == 0)
{
state.bw.Close();
state.hFile.Close();
state.fileTransfer = false;
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
Program.MainForm.log("Ended file transfer with " + ip);
}
}
else if( state.AvailableData > 7)
{
byte[] buffer = new byte[8];
int readBytes = state.Read(buffer, 0, 8);
if (readBytes == 8)
{
Packet packet = ByteArrayToStructure<Packet>(buffer);
if (packet.PacketType == PACKET_FILETRANSFER_INITIATE)
{
IPEndPoint ip = state.RemoteEndPoint as IPEndPoint;
String filename = getUniqueFileName("" + ip.Address);
if (filename == null)
{
Program.MainForm.log("Error getting filename for " + ip);
state.EndConnection();
return;
}
byte[] data = new byte[state.AvailableData];
readBytes = state.Read(data, 0, state.AvailableData);
state.waitingFor = packet.DataSize - readBytes;
state.hFile = new FileStream(filename, FileMode.Append);
state.bw = new BinaryWriter(state.hFile);
state.bw.Write(data);
state.bw.Flush();
state.fileTransfer = true;
Program.MainForm.log("Initiated file transfer with " + ip);
}
}
}
}
It receives all the data, when I debug my code and see that send() does not return the total data size (i.e. it has to be called more than once) and the image gets yellow lines or purple lines in it — I suspect there's something wrong with sending the data.
I mis-understood the question and solution intent. Thanks #Remy Lebeau for the comment to clarify that. Based on that, you can write a sendall() function as given in section 7.3 of http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf
int sendall(int s, char *buf, int *len)
{
int total = 0; // how many bytes we've sent
int bytesleft = *len; // how many we have left to send
int n = 0;
while(total < *len) {
n = send(s, buf+total, bytesleft, 0);
if (n == -1) {
/* print/log error details */
break;
}
total += n;
bytesleft -= n;
}
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
You need to check the returnvalue of send(). In particular, you can't simply assume that it is the number of bytes sent, there is also the case that there was an error. Try this instead:
while(datasize != 0)
{
n = send(...);
if(n == SOCKET_ERROR)
throw exception("send() failed with errorcode #" + to_string(WSAGetLastEror()));
// adjust pointer and remaining number of bytes
datasize -= n;
data += n;
}
BTW:
Make that BYTE const* data, you're not going to modify what it points to.
The rest of your code seems too complicated, in particular you don't solve things by aligning to magic numbers like 512.
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.