I'm trying to implement a number of IPC methods in the same code using the following steps:
1 - Process1 opens a message queue and reads the message sent from Process2
2 - Process1 closes and unlinks the message queue
3 - Process1 writes something to a shared memory.
At step 3 any shm_open(), memset() or memcpy() system calls fail and Eclipse hangs in a new window that says "can't find a source file at ***" for whatever function I call.
When I disable the queue receive operation and just do the shared memory everything works fine.
So I'm suspecting that there is some unfinished business happening within the queue which is blocking any further calls from the process
Here is the problem in code: (just added the relevant part)
...
static int receiveFromQ(char *msgQName)
{
int msgQFD;
char buffer[33];
/* Create and open the communication message queue */
msgQFD = mq_open(msgQName, O_RDONLY | O_CREAT, 0660, NULL);
/* Read the message from the queue and store it in the reception buffer */
memset(buffer, 0, sizeof(buffer));
mq_receive(msgQFD, buffer, sizeof(buffer), NULL); // This is a blocking point until a message is received
/* Use the data received ... */
/* Close the queue */
mq_close(msgQFD);
/* Remove the message queue */
mq_unlink(msgQName);
return 1;
}
int main(void)
{
char *key = SM_KEY;
int shmFD;
/* Receive the data from the queue */
int ret = receiveFromQ(MSGQ_NAME);
/* Creates a shared memory object in a kernel space, with size = 0 */
shmFD = shm_open(key, O_CREAT | O_RDWR | O_TRUNC, 0660); //The software stops here!
...
}
Instead of creating the shared memory, the software hangs at the shm_open() and claims that the source for the shm_open is not found.
As mentioned by #Petesh, the problem was inside the /* use the data received */ part which I omitted from the code because I thought it is irrelevant! To clarify: in this part I made a mistake with the size of data copied using memcpy() which caused a buffer overflow. This did not show any error but somehow blocked further processing of the program.
Thank you all for the useful comments.
memset(buffer, 0, sizeof(buffer));
This will set buffer[0] = 0 because sizeof(buffer) = sizeof(char*) = 1.
Better idea are:
char buffer[33] = {0};
Or
#define BUFFER_LEN 33U
...
char buffer[BUFFER_LEN];
...
memset(buffer, 0, sizeof(char) * BUFFER_LEN);
Or
memset(buffer, 0, sizeof(buffer) / sizeof(buffer[0]);
sizeof(buffer) / sizeof(buffer[0] calculate size of fixed array (non pointers allocate using malloc). So result will be 33.
Related
I have a function that receives a descriptor (you know, one of those things that open() and socket() spit), reads from it and does something with the data:
int do_something(int fd);
I want to test this function. Preferably, the input data should sit right next to the test assert for the sake of easy debugging. (Therefore, actual file reading should be avoided.) In my mind, the ideal would be something like
unsigned char test_input[] = { 1, 2, 3 };
int fd = char_array_to_fd(test_input);
ck_assert(do_something(fd) == 1234);
(ck_assert is from the Check framework. It's just a typical unit test assert.)
Is there a way to implement char_array_to_fd()? I don't mind if I need to NULL-terminate the array or send the length in.
I imagine that I can open a socket to myself and write on one end so the test function receives the data on the other end. I just don't want to write something awkward and find out that Unix had something less contrived all along. The solution should be any-Unix friendly.
(Basically, I'm asking for a C equivalent of ByteArrayInputStream.)
Alternatively: Should I be thinking in some other way to solve this problem?
On Linux, you can use memfd_create() to create a memory-backed temporary file:
unsigned char test_input[] = ...;
int fd = memfd_create( "test_input", 0 );
// write test data to the the "file"
write( fd, test_input, sizeof( test_input );
// reset file descriptor to the start of the "file"
lseek( fd, 0, SEEK_SET );
Note that completely lacks error checking.
You can use mkstemp to make a temporary file and write to it or read from it:
int fd = mkstemp("tempXXXXXX");
If you want something more dynamic, you can use socketpair to create a pair of connected sockets.
int pair[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, pair);
You can then fork process or thread to interact with your program under test.
#ChrisDodd's answer is already accepted, but I wanted to add the pipes solution I had developed (thanks to #Someprogrammerdude's comment) for completeness sake:
struct writer_args {
int fd;
unsigned char *buffer;
size_t size;
};
/* Pipe writer thread function */
void *write_buffer(void *_args)
{
struct writer_args *args = _args;
/*
* error handling omitted.
* Should probably also be thrown into a loop, in case it writes less
* than args->size.
*/
write(args->fd, args->buffer, args->size);
close(args->fd);
return NULL;
}
/*
* Wrapper for quick & easy testing of the do_something() function.
* Replaces the fd parameter for a char array and its size.
*/
static int __do_something(unsigned char *input, size_t size)
{
pthread_t writer_thread;
struct writer_args args;
int fd[2];
int result;
pipe(fd); /* error handling omitted */
/* fd[0] is for reading, fd[1] is for writing */
/*
* We want one thread for reading, another one for writing.
* This is because pipes have a nonstandardized maximum buffer capacity.
* If we write too much without reading, it will block forever.
*/
args.fd = fd[1];
args.buffer = input;
args.size = size;
/* error handling omitted */
pthread_create(&writer_thread, NULL, write_buffer, &args);
result = do_something(fd[0]);
close(fd[0]);
pthread_join(writer_thread, NULL); /* error handling omitted */
return result;
}
Then, I can keep testing do_something as much as I want:
ret = __do_something(input1, input1_size);
if (ret != 1234)
fprintf(stderr, "Fail. Expected:1234 Actual:%d\n", ret);
ret = __do_something(input2, input2_size);
if (ret != 0)
fprintf(stderr, "Fail. Expected:0 Actual:%d\n", ret);
ret = __do_something(input3, input3_size);
if (ret != 555)
fprintf(stderr, "Fail. Expected:555 Actual:%d\n", ret);
...
I am trying to make a simple server client program in C. On the client I try to receive the message from the server, but the size of the message is not predetermined. Therefore, I want to check how many bytes are coming in, and malloc the appropriate size.
I tried to use ioctl but it seems like it gets the info I want too late.
This is what I have.
char *message_from_server;
int length;
while(1){
ioctl(socket, FIONREAD, &length);
message_from_server = malloc(length);
read(socket, message_from_server, length);
}
The first time I use it, length is 0. The second time, length is equal to that of the first message. If I put the line ioctl(socket, FIONREAD, &length); after i read, that might give me trouble with mallocing the correct amount of space. Is this even a valid way to solve my problem?
I have heard that one can use realloc to solve my problem, but I am struggling to see how to it so solve my problem. If that is a better way to do it, I would be happy for any tips.
Thanks!
realloc allows you to increase the size of a memory block, preserving its content.
So, in your case:
read size of incoming packet
update memory block to store packet, preserving what have been read previously
read the packet
goto 1. or exit
Your code should look like:
/* memory to store message, initially, no memory */
char *message_from_server = NULL;
/* size of memory */
int total_length = 0;
/* sizeof incoming packet*/
int packet_lentgh;
/* position to write in memory */
int offset;
while(1){
/* read size of incoming packet*/
ioctl(socket, FIONREAD, &packet_lentgh);
if (0 != packet_lentgh)
{
/* something is ready to be read on socket */
/* update memory size */
total_length += packet_lentgh;
/* allocate much memory*/
message_from_server = realloc(message_from_server, total_length);
if (NULL == message_from_server)
{
perror("realloc");
abort();
}
/* compute the position to write in memory */
offset = total_length - packet_lentgh;
/* read the packet */
read(socket, message_from_server + offset, packet_lentgh);
}
else
{
/* nothing to read
wait for packet or stop loop... */
}
}
The script file has over 6000 bytes which is copied into a buffer.The contents of the buffer are then written to the device connected to the serial port.However the write function only returns 4608 bytes whereas the buffer contains 6117 bytes.I'm unable to understand why this happens.
{
FILE *ptr;
long numbytes;
int i;
ptr=fopen("compass_script(1).4th","r");//Opening the script file
if(ptr==NULL)
return 1;
fseek(ptr,0,SEEK_END);
numbytes = ftell(ptr);//Number of bytes in the script
printf("number of bytes in the calibration script %ld\n",numbytes);
//Number of bytes in the script is 6117.
fseek(ptr,0,SEEK_SET);
char writebuffer[numbytes];//Creating a buffer to copy the file
if(writebuffer == NULL)
return 1;
int s=fread(writebuffer,sizeof(char),numbytes,ptr);
//Transferring contents into the buffer
perror("fread");
fclose(ptr);
fd = open("/dev/ttyUSB3",O_RDWR | O_NOCTTY | O_NONBLOCK);
//Opening serial port
speed_t baud=B115200;
struct termios serialset;//Setting a baud rate for communication
tcgetattr(fd,&serialset);
cfsetispeed(&serialset,baud);
cfsetospeed(&serialset,baud);
tcsetattr(fd,TCSANOW,&serialset);
long bytesw=0;
tcflush(fd,TCIFLUSH);
printf("\nnumbytes %ld",numbytes);
bytesw=write(fd,writebuffer,numbytes);
//Writing the script into the device connected to the serial port
printf("bytes written%ld\n",bytesw);//Only 4608 bytes are written
close (fd);
return 0;
}
Well, that's the specification. When you write to a file, your process normally is blocked until the whole data is written. And this means your process will run again only when all the data has been written to the disk buffers. This is not true for devices, as the device driver is the responsible of determining how much data is to be written in one pass. This means that, depending on the device driver, you'll get all data driven, only part of it, or even none at all. That simply depends on the device, and how the driver implements its control.
On the floor, device drivers normally have a limited amount of memory to fill buffers and are capable of a limited amount of data to be accepted. There are two policies here, the driver can block the process until more buffer space is available to process it, or it can return with a partial write only.
It's your program resposibility to accept a partial read and continue writing the rest of the buffer, or to pass back the problem to the client module and return only a partial write again. This approach is the most flexible one, and is the one implemented everywhere. Now you have a reason for your partial write, but the ball is on your roof, you have to decide what to do next.
Also, be careful, as you use long for the ftell() function call return value and int for the fwrite() function call... Although your amount of data is not huge and it's not probable that this values cannot be converted to long and int respectively, the return type of both calls is size_t and ssize_t resp. (like the speed_t type you use for the baudrate values) long can be 32bit and size_t a 64bit type.
The best thing you can do is to ensure the whole buffer is written by some code snippet like the next one:
char *p = buffer;
while (numbytes > 0) {
ssize_t n = write(fd, p, numbytes);
if (n < 0) {
perror("write");
/* driver signals some error */
return 1;
}
/* writing 0 bytes is weird, but possible, consider putting
* some code here to cope for that possibility. */
/* n >= 0 */
/* update pointer and numbytes */
p += n;
numbytes -= n;
}
/* if we get here, we have written all numbytes */
For an assignment we have to create C program that functions similar to the cat command. The first hand-in requires it to mimic very minimal operations of cat....i.e print to output, redirect. The issue I'm having is that one requirement is to print an error in the case that an output file residing on a usb drive is lost, i.e usb pulled out whilst redirecting stdout to it.
How do I catch such an error, also how can perform a test-case for that particular error ??
Many Thanks....really have no idea
UPDATE CODE TEMP
int main(){
char c;
while((c = getchar()) != EOF){
putchar(c);
// Ensure newly created file exists
}
return EXIT_SUCCESS;
}
Assuming you are using fprintf(), from the man pages:
On success, the total number of characters written is returned.
So:
store the size of the char array you will write into a variable x
if fprintf() is less than x, the writing was interrupted.
exit gracefully
EDIT:
There are 2 things I'm thinking of:
1: When putchar() fails, it indicates an error when writing to the file. Since writing one byte doesn't take very long, this should be unlikely since it will be in a safe state once the byte is written (or you assume).
You can do this like so
if(putchar(c) == EOF){
//write error
}
2: If you're asked to quit the instant you detect a file removal, then you need to monitor the directory. Luckily, you're only looking at one directory. However that while loop gets in the way of things because getchar() is a blocking function (cannot return until something happens). You should use inotify to monitor the directory, then probably poll to poll the file descriptor of inotify(). When I did this I used select because we were forced to.
Some kind of an idea how to monitor a directory with inotify()
int length, i = 0;
char buffer[EVENT_BUF_LEN];
memset(buffer, 0, EVENT_BUF_LEN*sizeof(char));
//init inotify
fd = inotify_init();
if(fd < 0){
perror("inotify init");
}
//add directory to watch list
wd = inotify_add_watch(fd, path , IN_DELETE |
IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
//wait for event, since read() blocks
length = read( fd, buffer, EVENT_BUF_LEN );
if ( length < 0 ) {
perror("zero event length");
}
struct inotify_event *event;
while (i < length){
//cast the event to a char buffer
event = (struct inotify_event*) &buffer[i];
if (event->len){
//this was a custom function of mine
storeEvent(event);
}
i += EVENT_SIZE + event->len;
}
You'll have to check which attributes to use when adding a directory (like IN_DELETE or IN_MODIFY) since they will determine what triggers an inotify() event. Note this code will only detect one event, and blocks at the read() statement.
I created this program to pass a message to a parent process. I want the parent process to print out the message it receives. I'm not sure if this is an issue with reading the char array or message passing as I am quite new to programming in c. Here is my attempt:
struct msg {
long int mtype; /* message type */
char mtext[1028]; /* message text */
} msg;
int pid, len;
int msgflg = 0;
int msqid;
char *mymsg[1028];
size_t msgsz;
long int msgtyp;
switch(pid=fork()) //fork child process
{//Child process
case 0:
mymsg[1] = "serving for sender\n";
len = strlen(mymsg[1]);
msgsnd(msqid,mymsg[1],len,msgflg);
break;
case -1:
printf("fork failed");
exit(-1);
break;
default:
msg.mtype = 0;
msqid = msgget(IPC_PRIVATE,msgflg);
wait((int *) 0);
msgrcv(msqid,&msg,msgsz,msgtyp,IPC_NOWAIT);
printf("%s",msg.mtext);
msgctl(msqid, IPC_RMID, NULL);
exit(0);
}
My question is, why is the message serving for sending not being displayed when this code is compiled and executed?
You haven't really asked a question, but a couple of issues I can see with the code are:
char *mymsg[1028];
...
mymsg[1] = "serving for sender\n";
Here you have mymsg which is an array of 1028 pointers to char, which is intended to be treated as a string. (By the way, why 1028? Not that it matters, but just so you know 2^10 is 1024). However, this array contains pointers that are not initialized and are pointing to random locations. Important thing is, there is no space allocated for the possible message you want to put in them.
Second issue is that arrays in C start with index 0, so you probably meant to write
mymsg[0] = "serving for sender\n";
That doesn't matter however.
More importantly, you can't copy strings in C using =, you should use strcpy and copy to a memory location that you have already allocated. Here are two ways to do it:
char mymsg[1028][1028]; // if you are sure your messages fit in 1028 chars
...
mymsg[1] = malloc(strlen("serving for sender)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], "serving for sender\n");
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);
or
char *mymsg[1028];
...
char str_to_be_printed[] = "serving for sender\n";
mymsg[1] = malloc(strlen(str_to_be_printed)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], str_to_be_printed);
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);
Edit: In the second case where you already have the string somewhere (and not in the form of "this is a string"), assigning the pointers is enough and you don't to copy or allocate memory. However, if your situation is more complex than this, and between assignment of mymsg[1] = ... and msgsnd there are other code, you have to make sure the original string stays alive until msgsnd is done. Otherwise, you have a dangling pointer which will cause you problems. Here's the idea:
+-+-+-+-+-+-+-+-+--+
str_to_be_printed ----->|A| |s|t|r|i|n|g|\0|
+-+-+-+-+-+-+-+-+--+
^
mymsg[1]---------------/
If you free the memory of str_to_be_printed, access to mymsg[1] would cause segmentation fault/access violation.
Note that, the code I wrote is just to give you a guideline, don't copy-paste it.
There are few observation related to your code.
When you use system calls (any function which returns any error code) check the return value of the function. In the case of system calls you have used will set errno i.e. error number which can be used to check for error. You can use perror or strerror to see the message (Pointed out by Jonathan Leffler already)
You need to create message queue before using it (Again pointed out by Jonathan Leffler already).
You are sending char * in msgsnd & receiving struct msg type in msgrcv.
You have set the size to be passed in the message queue send & receive calls, for which you are using msgsz but uninitialized. Set value of msgsz to the size you want to send/receive. While sending you seem to sending 17 bytes but while receiving it is not set.
mtype should have a value greater than 0.
Type for pid should be pid_t, which seems do you little good in this case anyway.
Some code sections for your reference:
#include <stdio.h> /*For perror*/
...
/* Create message queue */
msqid = msgget(IPC_PRIVATE, IPC_CREAT);
if( 0 > msqid )
{
perror("msgget");
/* Handle error as per your requirement */
}
...
/* Sending & receiving messages */
...
struct msg {
long int mtype; /* message type */
char mtext[1028]; /* message text */
} sender_msg, receiver_msg;
...
size_t msgsz = 10; /* Send & receive 10 bytes, this can vary as per need. You can receive less than what was sent */
...
switch(fork())
{
case 0: /* Child */
sender_msg.mtype = 1;
strncpy(sender_msg.mtext,"01234567890123", 1027);
/* Sending the whole text size */
if ( 0 > msgsnd(msqid, &sender_msg, strlen(sender_msg.mtext),msgflg))
{
perror("msgsnd");
/* Handle error as per your requirement */
}
break;
case -1:
perror("fork");
exit(-1);
break;
default:
wait((int *) 0);
receiver_msg.mtype = 1;
/* Receive only 10 bytes as set in msgsz */
if( 0 > msgrcv(msqid,&receiver_msg,msgsz,msgtyp,IPC_NOWAIT))
{
perror("msgrcv");
/* Error handling */
}
printf("%s",receiver_msg.mtext);
if (0 > msgctl(msqid, IPC_RMID, NULL))
{
perror("msgctl");
/* Handle error as per your requirement */
}
break;
}
You seem to be using System V message queues APIs here, you can look into the POSIX message queue APIs like mq_open, mq_close, mq_send, mq_receive etc.
For message queue overview see the man pages (man mq_overview)
Use man pages for information about APIs as well.
Hope this helps!
You have several problems:
You need to create the message queue before you call fork(), so that both the parent and child have access to it;
The permissions of the message queue are set from the low-order bits of the second parameter of msgget(), so you need to specify at least read and write permissions for the owner of the message queue. You can use the constant S_IRWXU from <sys/stat.h> here;
You are passing msgsnd() a pointer to a string, but it actually wants a pointer to a message struct like your struct msg.
You should check for msgrcv() failing.
With these issues fixed, the corrected code looks like:
int pid;
int msqid;
msqid = msgget(IPC_PRIVATE, S_IRWXU);
if (msgid < 0) {
perror("msgget");
exit(1);
}
switch(pid=fork()) //fork child process
{//Child process
case 0:
msg.mtype = 1; /* Must be a positive value */
strcpy(msg.mtext, "serving for sender\n");
msgsnd(msqid, &msg, strlen(msg.mtext) + 1, 0);
break;
case -1:
printf("fork failed");
exit(2);
break;
default:
wait(NULL);
if (msgrcv(msqid, &msg, sizeof msg.mtext, 0, IPC_NOWAIT) >= 0)
printf("%s",msg.mtext);
else
perror("msgrcv");
msgctl(msqid, IPC_RMID, NULL);
exit(0);