0

I'm making a communication library that takes a filestream and uses it to read and write. The protocol defines timeouts, so I want to use them.

I'm using fread(3) and fwrite(3). I have heard of select(2), and it's what I'm looking for, except it uses file descriptors and not libc filestreams - I want to support custom filestreams created with fopencookie(3), useful for tests and other things, too. I have tried setting up SIGALRM with alarm(2) to get the EINTR error from fread(3) (setting up a callback for SIGALRM using signal(2)), but it won't stop the fopen call as expected...

Thanks in advance for any solution.

EDIT: So it looks like this works.. but only once. On the second call, it doesn't... Oo

/**
 *  sigalrm_handler:
 *  Shut up SIGALRM.
 *
 *  @arg    code        signal code (always SIGALRM)
 */

static __thread jmp_buf env_alrm;
static void sigalrm_handler(int signo)
{
    (void)signo;
    /* restore env */
    longjmp(env_alrm, 5);
}

/**
 *  _p7_fread:
 *  Read file with timeout.
 *
 *  @arg    ptr         the buffer pointer
 *  @arg    size        the size of an item
 *  @arg    nitems      the number of items in the buffer
 *  @arg    stream      the stream
 *  @arg    timeout     the timeout (seconds)
 *  @return             the number of read bytes
 */

size_t _p7_fread(void *ptr, size_t size, size_t nitems, FILE *stream,
    int timeout)
{
    size_t read_count = 0;

    /* set long jump */
    int val = setjmp(env_alrm);
    if (!val) {
    /* setup signal handler */
        if (signal(SIGALRM, &sigalrm_handler) == SIG_ERR)
            return (0);

        /* setup alarm */
        alarm(timeout);

        /* read */
        read_count = fread(ptr, size, nitems, stream);
    } else
        errno = EINTR;

    /* unset signal handler and alarm */
    signal(SIGALRM, NULL);
    alarm(0);

    /* return */
    return (read_count);
}

Again, thanks for any help ^^

Cakeisalie5
  • 384
  • 3
  • 10

1 Answers1

0

the function: fdopen() will get you file pointers from file descriptors.

Then you can use the function: select() with the file pointers that were returned from fdopen().

user3629249
  • 16,402
  • 1
  • 16
  • 17
  • But what about the internal buffers to the FILE* structure ? And what about the filestreams that don't have a file descriptor (I'm thinking about those created with `fopencookie`) ? – Cakeisalie5 Oct 09 '16 at 08:45
  • this is from: <> "The fdopen() function associates a stream with the existing file descriptor, fd. The mode of the stream (one of the values "r", "r+", "w", "w+", "a", "a+") must be compatible with the mode of the file descriptor. The file position indicator of the new stream is set to that belonging to fd, and the error and end-of-file indicators are cleared. Modes "w" or "w+" do not cause truncation of the file. The file descriptor is not dup'ed, and will be closed when the stream created by fdopen() is closed. The result of applying fdopen() to a shared memory object is undefined. " – user3629249 Oct 10 '16 at 01:54
  • So I've given a try to `select` and `fileno`. But the fact is `fileno` returns -1 on a custom stream created with `fopencookie`, so I can't use `select` with it. And if I want to test timeouts with custom filestreams... so that won't work for me. :/ – Cakeisalie5 Oct 11 '16 at 16:28
  • @Cakeisalie5, Exactly what are you trying to accomplish? Do you understand that a 'cookie' is a memory object not a real I/O stream, so some external force changing that memory will not trigger an event to be recognized by such as `select()`? – user3629249 Oct 12 '16 at 18:32
  • I've understood that, I'm using custom filestreams for testing. But that's why I can't use `select` for my case (as I also want to check timeouts on custom filestreams)... so I'm looking for a more general way to make `fopen`/`fwrite` timeout (/cause `EINTR`, which I haven't found how to cause even with `alarm`). – Cakeisalie5 Oct 13 '16 at 07:56