You are not logged in.

#1 2016-06-17 09:09:51

easysid
Member
From: India
Registered: 2013-01-01
Posts: 256

[SOLVED]Calling ping from a C program.

I am trying to write a C program to generate the sysinfos for the status bar. I am having some problems in getting the network status part right.

The idea is to ping a well known site (8.8.8.8) to check for internet connectivity. Between system(), which calls the shell anyway, and writing a raw socket, which seems a bit complex, I decided to  use execl() to call the ping binary. However, it seems to take too long to respond, even with the -w1 option passed.

Here is the code
myping.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>

#define _ADDR     "8.8.8.8"

int main()
{
    int null, bak, statval;
    // juggling stdout to supress ping output
    null = open("/dev/null", O_WRONLY);
    bak = dup(STDOUT_FILENO);
    dup2(null, STDOUT_FILENO);
    close(null);
    // execute command
    if(fork() == 0) {
        execl("/bin/ping", "ping", "-c1 -w1", _ADDR,  NULL);
        exit(1);
    }
    else
    {
        // restore stdout
        dup2(bak, STDOUT_FILENO);
        close(bak);
        wait(&statval);
        if(WIFEXITED(statval) && WEXITSTATUS(statval) == 0)
            printf("\nSuccess");
        else
            printf("\nFailed");
    }
    return 0;
}

But it takes too long, if the connection drops

$   TIMEFORMAT=$'\t\t%3R'

$  while :; do time ./a.out; sleep 3; done

Success		0.123
Success		0.123
Failed		10.003
Failed		3.013
Failed		1.078
Failed		0.998
Failed		0.998
Success		0.131
Success		0.131

Incidentally, using system() has no such issues (and saves the whole trying to suppress the ping output)

int main(){
    int x;
    x = system("ping -c1 -w1 8.8.8.8 > /dev/null 2>&1");
    if(x == 0)
            printf("\nSuccess");
        else
            printf("\nFailed");
}

Here is the time output

 c $  while :; do time ./a.out; sleep 3; done

Success		0.112
Success		0.106
Success		0.111
Failed		1.013
Failed		1.013
Failed		1.012
Failed		1.012
Success		0.111
Success		0.111

What am I doing wrong in the first case?
Also, is there a better way to supress the ping output from execl(), apart from temporarily reassigning stdout?

Thanks.

EDIT: sockets are better. I am still not sure why the delay was in ping, but the issue is resolved as connect() works as required.

Last edited by easysid (2016-06-17 16:49:54)

Offline

#2 2016-06-17 14:42:29

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 19,772

Re: [SOLVED]Calling ping from a C program.

What about the system() function?

ewaller@turing/home/ewaller[127] % cat test.c
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv)
{
  int x;
  x=system("ping -c 1 8.8.8.8 > /dev/null");
  printf("%i\n",x);
}
ewaller@turing/home/ewaller % gcc test.c
ewaller@turing/home/ewaller % time ./a.out
0

real	0m0.019s
user	0m0.000s
sys	0m0.000s
ewaller@turing/home/ewaller % 

Edit:  Clearly I did not read your whole post.   I think your problem is that the exec class of functions replaces your process.  I don't think it is supposed to return.

man page wrote:

The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.

Last edited by ewaller (2016-06-17 14:46:46)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#3 2016-06-17 15:01:39

easysid
Member
From: India
Registered: 2013-01-01
Posts: 256

Re: [SOLVED]Calling ping from a C program.

system() works as expected, but as I mentioned, I wanted to avoid spawning a shell.

exec() does not return except for failure, but that is the expected behavior. The call executes fine, but it is the wait(*int) that seems to be hanging up when the connection drops. 10 seconds is just too long, and I can't seem to get rid of this behaviour.

Offline

#4 2016-06-17 15:16:25

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: [SOLVED]Calling ping from a C program.

Calling ping seems like a ridiculously complex way to do this.  Just try to open an internet socket.  If the call to "connect()" succeeds, you have internet connectivity, if it fails, you (probably) don't.

This can all be done in about 5-6 lines of C code.

EDIT: this tries to connect to google.com, and upon success returns zero, otherwise returns 1:

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main() {
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr = { AF_INET, htons(80), inet_addr("216.58.218.238") };
	if (connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) != 0) return 1;
	close(sockfd);
	return 0;
}

"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#5 2016-06-17 16:47:54

easysid
Member
From: India
Registered: 2013-01-01
Posts: 256

Re: [SOLVED]Calling ping from a C program.

Thanks smile. socket connection is a better way. I used the google DNS to connect. There was the issue of it taking too long to timeout when the connection failed, upto a minute initially. However that was quickly fixed by the setsockopt() (Thanks to SO tongue)

int main() {
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr = {AF_INET, htons(_PORT), inet_addr(_SERVER)};
    struct timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
    setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
	if (connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) != 0)
        printf("Failed");
    else
        printf("Success");
	close(sockfd);
	return 0;
}

here are the times

$  while :; do time ./a.out ; sleep 3; done
Success		0.146s
Success		0.122s
Success		0.128s
Success		0.145s
Failed		1.000s
Failed		0.998s
Failed		0.998s
Success		0.106s
Success		0.128s
Success		0.123s

PS: Thanks to @Tribly for the dwmstatus script too! smile

Last edited by easysid (2016-06-17 16:58:25)

Offline

#6 2016-06-17 17:33:16

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: [SOLVED]Calling ping from a C program.

easysid wrote:

Thanks smile. socket connection is a better way. I used the google DNS to connect. There was the issue of it taking too long to timeout when the connection failed

It worked instantly for me either way, but I used google's front page server, not their DNS.  The latter could be the problem as 8.8.8.8 doesn't listen on port 80 (which is why I used their web server instead).


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#7 2016-06-17 18:11:16

easysid
Member
From: India
Registered: 2013-01-01
Posts: 256

Re: [SOLVED]Calling ping from a C program.

I connected to port 53 on the DNS server. In the loop, it seemed to hang a bit when I yanked out the Ethernet cable. Maybe an issue with connect waiting for some timeout.

Offline

Board footer

Powered by FluxBB