Error while running simple C Program from Pulse Audio - c++

I have used the simple C code of pulse audio for playback and record and it worked fine. But when I converted it to C++ it doesn't work. I am pasting both the codes. Please help. The C++ code doesn't show any error but doesn't playback any sound. But C++ code plays the recorded sound.
N.B: I am using 64 bit CentOS 6.2
C++ Code:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include "pulse/simple.h"
#include "pulse/error.h"
using namespace std;
#define BUFSIZE 32
int error;
/* The Sample format to use */
class AudioCapt
{
public:
AudioCapt();
void RecordSound(int argc,char *argv[],pa_simple *s_in,pa_sample_spec &ss,pa_simple *s_out,uint8_t buf[],ssize_t r);
void PlaybackSound(int argc, char*argv[],pa_simple *s_out,pa_sample_spec &ss,uint8_t buf[],ssize_t r);
};
void AudioCapt::RecordSound(int argc, char*argv[],pa_simple *s_in,pa_sample_spec &ss,pa_simple *s_out,uint8_t buf[],ssize_t r)
{
printf("Audio Capturing \n");
if (!(s_in = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
}
if (pa_simple_read(s_in, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno));
}
printf("Buffer :::: %d\n",buf[0]);
}
void AudioCapt::PlaybackSound(int argc, char*argv[],pa_simple *s_out,pa_sample_spec &ss,uint8_t buf[],ssize_t r)
{
printf("Audio PlayBack \n");
printf("Play Buffer::: %d\n",buf[0]);
if (!(s_out = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
}
/* ... and play it (Modified) */
if (pa_simple_write(s_out, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
}
/* Make sure that every single sample was played */
if (pa_simple_drain(s_out, &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));
}
}
int main(int argc, char * argv[])
{
pa_sample_spec ss;
ss.format = PA_SAMPLE_S16LE;
ss.rate = 44100;
ss.channels = 2;
pa_simple *s_in, *s_out = NULL;
AudioCapt *m_pMyObject;
for(;;)
{
uint8_t buf[BUFSIZE];
ssize_t r;
m_pMyObject->RecordSound(argc,argv,s_in,ss,s_out,buf,r);
m_pMyObject->PlaybackSound(argc,argv,s_out,ss,buf,r);
}
return 0;
}
C Code:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pulse/simple.h>
#include <pulse/error.h>
#define BUFSIZE 32
int main(int argc, char*argv[]) {
/* The Sample format to use */
static const pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
.channels = 2
};
pa_simple *s_in, *s_out = NULL;
int ret = 1;
int error;
/* Create a new playback stream */
if (!(s_out = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
}
if (!(s_in = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) {
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish;
}
for (;;) {
uint8_t buf[BUFSIZE];
ssize_t r;
#if 1
pa_usec_t latency;
if ((latency = pa_simple_get_latency(s_in, &error)) == (pa_usec_t) -1) {
fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error));
goto finish;
}
fprintf(stderr, "In: %0.0f usec \r\n", (float)latency);
if ((latency = pa_simple_get_latency(s_out, &error)) == (pa_usec_t) -1) {
fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error));
goto finish;
}
fprintf(stderr, "Out: %0.0f usec \r\n", (float)latency);
#endif
if (pa_simple_read(s_in, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno));
goto finish;
}
printf("Buffer :::: %d\n",buf[0]);
/* ... and play it */
if (pa_simple_write(s_out, buf, sizeof(buf), &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
goto finish;
}
}
/* Make sure that every single sample was played */
if (pa_simple_drain(s_out, &error) < 0) {
fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));
goto finish;
}
ret = 0;
finish:
if (s_in)
pa_simple_free(s_in);
if (s_out)
pa_simple_free(s_out);
return ret;
}

In RecordSound and PlaybackSound you're initializing temporary variables with pa_simple_new. This value is lost once function returns, and you passing NULL to next one.

I would suggest turning on compiler checks and fixing all errors and warnings issued by your compiler on this code.
To start, m_pMyObject is never initialized, so using it in the call to RecordSound will mean passing an uninitialized value as "this" to the method. This is generally a bad thing to do.
In RecordSound and PlaybackSound, you use size(buf) to tell the library how many bytes to read/write. The parameter buf is a pointer to uint8_t. So the compiler fills in the size of the pointer (probably 8 on a 64-bit machine). In these methods you should use the parameter you have for the size. In the calls, pass sizeof(buf) to that parameter.
I don't know how many streams the library can create before running out of memory/resources. Each call to RecordSound creates a recording stream, and the PlaybackSound creates a playback stream. These streams are never freed.
So to summarize, If using the uninitialized value to call the RecordSound method does not cause the program to crash, it will create a recording stream and record a couple samples, then it will create a playback stream and play back those two samples. Then it will try doing all this again.

Related

File download with libssh SFTP is corrupt

I'm using libssh to download a file from a Debian Linux server on my local Windows machine, the program is running without error but the downloaded file is corrupted. When I download via pscp it works, I don't know if I'm doing something wrong with regards to the buffer or something else.
The sizes of the generated files are identical, when I download it via other tools like FileZilla or WinSCP everything goes well. The file doesn't corrupt anymore. When I run my code then it gets corrupted
I'm running this code on Windows 10 with Visual Studio 2019. After messing with this code a lot I think the problem is with the write file writing function when I open the generated file in a hex editor I see differences in bytes only the end of the file that stays the same.
I ended up posting the Dart version of the code previously, but the C version is almost identical to the Dart version.
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NONSTDC_NO_DEPRECATE
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <stdexcept>
#include <string.h>
#include <exception>
#include <fstream>
#include <libssh/callbacks.h>
#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include "custom_exception.cpp"
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <io.h>
#include <time.h>
#include <chrono>
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
//using namespace std;
using std::string;
using std::cout;
using std::endl;
using std::cin;
// Good chunk size
#define MAX_XFER_BUF_SIZE 16384
int sftpDownloadFileTo(ssh_session session, const char* fullRemotePath, const char* fullLocalPath)
{
int access_type;
sftp_file file;
char buffer[MAX_XFER_BUF_SIZE * 8];//128KB
ssize_t nbytes, nwritten, rc;
int fd;
access_type = O_RDONLY;
sftp_session sftp = sftp_new(session);
if (sftp == NULL)
{
fprintf(stderr, "Error allocating SFTP session: %s\n",
ssh_get_error(session));
return SSH_ERROR;
}
rc = sftp_init(sftp);
if (rc != SSH_OK)
{
fprintf(stderr, "Error initializing SFTP session: %d.\n",
sftp_get_error(sftp));
sftp_free(sftp);
return rc;
}
file = sftp_open(sftp, fullRemotePath, access_type, 0);
if (file == NULL) {
fprintf(stderr, "Can't open file for reading: %s\n", ssh_get_error(session));
return SSH_ERROR;
}
fd = open(fullLocalPath, O_CREAT | O_RDWR, 0777);
if (fd < 0) {
fprintf(stderr, "Can't open file for writing: %s\n",
strerror(errno));
return SSH_ERROR;
}
for (;;) {
nbytes = sftp_read(file, buffer, sizeof(buffer));
if (nbytes == 0) {
break; // EOF
}
else if (nbytes < 0) {
fprintf(stderr, "Error while reading file: %s\n",
ssh_get_error(session));
sftp_close(file);
return SSH_ERROR;
}
nwritten = write(fd, buffer, nbytes);
if (nwritten != nbytes) {
fprintf(stderr, "Error writing: %s\n",
strerror(errno));
sftp_close(file);
return SSH_ERROR;
}
}
rc = sftp_close(file);
if (rc != SSH_OK) {
fprintf(stderr, "Can't close the read file: %s\n",
ssh_get_error(session));
return rc;
}
sftp_free(sftp);
return SSH_OK;
}
int main()
{
ssh_session my_ssh_session;
int rc;
int port = 22;
string password = "Ins257257";
auto host = "192.168.133.13";
auto username = "isaque.neves";
int verbosity = SSH_LOG_PROTOCOL;
// Abra a sessão e defina as opções
my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, host);
//ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
// Conecte-se ao servidor
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error connecting to host: %s\n",
ssh_get_error(my_ssh_session));
exit(-1);
}
// Autenticar-se
rc = ssh_userauth_password(my_ssh_session, username, password.c_str());
if (rc != SSH_AUTH_SUCCESS)
{
fprintf(stderr, "Error authenticating with password: %s\n",
ssh_get_error(my_ssh_session));
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
exit(-1);
}
clock_t tic = clock();
auto t1 = high_resolution_clock::now();
sftpDownloadFileTo(my_ssh_session, "/home/isaque.neves/go1.11.4.linux-amd64.tar.gz", "D:/MyDartProjects/fsbackup/libssh_binding/go1.11.4.linux-amd64.tar.gz");
auto t2 = high_resolution_clock::now();
clock_t toc = clock();
duration<double, std::milli> ms_double = t2 - t1;
std::cout << ms_double.count() << " ms\r\n";
printf("Elapsed: %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC);
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
std::cout << "End\n";
return 0;
}
https://github.com/insinfo/fsbackup/tree/main/libssh_binding
fd = open(fullLocalPath, O_CREAT | O_RDWR, 0777);
Here's your problem. Since you are running on Windows we need to adjust here.
fd = open(fullLocalPath, O_CREAT | O_RDWR | O_BINARY, 0777);
otherwise write() will try to adjust line endings.

Stress-ng: Writing an application program using execv to invoke stress-ng commands and return if it is success or failure

Stress-ng: How to write an application program in C or Cpp using execv to invoke stress-ng commands for CPU and memory testing in MIPS and return its status if it is success or failure?
Given an executable stress-ng file that has been cross-compiled to MIPS32 version using its toolchain.
Sample stress-ng commands:
stress-ng --vm 8 --vm-bytes 80% -t 1h
stress-ng --cpu 8 --cpu-ops 800000
Perhaps this will suffice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
int ret;
char *stress_ng = "/usr/bin/stress-ng";
char *argv_new[] = { stress_ng,
"--vm", "8", "--vm-bytes", "80%",
"-t", "2s", "-v", NULL };
char *env_new[] = { NULL };
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
} else if (pid == 0) {
ret = execve(stress_ng, argv_new, env_new);
if (ret < 0) {
fprintf(stderr, "execve failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
_exit(ret);
} else {
/* Parent */
int status;
ret = waitpid(pid, &status, 0);
if (ret < 0) {
fprintf(stderr, "waitpid failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
ret = WEXITSTATUS(status);
printf("stress-ng returned: %d\n", ret);
}
exit(0);
}
If you want to parse the output from stress-ng, you need to create a pipe between the parent and child and the parent needs to read and parse the output over the pipe, something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid;
int ret;
int fds[2];
char *stress_ng = "/usr/bin/stress-ng";
char *argv_new[] = { stress_ng,
"--vm", "8", "--vm-bytes", "80%",
"-t", "2s", "-v", NULL };
char *env_new[] = { NULL };
if (pipe(fds) < 0) {
fprintf(stderr, "pipe failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
} else if (pid == 0) {
//close(STDERR_FILENO);
close(STDIN_FILENO);
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
dup2(fds[1], STDERR_FILENO);
ret = execve(stress_ng, argv_new, env_new);
if (ret < 0) {
fprintf(stderr, "execve failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
close(fds[1]);
_exit(ret);
} else {
/* Parent */
int status;
FILE *fp;
char buffer[1024];
close(fds[1]);
fp = fdopen(fds[0], "r");
if (!fp) {
fprintf(stderr, "fdopen failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
while (fgets(buffer, sizeof(buffer), fp)) {
size_t len = strlen(buffer);
if (len > 0)
buffer[len - 1] = '\0';
if (strstr(buffer, "completed"))
printf("GOT: <%s>\n", buffer);
}
fclose(fp);
close(fds[0]);
ret = waitpid(pid, &status, 0);
if (ret < 0) {
fprintf(stderr, "waitpid failed: %d (%s)\n",
errno, strerror(errno));
exit(EXIT_FAILURE);
}
ret = WEXITSTATUS(status);
printf("stress-ng returned: %d\n", ret);
}
exit(0);
}

Programs Not Receiving and Sending Alternatively

Program seems to work, but can't figure out why its not running second part of code. For example, when I compile and execute msg2.cpp it prompts user to 'Enter some text'. When user inputs text msg1.cpp displays user input. The issue is msg1.cpp is not prompting user 'Enter some text'. Any suggestions on how I can receive and send message alternatively?
//msg2.cpp
/* The sender program is very similar to msg1.cpp. In the main set up, delete the
msg_to_receive declaration and replace it with buffer[BUFSIZ], remove the message
queue delete and make the following changes to the running loop.
We now have a call to msgsnd to send the entered text to the queue. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st {
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
long int msg_to_receive = 0;
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
while(running) {
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}
/* Then the messages are retrieved from the queue, until an end message is encountered.
Lastly, the message queue is deleted. */
while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
msg_to_receive, 0) == -1) {
fprintf(stderr, "msgrcv failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0) {
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
//msg1.cpp
/* Here's the receiver program. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
//string UserInput(string);
struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
//char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 0;
char buffer[BUFSIZ];
char some_text[MAX_TEXT];
//string input;
/* First, we set up the message queue. */
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
/* Then the messages are retrieved from the queue, until an end message is encountered.
Lastly, the message queue is deleted. */
while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
msg_to_receive, 0) == -1) {
fprintf(stderr, "msgrcv failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0) {
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
// Need to reset value, before entering second loop
// At this point, value enters loop, prompts user enter text
while(running) {
printf("Enter some text: ");
for (int i = 1; i < running; i++){
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
}
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}
exit(EXIT_SUCCESS);
}
My .02 currency units are on this snippet from msg1.cpp:
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
You seem to delete the message queue here as soon as the 'end' message has been received.
(Also: fprintf() & friends in C++ program?)

sendfile64 only copy about 2GB

I need to use sendfile64 to copy about 16GB of files. What I have achieved so far is
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
int main (int argc, char** argv)
{
long long src;
long long dest;
struct stat64 stat_buf;
off64_t offset = 0LL;
long long rc;
if (argc != 3) {
fprintf(stderr, "usage: %s <source> <destination>\n", argv[0]);
exit(1);
}
src = open64(argv[1], O_RDONLY);
if (src == -1) {
fprintf(stderr, "unable to open '%s': %s\n", argv[1], strerror(errno));
exit(1);
}
fstat64(src, &stat_buf);
dest = open64(argv[2], O_WRONLY|O_CREAT, stat_buf.st_mode);
if (dest == -1) {
fprintf(stderr, "unable to open '%s': %s\n", argv[2], strerror(errno));
exit(1);
}
/* copy file using sendfile */
rc = sendfile64 (dest, src, &offset, stat_buf.st_size);
if (rc == -1) {
fprintf(stderr, "error from sendfile: %s\n", strerror(errno));
exit(1);
}
if (rc != stat_buf.st_size) {
fprintf(stderr, "incomplete transfer from sendfile: %lld of %lld bytes\n",
rc,
(long long)stat_buf.st_size);
exit(1);
}
/* clean up and exit */
close(dest);
close(src);
return 0;
}
I have compiled using
g++ BigCopy2.cpp -o BigCopy2 -D_FILE_OFFSET_BITS=64 -DLARGEFILE64_SOURCE
The problem is I still can't copy more than 2GB of file.
Can someone point me where is my mistake?
You should use a loop to copy it all, sendfile() might, for various reasons, not copy all the data
with one call. As janneb points out, the return value of sendfile64 is a ssize_t, so we should not pass in more than SSIZE_MAX to sendfile, moreover the last argument to sendfile is a size_t which would be 32 bit on 32 bit platforms.
/* copy file using sendfile */
while (offset < stat_buf.st_size) {
size_t count;
off64_t remaining = stat_buf.st_size- offset;
if (remaining > SSIZE_MAX)
count = SSIZE_MAX;
else
count = remaining;
rc = sendfile64 (dest, src, &offset, count);
if (rc == 0) {
break;
}
if (rc == -1) {
fprintf(stderr, "error from sendfile: %s\n", strerror(errno));
exit(1);
}
}
if (offset != stat_buf.st_size) {
fprintf(stderr, "incomplete transfer from sendfile: %lld of %lld bytes\n",
rc,
(long long)stat_buf.st_size);
exit(1);
}
Note that you can replace all your 64 bit variants, off64_t, stat64, sendfile64, with off_t, stat, sendfile. As long as you have the -D_FILE_OFFSET_BITS=64 flag, that define will do the right thing and transform off_t to off64_t, sendfile to sendfile64 and so on if those types and functions are not already 64 bits (such as on 32 bit architectures).

Simple IPC via linux messages

I'm trying to write some example of client-server application which uses linux messages. Here is my code:
#include <mqueue.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#define MSG_SIZE 4096
#define MSG_MAX_COUNT 1024
#define MSG_TYPE_TO_UPPER 0
#define MSG_TYPE_EXIT 1
#define MQ_NAME "msg_queue"
namespace {
int str_toupper(char *str)
{
int len = 0;
for(; str[len]; ++len) {
str[len] = toupper(str[len]);
}
return len;
}
}
int main(int argc, char** argv)
{
if(argc != 2) {
fprintf(stderr, "Usage: msg_queue (client|server)\n");
exit(EXIT_FAILURE);
}
struct mq_attr attr; // MQueue attributes
mqd_t mqd; // MQueue descriptor
char buf[MSG_SIZE]; // Msg buffer
unsigned int type; // Msg type(priority)
// Set up MQueue attributes
attr.mq_maxmsg = MSG_MAX_COUNT;
attr.mq_msgsize = MSG_SIZE;
attr.mq_flags = 0;
attr.mq_curmsgs = 0;
mqd = mq_open(MQ_NAME, O_RDWR | O_CREAT, 0664, &attr);
if(mqd == -1) {
fprintf(stderr, "mq_open() failed for \""MQ_NAME"\": %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if(strcmp(argv[1], "server") == 0) {
while(mq_receive (mqd, buf, MSG_SIZE, &type) != -1) {
if(type == MSG_TYPE_EXIT) {
mq_unlink(MQ_NAME);
mq_close(mqd);
break;
} else if(type == MSG_TYPE_TO_UPPER) {
int len = str_toupper(buf);
if(mq_send (mqd, buf, len, MSG_TYPE_TO_UPPER) == -1) {
fprintf(stderr, "Server: mq_send() failed: %s", strerror(errno));
}
}
}
} else if(strcmp(argv[1], "client") == 0) {
while(1) {
printf("Input a message: <type>(0 - TO_UPPER, 1 - EXIT) <message>\n");
scanf("%u %s", &type, buf);
if(mq_send (mqd, buf, strlen(buf), type) == -1) {
fprintf(stderr, "Client: mq_send() failed: %s", strerror(errno));
}
if(type == MSG_TYPE_TO_UPPER) {
if(mq_receive (mqd, buf, MSG_SIZE, &type) == -1) {
fprintf(stderr, "Client: mq_receive() failed: %s", strerror(errno));
}
printf("\"%s\" received\n", buf);
} else if(type == MSG_TYPE_EXIT) {
mq_unlink(MQ_NAME);
mq_close(mqd);
break;
}
}
} else {
fprintf(stderr, "Usage: msg_queue (client|server)\n");
exit(EXIT_FAILURE);
}
return 0;
}
What is my mistake? It always prints error from the line 47 - fprintf(stderr, "mq_open() failed for \""MQ_NAME"\": %s\n", strerror(errno)); with errno = EINVAL.
I see two issues:
Your message queue name must begin with a / on Linux. See mq_overview(7):
Each message queue is identified by a name of the form
/somename; that is, a null-terminated string of up to NAME_MAX (i.e., 255)
characters consisting of an initial slash, followed by one or more characters,
none of which are slashes.
MSG_MAX_COUNT is most likely above your system limits. It must be less than (or equal to) the /proc/sys/fs/mqueue/max_size. See mq_open(3):
EINVAL: O_CREAT was specified in oflag, and attr was not NULL, but
attr->mq_maxmsg or attr->mq_msqsize was invalid. Both of these fields
must be greater than zero. In a process that is unprivileged (does not
have the CAP_SYS_RESOURCE capability), attr->mq_maxmsg must be less
than or equal to the msg_max limit, and attr->mq_msgsize must be less
than or equal to the msgsize_max limit. In addition, even in a
privileged process, attr->mq_maxmsg cannot exceed the HARD_MAX limit.
(See mq_overview(7) for details of these limits.)
The other limit is probably ok, but you should verify it too.