Cyzanfar
Cyzanfar

Reputation: 7136

signal alarm fails too soon

I have a signal where I set a callback handler and then in my function I call alarm(1) so that my program will time out after 1 second. Upon timing out I'd like it to retry to same blocking call recvfrom() until a set MAX_ATTEMPTS which is 5.

Problem:

It only retries 2 times before exiting the program. Any idea what might be going wrong?

/* declate signal for setting alarm */
signal(SIGALRM, timeout_hdler);
int attempts = 0;

while(1) {
    if(attempts > MAX_ATTEMPTS) {
        printf("Connection is not working, EXITING program");
        s.curr_state = CLOSED;
        /* we assume connection is failing so we shut down */
        exit(-1);
    }

    if (s.curr_state == CLOSED) {

        printf("Sending SYN_packet with seqnum: %d...\n", SYN_packet->seqnum);

        if (sendto(sockfd, SYN_packet, sizeof(SYN_packet), 0, server, socklen) == -1) {
            perror("Sendto error");
            exit(-1);
        }

        s.curr_state = SYN_SENT;

        printf("Current state SYN_SENT: %d\n", s.curr_state);
    }

    if (s.curr_state == SYN_SENT) {



        alarm(1);
        attempts++;
        printf("\nAttempt number: %d\n", attempts);
        printf("Waiting for SYNACK_packet...\n");

        if (recvfrom(
                sockfd, SYNACK_packet, sizeof(*SYNACK_packet), 0, (struct sockaddr *) &server, &socklen) == -1)
        {
            if (errno != EINTR) {
                perror("Recvfrom SYNACK_packet error\n");
                s.curr_state = CLOSED;
                exit(-1);
            }
        }

        if ((SYNACK_packet->type == SYNACK) && (validate_packet(SYNACK_packet) == 1)) {

            printf("SYNACK_packet received\n");

            s.address = *(struct sockaddr *) &server;
            s.sock_len = socklen;
            s.curr_state = ESTABLISHED;
            s.seq_num = SYNACK_packet->seqnum;
            printf("Current state ESTABLISHED: %d\n", s.curr_state);
            return sockfd;
        }
    }
}

The handler (which does nothing apart from printing):

void timeout_hdler(int signum) {
    printf("TIMEOUT has occured with signum: %d", signum);
}

Here is the output in my console (from the printf statement):

In Connect() with socket: 4, server: 2, socklen: 16
Sending SYN_packet with seqnum: 67...
Current state SYN_SENT: 1

Attempt number: 1
Waiting for SYNACK_packet...
TIMEOUT has occured with signum: 14
Attempt number: 2
Waiting for SYNACK_packet...
Alarm clock

Why is it exiting the program after only 2 attempts? Ideally I'd like it to retry 5 times before closing the connection (this is a Go Back N implementation using UDP)

UPDATE

I resolved the issue by reinstalling the signal: signal(SIGALRM, timeout_hdler); in my handler. But why is that? Am I doing this wrong?

void timeout_hdler(int signum) {
    printf("TIMEOUT has occured with signum: %d", signum);
    signal(SIGALRM, timeout_hdler);
}

Upvotes: 0

Views: 320

Answers (1)

Steffen Ullrich
Steffen Ullrich

Reputation: 123320

The semantics of signal depends on the OS and libc. But according to your output in your specific case the signal handler handlers gets reset to the default after the first invocation of the handler function. The default then results in the program exit if the signal is triggered again, i.e. the Alarm clock and exit you see in the output.

From the documentation of signal in Linux:

The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN. ....
In the original UNIX systems, when a handler that was established using signal() was invoked by the delivery of a signal, the disposition of the signal would be reset to SIG_DFL, and the system did not block delivery of further instances of the signal. ...

In other words: don't use signal. Instead you should use sigaction:

POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a signal handler is invoked; use that interface instead of signal().

Upvotes: 1

Related Questions