I'm trying to get the hang of message queues. For some reason, when displaying the message I typed back into the console, the string sometimes gets truncated, or altered. Does anyone know why this might be occuring?
void *readFromQueue() {
int ret;
mbr = malloc(sizeof(struct msgbuf)); // Allocate space to mbr.
while (TRUE) { // Forever...
ret = (int) msgrcv(msgId, mbr, sizeof(struct msgbuf), myId, MSG_NOERROR | IPC_NOWAIT); // Receive a message
if (ret == -1) { // Check for error.
//perror("Failed to receive message.");
} else {
printf("\t%160s", mbr->mtext);
}
}
}
I discovered that my bug was in my passing of the size of the struct msgbuf instead of the size of msgbuf.mtext.
ret = msgrcv(msgId, mbr, sizeof(mbr->mtext), myId, MSG_NOERROR | IPC_NOWAIT);
Related
I'm trying to send a message from kernel to user space using generic netlink and libnl, the part of my code which does this is implemented as follow:
int struct my_callback(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *obuff;
void *msg_head;
if ((obuff = genlmsg_new(0, GFP_KERNEL)) == NULL) { // I've tried to change the len to NLMSG_GOODSIZE but not worked
pr_err("Failed allocating message to an reply\n");
return 0;
}
if ((msg_head = genlmsg_put_reply(obuff, info, &lunatik_family, 0, LIST_STATES)) == NULL) {
pr_err("Failed to put generic netlink header\n");
return 0;
}
//I've tried to put a genlmsg_end(obuff, msg_head); but didn't work as well
if (genlmsg_reply(obuff, info) < 0) {
pr_err("Failed to send message to user space\n");
return 0;
}
pr_info("Message sent to user-space\n");
return 0;
}
P.s: LIST_STATES is a member of enum and have the value of 3
And my user space code is basically:
static int req_handler(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nlhdr;
struct genlmsghdr *genlhdr;
nlhdr = nlmsg_hdr(msg);
genlhdr = genlmsg_hdr(nlhdr);
printf("Received a message from kernel: %d\n", genlhdr->cmd);
return NL_OK;
}
int socket_init(struct nl_sock *sock)
{
int err = -1;
if ((sock = nl_socket_alloc()) == NULL)
return err;
if ((err = genl_connect(sock)))
return err;
if ((err = genl_ctrl_resolve(sock, LUNATIK_FAMILY)) < 0)
return err;
// I've tried to use NL_CB_VALID, but when I use it I receive no message at all
nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, req_handler, NULL);
return 0;
}
My output on dmesg is:
Message sent to user-space
And my output on user space is:
Received a message from kernel: 0
I should receive 3 instead of 0, I noticed that I'm receiving only the ACK message, but not the message that I'm sending, I would like to know why this is happening and what I'm doing wrong.
The result of genl_ctrl_resolve() is twofold:
If < 0, it's an error code.
If >= 0, it's the family identication number.
You're throwing away your family identication number. Instead of
if ((err = genl_ctrl_resolve(sock, LUNATIK_FAMILY)) < 0)
return err;
, do
if ((lunatik_family = genl_ctrl_resolve(sock, LUNATIK_FAMILY)) < 0)
return lunatik_family;
Later, when you're setting up the Netlink Header, make sure to use it:
if (!genlmsg_put(..., ..., ..., lunatik_family, ..., ..., LIST_STATES, ...))
/* handle error */
And one more thing: nl_socket_modify_cb() also returns an error code. Instead of
nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, req_handler, NULL);
return 0;
do
return nl_socket_modify_cb(sock, NL_CB_MSG_IN, NL_CB_CUSTOM, req_handler, NULL);
So I'm trying to do the following:
I have two participants (let's call them A and B) communicating via TCP socket (send() and recv()). A is sending a counter and a random Nonce, B is just responding with that same message it gets. A then checks if the response matches the sent packet and if yes, it increments the counter and repeats.
This is a code snippet illustrating what A does at the moment:
send(sock, payload, strlen(payload), 0);
struct timeval t_out;
t_out.tv_sec = 0;
t_out.tv_usec = 5000;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,&t_out,sizeof(t_out)) <0)
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (len < 0)
{
print("Timeout reached, recv failed: errno %d", errno);
}
else
{
rx_buffer[len] = 0;
if(strncmp(rx_buffer, payload, payload_len) == 0)
{
pack_nr++;
}
}
Now I'm encountering one problem.
Let's say B, for some reason, has a delay in responding. This causes something like that:
A sends something like "1xyz"
B has a delay ......
A times out and resends something like "1abc"
B's first response ("1xyz") reaches A, A decides that this is the wrong payload
B's second response ("1abc") reaches A too, but A is only executing one recv() and it's unseen for now
A resends something like "1uvw"
A reads "1abc" from recv() and again decides that this is the wrong payload
B's third response ("1uvw") reaches A, and so on and on
So what I'd like to do is to put a recv() in a loop, so that in step 5, A would first look for another response from B until the timeout is reached.
So is there clever way to do this? I was thinking about something like
send(sock, payload, strlen(payload), 0);
int flag = 0;
gettimeofday(&start_time, NULL);
while((tx_time < start_time + timeout) && flag = 0)
{
gettimeofday(&tx_time, NULL);
recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if(rx_buffer is okay)
{
flag = 1;
}
wait_a_bit();
}
if(flag == 1) pack_nr++;
"... B is just responding with that same message it gets. A then checks if the response matches the sent packet ..."
You have a code problem and a terminology problem.
First, the terminology problem: Don't say "matches the sent packet". The data can be sent in one packet or ten packets, TCP doesn't care. You don't receive packets, you receive data that may be split or combined across packets as TCP wishes. It really helps (trust me) to be very precise in your use of words. If you mean a message, say "message". If you mean data, say "data". If you mean a datagram, say "datagram".
Unfortunately, your code problem is enormous. You want B to respond to A with the same message it received. That means you need a protocol that sends and receives messages. TCP is not a message protocol. So you need to implement a message protocol and write code that actually sends and receives messages.
If A write "foobar", B might receive "foobar" or it might first receive "foo" and then later "bar". If A writes "foo" then "bar", B might receive "foobar" or "f" and then "oobar". That's TCP. If you need a message protocol, you need to implement one.
First off, you are not checking for a timeout correctly. recv() could fail for any number of reasons. You need to check errno (or WSAGetLastError() on Windows) to find out WHY it failed. But even if it did actually fail due to timeout, TCP is a byte stream, the delayed data may still show up (especially since 5000 microseconds (0.005 seconds) is way too short a timeout to reliably use for TCP network traffic), but your sender would have moved on. The only sensible thing to do if a timeout occurs in TCP is to close the connection, since you don't know the state of the stream anymore.
In your situation, you are basically implementing an ECHO protocol. Whatever the sender sends just gets echoed back as-is. As such, if you send 4 bytes (which you are not verifying, BTW), then you should keep reading until 4 bytes are received, THEN compare them. If any failure occurs in that process, immediately close the connection.
int sendAll(int sock, void *data, int len)
{
char *ptr = (char*) data;
while (len > 0) {
int sent = send(sock, ptr, len, 0);
if (sent < 0) {
if (errno != EINTR)
return -1;
}
else {
ptr += sent;
len -= sent;
}
}
return 0;
}
int recvAll(int sock, void *data, int len)
{
char *ptr = (char*) data;
while (len > 0) {
int recvd = recv(sock, ptr, len, 0);
if (recvd < 0) {
if (errno != EINTR)
return -1;
}
else if (recvd == 0) {
return 0;
}
else {
ptr += recvd;
len -= recvd;
}
}
return 1;
}
...
int payload_len = strlen(payload);
if (sendAll(sock, payload, payload_len) < 0)
{
// error handling
close(sock);
}
else
{
struct timeval t_out;
t_out.tv_sec = 5;
t_out.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &t_out, sizeof(t_out)) < 0)
{
// error handling
close(sock);
}
else
{
int res = recvAll(sock, rx_buffer, payload_len);
if (res < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
print("Timeout reached");
else
print("recv failed: errno %d", errno);
close(sock);
}
else if (res == 0)
{
print("disconnected");
close(sock);
}
else
{
if (memcmp(rx_buffer, payload, payload_len) == 0)
{
print("data matches");
pack_nr++;
}
else
print("data mismatch!");
}
}
}
I am working on a project for school and have run into the following problem. My server is blocking out on recv() despite my client already sending its full message.
This is what I want to happen:
Server Client
recv() <---- send()
send() ----> recv()
This is what is happening:
Server Client
recv() <---- send()
recv() ----- recv()
Some Background
2 Weeks ago I created the client by itself with an already coded server application. When I coded the client it functioned properly with the provided server, so I want to say that the client is wrong, but I don't know how to get the server that I coded to recognize that no more data will be coming in.
Code
Here is the code that I believe is relevant:
Client:
bytesSent = 0;
retVal = send(sock, phrase, msgLen, 0);
bytesSent = retVal;
while (bytesSent < msgLen) {
retVal = send(sock, phrase + bytesSent, msgLen - bytesSent, 0);
if (retVal == SOCKET_ERROR) {
DisplayFatalErr("send() function failed.");
exit(1);
}
bytesSent += retVal;
// May need to re-call send in order to keep sending the data.
}
...
bytesRead = 0;
while (bytesRead < msgLen) {
retVal = recv(sock, rcvBuffer, RCVBUFSIZ - 1, 0);
if (retVal <= 0) {
DisplayFatalErr("recv() function failed.");
exit(1);
}
bytesRead += retVal;
for (int i = 0; i < retVal; i++) {
printf("%c", rcvBuffer[i]);
}
}
Server:
char* rcvBuffer[RCVBUFSIZ]; // RCVBUFSIZ = 50
char* msg = "";
int bytesRead = 0;
do {
if ((bytesRead = recv(clientSock, rcvBuffer, RCVBUFSIZ - 1, 0)) == 0) {
break;
}
if (bytesRead < 0) {
return -1;
}
char* msgConcatenated;
int msgLen = strlen(msg);
msgConcatenated = malloc(msgLen + bytesRead);
if (msgConcatenated != NULL) {
int newMsgLen = strlen(msgConcatenated);
strncpy_s(msgConcatenated, newMsgLen, msg, msgLen);
strncat_s(msgConcatenated, newMsgLen, rcvBuffer, bytesRead);
msg = msgConcatenated;
}
} while (bytesRead != 0);
Let me know if I need to provide extra information.
When using TCP, to signal the other end of the socket that no more data will be sent, a packet with the FIN flag set must be sent. This is accomplished in Winsock by calling the function shutdown with SD_SEND as the second parameter. This will cause the program on the other end of the socket to no longer block when calling recv. Instead, recv will return 0 indicating that the connection has been gracefully closed (unless there is data left that has not been read yet). See the Microsoft documentation on the shutdown function for further information. This documentation page also contains some helpful information about graceful socket closure.
Also, as has been pointed out in the comments, your code contains a memory leak in the following line:
msg = msgConcatenated
In that line, you reassign msg without first freeing the memory that msg is pointing to. Unfortunately, fixing that memory leak is not easy, because you can't simply call free on msg before reassigning it. This is because, in the first iteration of the loop, msg can also be pointing to something else than dynamically allocated memory. Therefore, to fix the leak, you would also have to keep track of what type of memory msg is pointing to, or make it always point to dynamically allocated memory, even when the string is empty (i.e. when it only contains the terminating null character).
I'm trying to implement a program similar to this example:
the program passes an integer among 4 processes and each process decrements the integer
each process have its own mailbox
Each process check its mailbox for variable "counter" and if it was found it will decrements it
Then it send the counter variable to the next process
but there is a bug in the program and I cant find it.
note that this an assignment and Im just looking for tips that helps me find the bug.
typedef struct {
int counter;
char data[256];
int id; //id of the process that previously decremented the counter
} msg;
int main(int arqc, char *argv[]){
int key=9;
int id=0;
pid_t pid;
int num=5;
int i, k;
int arr[5];
//create 5 forks
if (arqc != 2){
num=5;
}else{
int ret = sscanf(argv[1], "%d", &num);
if (ret != 1)return 0;
}
for(i=0 ; i<num ; i++){
if ((pid = fork()) == -1) {
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
}
if (pid == 0) {
id=i;
}
else {
break;
}
}
//process 1 to n comes here
msg m;
int boxid = msgget(id, 0600 | IPC_CREAT);
arr[id]=boxid;
int firstRun=1;
//initiate the first move
if((id==0)&&(firstRun==1)){
m.counter = INIT_COUNTER;
//send msg to next process
msgsnd(arr[id], &m, sizeof(msg), 0); //send msg to own inbox
firstRun=0;
}
while(1){
//check inbox of current process
int rec = msgrcv(arr[id], &m, sizeof(msg), 0, 0);
printf("Im %d, counter is %d, rec is %d\n",id, m.counter, rec);
int index;
if(id==num){
index=0;
}else{
index=id+1;
}
//send message to the next inbox
int sent = msgsnd(arr[index], &m, sizeof(m), 0);
printf( "Error opening file: %s\n", strerror( errno ) );
sleep(1);
}
}
Your initial msgsnd is failing with an invalid argument and everything get munged from there on.
SysV message queues require a message type field as the first field in a message so you need to do something like this.
typedef struct
{
long int mtype;
int counter;
char data[256];
int id; //id of the process that previously decremented the counter
} msg;
You also have to set the message to something and set the correct length before you send it.
//initiate the first move
if ((id == 0) && (firstRun == 1))
{
m.mtype = 100;
m.counter = INIT_COUNTER;
strncpy(m.data, "some kind of message is nice", sizeof(m.data));
m.id = id;
size_t msgsize = sizeof(msg) - sizeof(long int);
//send msg to next process
int sent = msgsnd(arr[id], &m, msgsize, 0); //send msg to own inbox
if (sent == -1)
{
perror("msgsend");
exit(1);
}
firstRun = 0;
}
You run into problems beyond this (e.g. set the correct size on the msgrcvs) but this should get you over the initial hump.
First of all, it is unreasonable to expect the SO crowd to just solve the (homework?) problem for you without any effort on your side. It is unclear what the problem is, how the program behaves currently, and what steps were made to debug it.
Rants aside, I'd recommend cutting out all the steps leaving only two participants and getting it to work in that simple configuration. Once it works, add another one, make sure it still works and so on.
I am studing serial communication with win32 using C now. reading from serial port is given as below.
DWORD dwEventMask;
DWORD dwSize;
if(!SetCommMask(hSerial, EV_RXCHAR)){
//Error handling
printf("Error Setting Comm Mask \n");
}
if(WaitCommEvent(hSerial, &dwEventMask, NULL))
{
unsigned char szBuf[1024];
DWORD dwIncommingReadSize;
do
{
if(ReadFile(hSerial, &szBuf, 1, &dwIncommingReadSize, NULL) != 0) {
//Handle Error Condition
}
if(dwIncommingReadSize > 0)
{
dwSize += dwIncommingReadSize;
sb.sputn(&szBuf, dwIncommingReadSize);
printf("Reading from port \n");
}
else{
//Handle Error Condition
}
printf("Reading data from port \n");
} while(dwIncommingReadSize > 0);
}
else
{
//Handle Error Condition
}
They have used DWORD dwIncommingReadSize for while condition (while(dwIncommingReadSize > 0);.
Please explain how this condition is satifisfied. No modification can be seen for that.
Again please explain following part.
if(dwIncommingReadSize > 0)
{
dwSize += dwIncommingReadSize;
sb.sputn(&szBuf, dwIncommingReadSize);
printf("Reading from port \n");
}
This line:
if(ReadFile(hSerial, &szBuf, 1, &dwIncommingReadSize, NULL)
passes the address of dwIncommingReadSize (however badly spelt it may be) to the function so it can change it to whatever it wants.
It's similar to:
void fn (int *x) { *x = 42; }
:
int xyzzy = 1;
fn (&xyzzy);
// Here, xyzzy is now 42.
In terms of your second question, it's a little hard to tell without seeing more of the code, but it looks like it's simply increasing a "total size" variable for each block of data read in (plus whatever sb.sputn is supposed to do).
This is typical where a single read may not get all the data you want - you simply store what you got and then go back for more.