A
Andrea Crotti
I have to write data on a tun device, and I thought that for writing I
needed a queue to avoid losing packets.
But maybe it's not needed, I could just wait that it's free (assuming
that it WILL be free, there's only one process accessing).
What I did is a while loop where I check (with a select) when it's
writable and then write it to the queue.
Every time I also try to write the whol remaining of the queue.
It's something like that below (all code is
http://github.com/AndreaCrotti/Network-mote/blob/master/driver/tunnel.c):
--8<---------------cut here---------------start------------->8---
int tun_write(int fd, char *buf, int length){
int nwrite;
// should not exit directly here maybe?
//TODO: Maybe send is better here
if((nwrite = write(fd, buf, length)) < 0){
perror("Writing data");
exit(1);
}
return nwrite;
}
void tunWriteNoQueue(int client_no, char *buf, int len) {
int fd = *get_fd(client_no);
// use some simple error checking here instead
assert(tun_write(fd, buf, len) == len);
}
void addToWriteQueue(int client_no, char *buf, int len) {
int fd = *get_fd(client_no);
// add the message to the queue
write_queue *queue = &(tun_devices[client_no].queue);
add_to_queue(queue, buf);
/* printf("now queue %d <-> %d\n", queue->first, queue->last); */
// now use a select to try to send out everything
// try to send out as many messages as possible
char *message;
// quit immediately the loop if we sent everything or is not writable
while (1) {
message = fetch_from_queue(queue);
if (!message)
break;
if (is_writable(fd)) {
int nwrite = tun_write(fd, buf, len);
/* printf("wrote %d bytes\n", nwrite); */
if (nwrite) {
// otherwise means partially written data
assert(nwrite == len);
// only now we can remove it from the queue
delete_last(queue);
}
}
else
break;
}
}
/**
* Check if the device is ready for writing
*
* @param fd file descriptor to check
*/
int is_writable(int fd) {
fd_set fds;
struct timeval timeout = {.tv_sec = 3, .tv_usec = 0};
int rc;
FD_ZERO(&fds);
FD_SET(fd, &fds);
// is this fd+1 exactly what we need here?
rc = select(fd + 1, NULL, &fds, NULL, &timeout);
return FD_ISSET(fd,&fds) ? 1 : 0;
}
--8<---------------cut here---------------end--------------->8---
needed a queue to avoid losing packets.
But maybe it's not needed, I could just wait that it's free (assuming
that it WILL be free, there's only one process accessing).
What I did is a while loop where I check (with a select) when it's
writable and then write it to the queue.
Every time I also try to write the whol remaining of the queue.
It's something like that below (all code is
http://github.com/AndreaCrotti/Network-mote/blob/master/driver/tunnel.c):
--8<---------------cut here---------------start------------->8---
int tun_write(int fd, char *buf, int length){
int nwrite;
// should not exit directly here maybe?
//TODO: Maybe send is better here
if((nwrite = write(fd, buf, length)) < 0){
perror("Writing data");
exit(1);
}
return nwrite;
}
void tunWriteNoQueue(int client_no, char *buf, int len) {
int fd = *get_fd(client_no);
// use some simple error checking here instead
assert(tun_write(fd, buf, len) == len);
}
void addToWriteQueue(int client_no, char *buf, int len) {
int fd = *get_fd(client_no);
// add the message to the queue
write_queue *queue = &(tun_devices[client_no].queue);
add_to_queue(queue, buf);
/* printf("now queue %d <-> %d\n", queue->first, queue->last); */
// now use a select to try to send out everything
// try to send out as many messages as possible
char *message;
// quit immediately the loop if we sent everything or is not writable
while (1) {
message = fetch_from_queue(queue);
if (!message)
break;
if (is_writable(fd)) {
int nwrite = tun_write(fd, buf, len);
/* printf("wrote %d bytes\n", nwrite); */
if (nwrite) {
// otherwise means partially written data
assert(nwrite == len);
// only now we can remove it from the queue
delete_last(queue);
}
}
else
break;
}
}
/**
* Check if the device is ready for writing
*
* @param fd file descriptor to check
*/
int is_writable(int fd) {
fd_set fds;
struct timeval timeout = {.tv_sec = 3, .tv_usec = 0};
int rc;
FD_ZERO(&fds);
FD_SET(fd, &fds);
// is this fd+1 exactly what we need here?
rc = select(fd + 1, NULL, &fds, NULL, &timeout);
return FD_ISSET(fd,&fds) ? 1 : 0;
}
--8<---------------cut here---------------end--------------->8---