You are not logged in.
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)
Desktop screenshots :: Origami :: github
Offline
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.
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
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.
Desktop screenshots :: Origami :: github
Offline
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
Thanks . 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 )
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!
Last edited by easysid (2016-06-17 16:58:25)
Desktop screenshots :: Origami :: github
Offline
Thanks . 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
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.
Desktop screenshots :: Origami :: github
Offline