How to get NIC details from a C program? - c

I want to get the following details for all the NICs attached to my computer:
1) Interface name (eg. eth0)
2) Interface Number (like in Windows) if such a thing exists in Linux
3) NIC bandwidth capacity and mode (eg. 1Gb/s full duplex)

You can use getifaddrs()/freeifaddrs() to obtain a linked list of all interfaces, then ioctl(fd, SIOCGIFINDEX, struct ifreq *) to obtain the interface index for each. Since the interfaces are consecutive and always listed (regardless of whether or they are up (active) or not), I choose to enumerate them with a loop using ioctl(fd, SIOCGIFNAME, struct ifreq *) instead. In all cases fd is an AF_INET socket.
To obtain the duplex and speed of the interface, you need to use the ioctl(fd, SIOCETHTOOL, struct ifreq *) with the ifr_data pointing to a struct ethtool_cmd having cmd = ETHTOOL_GSET.
The ioctls should return -1 if they fail, and a nonnegative value (zero, I believe) if success.
Here is an example program:
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct interface {
int index;
int flags; /* IFF_UP etc. */
long speed; /* Mbps; -1 is unknown */
int duplex; /* DUPLEX_FULL, DUPLEX_HALF, or unknown */
char name[IF_NAMESIZE + 1];
};
static int get_interface_common(const int fd, struct ifreq *const ifr, struct interface *const info)
{
struct ethtool_cmd cmd;
int result;
/* Interface flags. */
if (ioctl(fd, SIOCGIFFLAGS, ifr) == -1)
info->flags = 0;
else
info->flags = ifr->ifr_flags;
ifr->ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET; /* "Get settings" */
if (ioctl(fd, SIOCETHTOOL, ifr) == -1) {
/* Unknown */
info->speed = -1L;
info->duplex = DUPLEX_UNKNOWN;
} else {
info->speed = ethtool_cmd_speed(&cmd);
info->duplex = cmd.duplex;
}
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1)
return errno;
return 0;
}
int get_interface_by_index(const int index, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (index < 1 || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
ifr.ifr_ifindex = index;
if (ioctl(socketfd, SIOCGIFNAME, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = index;
strncpy(info->name, ifr.ifr_name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int get_interface_by_name(const char *const name, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (!name || !*name || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(socketfd, SIOCGIFINDEX, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = ifr.ifr_ifindex;
strncpy(info->name, name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int main(int argc, char *argv[])
{
struct interface iface;
int arg;
int status = 0;
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s { -h | --help }\n", argv[0]);
fprintf(stderr, " %s\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (argc > 1) {
for (arg = 1; arg < argc; arg++) {
if (get_interface_by_name(argv[arg], &iface) != 0) {
fprintf(stderr, "%s: No such interface.\n", argv[arg]);
status = 1;
continue;
}
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
} else {
for (arg = 1; ; arg++) {
if (get_interface_by_index(arg, &iface) != 0)
break;
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
}
return status;
}
If you save the above as iflist.c, you can compile it using
gcc -W -Wall -O3 iflist.c -o iflist
To see the usage, run iflist -h. To list all interfaces, run it without parameters:
./iflist
The above will use the enumeration method I described. To list only specific interfaces, run it naming the interfaces:
./iflist eth0 lo
Duplex and speed is only listed for ethernet interfaces, of course.
Edited to add:
If the above program does not supply the bandwidth and mode for an interface, here is a simplified version which reports the exact reason (errors). This one takes the interface names as commandline parameters; it does not enumerate interfaces.
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int ethernet_interface(const char *const name,
int *const index, int *const speed, int *const duplex)
{
struct ifreq ifr;
struct ethtool_cmd cmd;
int fd, result;
if (!name || !*name) {
fprintf(stderr, "Error: NULL interface name.\n");
fflush(stderr);
return errno = EINVAL;
}
if (index) *index = -1;
if (speed) *speed = -1;
if (duplex) *duplex = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
const int err = errno;
fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err));
fflush(stderr);
return errno = err;
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
const int err = errno;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err));
return errno = err;
}
if (speed)
*speed = ethtool_cmd_speed(&cmd);
if (duplex)
switch (cmd.duplex) {
case DUPLEX_HALF: *duplex = 0; break;
case DUPLEX_FULL: *duplex = 1; break;
default:
fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex);
fflush(stderr);
*duplex = -1;
}
if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0)
*index = ifr.ifr_ifindex;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int err = errno;
fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err));
return errno = err;
}
return 0;
}
int main(int argc, char *argv[])
{
int arg, speed, index, duplex;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 0;
}
for (arg = 1; arg < argc; arg++) {
if (ethernet_interface(argv[arg], &index, &speed, &duplex))
return 1;
if (index == -1)
printf("%s: (no interface index)", argv[arg]);
else
printf("%s: interface %d", argv[arg], index);
if (speed == -1)
printf(", unknown bandwidth");
else
printf(", %d Mbps bandwidth", speed);
if (duplex == 0)
printf(", half duplex.\n");
else if (duplex == 1)
printf(", full duplex.\n");
else
printf(", unknown mode.\n");
}
return 0;
}
Questions?

(1) getifaddrs()
(2) if_indextoname(), if_nameindex(), if_nametoindex()
(3) I'm not sure about this one but you might be able to get at it through ioctl() and one of the SIOCGIF* parameters or from /proc.

the following link well explain the getifaddrs function with a working example
getifaddrs()

ethtool eth1
this command will list all the details about eth1 including speed, duplex, port...
you can use popen() to get the output and map it.
POPEN(3) Linux Programmer's Manual
POPEN(3)
NAME
popen, pclose - pipe stream to or from a process
SYNOPSIS
#include
FILE *popen(const char *command, const char *type);

Related

C function call is giving me a "too many arguments" error

I'm getting a "too many arguments in function call" error in my C program. The error occurs at a line where I'm calling a function that has a fixed number of arguments. I'm not sure why I'm getting this error, as I'm not passing in more arguments than the function expects. Here's the code where the error occurs:
if (mkdir(path, 0777) == -1)
Here is full code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#define BUF_SIZE 1024
#define MAX_ARGS 10
// Print the usage message for the program
void print_usage() {
fprintf(stderr, "Usage: syscalls <command> [arguments]\n");
}
// Read the contents of a file and write them to stdout
int read_file(const char *path) {
static char buf[BUF_SIZE];
int fd = open(path, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
ssize_t num_read;
while ((num_read = read(fd, buf, BUF_SIZE)) > 0) {
if (write(STDOUT_FILENO, buf, num_read) != num_read) {
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
return 1;
}
}
if (num_read == -1) {
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
return 1;
}
return 0;
}
// Write a set of lines to a file
int write_file(const char *path, char *lines[], int num_lines) {
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
int total_bytes = 0;
for (int i = 0; i < num_lines; i++) {
const char *line = lines[i];
size_t len = strlen(line);
ssize_t num_written = pwrite(fd, line, len, total_bytes);
if (num_written == -1) {
fprintf(stderr, "Failed to write to %s: %s\n", path, strerror(errno));
return 1;
}
total_bytes += num_written;
}
printf("Wrote %d B\n", total_bytes);
return 0;
}
// Create a directory
int make_directory(const char *path) {
if (mkdir(path, 0777) == -1) {
if (errno == EEXIST) {
fprintf(stderr, "%s already exists\n", path);
} else {
fprintf(stderr, "Failed to create %s: %s\n", path, strerror(errno));
}
return 1;
}
return 0;
}
// List the contents of a directory
int list_directory(const char *path) {
DIR *dir = opendir(path);
if (dir == NULL) {
fprintf(stderr, "Failed to open directory %s: %s\n", path, strerror(errno));
return 1;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
if (closedir(dir) == -1) {
fprintf(stderr, "Failed to close directory %s: %s\n", path, strerror(errno));
return 1;
}
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
print_usage();
return 1;
}
char *command = argv[1];
if (strcmp(command, "read") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return read_file(argv[2]);
} else if (strcmp(command, "write") == 0) {
if (argc < 4 || argc > MAX_ARGS + 2) {
print_usage();
return 1;
}
return write_file(argv[2], argv + 3, argc - 3);
} else if (strcmp(command, "mkdir") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return make_directory(argv[2]);
} else if (strcmp(command, "ls") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return list_directory(argv[2]);
} else {
print_usage();
return 1;
}
}
I am getting this error in terminal:
syscalls.c: In function 'write_file':
syscalls.c:54:31: warning: implicit declaration of function 'pwrite' [-Wimplicit-function-declaration]
ssize_t num_written = pwrite(fd, line, len, total_bytes);
^~~~~~
syscalls.c: In function 'make_directory':
syscalls.c:67:9: error: too many arguments to function 'mkdir'
if (mkdir(path, 0777) == -1) {
^~~~~
In file included from c:\mingw\include\unistd.h:56:0,
from syscalls.c:3:
c:\mingw\include\io.h:516:38: note: declared here
_CRTIMP __cdecl __MINGW_NOTHROW int mkdir (const char *);
Please help me to resolve this issue. Thank you
mkdir() is not specified in the C standard. It is specified in the POSIX standard, which is more or less a superset of the C standard.
This declaration of mkdir():
c:\mingw\include\io.h:516:38: note: declared here
_CRTIMP __cdecl __MINGW_NOTHROW int mkdir (const char *);
is the Microsoft version of the function, which takes a single argument, and does not conform to the POSIX standard.
From Microsoft's page:
The Microsoft-implemented POSIX function name mkdir is a deprecated
alias for the _mkdir function.
int _mkdir(
const char *dirname
);
Possible fix:
#ifdef _CRTIMP
#define mkdir(d,m) (mkdir)(d)
#endif
Credit: #chqrlie

How to use c-ares with epoll?

I have a working code with performs asynchronous DNS resolution with c-ares library calls. The program uses select to monitor file descriptors up to a maximum of FD_SETSIZE which is 1024 on my system. I want to use many more file descriptors so want to rewrite the code to use epoll instead of select.
Here is the select based function of my current program:
static void
wait_ares(ares_channel channel)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds > 0) {
tvp = ares_timeout(channel, NULL, &tv);
select(nfds, &read_fds, &write_fds, NULL, tvp);
ares_process(channel, &read_fds, &write_fds);
}
}
I've done some googling before posting my question and I've found out that to implement this with epoll I can no longer use ares_fds, ares_timeout and ares_process but must use ares_getsock() and ares_process_fd() instead. But further than that I have no idea how to do this and can't find any example codes using epoll with c-ares. Can anyone modify the code provided below to use epoll instead of select? Or at least give me some pointers to get me started?
#include <ares.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define TIMEOUT 3000 /* Max. number of ms for first try */
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
static int nwaiting;
static void
state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void
callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
printf("%s\n%s\n", host->h_name, ip);
}
}
static void
wait_ares(ares_channel channel)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds > 0) {
tvp = ares_timeout(channel, NULL, &tv);
select(nfds, &read_fds, &write_fds, NULL, tvp);
ares_process(channel, &read_fds, &write_fds);
}
}
int
main(int argc, char *argv[])
{
FILE * fp;
char domain[128];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = TIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
do {
if (nwaiting >= MAXWAITING || done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!done) {
if (fscanf(fp, "%127s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
fprintf(stderr, "done sending\n");
done = 1;
}
}
} while (nwaiting > 0);
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
return 0;
}
The program requires a file with a domain name on each line to work.
This is what I ended up coming up with.
#include <ares.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <errno.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define TIMEOUT 3000 /* Max. number of ms for first try */
#define DNS_MAX_EVENTS 10000
#define DNS_MAX_SERVERS 2
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
static int nwaiting;
ares_socket_t dns_client_fds[ARES_GETSOCK_MAXNUM] = {0};
struct epoll_event ev, events[DNS_MAX_EVENTS];
int i,bitmask,nfds, epollfd, timeout, fd_count, ret;
static void
state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void
callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
printf("%s\n%s\n", host->h_name, ip);
}
}
static void
wait_ares(ares_channel channel)
{
nfds=0;
bitmask=0;
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, dns_client_fds[i], NULL) < 0) {
continue;
}
}
}
memset(dns_client_fds, 0, sizeof(dns_client_fds));
bitmask = ares_getsock(channel, dns_client_fds, DNS_MAX_SERVERS);
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
ev.events = 0;
if (ARES_GETSOCK_READABLE(bitmask, i)) {
ev.events |= EPOLLIN;
}
if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
ev.events |= EPOLLOUT;
}
ev.data.fd = dns_client_fds[i];
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, dns_client_fds[i], &ev) < 0) {
if(errno == EEXIST) {
nfds++;
continue;
}
continue;
}
nfds++;
}
}
if(nfds==0)
{
return;
}
timeout = 1000;//millisecs
fd_count = epoll_wait(epollfd, events, DNS_MAX_EVENTS, timeout);
if (fd_count < 0) {
return;
}
if (fd_count > 0) {
for (i = 0; i < fd_count; ++i) {
ares_process_fd(channel, ((events[i].events) & (EPOLLIN) ? events[i].data.fd:ARES_SOCKET_BAD), ((events[i].events) & (EPOLLOUT)? events[i].data.fd:ARES_SOCKET_BAD));
}
} else {
ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
}
int
main(int argc, char *argv[])
{
FILE * fp;
char domain[128];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = TIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
memset(dns_client_fds, 0, sizeof(dns_client_fds));
memset((char *)&ev, 0, sizeof(struct epoll_event));
memset((char *)&events[0], 0, sizeof(events));
epollfd = epoll_create(DNS_MAX_SERVERS);
if (epollfd < 0) {
perror("epoll_create: ");
}
do {
if (nwaiting >= MAXWAITING || done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!done) {
if (fscanf(fp, "%127s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
fprintf(stderr, "done sending\n");
done = 1;
}
}
} while (nwaiting > 0);
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
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 TCP sockets: read () on socket returns Resourse temporarily unavailable

The system I realize consists of a ring of tokens (each token is a ckient-server process).
I tested it runnimy two processes.
In function serverMessageProcessor() I call readMessage() function, in which I use read() to read all parts of a message from an (in)socket and (after processes it) write another message on (out)socket.
The first time I do it, it works well, the second time, one of the read() function in my readMessage() function, gives read: Success (I use perror to catch read error) and read: Resourse temporarily unavailable on the other process.
There are some prints for debugging in the code.
I hope you can help me.
Thanks a lot in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h> //per le funzioni sui socket.
#include <arpa/inet.h> //per la funzione inet_aton().
#include <netinet/in.h> //per la struct sockaddr.
#include <sys/wait.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <ctype.h> //per la funzione isdigit().
#include <fcntl.h> //per rendere il socket bloccante o no.
#include <sys/select.h>
/* Error hendler */
void sys_error (const char *message) {
perror (message);
}
/* Connessione in ingresso */
int setUpConnectionIn(int port, int *sock_fd){
int sock_in;
struct sockaddr_in addr;
addr.sin_family = AF_INET; //Internet Address Family.
addr.sin_port=htons(port); //Local port.
addr.sin_addr.s_addr = htonl(INADDR_ANY); //Any incoming interface.
//Create socket for incoming connections.
if((sock_in = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
stampaStr("Errore: Creazione socket non riuscita.", 1);
return -1;
}
//Bind to the local address.
if(bind(sock_in, (struct sockaddr *) &addr, sizeof(addr)) < 0){
sys_error("Errore: impossibile assegnare l'indirizzo al socket.");
close(sock_in);
return -1;
}
//Mark the socket so it will listen for incoming connections.
if(listen(sock_in,5) < 0) {
sys_error("Errore: listen non riuscita.");
close(sock_in);
return -1;
}
*sock_fd = sock_in;
return 0;
}
/* Interfaccia Connessione in ingresso */
int setUpConnectionIn_2 (int sock_fd){
int connection_in;
if ((connection_in = accept(sock_fd, NULL, NULL)) < 0) {
sys_error ("Errore in funzione setUpConnectionIn_2");
return -1;
}
return connection_in;
}
/* Connessione in uscita */
int setUpConnectionOut (int *sock_fd, int connection_port, char *conn_addr){
int check;
struct sockaddr_in addr_out;
int sock_out;
addr_out.sin_family = AF_INET;
addr_out.sin_port = htons(connection_port);
if (inet_aton(conn_addr, &addr_out.sin_addr) < 0) {
sys_error ("Errore: inet_aton");
return -1;
}
if((sock_out = socket(PF_INET, SOCK_STREAM, 0))<0) {
sys_error("Errore: Creazione socket non riuscita.");
return -1;
}
stampaStr("In attesa di connessione alla stazione successiva..\n", 1);
while(connect(sock_out, (struct sockaddr *)&addr_out, sizeof(addr_out)) < 0);
*sock_fd = sock_out;
return 0;
}
int closed_ring = 0;
int readMessage (int *fd, unsigned char *cod, int *size, char **content) {
char *content_msg;
unsigned char cod_msg;
int size_msg;
int retval = fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) | O_NONBLOCK);
printf ("readMessage - prima read\n");
if (read(*fd, &cod_msg, 1) == 0) {
sys_error ("read - cod_msg");
return -1;
}
if (read(*fd, &size_msg, 4) == 0) {
sys_error ("read - size_msg");
return -1;
}
*content = (char *)malloc((size_msg+1)*sizeof(char));
(*content)[size_msg+1] = '\0';
if (read(*fd, *content, size_msg) == 0) {
sys_error ("read - content_msg");
return -1;
}
retval = fcntl(*fd, F_SETFL, (fcntl(*fd, F_GETFL) | O_NONBLOCK) & (~O_NONBLOCK));
printf ("readMessage - dopo read\n");
printf ("(readMessage)cod: %c - size: %d - msg: %s\n", cod_msg, size_msg, *content);
*cod = cod_msg;
*size = size_msg;
//content = (char *)malloc(size_msg*sizeof(char));
//memcpy(content, content_msg, strlen(content_msg));
//content = content_msg;
printf ("content: %s\n", *content);
return 0;
}
int buildMessage (char **new_msg, unsigned char cod, int size, char *content) {
int msg_len = size+6;
*new_msg = (char *)malloc(msg_len*sizeof(char));
(*new_msg)[0] = cod;
memcpy (((*new_msg)+1), &size, 4);
memcpy (((*new_msg)+5), content, size);
(*new_msg)[msg_len] = '\0';
//new_msg = msg;
return strlen (*new_msg);
}
int serverMessageProcessor (int *fd_in, int *out_fds) {
char *new_msg;
char *content_msg;
unsigned char cod_msg = 100;
int size_msg;
int msg_length;
char *tmp_PID_str;
uint64_t myPID;
uint64_t tempPID;
int fd;
if (readMessage (fd_in, &cod_msg, &size_msg, &content_msg) < 0) {
sys_error ("readMessage");
return -1;
}
printf ("(serverMessageProcessor) cod: %c - size: %d - msg: %s\n", cod_msg, size_msg, content_msg);
printf ("serverMessageProcessor - prima switch\n");
switch (cod_msg) {
case ('1'): {
fd = 0;
if ((myPID = getpid()) < 0) {
sys_error ("getpid");
return -1;
}
tmp_PID_str = (char *)malloc((size_msg+1)*sizeof(char));
tmp_PID_str[size_msg+1] = '\0';
printf ("serverMessageProcessor - prima memcpy(myPID) PID: %ld\n", myPID);
memcpy (tmp_PID_str, &myPID, sizeof(uint64_t));
printf ("serverMessageProcessor - dopo memcpy(myPID)\n");
if (strcmp (content_msg, tmp_PID_str) == 0) {
printf ("serverMessageProcessor - dopo strcmp TRUE (myPID, tempPID)\n");
closed_ring = 1;
} else {
//new_msg = (char *)malloc(size_msg+6)*sizeof(char));
printf ("serverMessageProcessor - dopo strcmp FALSE (myPID, tempPID)\n");
//msg_length = buildMessage (&new_msg, cod_msg, size_msg, content_msg);
msg_length = size_msg+6;
new_msg = (char *)malloc(msg_length*sizeof(char));
new_msg[0] = cod_msg;
memcpy (new_msg+1, &size_msg, 4);
memcpy (new_msg+5, content_msg, size_msg);
new_msg[msg_length] = '\0';
printf ("serverMessageProcessor - dopo buildMessage: %s\n", new_msg);
printf ("(serverMessageProcessor) cod: %c - size: %d - msg: %s\n", cod_msg, size_msg, content_msg);
if (write (out_fds[fd], &cod_msg, 1) < 0) {
sys_error ("write");
return -1;
}
if (write (out_fds[fd], &size_msg, 4) < 0) {
sys_error ("write");
return -1;
}
if (write (out_fds[fd], content_msg, size_msg) < 0) {
sys_error ("write");
return -1;
}
printf ("serverMessageProcessor - dopo write\n");
}
printf ("serverMessageProcessor - fuori if strcmp(myPID, tempPID)\n");
}
}
}
int main (int argc, char *argv[]) {
int listen_port, connection_port;
int connection;
int check = -1;
char *conn_addr;
char inter_lv = 'a';
int sock_in; //socket descriptor for reading.
int sock_out; //socket descriptor for writing.
struct sockaddr_in addr_in;
struct sockaddr_in addr_out;
int connection_flag = 0;
int out_fds[3];
/********************* VARIABILI GESTIONE MESSAGGI ************************/
char *new_msg = NULL;
char *content_msg = NULL;
unsigned char cod_msg;
int size_msg;
int msg_len;
uint64_t tempPID;
uint64_t myPID;
/**************************************************************************/
/********************** VARIABILI GESTIONE SOTTOPROCESSI ******************/
int pipe_IN[2];
int pipe_OUT[2];
int pipe_CLIENT[2];
int pid_client;
/**************************************************************************/
/***************************** VARIABILI PER SELECT SYSCALL ***************/
fd_set rfds;
struct timeval tv;
int retval;
/**************************************************************************/
if(readIntFromString(0, &listen_port, argv[1]) < 0){
printf("Invalid value of listen_port\n");
return -1;
}
if(listen_port >= 0 && listen_port <= 1023){
printf("Insert a port in range 0-1023\n");
return -1;
}
if(listen_port >= 49152){
printf("Insert a port not higher than 49152\n");
return -1;
}
if(readIntFromString(0, &connection_port, argv[2]) < 0){
printf("Invalid value of connection_port\n");
return -1;
}
if(connection_port >= 0 && connection_port <= 1023){
printf("Insert a port in range 0-1023\n");
return -1;
}
if(connection_port >= 49152){
printf("Insert a port not higher than 49152\n");
return -1;
}
conn_addr = argv[3];
if((toupper(argv[4][0]) == 'S' || toupper(argv[4][0]) == 'N') && argv[4][1] == '\0'){
inter_lv = toupper(argv[4][0]);
}else{
printf("Invalid Interactivity Level\n");
return -1;
}
/*********************** Circuit Building **************************/
if(setUpConnectionIn(listen_port, &sock_in) < 0) {
sys_error ("Errore in funzione: setUpConnectionIn");
return -1;
}
if (setUpConnectionOut (&sock_out, connection_port, conn_addr) < 0) {
sys_error ("Errore in funzione setUpConnectionOut");
return -1;
}
printf ("-------------out-connected-------------\n");
if ((connection = setUpConnectionIn_2 (sock_in)) < 0) {
sys_error ("Errore in funzione setUpConnectionIn_2");
return -1;
}
printf ("-------------in-connected--------------\n");
/**********************************************************************/
/* Controlla connection (socket in entrata) per vedere se è pronto per operazioni di I/O */
//retval = fcntl(connection, F_SETFL, fcntl(connection, F_GETFL) | O_NONBLOCK);
FD_ZERO(&rfds);
FD_SET(connection, &rfds);
out_fds[0] = sock_out;
/* Attende 5 secondi */
tv.tv_sec = 5;
tv.tv_usec = 0;
while (closed_ring == 0) {
if (connection_flag == 0) {
if ((myPID = getpid()) < 0) {
sys_error ("getpid");
return -1;
}
size_msg = sizeof(uint64_t);
msg_len = size_msg+6;
new_msg = (char*)malloc(msg_len*sizeof(char));
new_msg[0] = '1';
memcpy(new_msg+1, &size_msg, 4);
memcpy(new_msg+5, &myPID, size_msg);
new_msg[msg_len] = '\0';
printf ("(MAIN) myPID: %ld - cod: %c - size: %d - msg: %s\n", myPID, new_msg[0], size_msg, &(new_msg[5]));
if (write (out_fds[0], new_msg, msg_len) < 0) {
sys_error ("write");
return -1;
}
printf ("Message 1 (ring closing) sent: %s\n", new_msg);
connection_flag = 1;
}
retval = select(connection+1, &rfds, NULL, NULL, &tv);
if (retval == -1) {
sys_error ("select");
return -1;
} else if (retval) {
stampaStr("Available data on (in)socket\n", 1); /* FD_ISSET(0, &rfds) avrà valore TRUE */
/*************** DEBUG ************************
if (read (connection, &cod_msg, 1) == 0) {
sys_error ("read - main");
return -1;
} else {
printf ("read - main: %c\n", cod_msg);
}
**********************************************/
if (serverMessageProcessor (&connection, out_fds) < 0) {
sys_error ("serverMessageProcessor");
return -1;
}
} else {
stampaStr("None message in entry\n", 1);
char c = getchar();
fflush(stdin);
}
}
/* Creazione sottoprocesso per gestione connessioni con Client per iscrizione auto */
if (pipe(pipe_CLIENT) < 0) {
sys_error ("pipe_client");
return -1;
}
if ((pid_client = fork()) < 0) {
sys_error ("fork_client");
return -1;
} else if (pid_client == 0) { /* Processo figlio - accetta connessioni da Client */
printf("Subprocess to manage client(s) connection\n");
//while (1);
} else { /* Processo Padre */
printf("Parent process\n");
}
return 0;
}
When read() returns 0, it means the socket has been closed by the other end, it's not an error, so you shouldn't call sys_error(). An error is indicated by read() returning -1. That's why you're getting Success as the error message.
However, you've set the socket to be non-blocking, so read() will also return -1 when there's nothing available to be read. It will set errno = EAGAIN in this case, and the message for this is Resource temporarily Available.
You need to test for this and go back to your loop that waits for data with select(). This is normal for non-blocking sockets, so you shouldn't report it as an error.
So the code should be like:
if (read(*fd, &cod_msg, 1) == -1) {
if (errno == EAGAIN) {
return -2;
} else {
sys_error ("read - cod_msg");
return -1;
}
}
I've changed this to return -2 in the EAGAIN case, you'll need to change the caller to check for this so it doesn't call sys_error either.

c-code for parallax rfid reader on raspberry pi

I've searched for quite some time now for a solution to my problem.
I'd like to read RFID tags on my Raspberry, but I want to do it in C-code, as the rest of my project is written in C.
I have a few questions to the following C-code I found here on stackoverflow.com:
What .h includes do I need for the code below?
Where is the interface setup, that I'm using? (/dev/ttyAMA0)
Please help me to get this code snippet working right, as it's been holding me up for a few days already.
char read_rfid(char* rfid_num) {
fd_set input_fdset;
ssize_t length;
int done;
for(done=0; done < 14; ) {
FD_ZERO(&input_fdset);
FD_SET(fd,&input_fdset);
if(select(fd+1 ,&input_fdset, NULL,NULL,NULL) == -1) {
if (errno == EAGAIN) continue;
perror("Terminal select() failed");
return -1;
}
if(FD_ISSET(fd,&input_fdset)) {
if((length = read(fd,rfid_num+done,14-done)) == -1) {
if (errno == EAGAIN) continue;
perror("Terminal: read() failed");
return -1;
}
write(STDOUT_FILENO,rfid_num+done,length);
done += length;
}
}
return 0;
}
int setupRS232()
{
struct termios term_attr;
if((fd = open(RFID,O_RDWR)) == -1)
{
perror("Can't open Device");
return(1);
}
if(tcgetattr(fd,&term_attr) != 0)
{
perror("terminal: tcgetattr() failed");
return(1);
}
term_attr.c_cflag = BAUD|CS8|CRTSCTS|CLOCAL|CREAD;
term_attr.c_iflag = 0;
term_attr.c_oflag = 0;
term_attr.c_lflag = 0;
if(tcsetattr(fd,TCSAFLUSH,&term_attr) != 0)
{
perror("terminal: tcsetattr() failed");
return(1);
}
}
int main(int argc, char** argv)
{
char rfid_num[14];
int i;
if(setupRS232() == 1)
return(1);
puts("Waiting for transponder...");
read_rfid(rfid_num);
for(i=0;i<20;i++)
{
printf("%x\n",rfid_num[i]);
}
}
#include <unistd.h> // for read & write functions
#include <sys/select.h> // fd_set functions
#include <stdio.h> // for perror & printf family
#include <sys/types.h> // for open related function
#include <sys/stat.h> // for open related function
#include <fcntl.h> // for open related function
#include <termios.h> // for terminal functions
#include <errno.h> // for error code
#define RFID "path_to_rfid" // FIXME <- you should set this properly
char read_rfid(char* rfid_num, int fd)
{
fd_set input_fdset;
ssize_t length;
int done;
for(done=0; done < 14; ) {
FD_ZERO(&input_fdset);
FD_SET(fd,&input_fdset);
if(select(fd+1 ,&input_fdset, NULL,NULL,NULL) == -1) {
perror("Terminal select() failed");
return -1;
}
if(FD_ISSET(fd,&input_fdset)) {
if((length = read(fd,rfid_num+done,14-done)) == -1) {
perror("Terminal: read() failed");
return -1;
}
write(STDOUT_FILENO,rfid_num+done,length);
done += length;
}
}
return 0;
}
int setupRS232()
{
struct termios term_attr;
int fd = 0;
if((fd = open(RFID,O_RDWR)) == -1) {
perror("Can't open Device");
return(-1);
}
if(tcgetattr(fd,&term_attr) != 0)
{
perror("terminal: tcgetattr() failed");
close(fd);
return(-1);
}
term_attr.c_cflag = CBAUD|CS8|CRTSCTS|CLOCAL|CREAD;
term_attr.c_iflag = 0;
term_attr.c_oflag = 0;
term_attr.c_lflag = 0;
if(tcsetattr(fd,TCSAFLUSH,&term_attr) != 0) {
perror("terminal: tcsetattr() failed");
close(fd);
return(-1);
}
return (fd);
}
int main(int argc, char** argv)
{
char rfid_num[14];
int i;
int fd;
if((fd = setupRS232()) == -1) {
return(-1);
}
puts("Waiting for transponder...");
read_rfid(rfid_num, fd);
for(i=0;i<20;i++) {
printf("%x\n",rfid_num[i]);
}
return 0;
}
Now your code is ready to be compiled, at least in my machine I could compile with no errors.

Resources