EV_CLEAR flag confusion. What state of an event does it change? - c

My manual on kqueue says:
EV_CLEAR After the event is retrieved by the user, its state is
reset. This is useful for filters which report state
transitions instead of the current state. Note that some
filters may automatically set this flag internally.
I did a small program that sets a timer with EV_DISPATCH and after first wake-up, enables it.
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <sys/event.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <yma/yreport.h>
void ykq_kev_pev(struct kevent *ev);
int main()
{
int status;
struct kevent kev;
int kq;
if((kq = kqueue()) < 0){
fprintf(stderr, " * kqueue() failed\n errno = %d\n", errno);
return 1;
}
kev.ident = 1;
kev.filter = EVFILT_TIMER;
kev.flags = EV_ADD | EV_DISPATCH;
kev.data = 4;
kev.fflags = NOTE_SECONDS;
l_reg_ev:
status = kevent(kq, &kev, 1, NULL, 0, NULL);
if(status < 0){
fprintf(stderr, " * kevent() failed\n errno = %d\n", errno);
return 1;
}
for(;;){
status = kevent(kq, NULL, 0, &kev, 1, NULL);
if(status < 0){
fprintf(stderr, " * kevent() failed\n errno = %d\n", errno);
return 1;
}else if(status > 0){
if(kev.flags & EV_ERROR){
ykq_kev_pev(&kev);
return 1;
}
ykq_kev_pev(&kev);
kev.flags = EV_ENABLE;
goto l_reg_ev;
}
}
return 0;
}
void ykq_kev_pev(struct kevent *ev)
{
u_short flags = ev->flags;
u_int fflags = ev->fflags;
short filter = ev->filter;
int64_t data = ev->data;
static const char *p_null = "NULL";
static char const *vf[] = {
"EV_ADD ",
"EV_ENABLE ",
"EV_DISABLE ",
"EV_DISPATCH ",
"EV_DELETE ",
"EV_RECEIPT ",
"EV_ONESHOT ",
"EV_CLEAR ",
"EV_EOF ",
"EV_ERROR ",
};
static char const *vflt[] = {
"EVFILT_READ",
"EVFILT_WRITE",
"EVFILT_EMPTY",
"EVFILT_AIO",
"EVFILT_VNODE",
"EVFILT_PROC",
"EVFILT_PROCDESC",
"EVFILT_SIGNAL",
"EVFILT_TIMER",
"EVFILT_USER",
};
static char const *vsock_s[] = {
"listen backlog :",
"bytes avaible read :",
"bytes avaible write :",
"# times since last kevent call:",
"# times timeout has expired since last kevent call:",
};
char s_flags [255] = {0};
const char *p_filter = p_null;
const char *p_data_desc = p_null;
/* enable, or disable */
if(flags & EV_ENABLE){
strcat(s_flags,vf[1]);
}else if(flags & EV_DISABLE){
strcat(s_flags,vf[2]);
}
/* possible combination of flags */
if(flags & EV_ADD)
strcat(s_flags,vf[0]);
if(flags & EV_DISPATCH)
strcat(s_flags,vf[3]);
if(flags & EV_DELETE)
strcat(s_flags,vf[4]);
if(flags & EV_RECEIPT)
strcat(s_flags,vf[5]);
if(flags & EV_ONESHOT)
strcat(s_flags,vf[6]);
if(flags & EV_CLEAR)
strcat(s_flags,vf[7]);
if(flags & EV_EOF)
strcat(s_flags,vf[8]);
if(flags & EV_ERROR)
strcat(s_flags,vf[9]);
/* filter and fflags */
switch(filter){
case EVFILT_READ : p_filter = vflt[0]; break;
case EVFILT_WRITE: p_filter = vflt[1]; break;
case EVFILT_EMPTY: p_filter = vflt[2]; break;
case EVFILT_AIO: p_filter = vflt[3]; break;
case EVFILT_VNODE: p_filter = vflt[4]; break;
case EVFILT_PROC: p_filter = vflt[5]; break;
case EVFILT_PROCDESC: p_filter = vflt[6]; break;
case EVFILT_SIGNAL: p_filter = vflt[7]; break;
case EVFILT_TIMER: p_filter = vflt[8]; break;
case EVFILT_USER: p_filter = vflt[9]; break;
default: break;
}
if('\0' == *s_flags){
strcpy(s_flags, p_null);
}
/* signals */
switch(filter){
case EVFILT_SIGNAL :
p_data_desc = vsock_s[3];
break;
case EVFILT_TIMER :
p_data_desc = vsock_s[4];
default: break;
}
printf(" \t\t# event:\n"
"\tid : %lu\n",
ev->ident
);
if(*s_flags){
printf("\tflags : %s\n",
s_flags
);
}
printf("\tfilter : %s\n"
"\tdata : %s %ld\n",
p_filter,
p_data_desc, data
);
if(flags & EV_EOF){
printf("\terror : %s\n",
errnonm(fflags)
);
}else if((flags & EV_ERROR) && (0 != data)){
printf("\terror : %s\n",
errnonm(data)
);
}
}
The code originates from my efforts to understand socket programming. At some point I got confused with the state of the event flags. The above prints a series of:
# event:
id : 1
flags : EV_DISPATCH EV_CLEAR
filter : EVFILT_TIMER
data : # times timeout has expired since last kevent call: 1
What is expected, is that, after first goto, the EV_DISPATCH flag will get cleared. As per manual. What exactly are those "state", that the manual talks about. More specifically, what does EV_CLEAR do to event, and when?
I can not understand the source code for the all procedure at its full. That is why the only thing I can do, is to wait for clarification.
P.S The OS is FreeBSD 13.1.

Related

How to stop the repetition of inotify result?

In this code, I am trying to monitor two paths at the same time. I used while(1) for this purpose. But the problem that I am facing is that whenever I run the code, it gives me the same result two times like this.
Giving result
Pathname1 "file" is modified
Pathname1 "file" is modified
Expected result
Pathname1 "file" is modified
I debugged the code. After breaking the main function and stepping over it, the next command stops at this line length = read(fd, buffer, EVENT_BUF_LEN ). Whenever I break a line after this length variable command, the program starts and after modifying the file, the program stops at this line struct inotify_event *event = ( struct inotify_event *)&buffer[i]; Although the program should not break.
I also used IN_CLOSE_WRITE instead of IN_MODIFY but no change in the result.
typedef struct{
int length, fd, wd1, wd2;
char buffer[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
} notification;
notification inotify;
int getNotified(char *pathname1, char *pathname2){
inotify.fd = inotify_init();
inotify.wd1 = inotify_add_watch(inotify.fd, pathname1, IN_MODIFY);
inotify.wd2 = inotify_add_watch(inotify.fd, pathname2, IN_MODIFY);
while(1){
inotify.length = read(inotify.fd, inotify.buffer, EVENT_BUF_LEN);
int i = 0;
while(i < inotify.length){
struct inotify_event *event = (struct inotify_event *)&inotify.buffer[i];
if(event->len){
if(event->mask & IN_MODIFY){
if(event->wd == inotify.wd1){
printf("Pathname1 '%s' is modified\n", event->name);
break;
}
if(event->wd == inotify.wd2){
printf("Pathname2 '%s' is modified\n", event->name);
break;
}
}
}
i += EVENT_SIZE + event->len;
}
}
inotify_rm_watch(inotify.fd, inotify.wd1);
inotify_rm_watch(inotify.fd, inotify.wd2);
close(inotify.fd);
exit(0);
}
Some remarks:
You should not "break" as you go out of the inside "while" loop and call read() again
The IN_MODIFY event does not fill the event->name field (i.e. event->len = 0)
The number of IN_MODIFY events depends on how you modify the files ("echo xxx >> file" = write only = 1 IN_MODIFY; "echo xxx > file" = truncate + write = 2 IN_MODIFY)
Here is a proposition for your program (with additional prints):
#include <stdio.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <stdlib.h>
#define EVENT_BUF_LEN 4096
#define EVENT_SIZE sizeof(struct inotify_event)
typedef struct{
int length, fd, wd1, wd2;
char buffer[EVENT_BUF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));
} notification;
notification inotify;
int getNotified(char *pathname1, char *pathname2){
inotify.fd = inotify_init();
inotify.wd1 = inotify_add_watch(inotify.fd, pathname1, IN_MODIFY);
printf("wd1 = %d\n", inotify.wd1);
inotify.wd2 = inotify_add_watch(inotify.fd, pathname2, IN_MODIFY);
printf("wd2 = %d\n", inotify.wd2);
while(1){
inotify.length = read(inotify.fd, inotify.buffer, EVENT_BUF_LEN);
int i = 0;
printf("read() = %d\n", inotify.length);
while(i < inotify.length){
struct inotify_event *event = (struct inotify_event *)&inotify.buffer[i];
printf("event->len = %u\n", event->len);
if(event->mask & IN_MODIFY){
if(event->wd == inotify.wd1){
printf("Pathname1 is modified\n");
} else if (event->wd == inotify.wd2){
printf("Pathname2 is modified\n");
}
}
i += (EVENT_SIZE + event->len);
printf("i=%d\n", i);
}
}
inotify_rm_watch(inotify.fd, inotify.wd1);
inotify_rm_watch(inotify.fd, inotify.wd2);
close(inotify.fd);
exit(0);
}
int main(void)
{
getNotified("/tmp/foo", "/tmp/bar");
return 0;
} // main
Here is an example of execution:
$ gcc notif.c -o notif
$ > /tmp/foo
$ > /tmp/bar
$ ./notif
wd1 = 1
wd2 = 2
====== Upon "> /tmp/foo": 1 event (truncate operation)
read() = 16
event->len = 0
Pathname1 is modified
i=16
====== Upon "echo qwerty > /tmp/foo": 2 events (write operation, one event for truncate operation and one for the write of "qwerty" at the beginning of the file)
read() = 16
event->len = 0
Pathname1 is modified
i=16
read() = 16
event->len = 0
Pathname1 is modified
i=16
====== Upon "echo qwerty >> /tmp/foo": 1 event (write of "qwerty" at the end of the file)
read() = 16
event->len = 0
Pathname1 is modified
i=16
If the two pathnames refer to the same inode, then inotify.wd1 == inotify.wd2. In that case, because you have
if (event->wd == inotify.wd1) {
printf("Pathname1 '%s' is modified\n", event->name);
}
if (event->wd == inotify.wd2) {
printf("Pathname2 '%s' is modified\n", event->name);
}
both bodies would be executed; but the outputs would differ (Pathname1 ... and Pathname2 ...).
You really should be monitoring the directories the files reside in, rather than the actual pathnames, so you can catch rename events also. (Many editors create a temporary file, and rename or hardlink the temporary file over the old file, so that programs see either the old or the new file, and never a mix of the two.)
Consider the following program, which does not exhibit any undue duplication of events:
// SPDX-License-Identifier: CC0-1.0
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/inotify.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
static volatile sig_atomic_t done = 0;
static void handle_done(int signum)
{
done = signum;
}
static int install_done(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
return sigaction(signum, &act, NULL);
}
struct monitor {
/* Supplied by caller */
const char *directory;
const char *pathname;
int (*modified)(struct monitor *);
int (*completed)(struct monitor *);
/* Reserved for internal use */
int dirwatch;
};
int monitor_files(struct monitor *const list, const size_t count)
{
char *events_ptr = NULL;
size_t events_len = 65536;
size_t i;
int err;
/* Verify sane parameters */
if (count < 1) {
errno = ENOENT;
return -1;
} else
if (!list) {
errno = EINVAL;
return -1;
}
for (i = 0; i < count; i++) {
if (!list[i].directory || !list[i].directory[0]) {
errno = EINVAL;
return -1;
}
if (!list[i].pathname || !list[i].pathname[0]) {
errno = EINVAL;
return -1;
}
list[i].dirwatch = -1;
}
/* Obtain a descriptor for inotify event queue */
int queue = inotify_init1(IN_CLOEXEC);
if (queue == -1) {
/* errno set by inotify_init1() */
return -1;
}
/* Use a reasonable dynamically allocated buffer for events */
events_ptr = malloc(events_len);
if (!events_ptr) {
close(queue);
errno = ENOMEM;
return -1;
}
/* Add a watch for each directory to be watched */
for (i = 0; i < count; i++) {
list[i].dirwatch = inotify_add_watch(queue, list[i].directory, IN_CLOSE_WRITE | IN_MOVED_TO | IN_MODIFY);
if (list[i].dirwatch == -1) {
err = errno;
close(queue);
free(events_ptr);
errno = err;
return -1;
}
}
/* inotify event loop */
err = 0;
while (!done) {
ssize_t len = read(queue, events_ptr, events_len);
if (len == -1) {
/* Interrupted due to signal delivery? */
if (errno == EINTR)
continue;
/* Error */
err = errno;
break;
} else
if (len < -1) {
/* Should never occur */
err = EIO;
break;
} else
if (len == 0) {
/* No events watched anymore */
err = 0;
break;
}
char *const end = events_ptr + len;
char *ptr = events_ptr;
while (ptr < end) {
struct inotify_event *event = (struct inotify_event *)ptr;
/* Advance buffer pointer for next event */
ptr += sizeof (struct inotify_event) + event->len;
if (ptr > end) {
close(queue);
free(events_ptr);
errno = EIO;
return -1;
}
/* Call all event handlers, even duplicate ones */
for (i = 0; i < count; i++) {
if (event->wd == list[i].dirwatch && !strcmp(event->name, list[i].pathname)) {
if ((event->mask & (IN_MOVED_TO | IN_CLOSE_WRITE)) && list[i].completed) {
err = list[i].completed(list + i);
if (err)
break;
} else
if ((event->mask & IN_MODIFY) && list[i].modified) {
err = list[i].modified(list + i);
if (err)
break;
}
}
}
if (err)
break;
}
if (err)
break;
}
close(queue);
free(events_ptr);
errno = 0;
return err;
}
static int report_modified(struct monitor *m)
{
printf("%s/%s: Modified\n", m->directory, m->pathname);
fflush(stdout);
return 0;
}
static int report_completed(struct monitor *m)
{
printf("%s/%s: Completed\n", m->directory, m->pathname);
fflush(stdout);
return 0;
}
int main(void)
{
struct monitor watch[2] = {
{ .directory = ".",
.pathname = "file1",
.modified = report_modified,
.completed = report_completed },
{ .directory = ".",
.pathname = "file2",
.modified = report_modified,
.completed = report_completed }
};
int err;
if (install_done(SIGINT) == -1 ||
install_done(SIGHUP) == -1 ||
install_done(SIGTERM) == -1) {
fprintf(stderr, "Cannot set signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
fprintf(stderr, "To stop this program, press Ctrl+C, or send\n");
fprintf(stderr, "INT, HUP, or TERM signal (to process %ld).\n", (long)getpid());
fflush(stderr);
err = monitor_files(watch, 2);
if (err == -1) {
fprintf(stderr, "Error monitoring files: %s.\n", strerror(errno));
return EXIT_FAILURE;
} else
if (err) {
fprintf(stderr, "Monitoring files failed [%d].\n", err);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
If you compile it using e.g. gcc -Wall -Wextra -O2 example.c -o example and run it via ./example, it will report IN_MODIFY events (as "Modified") and IN_CLOSE_WRITE and IN_MOVED_TO events (as "Completed") for file1 and file2 in the same directory (current working directory). To exit the program, press Ctrl+C.
(Note that we should probably add third event type, "Deleted", corresponding to IN_DELETE and IN_MOVED_FROM events.)
If you open file1 or file2 in say a text editor, saving the file generates one or more Modified (IN_MODIFY) events, and exactly one Completed (IN_CLOSE_WRITE or IN_MOVED_TO) event. This is because each open()/truncate()/ftruncate() syscall that causes the file to be truncated, generates one IN_MODIFY event for that file; as does every underlying write() syscall that modifies the file contents. Thus, it is natural to receive multiple IN_MODIFY events when some process modifies the file.
If you have multiple struct monitor entries in the list with the same effective directory and the same pathname, the example program will provide multiple events for them. If you wish to avoid this, just make sure that whenever .pathname matches, the two get differing .dirwatches.
rewriting the while() loop into a for() loop, and flattening out the if()s"
while(1){
int i ;
struct inotify_event *event ;
inotify.length = read(inotify.fd, inotify.buffer, EVENT_BUF_LEN);
for(i=0; i < inotify.length; i += EVENT_SIZE + event->len ) {
event = (struct inotify_event *)&inotify.buffer[i];
if (!event->len) continue;
if (!(event->mask & IN_MODIFY)) continue;
if (event->wd == inotify.wd1){
printf("Pathname1 '%s' is modified\n", event->name);
continue;
}
if (event->wd == inotify.wd2){
printf("Pathname2 '%s' is modified\n", event->name);
continue;
}
}
}

Empty packet on SOCK_SEQPACKET Unix Socket

I'm playing with SOCK_SEQPACKET type on Unix sockets.
The code I'm using for reading is the classic
ssize_t recv_size = recv(sd, buffer, sizeof(buffer), 0);
if (recv_size < 0) {
handle_error("recv", errno);
} else if (recv_size > 0) {
handle_packet(buffer, recv_size);
} else {
// recv_size == 0 => peer closed socket.
handle_end_of_stream();
}
While this works just fine, I noticed it is not able to distinguish between a socket closure and a message of size 0. In other words, if on the other end I issue a sequence of calls like this:
send(sd, "hello", strlen("hello"), 0);
send(sd, "", 0, 0);
send(sd, "world", strlen("world"), 0);
…the reader will only receive "hello" and react to the second message with a socket closure, missing the "world" message entirely.
I was wondering if there's some way to disambiguate between the two situations.
What if you make some sort of "confirmation" function on both ends. For example instead of handle_end_of_stream, make something like this:
->send(xx, "UNIQUE_MESSAGE", strlen("UNIQUE_MESSAGE"), 0);
< you receive "UNIQUE_RESPONSE" if connection is still up, if you don't, you know for sure that the other end is closed. Just filter out some sort of "UNIQUE_MESSAGE" and "UNIQUE_RESPONSE" inf your "confirmation" function.
As I mentioned in a comment, zero-length seqpackets (as well as zero-length datagrams) can behave oddly, typically mistaken for disconnects; and for that reason, I definitely recommend against using zero-length seqpackets or datagrams for any purpose.
To illustrate the main problem, and explore the details, I created two test programs. First is receive.c, which listens on an Unix domain seqpacket socket, accepts one connection, and describes what it receives:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <string.h>
#include <poll.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
static volatile sig_atomic_t done = 0;
static void handle_done(int signum)
{
done = 1;
}
static int install_done(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
static inline unsigned int digit(const int c)
{
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'A': case 'a': return 10;
case 'B': case 'b': return 11;
case 'C': case 'c': return 12;
case 'D': case 'd': return 13;
case 'E': case 'e': return 14;
case 'F': case 'f': return 15;
default: return 16;
}
}
static inline unsigned int octbyte(const char *src)
{
if (src) {
const unsigned int o0 = digit(src[0]);
if (o0 < 4) {
const unsigned int o1 = digit(src[1]);
if (o1 < 8) {
const unsigned int o2 = digit(src[2]);
if (o2 < 8)
return o0*64 + o1*8 + o2;
}
}
}
return 256;
}
static inline unsigned int hexbyte(const char *src)
{
if (src) {
const unsigned int hi = digit(src[0]);
if (hi < 16) {
const unsigned int lo = digit(src[1]);
if (lo < 16)
return 16*hi + lo;
}
}
return 256;
}
size_t set_unix_path(const char *src, struct sockaddr_un *addr)
{
char *dst = addr->sun_path;
char *const end = addr->sun_path + sizeof (addr->sun_path) - 1;
unsigned int byte;
if (!src || !addr)
return 0;
memset(addr, 0, sizeof *addr);
addr->sun_family = AF_UNIX;
while (*src && dst < end)
if (*src == '\\')
switch (*(++src)) {
case '0':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else {
*(dst++) = '\0';
src++;
}
break;
case '1':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case '2':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case '3':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case 'x':
byte = hexbyte(src + 1);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case 'a': *(dst++) = '\a'; src++; break;
case 'b': *(dst++) = '\b'; src++; break;
case 't': *(dst++) = '\t'; src++; break;
case 'n': *(dst++) = '\n'; src++; break;
case 'v': *(dst++) = '\v'; src++; break;
case 'f': *(dst++) = '\f'; src++; break;
case 'r': *(dst++) = '\r'; src++; break;
case '\\': *(dst++) = '\\'; src++; break;
default: *(dst++) = '\\';
}
else
*(dst++) = *(src++);
*(dst++) = '\0';
return (size_t)(dst - (char *)addr);
}
int main(int argc, char *argv[])
{
struct sockaddr_un addr, conn;
socklen_t addrlen, connlen;
int socketfd, connfd;
if (argc != 2 || !argv[1][0] || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s SOCKET_PATH\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (install_done(SIGINT) ||
install_done(SIGHUP) ||
install_done(SIGTERM)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
socketfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (socketfd == -1) {
fprintf(stderr, "Cannot create an Unix domain seqpacket socket: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
addrlen = set_unix_path(argv[1], &addr);
if (bind(socketfd, (const struct sockaddr *)&addr, addrlen) == -1) {
fprintf(stderr, "Cannot bind to %s: %s.\n", argv[1], strerror(errno));
close(socketfd);
return EXIT_FAILURE;
}
if (listen(socketfd, 1) == -1) {
fprintf(stderr, "Cannot listen for incoming connections: %s.\n", strerror(errno));
close(socketfd);
return EXIT_FAILURE;
}
memset(&conn, 0, sizeof conn);
connlen = sizeof conn;
connfd = accept(socketfd, (struct sockaddr *)&conn, &connlen);
if (connfd == -1) {
close(socketfd);
fprintf(stderr, "Canceled.\n");
return EXIT_SUCCESS;
}
if (connlen > 0)
fprintf(stderr, "Connected, peer address size is %d.\n", (int)connlen);
else
fprintf(stderr, "Connected; no peer address.\n");
while (!done) {
char buffer[65536];
ssize_t n;
int r;
n = recv(connfd, buffer, sizeof buffer, 0);
if (n > 0)
fprintf(stderr, "Received %zd bytes.\n", n);
else
if (n == 0) {
struct pollfd fds[1];
fds[0].fd = connfd;
fds[0].events = 0;
fds[0].revents = 0;
r = poll(fds, 1, 0);
if (r > 0 && (fds[0].revents & POLLHUP)) {
fprintf(stderr, "Disconnected (revents = %d).\n", fds[0].revents);
break;
} else
if (r > 0)
fprintf(stderr, "recv() == 0, poll() == %d, revents == %d\n", r, fds[0].revents);
else
if (r == 0)
fprintf(stderr, "Received a zero-byte seqpacket.\n");
else
fprintf(stderr, "recv() == 0, poll() == %d, revents == %d\n", r, fds[0].revents);
}
}
close(connfd);
close(socketfd);
return EXIT_SUCCESS;
}
You can compile the above using e.g. gcc -Wall -O2 receive.c -o receive. To run, give it the Unix domain address to listen on. In Linux, you can use the abstract namespace by prepending \0 to the address; for example, by running ./receive '\0example' . Otherwise, the socket address will be visible in the filesystem, and you'll need to remove it (as if it was a file, using rm) before running ./receive again with the same socket address.
We also need an utility to send seqpackets. The following send.c is very similar (reuses much of the same code). You specify the Unix domain address to connect to, and one or more seqpacket lengths. You can also specify delays in milliseconds (just prepend a -; i.e., negative integers are delays in milliseconds):
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <string.h>
#include <poll.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
static volatile sig_atomic_t done = 0;
static void handle_done(int signum)
{
done = 1;
}
static int install_done(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = handle_done;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
static inline unsigned int digit(const int c)
{
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'A': case 'a': return 10;
case 'B': case 'b': return 11;
case 'C': case 'c': return 12;
case 'D': case 'd': return 13;
case 'E': case 'e': return 14;
case 'F': case 'f': return 15;
default: return 16;
}
}
static inline unsigned int octbyte(const char *src)
{
if (src) {
const unsigned int o0 = digit(src[0]);
if (o0 < 4) {
const unsigned int o1 = digit(src[1]);
if (o1 < 8) {
const unsigned int o2 = digit(src[2]);
if (o2 < 8)
return o0*64 + o1*8 + o2;
}
}
}
return 256;
}
static inline unsigned int hexbyte(const char *src)
{
if (src) {
const unsigned int hi = digit(src[0]);
if (hi < 16) {
const unsigned int lo = digit(src[1]);
if (lo < 16)
return 16*hi + lo;
}
}
return 256;
}
size_t set_unix_path(const char *src, struct sockaddr_un *addr)
{
char *dst = addr->sun_path;
char *const end = addr->sun_path + sizeof (addr->sun_path) - 1;
unsigned int byte;
if (!src || !addr)
return 0;
memset(addr, 0, sizeof *addr);
addr->sun_family = AF_UNIX;
while (*src && dst < end)
if (*src == '\\')
switch (*(++src)) {
case '0':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else {
*(dst++) = '\0';
src++;
}
break;
case '1':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case '2':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case '3':
byte = octbyte(src);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case 'x':
byte = hexbyte(src + 1);
if (byte < 256) {
*(dst++) = byte;
src += 3;
} else
*(dst++) = '\\';
break;
case 'a': *(dst++) = '\a'; src++; break;
case 'b': *(dst++) = '\b'; src++; break;
case 't': *(dst++) = '\t'; src++; break;
case 'n': *(dst++) = '\n'; src++; break;
case 'v': *(dst++) = '\v'; src++; break;
case 'f': *(dst++) = '\f'; src++; break;
case 'r': *(dst++) = '\r'; src++; break;
case '\\': *(dst++) = '\\'; src++; break;
default: *(dst++) = '\\';
}
else
*(dst++) = *(src++);
*(dst++) = '\0';
return (size_t)(dst - (char *)addr);
}
static inline long sleep_ms(const long ms)
{
struct timespec t;
if (ms > 0) {
t.tv_sec = ms / 1000;
t.tv_nsec = (ms % 1000) * 1000000;
if (nanosleep(&t, &t) == -1 && errno == EINTR)
return 1000 * (unsigned long)(t.tv_sec)
+ (unsigned long)(t.tv_nsec / 1000000);
return 0;
} else
return ms;
}
static int parse_long(const char *src, long *dst)
{
const char *end = src;
long val;
if (!src || !*src)
return errno = EINVAL;
errno = 0;
val = strtol(src, (char **)&end, 0);
if (errno)
return errno;
if (end == src)
return errno = EINVAL;
while (*end == '\t' || *end == '\n' || *end == '\v' ||
*end == '\f' || *end == '\r' || *end == ' ')
end++;
if (*end)
return errno = EINVAL;
if (dst)
*dst = val;
return 0;
}
int main(int argc, char *argv[])
{
char buffer[65536];
struct sockaddr_un conn;
socklen_t connlen;
int connfd, arg;
ssize_t n;
long val, left;
if (argc < 3 || !argv[1][0] || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s SOCKET_PATH [ LEN | -MS ] ...\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "All arguments except the first one, SOCKET_PATH, are integers.\n");
fprintf(stderr, "A positive integer causes a seqpacket of that length to be sent,\n");
fprintf(stderr, "a negative value causes a delay (magnitude in milliseconds).\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
if (install_done(SIGINT) ||
install_done(SIGHUP) ||
install_done(SIGTERM)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* Fill buffer with some data. Anything works. */
{
size_t i = sizeof buffer;
while (i-->0)
buffer[i] = (i*i) ^ i;
}
connfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (connfd == -1) {
fprintf(stderr, "Cannot create an Unix domain seqpacket socket: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
connlen = set_unix_path(argv[1], &conn);
if (connect(connfd, (const struct sockaddr *)&conn, connlen) == -1) {
fprintf(stderr, "Cannot connect to %s: %s.\n", argv[1], strerror(errno));
close(connfd);
return EXIT_FAILURE;
}
/* To avoid output affecting the timing, fully buffer stdout. */
setvbuf(stdout, NULL, _IOFBF, 65536);
for (arg = 2; arg < argc; arg++)
if (parse_long(argv[arg], &val)) {
fprintf(stderr, "%s: Not an integer.\n", argv[arg]);
close(connfd);
return EXIT_FAILURE;
} else
if (val > (long)sizeof buffer) {
fprintf(stderr, "%s: Seqpacket size too large. Current limit is %zu.\n", argv[arg], sizeof buffer);
close(connfd);
return EXIT_FAILURE;
} else
if (val >= 0) {
n = send(connfd, buffer, (size_t)val, 0);
if (n == (ssize_t)val)
printf("Sent %ld-byte seqpacket successfully.\n", val);
else
if (n != (ssize_t)val && n >= 0)
fprintf(stderr, "Sent %zd bytes of a %ld-byte seqpacket.\n", n, val);
else
if (n < -1) {
fprintf(stderr, "C library bug: send() returned %zd.\n", n);
close(connfd);
return EXIT_FAILURE;
} else
if (n == -1) {
fprintf(stderr, "Send failed: %s.\n", strerror(errno));
close(connfd);
return EXIT_FAILURE;
}
} else {
left = sleep_ms(-val);
if (left)
fprintf(stderr, "Slept %ld milliseconds (out of %ld ms).\n", -val-left, -val);
else
printf("Slept %ld milliseconds.\n", -val);
}
if (close(connfd) == -1) {
fprintf(stderr, "Error closing connection: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("All done, connection closed.\n");
fflush(stdout);
return EXIT_SUCCESS;
}
Compile this using e.g. gcc -Wall -O2 send.c -o send .
For testing, I recommend you use two terminal windows. Run send in one, and receive in the other. For simplicity, I'll show the corresponding commands and outputs side-by-side. The machine this runs on is a Core i5 7200U laptop (HP EliteBook 830), running Ubuntu 16.04.4 LTS, 64-bit Linux kernel version 4.15.0-24-generic, and binaried compiled using GCC-5.4.0 20160609 (5.4.0-6ubuntu1~16.04.10) and the abovementioned commands (gcc -Wall -O2).
When we use a small delay before the final send, everything seems to work just fine:
$ ./send '\0example' 1 0 3 0 0 -1 6 │ $ ./receive '\0example'
│ Connected, peer address size is 2.
Sent 1-byte seqpacket successfully. │ Received 1 bytes.
Sent 0-byte seqpacket successfully. │ Received a zero-byte seqpacket.
Sent 3-byte seqpacket successfully. │ Received 3 bytes.
Sent 0-byte seqpacket successfully. │ Received a zero-byte seqpacket.
Sent 0-byte seqpacket successfully. │ Received a zero-byte seqpacket.
Slept 1 milliseconds. │
Sent 6-byte seqpacket successfully. │ Received 6 bytes.
All done, connection closed. │ Disconnected (revents = 16).
However, when the sender sends the final few seqpackets (starting with a zero-length one) without any delays in between, I observe this:
$ ./send '\0example' 1 0 3 0 0 6 │ ./receive '\0example'
│ Connected, peer address size is 2.
Sent 1-byte seqpacket successfully. │ Received 1 bytes.
Sent 0-byte seqpacket successfully. │ Received a zero-byte seqpacket.
Sent 3-byte seqpacket successfully. │ Received 3 bytes.
Sent 0-byte seqpacket successfully. │
Sent 0-byte seqpacket successfully. │
Sent 6-byte seqpacket successfully. │
All done, connection closed. │ Disconnected (revents = 16).
See how the two zero-byte seqpackets and the 6-byte seqpacket are missed (because poll() returned revents == POLLHUP. (POLLHUP == 0x0010 == 16, so there were no other flags set either time.)
I am personally not sure if this is a bug or not. In my opinion, it is just and indication that using zero-length seqpackets is problematic, and should be avoided.
(The peer address length is 2 above, because the sender does not bind to any address, and therefore uses an unnamed Unix domain socket address (as described in the man unix man page). I don't think it is important, but I left it in just in case.)
There was a discussion on one possible solution to the problem at hand, via MSG_EOR (since recvmsg() should add MSG_EOR to the msg_flags field in the msghdr structure; and since it "should be set for all seqpackets", even zero-length ones, it would be a reliable way to detect zero-length seqpackets from end-of-input/read-side shutdown/disconnect) in the Linux Kernel Mailing List (and linux-netdev list) in May 2007. (The archived thread at Marc.info is here)
However, in Linux Unix domain seqpacket sockets, the MSG_EOR is not set nor passed, according to the initial poster, Sam Kumar. The discussion did not lead anywhere; as I read it, nobody was sure what the expected behaviour even should be.
Looking at the Linux kernel changelog for Unix domain sockets, there have been no related changes since that thread either (as of 23 July 2018).
The above programs were written in one sitting, without review; so, they could easily have bugs or thinkos in them. If you notice any, or obtain very different results (but do note timing-based effects are sometimes hard to replicate), do let me know in a comment, so I can check, and fix if necessary.

Reading from Serial Port in linux using C language

I am new to serail programing in Linux (Fedora 12) using C Language. I have a simple device, it is supposed to get 3 bytes command in hex (wirte) like {0x02,0x03,0x0D} and return 4 bytes response.
First I wrote a simple java program on windows, and I get the correct response.. as and when,I switch to linux, I can't read from serial com port neither using java nor C language.
I tried using libraries like rs232 .. but still the problem remains.
I can open "/dev/ttyS0", and write on it .. (none of them returns any Error), but read is not possible ..
If I use canonical mode, the program blocks on reading until i kill the program.. If use non-canonical mode, with VMIN=0 and VTIME=5, read function returns whith -107725432 bytes for example ..
(I have tried reading and writing byte by byte or all at the same time .. no difference ..)
rs232.c
#include "rs232.h"
int Cport[6],
error;
struct termios new_port_settings,
old_port_settings[6];
char comports[6][16]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5"};
int RS232_OpenComport(int comport_number, int baudrate, const char *mode)
{
int baudr,
status;
if((comport_number>5)||(comport_number<0))
{
printf("illegal comport number\n");
return(1);
}
switch(baudrate)
{
case 2400 : baudr = B2400;
break;
case 4800 : baudr = B4800;
break;
case 9600 : baudr = B9600;
break;
case 19200 : baudr = B19200;
break;
default : printf("invalid baudrate\n");
return(1);
break;
}
int cbits=CS8,
cpar=0,
ipar=IGNPAR,
bstop=0;
if(strlen(mode) != 3)
{
printf("invalid mode \"%s\"\n", mode);
return(1);
}
switch(mode[0])
{
case '8': cbits = CS8;
break;
case '7': cbits = CS7;
break;
case '6': cbits = CS6;
break;
case '5': cbits = CS5;
break;
default : printf("invalid number of data-bits '%c'\n", mode[0]);
return(1);
break;
}
switch(mode[1])
{
case 'N':
case 'n': cpar = 0;
ipar = IGNPAR;
break;
case 'E':
case 'e': cpar = PARENB;
ipar = INPCK;
break;
case 'O':
case 'o': cpar = (PARENB | PARODD);
ipar = INPCK;
break;
default : printf("invalid parity '%c'\n", mode[1]);
return(1);
break;
}
switch(mode[2])
{
case '1': bstop = 0;
break;
case '2': bstop = CSTOPB;
break;
default : printf("invalid number of stop bits '%c'\n", mode[2]);
return(1);
break;
}
Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY);
if(Cport[comport_number]==-1)
{
perror("unable to open comport ");
return(1);
}
/* lock access so that another process can't also use the port */
if(flock(Cport[comport_number], LOCK_EX | LOCK_NB) != 0)
{
close(Cport[comport_number]);
perror("Another process has locked the comport.");
return(1);
}
error = tcgetattr(Cport[comport_number], old_port_settings + comport_number);
if(error==-1)
{
close(Cport[comport_number]);
perror("unable to read portsettings ");
return(1);
}
memset(&new_port_settings, 0, sizeof(new_port_settings)); /* clear the new struct */
new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD;
new_port_settings.c_iflag = ipar;
new_port_settings.c_oflag = 0;
new_port_settings.c_lflag = 0;
new_port_settings.c_cc[VMIN] = 0; /* block untill n bytes are received */
new_port_settings.c_cc[VTIME] = 5; /* block untill a timer expires (n * 100 mSec.) */
cfsetispeed(&new_port_settings, baudr);
cfsetospeed(&new_port_settings, baudr);
error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings);
if(error==-1)
{
close(Cport[comport_number]);
perror("unable to adjust portsettings ");
return(1);
}
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
perror("unable to get portstatus");
return(1);
}
status |= TIOCM_DTR; /* turn on DTR */
status |= TIOCM_RTS; /* turn on RTS */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
perror("unable to set portstatus");
return(1);
}
return(0);
}
int RS232_PollComport(int comport_number, unsigned char *buf, int size)
{
int n;
n = read(Cport[comport_number], buf, size);
return(n);
}
int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
{
return(write(Cport[comport_number], buf, size));
}
void RS232_CloseComport(int comport_number)
{
int status;
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
{
perror("unable to get portstatus");
}
status &= ~TIOCM_DTR; /* turn off DTR */
status &= ~TIOCM_RTS; /* turn off RTS */
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
{
perror("unable to set portstatus");
}
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
close(Cport[comport_number]);
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
}
void RS232_flushRXTX(int comport_number)
{
tcflush(Cport[comport_number], TCIOFLUSH);
}
and
main.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "rs232.h"
int main()
{
int cport_nr=0, bdrate=9600; /* 9600 baud */
char mode[]={'8','N','1',0},
str[512];
unsigned char buf[6000];
memset(buf, '\0' , 6000);
int buf_SIZE=sizeof(buf);
if(RS232_OpenComport(cport_nr, bdrate, mode))
{
printf("Can not open comport\n");
return(0);
}
unsigned char wr_buff[5];
memset(wr_buff, '\0', 5);
wr_buff[0] = 0x02;
wr_buff[1] = 0x01;
wr_buff[2] = 0x0D;
int cnt = RS232_SendBuf(cport_nr, wr_buff, 3);
printf("Number of bytes that has been written: %d\n",cnt);
if (cnt <= 0 )
return(-1);
cnt =0 ;
usleep(100000);
printf("Start Reading ... \n");
int i = 0;
do {
cnt = RS232_PollComport(cport_nr,(buf+i), 1);
i++;}
while(cnt>0);
printf ("%d bytes have been read\n");
RS232_CloseComport(cport_nr);
return (1);
}
I am really confused .. I tried almost every samples on the Internet .. An
y Idea Please?!
I have traced the program, using strace ..
...
write(3,"\2\3\r",3) = 3
fstat64(1 , {st_mode=S_IFREG| 0755, st_size =0,..}) = 0
mmap2(NULL,4096,PROT_READ|PROT_WRITE, MAP_PRIVATE| MAP_ANONYMOUS,-1,0) = 0Xb78b4000
nanosleep({0, 100000000}, NULL) = 0
read(3,"",1) = 0
.....
Can the problem be related to fedora12?
P.S. : if I haven't got response in windows, I was sure that its a problem with the device.
Solved ...
it was a mistake of me ...
In fact, every thing was ok,
the problem was in the way I print number of bytes have been read.. I had forgotten to put "cnt" in respect of %d ...
printf ("%d bytes have been read\n"); --> printf ("%d bytes have been read\n",cnt);
also i should have read only 4 bytes based on the protocol of communication with my device ..

libssh2: libssh2_channel_write() doesn't seem to write data on the channel

I am trying to execute a command on a router via ssh. After the login, when I execute the command on the device, it asks for an additional password. I am not able to send the password using libssh2_channel_write(). Here is the code snippet (modified the ssh2_exec.c that comes with the library). This is a snippet where the device is authenticated and the command has been issued. This loop just tries to get read the output of the executed command:
for( ;; )
{
/* loop until we block */
int rc;
do
{
char buffer[0x4000];
rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
if( rc > 0 )
{
int i;
char *enable = "stic-isr2951-t1";
int ret;
bytecount += rc;
fprintf(stderr, "We read [%d] bytes:\n", bytecount);
for( i=0; i < rc; ++i )
fputc( buffer[i], stderr);
**if ( strstr(buffer, "assword:") != NULL ){
fprintf(stderr, "Sending the additional password now\n");
ret = libssh2_channel_write(channel, enable, strlen(enable));
fprintf(stderr, "Wrote [%d] bytes\n", ret);
}**
}
else {
if( rc != LIBSSH2_ERROR_EAGAIN )
/* no need to output this for the EAGAIN case */
fprintf(stderr, "libssh2_channel_read returned %d\n", rc);
}
}
while( rc > 0 );
/* this is due to blocking that would occur otherwise so we loop on
this condition */
if( rc == LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
else
break;
}
In the snippet above, the code that detects that the device is posting a password prompt is:
if ( strstr(buffer, "assword:") != NULL ){
fprintf(stderr, "Sending the additional password now\n");
ret = libssh2_channel_write(channel, enable, strlen(enable));
fprintf(stderr, "Wrote [%d] bytes\n", ret);
}
That's where I have a problem. The password being sent on the channel isn't working as the device continues to timeout expecting the password. There is no indication that libssh2_channel_write() failed as the return value says it wrote the password properly.
Am I missing something?
EDIT:
The problem with the continuous timeout password prompted was because the password didn't have \n at the end. I was expecting the lib to take care of it but it didn't.
Now that I am able to send the password to the remote device, I run into another issue. After I send the password via libssh2_channel_write(), subsequent libssh2_channel_read() fails with
LIBSSH2_ERROR_SOCKET_RECV
I am not sure why is this happening. Logic was to check if the libssh2_channel_write() was successful by doing a subsequent read() (which would give the command prompt on the remote device) and then issue the command to be executed on the remote device followed by a subsequent read to get the command output. Am I doing something wrong? This doesn't seem to be working. Here's the complete code snippet:
/*
* Sample showing how to use libssh2 to execute a command remotely.
*
* The sample code has fixed values for host name, user name, password
* and command to run.
*
* Run it like this:
*
* $ ./ssh2_exec 127.0.0.1 user password "uptime"
*
*/
#include "libssh2_config.h"
#include <libssh2.h>
#include <string.h>
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int rc;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&fd);
FD_SET(socket_fd, &fd);
/* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session);
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd;
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd;
rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
return rc;
}
int main(int argc, char *argv[])
{
const char *hostname = "10.10.10.10";
const char *commandline = "show version";
const char *username = "user1";
const char *password = "password1";
unsigned long hostaddr;
int flag = 0;
int sock;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
int rc;
int exitcode;
char *exitsignal=(char *)"none";
int bytecount = 0;
size_t len;
LIBSSH2_KNOWNHOSTS *nh;
int type;
if (argc > 1)
/* must be ip address only */
hostname = argv[1];
if (argc > 2) {
username = argv[2];
}
if (argc > 3) {
password = argv[3];
}
if (argc > 4) {
commandline = argv[4];
}
rc = libssh2_init (0);
if (rc != 0) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
return 1;
}
hostaddr = inet_addr(hostname);
printf("host address is: %ld\n", hostaddr);
/* Ultra basic "connect to port 22 on localhost"
* Your code is responsible for creating the socket establishing the
* connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance */
session = libssh2_session_init();
if (!session)
return -1;
//libssh2_trace(session, LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_SOCKET);
/* tell libssh2 we want it all done non-blocking */
libssh2_session_set_blocking(session, 0);
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
while ((rc = libssh2_session_handshake(session, sock)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -1;
}
nh = libssh2_knownhost_init(session);
if(!nh) {
/* eeek, do cleanup here */
return 2;
}
/* read all hosts from here */
libssh2_knownhost_readfile(nh, "known_hosts",
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
/* store all known hosts to here */
libssh2_knownhost_writefile(nh, "dumpfile",
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
fingerprint = libssh2_session_hostkey(session, &len, &type);
if(fingerprint) {
struct libssh2_knownhost *host;
#if LIBSSH2_VERSION_NUM >= 0x010206
/* introduced in 1.2.6 */
int check = libssh2_knownhost_checkp(nh, hostname, 22,
fingerprint, len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
LIBSSH2_KNOWNHOST_KEYENC_RAW,
&host);
#else
/* 1.2.5 or older */
int check = libssh2_knownhost_check(nh, hostname,
fingerprint, len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
LIBSSH2_KNOWNHOST_KEYENC_RAW,
&host);
#endif
fprintf(stderr, "Host check: %d, key: %s\n", check,
(check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
host->key:"<none>");
/*****
* At this point, we could verify that 'check' tells us the key is
* fine or bail out.
*****/
}
else {
/* eeek, do cleanup here */
return 3;
}
libssh2_knownhost_free(nh);
if ( strlen(password) != 0 ) {
/* We could authenticate via password */
while ((rc = libssh2_userauth_password(session, username, password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
}
else {
/* Or by public key */
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
"/home/user/"
".ssh/id_rsa.pub",
"/home/user/"
".ssh/id_rsa",
password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "\tAuthentication by public key failed\n");
goto shutdown;
}
}
#if 1
//libssh2_trace(session, ~0 );
#endif
/* Exec non-blocking on the remove host */
while( (channel = libssh2_channel_open_session(session)) == NULL &&
libssh2_session_last_error(session,NULL,NULL,0) ==
LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
if( channel == NULL )
{
fprintf(stderr,"Error\n");
exit( 1 );
}
while( (rc = libssh2_channel_exec(channel, commandline)) ==
LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
if( rc != 0 )
{
fprintf(stderr,"Error\n");
exit( 1 );
}
for( ;; )
{
/* loop until we block */
int rc;
do
{
char buffer[0x4000];
rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
if( rc > 0 )
{
int i;
char *enable = "check-password\n";
int ret;
bytecount += rc;
fprintf(stderr, "We read [%d] bytes:\n", bytecount);
fputc('[', stderr);
for( i=0; i < rc; ++i )
fputc( buffer[i], stderr);
fputc(']', stderr);
if ( strstr(buffer, "Password:") != NULL ){
fprintf(stderr, "Sending the password now\n");
while((ret = libssh2_channel_write(channel, enable, strlen(enable))) == LIBSSH2_ERROR_EAGAIN) {
printf("ERROR_EAGAIN - sending password again\n");
}
fprintf(stderr, "Wrote [%d] bytes: \n", ret);
flag = 1;
continue;
}
if (!flag){ // start
char *cmd = "show clock\n";
int ret;
fprintf(stderr, "THIS is Fetching show clock command now\n");
while((ret = libssh2_channel_write(channel, cmd, strlen(cmd))) == LIBSSH2_ERROR_EAGAIN) {
printf("ERROR_EAGAIN - sending show clock again\n");
}
flag = 1;
} // end
}
else {
if(rc != LIBSSH2_ERROR_EAGAIN)
fprintf(stderr, "libssh2_channel_read returned [%d]:\n ", rc);
}
}
while( rc > 0 );
/* this is due to blocking that would occur otherwise so we loop on
this condition */
if( rc == LIBSSH2_ERROR_EAGAIN )
{
int check;
check = waitsocket(sock, session);
}
else
break;
}
exitcode = 127;
while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
waitsocket(sock, session);
if( rc == 0 )
{
exitcode = libssh2_channel_get_exit_status( channel );
libssh2_channel_get_exit_signal(channel, &exitsignal,
NULL, NULL, NULL, NULL, NULL);
}
if (exitsignal)
fprintf(stderr, "\nGot signal: %s\n", exitsignal);
else
fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
libssh2_channel_free(channel);
channel = NULL;
shutdown:
libssh2_session_disconnect(session,
"Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
fprintf(stderr, "all done\n");
libssh2_exit();
return 0;
}
Any thoughts?

Simple, small C program for testing serial bandwidth

I have two laptops with a serial port. How do I test the actual bandwidth of the serial port between the two machines using a simple, small C program?
In reality, I need to do this on an embedded Linux system which is why the utility must be a small, simple C program (because the embedded environment only has limited library support meaning it doesn't have python, perl, or any other fancy libraries).
I started this as a new question because I didn't want to take this question off topic: Serial port loopback test
That question was regarding testing the bandwidth of a serial port in loopback mode, so that you don't have to plug in an actual serial cable. The author (sdaau) put a lot of time into creating a multi-threaded serial bandwidth test program to answer his own question. I then used his simple C program and extended it to be used between two different physical machines connected with a serial cable.
It is necessary to start the "remote" side which will wait for the "initiator" side (the local side) to send a go byte, in which both will proceed to transfer data asynchronously. The program (which sdaau calls writeread.c) spawns 2 threads: one which writes data and the other which reads data. In this way, you are fully utilizing the serial port. You can pass in a datafile as a command-line argument.
As an example, here is the "remote" side:
./writeread /dev/ttyUSB0 115200 ./datafile.dat 3> output
As an example, here is the "local" (or initiator) side:
./writeread /dev/ttyUSB0 115200 ./datafile.dat -I 3> output
Note that I had some trouble redirecting the output on the remote side, meaning that 3> output didn't really work. I'm not sure whats going on with that, but my local side worked fine. Also, note the remote side's output timing is skewed because it has a timer running while it is waiting for the initiator. This means you should only trust the bandwidth printout from the local initiator side (see the original question for output results details).
Since both sides are sending the same datafile in this example, you should be able to compare the "output" file with the datafile:
diff output datafile.dat
Complie the code with:
gcc -c -Wall writeread.c
gcc writeread.o -lpthread -o writeread
Here is the modified writeread.c code:
/*
writeread.c - based on writeread.cpp
[SOLVED] Serial Programming, Write-Read Issue - http://www.linuxquestions.org/questions/programming-9/serial-programming-write-read-issue-822980/
build with: gcc -o writeread -lpthread -Wall -g writeread.c
*/
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
#include "writeread.h"
int serport_fd;
//POSIX Threads Programming - https://computing.llnl.gov/tutorials/pthreads/#PassingArguments
struct write_thread_data{
int fd;
char* comm; //string to send
int bytesToSend;
int writtenBytes;
int iator; // Initiator. 0 = False, 1 = True
};
void usage(char **argv)
{
fprintf(stdout, "Usage:\n");
fprintf(stdout, "%s port baudrate file/string [-I]\n", argv[0]);
fprintf(stdout, " The -I is for initiator. Run on the remote side which "
"will wait, then start locally with -I which will initiate "
"the test.\n");
fprintf(stdout, "Examples:\n");
fprintf(stdout, "%s /dev/ttyUSB0 115200 /path/to/somefile.txt\n", argv[0]);
fprintf(stdout, "%s /dev/ttyUSB0 115200 \"some text test\"\n", argv[0]);
}
// POSIX threads explained - http://www.ibm.com/developerworks/library/l-posix1.html
// instead of writeport
void *write_thread_function(void *arg) {
int go = 0;
int lastBytesWritten;
struct write_thread_data *my_data;
my_data = (struct write_thread_data *) arg;
fprintf(stdout, "write_thread_function spawned\n");
// Are we the initiator?
if (my_data->iator == 1) {
// We are the initiator, send the start command
go = 0xde;
write(my_data->fd, &go, 1);
} else {
// We wait for the initiator to send us the start command
fprintf(stdout, "Waiting for initiator (start other end with -I)...\n");
read(my_data->fd, &go, 1);
if (go == 0xde) {
fprintf(stdout, "Go!\n");
} else {
fprintf(stdout, "Error: Did not receive start command [0x%x]\n", go);
return NULL;
}
}
my_data->writtenBytes = 0;
while(my_data->writtenBytes < my_data->bytesToSend)
{
lastBytesWritten = write( my_data->fd, my_data->comm + my_data->writtenBytes, my_data->bytesToSend - my_data->writtenBytes );
my_data->writtenBytes += lastBytesWritten;
if ( lastBytesWritten < 0 )
{
fprintf(stdout, "write failed!\n");
return 0;
}
fprintf(stderr, " write: %d - %d\n", lastBytesWritten, my_data->writtenBytes);
}
return NULL; //pthread_exit(NULL)
}
int main( int argc, char **argv )
{
if( argc < 4 ) {
usage(argv);
return 1;
}
char *serport;
char *serspeed;
speed_t serspeed_t;
char *serfstr;
int serf_fd; // if < 0, then serfstr is a string
int sentBytes;
int readChars;
int recdBytes, totlBytes;
char* sResp;
char* sRespTotal;
struct timeval timeStart, timeEnd, timeDelta;
float deltasec, expectBps, measReadBps, measWriteBps;
struct write_thread_data wrdata;
pthread_t myWriteThread;
/* Re: connecting alternative output stream to terminal -
* http://coding.derkeiler.com/Archive/C_CPP/comp.lang.c/2009-01/msg01616.html
* send read output to file descriptor 3 if open,
* else just send to stdout
*/
FILE *stdalt;
if(dup2(3, 3) == -1) {
fprintf(stdout, "stdalt not opened; ");
stdalt = fopen("/dev/tty", "w");
} else {
fprintf(stdout, "stdalt opened; ");
stdalt = fdopen(3, "w");
}
fprintf(stdout, "Alternative file descriptor: %d\n", fileno(stdalt));
// Get the PORT name
serport = argv[1];
fprintf(stdout, "Opening port %s;\n", serport);
// Get the baudrate
serspeed = argv[2];
serspeed_t = string_to_baud(serspeed);
fprintf(stdout, "Got speed %s (%d/0x%x);\n", serspeed, serspeed_t, serspeed_t);
//Get file or command;
serfstr = argv[3];
// Are we the initiator?
if (argc == 5 &&
strncmp(argv[4], "-I", 3) == 0 )
{
wrdata.iator = 1; // Initiator. 0 = False, 1 = True
} else {
wrdata.iator = 0; // Initiator. 0 = False, 1 = True
}
serf_fd = open( serfstr, O_RDONLY );
fprintf(stdout, "Got file/string '%s'; ", serfstr);
if (serf_fd < 0) {
wrdata.bytesToSend = strlen(serfstr);
wrdata.comm = serfstr; //pointer already defined
fprintf(stdout, "interpreting as string (%d).\n", wrdata.bytesToSend);
} else {
struct stat st;
stat(serfstr, &st);
wrdata.bytesToSend = st.st_size;
wrdata.comm = (char *)calloc(wrdata.bytesToSend, sizeof(char));
read(serf_fd, wrdata.comm, wrdata.bytesToSend);
fprintf(stdout, "opened as file (%d).\n", wrdata.bytesToSend);
}
sResp = (char *)calloc(wrdata.bytesToSend, sizeof(char));
sRespTotal = (char *)calloc(wrdata.bytesToSend, sizeof(char));
// Open and Initialise port
serport_fd = open( serport, O_RDWR | O_NOCTTY | O_NONBLOCK );
if ( serport_fd < 0 ) { perror(serport); return 1; }
initport( serport_fd, serspeed_t );
wrdata.fd = serport_fd;
sentBytes = 0; recdBytes = 0;
gettimeofday( &timeStart, NULL );
// start the thread for writing..
if ( pthread_create( &myWriteThread, NULL, write_thread_function, (void *) &wrdata) ) {
printf("error creating thread.");
abort();
}
// run read loop
while ( recdBytes < wrdata.bytesToSend )
{
while ( wait_flag == TRUE );
if ( (readChars = read( serport_fd, sResp, wrdata.bytesToSend)) >= 0 )
{
//~ fprintf(stdout, "InVAL: (%d) %s\n", readChars, sResp);
// binary safe - add sResp chunk to sRespTotal
memmove(sRespTotal+recdBytes, sResp+0, readChars*sizeof(char));
/* // text safe, but not binary:
sResp[readChars] = '\0';
fprintf(stdalt, "%s", sResp);
*/
recdBytes += readChars;
} else {
if ( errno == EAGAIN )
{
fprintf(stdout, "SERIAL EAGAIN ERROR\n");
return 0;
}
else
{
fprintf(stdout, "SERIAL read error: %d = %s\n", errno , strerror(errno));
return 0;
}
}
fprintf(stderr, " read: %d\n", recdBytes);
wait_flag = TRUE; // was ==
//~ usleep(50000);
}
if ( pthread_join ( myWriteThread, NULL ) ) {
printf("error joining thread.");
abort();
}
gettimeofday( &timeEnd, NULL );
// binary safe - dump sRespTotal to stdalt
fwrite(sRespTotal, sizeof(char), recdBytes, stdalt);
// Close the open port
close( serport_fd );
if (!(serf_fd < 0)) {
close( serf_fd );
free(wrdata.comm);
}
free(sResp);
free(sRespTotal);
fprintf(stdout, "\n+++DONE+++\n");
sentBytes = wrdata.writtenBytes;
totlBytes = sentBytes + recdBytes;
timeval_subtract(&timeDelta, &timeEnd, &timeStart);
deltasec = timeDelta.tv_sec+timeDelta.tv_usec*1e-6;
expectBps = atoi(serspeed)/10.0f;
measWriteBps = sentBytes/deltasec;
measReadBps = recdBytes/deltasec;
fprintf(stdout, "Wrote: %d bytes; Read: %d bytes; Total: %d bytes. \n", sentBytes, recdBytes, totlBytes);
fprintf(stdout, "Start: %ld s %ld us; End: %ld s %ld us; Delta: %ld s %ld us. \n", timeStart.tv_sec, timeStart.tv_usec, timeEnd.tv_sec, timeEnd.tv_usec, timeDelta.tv_sec, timeDelta.tv_usec);
fprintf(stdout, "%s baud for 8N1 is %d Bps (bytes/sec).\n", serspeed, (int)expectBps);
fprintf(stdout, "Measured: write %.02f Bps (%.02f%%), read %.02f Bps (%.02f%%), total %.02f Bps.\n", measWriteBps, (measWriteBps/expectBps)*100, measReadBps, (measReadBps/expectBps)*100, totlBytes/deltasec);
return 0;
}
And here is the .h file which I have renamed from the original question to writeread.h:
/* writeread.h
(C) 2004-5 Captain http://www.captain.at
Helper functions for "ser"
Used for testing the PIC-MMC test-board
http://www.captain.at/electronic-index.php
*/
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#define TRUE 1
#define FALSE 0
int wait_flag = TRUE; // TRUE while no signal received
// Definition of Signal Handler
void DAQ_signal_handler_IO ( int status )
{
//~ fprintf(stdout, "received SIGIO signal %d.\n", status);
wait_flag = FALSE;
}
int writeport( int fd, char *comm )
{
int len = strlen( comm );
int n = write( fd, comm, len );
if ( n < 0 )
{
fprintf(stdout, "write failed!\n");
return 0;
}
return n;
}
int readport( int fd, char *resp, size_t nbyte )
{
int iIn = read( fd, resp, nbyte );
if ( iIn < 0 )
{
if ( errno == EAGAIN )
{
fprintf(stdout, "SERIAL EAGAIN ERROR\n");
return 0;
}
else
{
fprintf(stdout, "SERIAL read error: %d = %s\n", errno , strerror(errno));
return 0;
}
}
if ( resp[iIn-1] == '\r' )
resp[iIn-1] = '\0';
else
resp[iIn] = '\0';
return iIn;
}
int getbaud( int fd )
{
struct termios termAttr;
int inputSpeed = -1;
speed_t baudRate;
tcgetattr( fd, &termAttr );
// Get the input speed
baudRate = cfgetispeed( &termAttr );
switch ( baudRate )
{
case B0: inputSpeed = 0; break;
case B50: inputSpeed = 50; break;
case B110: inputSpeed = 110; break;
case B134: inputSpeed = 134; break;
case B150: inputSpeed = 150; break;
case B200: inputSpeed = 200; break;
case B300: inputSpeed = 300; break;
case B600: inputSpeed = 600; break;
case B1200: inputSpeed = 1200; break;
case B1800: inputSpeed = 1800; break;
case B2400: inputSpeed = 2400; break;
case B4800: inputSpeed = 4800; break;
case B9600: inputSpeed = 9600; break;
case B19200: inputSpeed = 19200; break;
case B38400: inputSpeed = 38400; break;
case B115200: inputSpeed = 115200; break;
case B2000000: inputSpeed = 2000000; break; //added
}
return inputSpeed;
}
/* ser.c
(C) 2004-5 Captain http://www.captain.at
Sends 3 characters (ABC) via the serial port (/dev/ttyS0) and reads
them back if they are returned from the PIC.
Used for testing the PIC-MMC test-board
http://www.captain.at/electronic-index.php
*/
int initport( int fd, speed_t baudRate )
{
struct termios options;
struct sigaction saio; // Definition of Signal action
// Install the signal handler before making the device asynchronous
saio.sa_handler = DAQ_signal_handler_IO;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction( SIGIO, &saio, NULL );
// Allow the process to receive SIGIO
fcntl( fd, F_SETOWN, getpid() );
// Make the file descriptor asynchronous (the manual page says only
// O_APPEND and O_NONBLOCK, will work with F_SETFL...)
fcntl( fd, F_SETFL, FASYNC );
//~ fcntl( fd, F_SETFL, FNDELAY); //doesn't work; //fcntl(file, F_SETFL, 0);
// Get the current options for the port...
tcgetattr( fd, &options );
/*
// Set port settings for canonical input processing
options.c_cflag = BAUDRATE | CRTSCTS | CLOCAL | CREAD;
options.c_iflag = IGNPAR | ICRNL;
//options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = ICANON;
//options.c_lflag = 0;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 0;
*/
/* ADDED - else 'read' will not return, unless it sees LF '\n' !!!!
* From: Unix Programming Frequently Asked Questions - 3. Terminal I/O -
* http://www.steve.org.uk/Reference/Unix/faq_4.html
*/
/* Disable canonical mode, and set buffer size to 1 byte */
options.c_lflag &= (~ICANON);
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 1;
// Set the baud rates to...
cfsetispeed( &options, baudRate );
cfsetospeed( &options, baudRate );
// Enable the receiver and set local mode...
options.c_cflag |= ( CLOCAL | CREAD );
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Flush the input & output...
tcflush( fd, TCIOFLUSH );
// Set the new options for the port...
tcsetattr( fd, TCSANOW, &options );
return 1;
}
/*
ripped from
http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/stty.c
*/
#define STREQ(a, b) (strcmp((a), (b)) == 0)
struct speed_map
{
const char *string; /* ASCII representation. */
speed_t speed; /* Internal form. */
unsigned long int value; /* Numeric value. */
};
static struct speed_map const speeds[] =
{
{"0", B0, 0},
{"50", B50, 50},
{"75", B75, 75},
{"110", B110, 110},
{"134", B134, 134},
{"134.5", B134, 134},
{"150", B150, 150},
{"200", B200, 200},
{"300", B300, 300},
{"600", B600, 600},
{"1200", B1200, 1200},
{"1800", B1800, 1800},
{"2400", B2400, 2400},
{"4800", B4800, 4800},
{"9600", B9600, 9600},
{"19200", B19200, 19200},
{"38400", B38400, 38400},
{"exta", B19200, 19200},
{"extb", B38400, 38400},
#ifdef B57600
{"57600", B57600, 57600},
#endif
#ifdef B115200
{"115200", B115200, 115200},
#endif
#ifdef B230400
{"230400", B230400, 230400},
#endif
#ifdef B460800
{"460800", B460800, 460800},
#endif
#ifdef B500000
{"500000", B500000, 500000},
#endif
#ifdef B576000
{"576000", B576000, 576000},
#endif
#ifdef B921600
{"921600", B921600, 921600},
#endif
#ifdef B1000000
{"1000000", B1000000, 1000000},
#endif
#ifdef B1152000
{"1152000", B1152000, 1152000},
#endif
#ifdef B1500000
{"1500000", B1500000, 1500000},
#endif
#ifdef B2000000
{"2000000", B2000000, 2000000},
#endif
#ifdef B2500000
{"2500000", B2500000, 2500000},
#endif
#ifdef B3000000
{"3000000", B3000000, 3000000},
#endif
#ifdef B3500000
{"3500000", B3500000, 3500000},
#endif
#ifdef B4000000
{"4000000", B4000000, 4000000},
#endif
{NULL, 0, 0}
};
static speed_t
string_to_baud (const char *arg)
{
int i;
for (i = 0; speeds[i].string != NULL; ++i)
if (STREQ (arg, speeds[i].string))
return speeds[i].speed;
return (speed_t) -1;
}
/* http://www.gnu.org/software/libtool/manual/libc/Elapsed-Time.html
Subtract the `struct timeval' values X and Y,
storing the result in RESULT.
Return 1 if the difference is negative, otherwise 0. */
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
{
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000) {
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait.
tv_usec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}

Resources