SegFault in read function for serial device - c

I'm attempting to interface with a measurement device through serial. I have already created one successful program that works and does what I want, but it doesn't have live user input.
My problem comes from a program I'm creating where I want to make a live serial terminal to interact with the device. In this program I have the user type the commands to the machine and for some commands the machine has to return a 1 or 0. This is where the problem comes. In the live environment, when I read a 1 after a command I get a segfault.
This is the segment that deals with commands that require the machine to send a 1 or 0.
buf = malloc(1);
if (buf == NULL)
{
perror("memory error");
goto fail;
}
...
if (write == 0)
{
for (i = 0; i < read_com.num; i++)
{
if (strcmp(buff, read_com.check[i]) == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
ret = read_port(fd, buf, 1);
if (ret < 0)
goto fail;
printf("Read success");
write = 1;
break;
}
}
}
This is the read port function where the segfault is occurring
int read_port(int fd, char *buf, const size_t size)
{
ssize_t r;
size_t received;
received = 0;
while (received < size)
{
r = read(fd, buf + received, size - received);
if (r < 0)
{
perror("failed to read from port");
return -1;
}
if (r == 0)
{
break;
}
received += r;
}
return received;
}
All code below:
live.c:
#include "GPIB_prof.h"
#include "serial.h"
#include "commands.h"
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
const struct com read_com = {3, {"OPC?;PRES;\r", "OPC?;WAIT;\r", "CORRON;\r"}};
const struct com numc = {3, {"STAR", "STOP", "POIN"}};
int main(int argc, char *argv[])
{
int fd;
int ret;
char *buff;
char *buf;
int i;
bool write = 0;
int fin = 0;
char *numb;
char *rem;
int star;
int stop;
int poin;
char *dat;
int fc = 0;
char *file;
FILE *temp;
FILE *f;
rem = malloc(256);
if (rem == NULL)
{
perror("memory error");
goto fail;
}
numb = malloc(4);
if (numb == NULL)
{
perror("memory error");
goto fail;
}
buff = malloc(256);
if (buff == NULL)
{
perror("memory error");
goto fail;
}
buf = malloc(1);
if (buf == NULL)
{
perror("memory error");
goto fail;
}
file = malloc(5);
if (file == NULL)
{
perror("memory error");
goto fail;
}
if (argc < 3)
{
printf("Usage: %s [serial device] [baud rate]", argv[0]);
goto fail;
}
fd = open_port(argv[1], atoi(argv[2]));
if (fd < 0)
goto fail;
ret = GPIB_conf(fd, 0);
if (ret < 0)
goto fail;
while (fin == 0)
{
write = 0;
scanf("%s", buff);
strcat(buff, "\r");
//if (ret<0) goto fail;
for (i = 0; i < strlen(buff); i++)
{
if (i < 4)
{
numb[i] = buff[i];
}
else
{
rem[i - 4] = buff[i];
}
}
if (strcmp(numb, "OUTP") == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
ret = read_port(fd, dat, 50 * poin);
if (ret < 0)
goto fail;
else
goto data;
}
if (write == 0)
{
for (i = 0; i < read_com.num; i++)
{
if (strcmp(buff, read_com.check[i]) == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
ret = read_port(fd, buf, 1);
if (ret < 0)
goto fail;
printf("Read success");
write = 1;
break;
}
}
}
if (write == 0)
{
for (i = 0; i < numc.num; i++)
{
if (strcmp(numb, numc.check[i]) == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
if (strcmp(numb, "STAR") == 0)
{
star = atoi(rem);
}
else if (strcmp(numb, "STOP") == 0)
{
stop = atoi(rem);
}
else if (strcmp(numb, "POIN") == 0)
{
poin = atoi(rem);
dat = malloc(50 * poin);
if (dat == NULL)
{
perror("memory error");
goto fail;
}
fc++;
}
break;
}
}
if (write == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
}
}
}
printf("Start freq: %d\nStop freq: %d\n", star, stop);
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return 0;
data:
ret = sprintf(file, "data%d", fc);
if (ret < 0)
goto fail;
temp = fopen(file, "w+");
if (temp == NULL)
{
perror("failed to open file");
fclose(temp);
goto fail;
}
fclose(temp);
ret = remove(file);
if (ret != 0)
{
perror("failed to remove file");
goto fail;
}
f = fopen(file, "w");
if (f == NULL)
{
perror("failed to open file");
fclose(f);
goto fail;
}
for (i = 0; i < (50 * poin); i++)
{
ret = fprintf(f, "%c", dat[i]);
if (ret < 0)
{
fclose(f);
goto fail;
}
}
fclose(f);
fin++;
fail:
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return -1;
}
serial.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <stdint.h>
#include <unistd.h>
#include "serial.h"
#include "GPIB_prof.h"
struct termios options;
int open_port(const char *dev, uint32_t baud)
{
int fd;
int ret;
char *baud_f;
struct termios opt;
baud_f = malloc(8 * sizeof(char));
if (baud_f == NULL)
{
perror("memory error");
goto fail;
}
fd = open(dev, O_RDWR, 0777);
if (fd < 0)
{
perror(dev);
goto fail;
}
ret = tcflush(fd, TCIOFLUSH);
if (ret)
{
perror("tcgetattr failed");
goto fail;
}
opt.c_cflag = (opt.c_cflag & ~CSIZE) | CS8;
opt.c_cflag &= ~IGNBRK;
opt.c_lflag = 0;
opt.c_oflag = 0;
opt.c_cc[VTIME] = 5;
opt.c_cc[VMIN] = 1;
opt.c_iflag &= ~(IXON | IXOFF | IXANY);
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_cflag &= ~(PARENB | PARODD);
opt.c_cflag |= 0;
opt.c_cflag &= ~CSTOPB;
ret = sprintf(baud_f, "B%d", baud);
if (ret < 0)
{
perror("memory error");
goto fail;
}
baud = (uintptr_t)baud_f;
cfsetospeed(&opt, baud);
cfsetispeed(&opt, baud);
ret = tcsetattr(fd, TCSANOW, &opt);
if (ret)
{
perror("tcsetarre failed");
goto fail;
}
free(baud_f);
return fd;
fail:
free(baud_f);
close(fd);
return -1;
}
int read_port(int fd, char *buf, const size_t size)
{
ssize_t r;
size_t received;
received = 0;
while (received < size)
{
r = read(fd, buf + received, size - received);
if (r < 0)
{
perror("failed to read from port");
return -1;
}
if (r == 0)
{
break;
}
received += r;
}
return received;
}
int write_port(int fd, const char *buf, const size_t size)
{
ssize_t res;
res = write(fd, buf, size);
if (res != (ssize_t)size)
{
perror("failed to write to port");
return -1;
}
usleep(size * 100);
return 0;
}
int GPIB_conf(int fd, int profile)
{
int ret;
switch (profile)
{
case 0:
ret = def(fd);
if (ret < 0)
goto fail;
}
return 0;
fail:
return -1;
}
serial.h
#ifndef _SERIAL_H_
#define _SERIAL_H_
#include <stdint.h>
#include <stddef.h>
#include "GPIB_prof.h"
int open_port (const char *dev, uint32_t baud);
int read_port (int fd, char *buf, size_t size);
int write_port (int fd, const char *buf, size_t size);
int GPIB_conf (int fd, int profile);
#endif
commands.h:
#ifndef _COMMANDS_H_
#define _COMMANDS_H_
struct com
{
const int num;
const char *check[];
};
#endif
GPIB_prof.c:
#include "GPIB_prof.h"
#include "serial.h"
int def(int fd)
{
int ret;
ret = write_port(fd, "++mode 1\r", 9);
if (ret < 0)
goto fail;
ret = write_port(fd, "++addr 16\r", 10);
if (ret < 0)
goto fail;
ret = write_port(fd, "++eoi 0\r", 8);
if (ret < 0)
goto fail;
ret = write_port(fd, "++eot_enable 1\r", 15);
if (ret < 0)
goto fail;
ret = write_port(fd, "++eot_char 13\r", 14);
if (ret < 0)
goto fail;
ret = write_port(fd, "++ifc\r", 6);
if (ret < 0)
goto fail;
ret = write_port(fd, "++auto 1\r", 9);
if (ret < 0)
goto fail;
return 0;
fail:
return -1;
}
GPIB_prof.h:
#ifndef _PROFILE_H_
#define _PROFILE_H_
int def(int fd);
#endif

Caveat: This may not be a total solution as there are many compiler warnings for possibly uninitialized variables, etc.
Note that I'd rename some variables. You have a global called read. That tends to conflict with the standard read function. (i.e.) don't define functions/variables that conflict with standard functions/variables: caveat emptor.
Here is the compiler output I get for (e.g.) cc -o orig orig.c -Wall -Wextra -O2.
Notably, a number of pointer variables may have uninitialized values. This really should be restructured and the warnings fixed as the code is fragile and the compiler is pointing out things that could easily explain your runtime error(s).
orig.c: In function ‘GPIB_conf’:
orig.c:136:15: warning: unused parameter ‘fd’ [-Wunused-parameter]
GPIB_conf(int fd, int profile)
~~~~^~
orig.c: In function ‘main’:
orig.c:217:17: warning: comparison of integer expressions of different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare]
for (i = 0; i < strlen(buff); i++) {
^
orig.c:325:5: warning: increment of a boolean expression [-Wbool-operation]
fin++;
^~
orig.c: In function ‘open_port’:
orig.c:96:2: warning: ‘fd’ may be used uninitialized in this function [-Wmaybe-uninitialized]
close(fd);
^~~~~~~~~
orig.c: In function ‘main’:
orig.c:295:27: warning: ‘%d’ directive writing between 1 and 10 bytes into a region of size 1 [-Wformat-overflow=]
ret = sprintf(file, "data%d", fc);
^~
orig.c:295:22: note: directive argument in the range [0, 2147483647]
ret = sprintf(file, "data%d", fc);
^~~~~~~~
orig.c:295:8: note: ‘sprintf’ output between 6 and 15 bytes into a destination of size 5
ret = sprintf(file, "data%d", fc);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
orig.c:332:2: warning: ‘file’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(file);
^~~~~~~~~~
orig.c:333:2: warning: ‘dat’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(dat);
^~~~~~~~~
orig.c:329:2: warning: ‘numb’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(numb);
^~~~~~~~~~
orig.c:331:2: warning: ‘buf’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(buf);
^~~~~~~~~
orig.c:330:2: warning: ‘buff’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(buff);
^~~~~~~~~~
orig.c:230:32: warning: ‘poin’ may be used uninitialized in this function [-Wmaybe-uninitialized]
ret = read_port(fd, dat, 50 * poin);
~~~^~~~~~
I had to refactor/nop some of the code to get it to compile without the full definitions in the [missing] .h files. However, these hacks do not account for the warnings above.
#include "GPIB_prof.h"
#include "serial.h"
#include "commands.h"
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#define def(_fd) \
0
struct com {
int num;
char *check[3];
};
const struct com read_com = { 3, {"OPC?;PRES;\r", "OPC?;WAIT;\r", "CORRON;\r"} };
const struct com numc = { 3, {"STAR", "STOP", "POIN"} };
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <stdint.h>
#include <unistd.h>
#include "serial.h"
#include "GPIB_prof.h"
struct termios options;
int
open_port(const char *dev, uint32_t baud)
{
int fd;
int ret;
char *baud_f;
struct termios opt;
baud_f = malloc(8 * sizeof(char));
if (baud_f == NULL) {
perror("memory error");
goto fail;
}
fd = open(dev, O_RDWR, 0777);
if (fd < 0) {
perror(dev);
goto fail;
}
ret = tcflush(fd, TCIOFLUSH);
if (ret) {
perror("tcgetattr failed");
goto fail;
}
opt.c_cflag = (opt.c_cflag & ~CSIZE) | CS8;
opt.c_cflag &= ~IGNBRK;
opt.c_lflag = 0;
opt.c_oflag = 0;
opt.c_cc[VTIME] = 5;
opt.c_cc[VMIN] = 1;
opt.c_iflag &= ~(IXON | IXOFF | IXANY);
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_cflag &= ~(PARENB | PARODD);
opt.c_cflag |= 0;
opt.c_cflag &= ~CSTOPB;
ret = sprintf(baud_f, "B%d", baud);
if (ret < 0) {
perror("memory error");
goto fail;
}
baud = (uintptr_t) baud_f;
cfsetospeed(&opt, baud);
cfsetispeed(&opt, baud);
ret = tcsetattr(fd, TCSANOW, &opt);
if (ret) {
perror("tcsetarre failed");
goto fail;
}
free(baud_f);
return fd;
fail:
free(baud_f);
close(fd);
return -1;
}
int
read_port(int fd, char *buf, const size_t size)
{
ssize_t r;
size_t received;
received = 0;
while (received < size) {
r = read(fd, buf + received, size - received);
if (r < 0) {
perror("failed to read from port");
return -1;
}
if (r == 0) {
break;
}
received += r;
}
return received;
}
int
write_port(int fd, const char *buf, const size_t size)
{
ssize_t res;
res = write(fd, buf, size);
if (res != (ssize_t) size) {
perror("failed to write to port");
return -1;
}
usleep(size * 100);
return 0;
}
int
GPIB_conf(int fd, int profile)
{
int ret;
switch (profile) {
case 0:
ret = def(fd);
if (ret < 0)
goto fail;
}
return 0;
fail:
return -1;
}
int
main(int argc, char *argv[])
{
int fd;
int ret;
char *buff;
char *buf;
int i;
bool write = 0;
bool fin = 0;
char *numb;
char *rem;
int star;
int stop;
int poin;
char *dat;
int fc = 0;
char *file;
FILE *temp;
FILE *f;
rem = malloc(256);
if (rem == NULL) {
perror("memory error");
goto fail;
}
numb = malloc(4);
if (numb == NULL) {
perror("memory error");
goto fail;
}
buff = malloc(256);
if (buff == NULL) {
perror("memory error");
goto fail;
}
buf = malloc(1);
if (buf == NULL) {
perror("memory error");
goto fail;
}
file = malloc(5);
if (file == NULL) {
perror("memory error");
goto fail;
}
if (argc < 3) {
printf("Usage: %s [serial device] [baud rate]", argv[0]);
goto fail;
}
fd = open_port(argv[1], atoi(argv[2]));
if (fd < 0)
goto fail;
ret = GPIB_conf(fd, 0);
if (ret < 0)
goto fail;
while (fin == 0) {
write = 0;
scanf("%s", buff);
strcat(buff, "\r");
// if (ret<0) goto fail;
for (i = 0; i < strlen(buff); i++) {
if (i < 4) {
numb[i] = buff[i];
}
else {
rem[i - 4] = buff[i];
}
}
if (strcmp(numb, "OUTP") == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
ret = read_port(fd, dat, 50 * poin);
if (ret < 0)
goto fail;
else
goto data;
}
if (write == 0) {
for (i = 0; i < read_com.num; i++) {
if (strcmp(buff, read_com.check[i]) == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
ret = read_port(fd, buf, 1);
if (ret < 0)
goto fail;
printf("Read success");
write = 1;
break;
}
}
}
if (write == 0) {
for (i = 0; i < numc.num; i++) {
if (strcmp(numb, numc.check[i]) == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
if (strcmp(numb, "STAR") == 0) {
star = atoi(rem);
}
else if (strcmp(numb, "STOP") == 0) {
stop = atoi(rem);
}
else if (strcmp(numb, "POIN") == 0) {
poin = atoi(rem);
dat = malloc(50 * poin);
if (dat == NULL) {
perror("memory error");
goto fail;
}
fc++;
}
break;
}
}
if (write == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
}
}
}
printf("Start freq: %d\nStop freq: %d\n", star, stop);
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return 0;
data:
ret = sprintf(file, "data%d", fc);
if (ret < 0)
goto fail;
temp = fopen(file, "w+");
if (temp == NULL) {
perror("failed to open file");
fclose(temp);
goto fail;
}
fclose(temp);
ret = remove(file);
if (ret != 0) {
perror("failed to remove file");
goto fail;
}
f = fopen(file, "w");
if (f == NULL) {
perror("failed to open file");
fclose(f);
goto fail;
}
for (i = 0; i < (50 * poin); i++) {
ret = fprintf(f, "%c", dat[i]);
if (ret < 0) {
fclose(f);
goto fail;
}
}
fclose(f);
fin++;
fail:
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return -1;
}

Related

testing the program for various memory allocation errors and memory leaks

The tee utility copies its standard input to both stdout and to a file. This allows the user to view the output of a command on the console while writing a log to a file at the same time.
My program implements the tee command from linux POSIX system calls, with the -a option.
How can I modify the program to test for possible memory allocation errors? Positive memory leaks.
Also, the memory allocation doesn't seem right to me. When creating a new buffer each time I call getline(), should I declare and initialize line outside the loop and reallocate it only after the loop has ended?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "apue.h"
int writeAll(int fd, char *buf, int buflen);
int main(int argc, char *argv[]) {
struct stat status;
int option;
bool append = false;
int errCode = 0;
while ((option = getopt(argc, argv, "a")) != -1) {
switch (option) {
case 'a':
append = true;
break;
}
}
// We need to write in all the files given as parameter AND stdout.
int numFileDescriptors = argc - optind + 1;
int *fileDescriptors = malloc((numFileDescriptors + 1) * sizeof(*fileDescriptors));
char **fileNames = malloc((numFileDescriptors + 1) * sizeof(*fileNames));
int lastFileDescriptor = 0;
fileDescriptors[0] = STDOUT_FILENO;
fileNames[0] = "stdout";
int flags = O_CREAT | O_WRONLY;
if (append) {
flags = flags | O_APPEND;
} else {
flags = flags | O_TRUNC;
}
for (int i = optind; i < argc; i++) {
if (access(argv[i], F_OK) == 0) {
if (access(argv[i], W_OK) < 0) {
err_msg("%s: Permission denied", argv[i]);
errCode = 1;
continue;
}
}
if (lstat(argv[i], &status) < 0) {
status.st_mode = 0;
}
if (S_ISDIR(status.st_mode)) {
err_msg("%s: Is a directory", argv[i]);
errCode = 1;
continue;
}
int fd = open(argv[i], flags, 0644);
if (fd < 0) {
err_msg("%s: Failed to open", argv[i]);
errCode = 1;
continue;
}
lastFileDescriptor = lastFileDescriptor + 1;
fileDescriptors[lastFileDescriptor] = fd;
fileNames[lastFileDescriptor] = argv[i];
}
while (true) {
size_t len = 0;
ssize_t read = 0;
char *line = NULL;
read = getline(&line, &len, stdin);
if (read == -1) {
break;
}
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, strlen(line));
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
for (int i = 0; i <= lastFileDescriptor; i++) {
close(fileDescriptors[i]);
}
free(fileDescriptors);
free(fileNames);
return errCode;
}
int writeAll(int fd, char *buf, int buflen) {
ssize_t written = 0;
while (written < buflen) {
int writtenThisTime = write(fd, buf + written, buflen - written);
if (writtenThisTime < 0) {
return writtenThisTime;
}
written = written + writtenThisTime;
}
return written;
}
Testing for memory allocation failure is simple: just add tests, report the failure and exit with a non zero exit status.
To avoid memory leaks, you must free the line that was allocated by getline inside the while (true) loop:
while (true) {
size_t len = 0;
char *line = NULL;
ssize_t nread = getline(&line, &len, stdin);
if (nread == -1) {
if (errno == ENOMEM) {
fprintf(stderr, "out of memory\n");
exit(1);
}
free(line);
break;
}
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, nread);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
free(line);
}
Alternately, you can reuse the same line for the next iteration and only free the buffer after the while loop:
size_t len = 0;
char *line = NULL;
while (true) {
ssize_t nread = getline(&line, &len, stdin);
if (nread == -1) {
if (errno == ENOMEM) {
fprintf(stderr, "out of memory\n");
exit(1);
}
break;
}
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, nread);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
free(line);
Note that reading a full line at a time is risky as the input might contain very long, possibly unlimited lines (eg: /dev/zero). You might want to use fgets() to read a line with a limited length and dispatch the contents as you read, possibly splitting long lines:
char line[4096];
while (fgets(line, sizeof line, stdin)) {
size_t len = strlen(line);
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, len);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
The above code has a limitation: if the input streams contains null bytes, they will cause some data to be lost in translation. A solution is to not use fgets(), but getchar() directly:
for (;;) {
char line[4096];
size_t len = 0;
int c;
while (len < sizeof(line) && (c = getchar()) != EOF)) {
if ((line[len++] = c) == '\n')
break;
}
if (len > 0) {
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, len);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
if (c == EOF)
break;
}

Question about sharing mmapped area between 2 different processes

I'm trying to share mmapped area in 2 processes.
In my program, I create memory_update() process and memory_read() process.
This memory_update() process update mmapped area and tried to read that area in memory_read() process.
But I got when I tried to read the mmapped area.
So far, I don't have good luck to find a solution for this problem.
If you have any idea, please leave your comments.
Here is the source code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define COLUMN 80
#define ROW 10
#define BUFSIZE 80
#define SHM_KEY 0x9998
struct _row {
int32_t flag;
unsigned char *buffer;
};
typedef enum {
DATA_READY,
DATA_RESET
} msg_type_t;
struct _ipc_message {
msg_type_t type;
int32_t value;
};
typedef struct _ipc_message ipc_message_t;
typedef struct _row row_t;
int32_t format_number_string(char *buf, int32_t num)
{
sprintf(buf, "%02d", num);
return 0;
}
int32_t update_row(char *buf, char *str)
{
strncpy(buf, str, 80);
return 0;
}
int32_t print_row(char *buf)
{
printf("print_row buf = %p\n", (void *)buf);
printf("%s\n", buf);
return 0;
}
int32_t memory_update(int32_t sk)
{
row_t *p_row;
ipc_message_t msg;
unsigned char *shared_mem;
unsigned char *ptr;
char rbuf[BUFSIZE];
char nbuf[3];
int32_t shmid;
int32_t i;
int32_t ret;
int32_t fd;
shmid = shmget(SHM_KEY, ROW * sizeof(row_t), 0644 | IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory Error");
return -1;
}
/* Attach Shared Memory */
shared_mem = shmat(shmid, NULL, 0);
if (shared_mem == (void *)-1)
{
perror("Shared Memory Attach Error");
return -1;
}
fd = open("testfile", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0)
{
perror("File Open Error");
}
ptr = mmap(
NULL,
COLUMN * ROW,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0);
printf("ptr = %p\n", (void *)ptr);
for (i = 0 ; i < ROW ; i++)
{
format_number_string(nbuf, i);
memset(rbuf, 0x20, BUFSIZE);
sprintf(rbuf, "LINE %s :", nbuf);
rbuf[strlen(rbuf)] = ' ';
rbuf[BUFSIZE-1] = 0x0;
update_row(&ptr[i * COLUMN], rbuf);
}
for (i = 0 ; i < ROW ; i++)
{
p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
p_row->flag = 0x99;
p_row->buffer = &ptr[i * COLUMN];
// print_row(p_row->buffer);
}
msg.type = DATA_READY;
msg.value = 0;
send(sk, (void *)&msg, sizeof(ipc_message_t), 0);
i = 0;
for ( ; i < ROW ; i++)
{
p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
if (p_row->flag == 0x0)
{
printf("row[%d] has processed\n", i);
}
else
{
i--;
sleep(1);
}
}
/* Detach Shared Memory */
ret = shmdt(shared_mem);
if (ret == -1)
{
perror("Shared Memory Detach Error");
return -1;
}
ret = munmap(ptr, COLUMN * ROW);
if (ret != 0)
{
printf("UnMapping Failed\n");
return -1;
}
close(fd);
return 0;
}
int32_t memory_read(int32_t sk)
{
row_t *p_row;
ipc_message_t msg;
unsigned char *shared_mem;
int32_t shmid;
int32_t ret;
int32_t i;
while (1)
{
ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
if (ret < 0)
{
perror("recv error");
return -1;
}
if (msg.type != DATA_READY)
{
continue;
}
else
{
break;
}
}
shmid = shmget(SHM_KEY, ROW * sizeof(row_t), 0644 | IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory Error");
return -1;
}
/* Attach Shared Memory */
shared_mem = shmat(shmid, NULL, 0);
if (shared_mem == (void *)-1)
{
perror("Shared Memory Attach Error");
return -1;
}
for (i = 0 ; i < ROW ; i++)
{
p_row = (row_t *)&shared_mem[i * sizeof(row_t)];
printf("memory_read process [%d]\n", i);
print_row(p_row->buffer);
p_row->flag = 0x0;
sleep(1);
}
/* Detach Shared Memory */
ret = shmdt(shared_mem);
if (ret == -1)
{
perror("Shared Memory Detach Error");
return -1;
}
return 0;
}
int32_t main(void)
{
pid_t pid;
int32_t sp[2];
int32_t ret;
static const int32_t ps = 0;
static const int32_t cs = 1;
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
if (ret == -1)
{
perror("socketpair");
return -1;
}
pid = fork();
if (pid == 0)
{
close(sp[ps]);
memory_update(sp[cs]);
}
else
{
close(sp[cs]);
memory_read(sp[ps]);
}
return 0;
}
And this is the output.
$ ./mmm
ptr = 0x7fdc214a8000
memory_read process [0]
print_row buf = 0x7fdc214a8000
Segmentation fault (core dumped)
Modifed code to mmap before forking.
And it is working as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define COLUMNS 80
#define ROWS 60
#define BUFSIZE 80
typedef enum {
DATA_PRODUCED,
DATA_CONSUMED
} msg_type_t;
struct _ipc_message {
msg_type_t type;
int32_t value;
};
typedef struct _ipc_message ipc_message_t;
int32_t memory_update(int32_t sk, char *buf)
{
ipc_message_t msg;
int32_t ret;
char *msg2 = "updated buffer";
printf("memory_update : 1.buf = %s\n", buf);
memset(buf, 0, 80);
strncpy(buf, msg2, strlen(msg2));
buf[strlen(msg2)] = 0;
printf("memory_update : 2.buf = %s\n", buf);
printf("memory_update : send message from memory_update process\n");
msg.type = DATA_PRODUCED;
msg.value = 0;
send(sk, (void *)&msg, sizeof(ipc_message_t), 0);
while (1)
{
printf("memory_update : receive message from memory_read process\n");
ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
if (ret < 0)
{
perror("recv error");
return -1;
}
if (msg.type != DATA_CONSUMED)
{
continue;
}
else
{
break;
}
}
printf("memory_update : 3.buf = %s\n", buf);
return 0;
}
int32_t memory_read(int32_t sk, char *buf)
{
ipc_message_t msg;
int32_t ret;
int32_t i;
char *msg3 = "buffer processed";
printf("memory_read : 1.buf = %s\n", buf);
while (1)
{
printf("memory_read : receive message from memory_update process\n");
ret = recv(sk, (void *)&msg, sizeof(ipc_message_t), 0);
if (ret < 0)
{
perror("recv error");
return -1;
}
if (msg.type != DATA_PRODUCED)
{
continue;
}
else
{
break;
}
}
printf("memory_read : 2.buf = %s\n", buf);
memset(buf, 0, 80);
strncpy(buf, msg3, strlen(msg3));
buf[strlen(msg3)] = 0;
printf("memory_read : 3.buf = %s\n", buf);
printf("memory_read : send message from memory_update process\n");
msg.type = DATA_CONSUMED;
msg.value = 0;
send(sk, (void *)&msg, sizeof(ipc_message_t), 0);
return 0;
}
int32_t main(void)
{
pid_t pid;
int32_t sp[2];
int32_t ret;
int32_t fd;
int32_t i;
char *ptr;
char *msg1 = "initial message";
static const int32_t ps = 0;
static const int32_t cs = 1;
fd = open("80bytes", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0)
{
perror("File Open Error");
}
ptr = mmap(
NULL,
80,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0);
memset(ptr, 0, 80);
strncpy(ptr, msg1, strlen(msg1));
ptr[strlen(msg1)] = 0;
printf("ptr = %s\n", ptr);
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
if (ret == -1)
{
perror("socketpair");
return -1;
}
pid = fork();
if (pid == 0) /* child process */
{
close(sp[ps]);
memory_update(sp[cs], ptr);
}
else /* parent process */
{
close(sp[cs]);
memory_read(sp[ps], ptr);
ret = munmap(ptr, 80);
if (ret != 0)
{
printf("UnMapping Failed\n");
return -1;
}
close(fd);
}
return 0;
}

race condition when writing to same file in c

i wrote a program to answer this question
but when i run the program i get this result
as of the answer of this exercise, i expect that the volume of the f1 be 2MB but when i run the program the result was 1Mb. can someone explain this difference?
the code was compiled by gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04).
int main(int argc, char *argv[]) {
int is_append = 1;
int fd;
int flags;
int number_of_bytes;
char buf = '0';
off_t offset;
mode_t mode;
if (argc < 3 || argv[3] == "help")
{
usage_error();
return -1;
}
if(4 == argc && strcmp("x", argv[3])) {
usage_error();
return -1;
}
if(4 == argc) { // the x argument is specified
is_append = 0;
}
flags = O_CREAT | (O_APPEND & is_append) | O_WRONLY;
mode = S_IWUSR | S_IRUSR;
number_of_bytes = atoi(argv[3]);
if (number_of_bytes <= 0)
{
printf("num-bytes must be grater than 0!\n");
return -1;
}
fd = open(argv[3], flags, mode);
if(-1 == fd) {
printf("error in open.\n");
return -1;
}
for (size_t i = 0; i < number_of_bytes; i++)
{
if(!is_append) {
offset = lseek(fd, 0, SEEK_END);
}
if(-1 == write(fd, &buf, 1)) {
printf("error in write.\n");
return -1;
}
}
return 0;
}

Code executes correctly only if prints are present (C) [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I'm setting up a prototype for a DAQ system for Zynq FPGAs. I receive data from a server through ethernet, write it to a FIFO using the DMA and viceversa using two different pthreads. However, threads work correctly only if printf are executed. I expect there is a memory leak or some lines leading to a undefined behaviour, but I can't spot it.
Placing output to stderr has the same result. Changing addresses does nothing different.
Sorry for the shameful code, but I tried replacing almost every line by now to spot the problem.
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/stat.h>
#include <stdint.h>
#include <errno.h>
#include <time.h>
#define PORT 8080
#define SA struct sockaddr
#define MM2S_CONTROL_REGISTER 0x00
#define MM2S_STATUS_REGISTER 0x04
#define MM2S_START_ADDRESS 0x18
#define MM2S_LENGTH 0x28
#define S2MM_CONTROL_REGISTER 0x30
#define S2MM_STATUS_REGISTER 0x34
#define S2MM_DESTINATION_ADDRESS 0x48
#define S2MM_LENGTH 0x58
#define VIRT_ADDR 0x40400000
#define FIFO_ADDR 0x0c000000
#define SEND_ADDR 0x0a000000
#define RECV_ADDR 0x0b000000
#define TIMEOUT 10
#define MAX_TRANSF 12274
unsigned int dma_set(unsigned int *dma_virtual_address, int offset, unsigned int value);
unsigned int dma_get(unsigned int *dma_virtual_address, int offset);
int dma_mm2s_sync(unsigned int *dma_virtual_address);
int dma_s2mm_sync(unsigned int *dma_virtual_address);
unsigned int dma_s2mm_status(unsigned int *dma_virtual_address);
unsigned int dma_mm2s_status(unsigned int *dma_virtual_address);
void memdump(void *virtual_address, int byte_count);
void print_status(unsigned int status);
unsigned long int elements = 0;
clock_t start_time;
typedef struct arg_struct {
unsigned int *virtual_address;
unsigned int *virtual_buffer;
unsigned int *head;
unsigned int *tail;
unsigned int buffsize;
unsigned int fifosize;
unsigned int sockfd;
pthread_mutex_t *lock;
char verbose;
} arguments;
unsigned int dma_set(unsigned int *dma_virtual_address, int offset, unsigned int value) {
dma_virtual_address[offset >> 2] = value;
}
unsigned int dma_get(unsigned int *dma_virtual_address, int offset) {
return dma_virtual_address[offset >> 2];
}
int dma_mm2s_sync(unsigned int *dma_virtual_address) {
unsigned int mm2s_status = dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
while (!(mm2s_status & 1 << 12) || !(mm2s_status & 1 << 1)) {
dma_s2mm_status(dma_virtual_address);
dma_mm2s_status(dma_virtual_address);
mm2s_status = dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
}
}
int dma_s2mm_sync(unsigned int *dma_virtual_address) {
unsigned int s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
while (!(s2mm_status & 1 << 12) || !(s2mm_status & 1 << 1)) {
dma_s2mm_status(dma_virtual_address);
dma_mm2s_status(dma_virtual_address);
s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
}
}
unsigned int dma_s2mm_status(unsigned int *dma_virtual_address) {
return dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
}
unsigned int dma_mm2s_status(unsigned int *dma_virtual_address) {
return dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
}
void print_mm2s_status(unsigned int status) {
fprintf(stderr, "[*] Stream to memory-mapped status (0x%08x#0x%02x):", status, S2MM_STATUS_REGISTER);
print_status(status);
}
void print_s2mm_status(unsigned int status) {
fprintf(stderr, "[*] Memory-mapped to stream status (0x%08x#0x%02x):", status, MM2S_STATUS_REGISTER);
print_status(status);
}
void print_status(unsigned int status) {
if (status & 0x00000001) fprintf(stderr, " halted");
else fprintf(stderr, " running");
if (status & 0x00000002) fprintf(stderr, " idle");
if (status & 0x00000008) fprintf(stderr, " SGIncld");
if (status & 0x00000010) fprintf(stderr, " DMAIntErr");
if (status & 0x00000020) fprintf(stderr, " DMASlvErr");
if (status & 0x00000040) fprintf(stderr, " DMADecErr");
if (status & 0x00000100) fprintf(stderr, " SGIntErr");
if (status & 0x00000200) fprintf(stderr, " SGSlvErr");
if (status & 0x00000400) fprintf(stderr, " SGDecErr");
if (status & 0x00001000) fprintf(stderr, " IOC_Irq");
if (status & 0x00002000) fprintf(stderr, " Dly_Irq");
if (status & 0x00004000) fprintf(stderr, " Err_Irq");
fprintf(stderr, "\n");
}
void memdump(void *virtual_address, int byte_count) {
char * p = virtual_address;
int offset;
for (offset = 0; offset < byte_count; offset++) {
fprintf(stderr, "%02x", p[offset]);
if (offset % 4 == 3) {
fprintf(stderr, " ");
}
}
}
void DMATransfer(unsigned int *virtual_address, long unsigned int src, long unsigned int dest, unsigned int length, char verbose) {
unsigned int s2mm_status = 0;
unsigned int mm2s_status = 0;
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 4);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 4);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 0);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_DESTINATION_ADDRESS, dest);
dma_set(virtual_address, MM2S_START_ADDRESS, src);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0xf001);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 0xf001);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_LENGTH, length);
dma_set(virtual_address, MM2S_LENGTH, length);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_mm2s_sync(virtual_address);
dma_s2mm_status(virtual_address);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
}
int GetCPULoad() {
int FileHandler;
char FileBuffer[1024];
float load;
FileHandler = open("/proc/loadavg", O_RDONLY);
if(FileHandler < 0) {
return -1;
}
read(FileHandler, FileBuffer, sizeof(FileBuffer) - 1);
sscanf(FileBuffer, "%f", &load);
close(FileHandler);
return (int)(load * 100);
}
void *sender(void *params) {
arguments *args = params;
if (args->head == NULL) {
fprintf(stderr, "[-] Head pointer not valid\n");
exit(0);
}
if (args->tail == NULL) {
fprintf(stderr, "[-] Tail pointer not valid\n");
exit(0);
}
if (args->virtual_address == NULL) {
fprintf(stderr, "[-] AXI DMA register pointer not valid\n");
exit(0);
}
if (args->virtual_buffer == NULL) {
fprintf(stderr, "[-] Send buffer pointer not valid\n");
exit(0);
}
unsigned long int units_sent = 0;
unsigned int myhead = 0;
unsigned int mytail = 0;
for (;;) {
pthread_mutex_lock(args->lock);
myhead = *(args->head);
mytail = *(args->tail);
pthread_mutex_unlock(args->lock);
fprintf(stderr, "[*] Send Head: %d Tail: %d\n", myhead, mytail);
if (myhead != mytail) {
int remaining = args->buffsize;
int sent = 0;
int src = FIFO_ADDR + mytail * args->buffsize;
if (args->verbose > 2) {
fprintf(stderr, "[*] Sender: DMA is transferring data from 0x%x to 0x%x\n", src, SEND_ADDR);
}
unsigned int length = args->buffsize;
unsigned int verb = args->verbose > 2 ? 1 : 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
length = remaining < MAX_TRANSF ? remaining : remaining % MAX_TRANSF;
DMATransfer(args->virtual_address, src + sent, SEND_ADDR, length, verb);
remaining -= args->buffsize;
sent += remaining;
}
pthread_mutex_unlock(args->lock);
elements--;
units_sent++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f elements in FIFO: %lu\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, elements);
fprintf(stderr, "[*] %f DMA tranfer to buffer: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_sent);
}
remaining = args->buffsize;
sent = 0;
int result = 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
result = send(args->sockfd, args->virtual_buffer + sent, remaining, 0);
if (result > 0) {
remaining -= result;
sent += remaining;
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
*(args->tail) = (mytail + 1) % (args->fifosize + 1);
pthread_mutex_unlock(args->lock);
//memset(args->virtual_buffer, 0, args->buffsize);
if (args->verbose > 2) {
fprintf(stderr, "[*] %f Unit sent: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_sent);
}
if (args->verbose > 0) {
fprintf(stderr, "[*] Packet retrieved");
}
if (args->verbose > 1) {
fprintf(stderr, " content: ");
memdump(args->virtual_buffer, args->buffsize);
}
if (args->verbose > 0) {
fprintf(stderr, "\n");
}
if (args->verbose > 2) {
fprintf(stderr, "[*] %f CPU Usage: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, GetCPULoad());
}
}
printf("0000000000000000000000000\n");
}
}
void *receiver(void *params) {
arguments *args = params;
if (args->head == NULL) {
fprintf(stderr, "[-] Head pointer not valid\n");
exit(0);
}
if (args->tail == NULL) {
fprintf(stderr, "[-] Tail pointer not valid\n");
exit(0);
}
if (args->virtual_address == NULL) {
fprintf(stderr, "[-] AXI DMA register pointer not valid\n");
exit(0);
}
if (args->virtual_buffer == NULL) {
fprintf(stderr, "[-] Recv buffer pointer not valid\n");
exit(0);
}
unsigned long int units_received = 0;
unsigned int myhead = 0;
unsigned int mytail = 0;
for (;;) {
pthread_mutex_lock(args->lock);
myhead = *(args->head);
mytail = *(args->tail);
pthread_mutex_unlock(args->lock);
fprintf(stderr, "[*] Recv Head: %d Tail: %d\n", myhead, mytail);
if (mytail != myhead + 1) {
int remaining = args->buffsize;
int received = 0;
int result = 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
result = recv(args->sockfd, args->virtual_buffer + received, remaining, 0);
fprintf(stderr, "[*] Recv result: %d\n", result);
if (result > 0) {
remaining -= result;
received += result;
} else if (result == 0) {
fprintf(stderr, "[-] Remote side closed his end of the connection before all data was received\n");
exit(0);
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
printf("++++++++++++++++++++++++++++\n");
pthread_mutex_unlock(args->lock);
units_received++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f Unit recv: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_received);
}
remaining = args->buffsize;
received = 0;
int dest = FIFO_ADDR + myhead * args->buffsize;
if (args->verbose > 2) {
fprintf(stderr, "[*] Receiver: DMA is transferring data from 0x%x to 0x%x\n", RECV_ADDR, dest);
}
unsigned int length = args->buffsize;
unsigned int verb = args->verbose > 2 ? 1 : 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
printf("############################\n");
length = remaining < MAX_TRANSF ? remaining : remaining % MAX_TRANSF;
DMATransfer(args->virtual_address, RECV_ADDR, dest + received, length, verb);
remaining -= args->buffsize;
received += args->buffsize;
}
printf("*************************\n");
*(args->head) = (myhead + 1) % (args->fifosize + 1);
pthread_mutex_unlock(args->lock);
//memset(args->virtual_buffer, 0, args->buffsize);
elements++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f elements in FIFO: %lu\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, elements);
fprintf(stderr, "[*] %f DMA tranfer to DDR: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_received);
}
if (args->verbose > 0) {
fprintf(stderr, "[*] Packet received");
}
if (args->verbose > 1) {
fprintf(stderr, " content: ");
memdump(args->virtual_buffer, args->buffsize);
}
if (args->verbose > 0) {
fprintf(stderr, "\n");
}
if (args->verbose > 2) {
fprintf(stderr, "[*] %f CPU Usage: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, GetCPULoad());
}
}
printf("77777777777777777777777777777\n");
}
}
int isValidIpAddress(char *ipAddress) {
struct sockaddr_in sa;
int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
if (result != 0) {
return 0;
} else {
return 1;
}
}
int main(int argc, char *argv[]) {
if (argc < 3 || argc > 5) {
fprintf(stderr, "\nUsage: DAQTest [IP address] [fifo size]\nExample: DAQTest 192.168.1.81 64\n\n");
fprintf(stderr, "Optional flags: -v Verbose (print operations)\n");
fprintf(stderr, " -vv Very verbose (also print data content)\n");
fprintf(stderr, " -vvv Extremely verbose (also print DMA info)\n\n");
exit(0);
}
if (isValidIpAddress(argv[1]) == 1) {
fprintf(stderr, "[-] Invalid ip address\n");
exit(0);
}
int fifosize = atoi(argv[2]);
if (fifosize < 0 || fifosize > 8192) {
fprintf(stderr, "[-] Invalid fifo size\n");
exit(0);
}
char verbose = 0;
if (argc == 4) {
if (strcmp(argv[3], "-v") == 0) {
verbose = 1;
} else if (strcmp(argv[3], "-vv") == 0) {
verbose = 2;
} else if (strcmp(argv[3], "-vvv") == 0) {
verbose = 3;
} else {
fprintf(stderr, "[-] Unwanted parameter\n");
exit(0);
}
}
struct sockaddr_in servaddr, cli;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd) {
fprintf(stderr, "[-] Socket creation failed\n");
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
servaddr.sin_port = htons(PORT);
/*
struct timeval tv;
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
*/
if (connect(sockfd, (SA * ) & servaddr, sizeof(servaddr)) != 0) {
fprintf(stderr, "[-] Connection failed\n");
exit(0);
}
fprintf(stderr, "[+] Connected to the server\n");
int buffsize = 0;
char* recv_buffer = (char*)&buffsize;
int remaining = sizeof(int);
int received = 0;
int result = 0;
while (remaining > 0) {
result = recv(sockfd, recv_buffer + received, remaining, 0);
if (result > 0) {
remaining -= result;
received += result;
} else if (result == 0) {
fprintf(stderr, "[-] Remote side closed his end of the connection before all data was received\n");
exit(0);
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
//fprintf(stderr, "[*] Page size: %ld\n", sysconf(_SC_PAGE_SIZE));
int dh = open("/dev/mem", O_RDWR | O_SYNC);
unsigned int *virtual_address = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, dh, VIRT_ADDR);
unsigned int *virtual_sendbuff = mmap(NULL, buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, SEND_ADDR);
unsigned int *virtual_recvbuff = mmap(NULL, buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, RECV_ADDR);
unsigned int *virtual_fifo = mmap(NULL, (fifosize + 1) * buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, FIFO_ADDR);
if (virtual_address == MAP_FAILED) {
fprintf(stderr, "[-] AXI DMA registers mmap failed\n");
}
if (virtual_sendbuff == MAP_FAILED) {
fprintf(stderr, "[-] Send buffer mmap failed\n");
}
if (virtual_sendbuff == MAP_FAILED) {
fprintf(stderr, "[-] Send buffer mmap failed\n");
}
if (virtual_recvbuff == MAP_FAILED) {
fprintf(stderr, "[-] Receiver buffer mmap failed\n");
}
if (virtual_fifo == MAP_FAILED) {
fprintf(stderr, "[-] Fifo mmap failed\n");
}
memset(virtual_address, 0, buffsize);
memset(virtual_sendbuff, 0, buffsize);
memset(virtual_recvbuff, 0, buffsize);
memset(virtual_fifo, 0, buffsize);
int head = 0, tail = 0;
pthread_t sendth, recvth;
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
arguments send_args;
send_args.virtual_address = virtual_address;
send_args.virtual_buffer = virtual_sendbuff;
send_args.head = &head;
send_args.tail = &tail;
send_args.buffsize = buffsize;
send_args.fifosize = fifosize;
send_args.sockfd = sockfd;
send_args.lock = &lock;
send_args.verbose = verbose;
arguments recv_args;
recv_args.virtual_address = virtual_address;
recv_args.virtual_buffer = virtual_recvbuff;
recv_args.head = &head;
recv_args.tail = &tail;
recv_args.buffsize = buffsize;
recv_args.fifosize = fifosize;
recv_args.sockfd = sockfd;
recv_args.lock = &lock;
recv_args.verbose = verbose;
start_time = clock();
if (pthread_create(&sendth, NULL, sender, &send_args)) {
fprintf(stderr, "[-] Error creating sender thread\n");
exit(0);
}
if (pthread_create(&recvth, NULL, receiver, &recv_args)) {
fprintf(stderr, "[-] Error creating receiver thread\n");
exit(0);
}
if (pthread_join(sendth, NULL)) {
fprintf(stderr, "[-] Error joining sender thread\n");
exit(0);
}
if (pthread_join(recvth, NULL)) {
fprintf(stderr, "[-] Error joining receiver thread\n");
exit(0);
}
pthread_mutex_destroy(&lock);
close(sockfd);
fprintf(stderr, "[+] Exit\n");
return 0;
}
Try replacing the print statements with delays.
As you're doing networking, you're speed constrained by your network connection. If you do not take this into considerations, your transfer buffers may overflow. The print statements add a certain delay, which might prevent this. Replacing them with actual delays would check for this.
A better solution - if this were indeed the problem - would then be to check for buffer availability before writing.

C socket: recv and send all data

I would like to obtain a behavior similar to this:
Server run
Client run
Client type a command like "help" or other
Server responds appropriately
go to 3
The problem is that when my function excCommand("help") run just a little text is received and printed.
My text file is this:
COMMAND HELP:
help - Display help
quit - Shutdown client
only COMMAND HELP is printed.
Another problem is that when i type a command nothing is printed and after 2 command client exit.
This is the piece in particular:
while (quit)
{
getLine("client> ", command, 10);
if (strcmp(command, "quit") == 0)
quit = 0;
else
excCommand(command);
}
This is the server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
int main(int argc, char *argv[])
{
if (argc != 2)
ErrorWithUserMessage("Parameter(s)", "<Server Port>");
char *service = argv[1];
int servSock = SetupTCPServerSocket(service);
if (servSock < 0)
ErrorWithUserMessage("SetupTCPServerSocket() failed: ", "unable to establish");
unsigned int childProcessCount = 0;
while (1)
{
int clntSock = AcceptTCPConnection(servSock);
pid_t processID = fork();
if (processID < 0)
ErrorWithSystemMessage("fork() failed");
else if (processID == 0)
{
close(servSock);
HandleTCPClient(clntSock);
exit(EXIT_SUCCESS);
}
printf("with child process: %d\n", processID);
close(clntSock);
childProcessCount++;
//clean up zombies
while (childProcessCount)
{
processID = waitpid((pid_t) - 1, NULL, WNOHANG);
if (processID < 0)
ErrorWithSystemMessage("waitpid() failed");
else if (processID == 0)
break;
else
childProcessCount--;
}
}
}
Handler:
void HandleTCPClient(int clntSock)
{
char buffer[BUFSIZE];
ssize_t numBytesRcvd = recv(clntSock, buffer, BUFSIZE, 0);
buffer[numBytesRcvd] = '\0';
if (numBytesRcvd < 0)
ErrorWithSystemMessage("recv() failed");
if (strcmp(buffer, "help") == 0)
{
FILE *fp = fopen("help.txt", "r");
if (fp)
{
char line[128];
while (fgets(line, sizeof(line), fp) != NULL)
{
if (send(clntSock, line, sizeof(line), 0) < 0)
ErrorWithSystemMessage("send() failed");
}
fclose(fp);
}
}
close(clntSock);
}
and this is my client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "common.h"
int sock;
void getLine(char *message, char *buf, int maxLen)
{
printf("%s", message);
fgets(buf, maxLen, stdin);
buf[strlen(buf) - 1] = 0;
}
void excCommand(char *command)
{
if ( send(sock, command, strlen(command), 0) < 0)
ErrorWithSystemMessage("send() failed");
char replyMessage[BUFSIZE];
ssize_t numBytesRecv = 0;
do
{
numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
if ( numBytesRecv < 0)
ErrorWithSystemMessage("recv() failed");
printf("%s\n", replyMessage);
memset(&replyMessage, 0, sizeof(replyMessage));
}
while (numBytesRecv > 0);
}
void PrintFile(const char *filename)
{
FILE *fp;
fp = fopen(filename, "r");
if (fp)
{
char line[128];
while (fgets(line, sizeof(line), fp) != NULL)
fputs(line, stdout);
fputs("\n", stdout);
fclose(fp);
}
}
int main(int argc, char *argv[])
{
int quit = 1;
char command[10];
if (argc < 2 || argc > 3)
{
ErrorWithUserMessage("Parameter(s)", "<Server Address> <Server Port>");
}
char *server = argv[1];
char *service = argv[2];
sock = SetupTCPClientSocket(server, service);
if (sock < 0)
ErrorWithUserMessage("SetupTCPClientSocket() failed: ", "unable to connect");
printf("Connection established!\n\n");
PrintFile("menu.txt");
excCommand("help");
while (quit)
{
getLine("client> ", command, 10);
if (strcmp(command, "quit") == 0)
quit = 0;
else
excCommand(command);
}
fputs("\n", stdout);
close(sock);
exit(EXIT_SUCCESS);
}
sorry for being so long-winded
The recv() and send() functions do not guarantee to send/recv all data (see man recv, man send)
You need to implement your own send_all() and recv_all(), something like
bool send_all(int socket, void *buffer, size_t length)
{
char *ptr = (char*) buffer;
while (length > 0)
{
int i = send(socket, ptr, length);
if (i < 1) return false;
ptr += i;
length -= i;
}
return true;
}
The following guide may help you Beej's Guide to Network Programming
Usual problems.
void excCommand(char *command)
{
if ( send(sock, command, strlen(command), 0) < 0)
ErrorWithSystemMessage("send() failed");
char replyMessage[BUFSIZE];
ssize_t numBytesRecv = 0;
do
{
numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
if ( numBytesRecv < 0)
ErrorWithSystemMessage("recv() failed");
printf("%s\n", replyMessage);
Invalid. numBytesRecv could have been zero, in which case there is no message at all, otherwise at this point must be positive, as you've already tested for negative, and it indicates the actual length of the message, which isn't necessarily null-terminated. Change to:
if (numBytesRecv == 0)
break;
printf("%.*s\n", numBytesRecv, replyMessage);
and then:
memset(&replyMessage, 0, sizeof(replyMessage));
Pointless. Remove.
}
while (numBytesRecv > 0);
At this point you should check for numBytesRecv < 0 and call perror() or one of its friends.
I choose to send before each send() if i have to continue or not.
so i first have 3 define
#define BUFFSIZE 1024
#define CONT "CONT"
#define DONE "DONE"
Then to send my data
int send_to_socket(int sock, char *msg)
{
size_t len;
int ret[2];
len = strlen(msg);
ret[0] = send(sock, (len <= BUFFSIZE) ? DONE : CONT, 4, 0);
ret[1] = send(sock, msg, BUFFSIZE, 0);
if (ret[0] <= 0 || ret[1] <= 0)
{
perror("send_to_socket");
return (-1);
}
if (len > BUFFSIZE)
return (send_to_socket(sock, msg + BUFFSIZE));
return (1);
}
And to receive it :
char *recv_from_socket(int cs)
{
char state[5];
char buff[BUFFSIZE+1];
char *msg;
int ret[2];
msg = NULL;
while (42)
{
bzero(state, 5);
bzero(buff, BUFFSIZE+1);
ret[0] = recv(cs, state, 4, 0);
ret[1] = recv(cs, buff, BUFFSIZE, 0);
if (ret[0] <= 0 || ret[1] <= 0)
{
perror("recv_from_socket");
return (NULL);
}
// strfljoin() is selfmade
// join the string and free the left argument to prevent memory leaks.
// return fresh new string
msg = (msg) ? ft_strfljoin(msg, buff) : strdup(buff);
if (strncmp(state, DONE, 4) == 0)
break ;
i++;
}
return (msg);
}

Resources