I need to write program which follow such steps:
Start program (daemon)
Wait (sleep, block) until I have wifi connection up
Send/get some data from server
Wait until wifi connection goes down
goto 2
Problem with step 2. I dont know how to catch moment when there is established network connection. There is /proc/net/wireless entry, where information about available wireless connections appear, but trying to monitor it with inotify have no success. Network connection is established asynchronously.
Here is my test code with inotify (copied mostly from R.Loves book):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/select.h>
#define BUF_LEN 1024
int
main() {
int fd, wd, rc;
char buf[BUF_LEN];
ssize_t len, i = 0;
static fd_set read_fds;
fd = inotify_init();
if (fd == -1) {
perror("inotify_init");
exit(EXIT_FAILURE);
}
wd = inotify_add_watch(fd, "/proc/net/wireless", IN_ALL_EVENTS);
if (wd == -1) {
perror("inotify_add_watch");
exit(EXIT_FAILURE);
}
for (;;) {
FD_ZERO(&read_fds);
FD_SET(wd, &read_fds);
rc = select(wd + 1, &read_fds, NULL, NULL, NULL);
if (rc == -1)
perror("select");
len = read(fd, buf, BUF_LEN);
while (i < len) {
struct inotify_event *event = (struct inotify_event *) &buf[i];
printf("wd=%d mask=%d cookie=%d len=%d dir=%s\n",
event->wd, event->mask, event->cookie, event->len,
(event-> mask & IN_ISDIR) ? "yes" : "no");
if (event->len)
printf("name=%s\n", event->name);
i += sizeof(struct inotify_event) + event->len;
}
sleep(1);
}
return 0;
}
It only catches evernt when I do cat /proc/net/wireless
Question: How to catch moment, when I have network connection running (wifi), using only Linux features?
P.S. This is my first post here, hope everything is ok.
You can detect when a network connection (not just wifi) beomes link-ready through the netlink interface, rtnetlink.
This is not an easy interface to program against, so you might wish to invoke the process "ip monitor link" instead. If you see the interface have the LOWER_UP flag, that means it's ready to send/ receive (EDIT: You may also want to check the NO_CARRIER flag is absent; see Simon's comment).
However, there is also a problem that you may have a race condition with a daemon like NetworkManager, which will (if so configured) attempt to get an IP address after the link becomes available.
Related
I've been making a map making robot car with Arduino for class. I want to make a user interface for it in C (on a PC running Linux) that would work like this: the user can press a Start and a Stop button, or click a specific area of the map to send the robot to there. Right now my test setup code looks like this:
Arduino:
`
if (BTSerial.available() > 0) {
c = BTSerial.readStringUntil('\n').toInt();
BTSerial.write(c);
if(c == 8) {
Buzzing(SOS);
BTSerial.println("eight");
}
}
**PC program**:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc addr = { 0 };
int s, status;
char dest[18] = "98:DA:60:03:F2:92";
// allocate a socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// set the connection parameters (who to connect to)
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
// send a message
if( status == 0 ) {
status = write(s, "8", 2);
}
if( status < 0 ) perror("uh oh");
int client, bytes_read;
char buf[1024] = { 0 };
// put socket into listening mode
listen(s, 1);
// read data from the client
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received [%s]\n", buf);
}
close(s);
return 0;
}
`
Ideally if I send the number 8 to the Arduino it would send back the string "eight". When I run my PC program, my PC connects to the Arduino (I get a notification from the OS that my PC is connected and also the led on my HC-06 Bluetooth module connected to the Arduino stops blinking signaling that a device was connected to it) and the buzzer connected to the Arduino starts buzzing the morse code of SOS as expected. However after a second my program terminates, the Bluetooth connection ends (I get a notification that my PC is disconnected and the led on the Bluetooth module starts blinking again) and I don't get back the expected "eight" string.
I'm still just a beginner when it comes to the C language and since I can not find a detailed documentation of BlueZ, I'm kind of stuck. Any help would be greatly appreciated!
I tried to combine the server and the client code from this site: https://people.csail.mit.edu/albert/bluez-intro/x502.html#rfcomm-server.c
I also tested my code on the Arduino using Putty on PC and it worked with it properly.
Calling listen on the socket doesn't do what you think it does. Listening does not mean "wait for data". It means "wait for connect". And you cannot read from the listening socket; you can only accept the connection.
Your socket is already connected. Don't listen. Just read.
So after a bit of work I finally could get it working. I only needed to change the first parameter of the read() function. Here's my final code:
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv)
{
struct sockaddr_rc addr = { 0 }, rem_addr = { 0 };
int s, status;
char dest[18] = "98:DA:60:03:F2:92";
// allocate a socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
// set the connection parameters (who to connect to)
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
// connect to server
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
// send a message
if( status == 0 ) {
status = write(s, "8", 2);
}
if( status < 0 ) perror("uh oh");
int bytes_read;
char buf[1024] = { 0 };
// read data from the client
bytes_read = read(s, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("%s", buf);
}
close(s);
return 0;
}
This code sends the number "8" to the Arduino, to which the Arduino replies with the string "eight". It's probably not the nicest C code for Bluetooth connection, but at least it's working I guess.
I'm writing a daemon which checks the battery capacity. This is for a solar powered embedded device running Linux. I've read that it's a bad idea to use sleep() in daemons, thus I'm trying to use events. So I wrote some PoCs, but I'm not getting any events! My first implementation, as they recommended to me, uses libudev and poll():
#include <fcntl.h>
#include <libudev.h>
#include <poll.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
struct udev *udev;
struct udev_monitor *mon;
struct pollfd fds[1];
int fd;
udev = udev_new();
if (udev == NULL)
return 1;
mon = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "power_supply", NULL);
udev_monitor_enable_receiving(mon);
fd = udev_monitor_get_fd(mon);
fds[0].fd = fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
if (poll(fds, 1, -1) > 0) {
/* Never gets here! */
struct udev_device *const dev = udev_monitor_receive_device(mon);
if (dev != NULL) {
puts(udev_device_get_sysname(dev));
udev_device_unref(dev);
}
else
fputs("udev_monitor_receive_device() failed\n", stderr);
}
udev_unref(udev);
return 0;
}
They only event I get, is when I plug/unplug the charger! Then I thought that the status bar I use in my laptop's installation does show the battery capacity. I looked at the source and they're using inotify to monitor the battery's uevent. But I've read everywhere that I shouldn't use inotify for sysfs! I tried nonetheless:
#include <stdio.h>
#include <sys/inotify.h>
#include <unistd.h>
#define BAT_PATH "/sys/class/power_supply/BAT0"
int main(void)
{
struct inotify_event ev = {0};
int wd, ret = 1;
ssize_t len;
const int fd = inotify_init1(IN_CLOEXEC);
if (fd < 0) {
perror("inotify_init() failed");
return ret;
}
/* else */
wd = inotify_add_watch(fd, BAT_PATH "/uevent", IN_ACCESS);
if (wd < 0)
goto end;
/* else */
len = read(fd, &ev, sizeof(ev));
/* Again... never gets here. */
if (len > 0 && (ev.mask & IN_ACCESS))
puts("It worked!");
inotify_rm_watch(fd, wd);
ret = 0;
end:
close(fd);
return ret;
}
Turns out that doesn't work either! How can it work for my status bar but not work when I try it? Am I doing something horribly wrong? Thank you.
Regarding your first implementation (would comment but not enough rep. as i know nothing about libudev): the guide i followed to successfully use sysfs to poll() a GPIO for interrupt suggests to look for a POLLPRI event, instead of POLLIN as you show in the first implementation (see man poll for event types).
More importantly, you say you get a single event when you connect/disconnect charger, do you mean a single event per software execution? If this is the case, it might be due to the fact that you don't clear the interrupt flag: after poll() hits, in sysfs one needs to int len = read(fds[0].fd, *buf, SIZE); to mark the interrupt as served, and also lseek(fds[0].fd, 0, 0); in order for the next read() to be succesful (see my other answer here for a code example).
i dont know whether this answer will help you or not, but i am writing answer because if any other users face same issue they can get it resolved.
the solution is:
you need to monitor kernel Events, so you need to change line
form
mon = udev_monitor_new_from_netlink(udev, "udev");
to
mon = udev_monitor_new_from_netlink(udev, "kernel");
then you will get events.
I have a client server connection where the client is sending data to the server.
while (1) {
bzero(buffer, 256);
sleep(1);
n = read(sock, buffer);
if(n < 0) error("ERROR reading from socket");
c = message[0];
//do something
}//close while loop
The issue i only want to wait for a read to happen only for some seconds - in my code, if the client does not send anything, it gets stuck waiting for the server to read something.
How can I wait for a read to happen only some seconds please?
If your socket is non-blocking you can use the select function.
If your socket is blocking you can set a read timeout using the setsockopt function. See this stackoverflow question for more details. Linux: is there a read or recv from socket with timeout?
You can use select() api for this purpose. In this api u can mention the time in select api in seconds and microseconds.
Basically the read call attempts to read so if you don't want to get stack on it you've to declare the sock variable as non-blocking or to use the select function with timeout (man select). In the first case you can't wait for some seconds but you can try to read k times and then go through. Here's the example for non-blocking socket:
/*
* Non-blocking socket solution
* just put the read in a for-loop
* if you want to read k times
*/
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int r1;
/*Setting the socket as non-blocking*/
int flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
errno = 0; /*If the read fails it sets errno*/
if((r1=read(sock,buf_in,N))== -1) { /*If the read returns an error*/
if(errno != EAGAIN && errno != EWOULDBLOCK){ /*If the error is not caused by the non-blocking socket*/
perror("Error in read\n");
exit(EXIT_FAILURE);
}
}
Here's the select solution:
/*
* Select solution.
* This is not a complete solution but
* it's almost everything you've to do
*/
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#define SVC(r,c,e) \
errno = 0; \
if((r=c)==-1) { perror(e);exit(errno); }
int r = 0;
int fd_skt;
fd_set rdset;
fd_set set;
struct timeval tv; /*Timer structure*/
int fd_num_max = 0; /*Maximum opened file descriptor*/
if(fd_skt > fd_num_max) fd_num_max = fd_skt;
FD_ZERO(set);
FD_SET(fd_skt,set); /*fd_skt is where you're waiting for new connection request*/
/*Setting the timer*/
tv.tv_sec = 0;
tv.tv_usec = 200*1000;
rdset = set;
SVC(r,select((fd_num_max+1),(&rdset),NULL,NULL,&tv),"Unable to select\n");
I am writing a small little IRC bot in C using openssl to start a secure socket. It isn't the most beautifully written bot, but its mostly just to see how the openssl API works. Currently I have the following code:
#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
int main() {
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
BIO *bio;
SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());
SSL * ssl;
SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs/");
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, & ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
BIO_set_nbio(bio, 1);
BIO_set_conn_hostname(bio, "irc.freenode.net:6697");
BIO_do_connect(bio);
if(SSL_get_verify_result(ssl) != X509_V_OK) {
printf("error\n");
}
char irc1[] = "NICK bartender\r\n";
char irc2[] = "USER bartender * * :serve(&drinks);\r\n";
BIO_write(bio, irc1, strlen(irc1));
BIO_write(bio, irc2, strlen(irc2));
fd_set read_set;
int sock = BIO_get_fd(bio, NULL);
while(1) {
FD_ZERO(&read_set);
FD_SET(sock, &read_set);
struct timeval timeout = { 0, 0 };
select(sock+1, &read_set, NULL, NULL, &timeout);
if(FD_ISSET(sock, &read_set)) {
char buf[21];
size_t x = BIO_read(bio, buf, 20);
if(x == 0) {
continue;
} else if(x == -1){
int code = ERR_get_error();
if(code == 0) {
continue;
}
printf("(%d)%s\n", code, ERR_error_string(code, NULL));
} else {
buf[x] = '\0';
printf("%s", buf);
}
}
}
}
Whenever I compile and run this code, it just hangs and prints nothing. However, if I remove line 20 (which currently puts the socket into nonblocking mode) it works fine. Why does putting the socket in non-blocking mode cause this behavior? Thank you and have a great day!
Whenever I run this code, it just hangs and prints nothing. However, if I remove line 20 (which currently puts the socket into nonblocking mode) it works fine.
BIO_do_connect returns immediately in non-blocking mode. You should loop on BIO_should_retry. Here's what the man page has to say about BIO_do_connect:
BIO_do_connect() attempts to connect the supplied BIO. It returns 1 if
the connection was established successfully. A zero or negative value
is returned if the connection could not be established, the call
BIO_should_retry() should be used for non blocking connect BIOs to
determine if the call should be retried.
Why does putting the socket in non-blocking mode cause this behavior?
The call to BIO_do_connect returns immediately; the socket/bio is probably not ready for data (yet).
An alternative to looping on BIO_do_connect/BIO_should_retry is to wait on the underlying file descriptor. Its the technique used by OpenSSL in the ocsp subcommand (the source can be found in <openssl src>/apps/ocsp.c):
if (req_timeout != -1)
BIO_set_nbio(cbio, 1);
rv = BIO_do_connect(cbio);
if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) {
BIO_puts(err, "Error connecting BIO\n");
return NULL;
}
if (BIO_get_fd(cbio, &fd) < 0) {
BIO_puts(bio_err, "Can't get connection fd\n");
goto err;
}
if (req_timeout != -1 && rv <= 0) {
FD_ZERO(&confds);
openssl_fdset(fd, &confds);
tv.tv_usec = 0;
tv.tv_sec = req_timeout;
rv = select(fd + 1, NULL, (void *)&confds, NULL, &tv);
if (rv == 0) {
BIO_puts(err, "Timeout on connect\n");
return NULL;
}
}
Also see Non-blocking BIO and BIO_do_connect problem on the OpenSSL Users mailing list. There's also a few hits on Stack Overflow, but I'm not sure which is the best fit for this question:
nonblocking BIO_do_connect blocked when there is no internet connected
OpenSSL connection fails with non-blocking socket
Changing an OpenSSL BIO from blocking to non-blocking mode
Unable to establish connection using OpenSSL BIO interface
I recently did some testing with kernel events and I came up with the following:
Does it make sense to use a kernel event for accepting sockets? My testing showed that I was only able to handle one accept at once (even if the eventlist array is bigger)(Makes sense to me cause .ident == sockfd is only true for one socket).
I thought the use of kevent is mainly to read from multiple sockets at once. Is that true?
Is this how a TCP server is done with a kqueue implementation? :
Listening Thread (without kqueue)
Accepts new connections and adds FD to a worker kqueue.
QUESTION: Is this even possible? My testing showed yes, but is it guaranteed that the worker thread will be aware of the changes and is kevent really thread safe?
Worker thread (with kqueue)
Waits on reads on file descriptors added from the listening thread.
QUESTION: How many sockets at once would make sense to check for updates?
Thanks
This is not really an answer but I made a little server script with kqueue explaining the problem:
#include <stdio.h> // fprintf
#include <sys/event.h> // kqueue
#include <netdb.h> // addrinfo
#include <arpa/inet.h> // AF_INET
#include <sys/socket.h> // socket
#include <assert.h> // assert
#include <string.h> // bzero
#include <stdbool.h> // bool
#include <unistd.h> // close
int main(int argc, const char * argv[])
{
/* Initialize server socket */
struct addrinfo hints, *res;
int sockfd;
bzero(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
assert(getaddrinfo("localhost", "9090", &hints, &res) == 0);
sockfd = socket(AF_INET, SOCK_STREAM, res->ai_protocol);
assert(sockfd > 0);
{
unsigned opt = 1;
assert(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == 0);
#ifdef SO_REUSEPORT
assert(setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)) == 0);
#endif
}
assert(bind(sockfd, res->ai_addr, res->ai_addrlen) == 0);
freeaddrinfo(res);
/* Start to listen */
(void)listen(sockfd, 5);
{
/* kevent set */
struct kevent kevSet;
/* events */
struct kevent events[20];
/* nevents */
unsigned nevents;
/* kq */
int kq;
/* buffer */
char buf[20];
/* length */
ssize_t readlen;
kevSet.data = 5; // backlog is set to 5
kevSet.fflags = 0;
kevSet.filter = EVFILT_READ;
kevSet.flags = EV_ADD;
kevSet.ident = sockfd;
kevSet.udata = NULL;
assert((kq = kqueue()) > 0);
/* Update kqueue */
assert(kevent(kq, &kevSet, 1, NULL, 0, NULL) == 0);
/* Enter loop */
while (true) {
/* Wait for events to happen */
nevents = kevent(kq, NULL, 0, events, 20, NULL);
assert(nevents >= 0);
fprintf(stderr, "Got %u events to handle...\n", nevents);
for (unsigned i = 0; i < nevents; ++i) {
struct kevent event = events[i];
int clientfd = (int)event.ident;
/* Handle disconnect */
if (event.flags & EV_EOF) {
/* Simply close socket */
close(clientfd);
fprintf(stderr, "A client has left the server...\n");
} else if (clientfd == sockfd) {
int nclientfd = accept(sockfd, NULL, NULL);
assert(nclientfd > 0);
/* Add to event list */
kevSet.data = 0;
kevSet.fflags = 0;
kevSet.filter = EVFILT_READ;
kevSet.flags = EV_ADD;
kevSet.ident = nclientfd;
kevSet.udata = NULL;
assert(kevent(kq, &kevSet, 1, NULL, 0, NULL) == 0);
fprintf(stderr, "A new client connected to the server...\n");
(void)write(nclientfd, "Welcome to this server!\n", 24);
} else if (event.flags & EVFILT_READ) {
/* sleep for "processing" time */
readlen = read(clientfd, buf, sizeof(buf));
buf[readlen - 1] = 0;
fprintf(stderr, "bytes %zu are available to read... %s \n", (size_t)event.data, buf);
sleep(4);
} else {
fprintf(stderr, "unknown event: %8.8X\n", event.flags);
}
}
}
}
return 0;
}
Every time a client sends something the server experiences a "lag" of 4 seconds. (I exaggerated a bit, but for testing quite reasonable). So how do get around to that problem? I see worker threads (pool) with own kqueue as possible solution, then no connection lag would occur. (each worker thread reads a certain "range" of file descriptors)
Normally, you use kqueue as an alternative to threads. If you're going to use threads, you can just set up a listening thread and a worker threadpool with one thread per accepted connection. That's a much simpler programming model.
In an event-driven framework, you would put both the listening socket and all the accepted sockets into the kqueue, and then handle events as they occur. When you accept a socket, you add it to the kqueue, and when a socket handler finishes it works, it could remove the socket from the kqueue. (The latter is not normally necessary because closing a fd automatically removes any associated events from any kqueue.)
Note that every event registered with a kqueue has a void* userdata, which can be used to identify the desired action when the event fires. So it's not necessary that every event queue have a unique event handler; in fact, it is common to have a variety of handlers. (For example, you might also want to handle a control channel set up through a named pipe.)
Hybrid event/thread models are certainly possible; otherwise, you cannot take advantage of multicore CPUs. One possible strategy is to use the event queue as a dispatcher in a producer-consumer model. The queue handler would directly handle events on the listening socket, accepting the connection and adding the accepted fd into the event queue. When a client connection event occurs, the event would be posted into the workqueue for later handling. It's also possible to have multiple workqueues, one per thread, and have the accepter guess which workqueue a new connection should be placed in, presumably on the basis of that thread's current load.