Author Topic: [C] fdman  (Read 5424 times)

0 Members and 1 Guest are viewing this topic.

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
[C] fdman
« on: December 09, 2006, 06:56:21 pm »
fdman (short for fd manager) is a short and simple callback driven file descriptor (fd) multiplexer.  It is useful when dealing with a large set of mixed types of descriptors.  This is another component of my free time project.  At the moment I'm working on a secure UDP communication library that uses fdman.  Since UDP isn't the only communication that daemon needs to do (it needs to do local (unix) domain communication for example), I need something that centrally manages the descriptors.

The header:
Code: [Select]
#include <sys/select.h>
#include <sys/types.h>

#ifndef FDMAN_H
#define FDMAN_H

#define FDMAN_MAX FD_SETSIZE
#define FDMAN_READ 0x01
#define FDMAN_WRITE 0x02
#define FDMAN_EXCEPT 0x04

struct fdarg {
int fd;
uint8_t opt;
void *arg;
void (*cb)( struct fdarg *fda );
};

struct fdman {
struct fdarg fda[FDMAN_MAX];
fd_set rfds, wfds, efds;
int maxfd;
};

void fdman_init( struct fdman *fdm );
void fdman_set( struct fdman *fdm, struct fdarg *fda );
void fdman_unset( struct fdman *fdm, int fd );
int fdman_select( struct fdman *fdm, struct timeval *to );

#endif

Parameters

Code: [Select]
struct fdarg {
int fd; /* Descriptor */
uint8_t opt; /* Option bit mask, can be OR'd FDMAN_READ, FDMAN_WRITE, FDMAN_EXCEPT */
void *arg; /* Arbitrary argument pointer ... useful for the callback function */
void (*cb)( struct fdarg *fda ); /* Callback function */
};

When used as a parameter for fdman_set, the opt bitmask is used to set desired events.  When used with the callback function, the opt bitmask reflects the events that occurred.

Functions

void fdman_init( struct fdman *fdm ); /* Initializes a fdman struct */
void fdman_set( struct fdman *fdm, struct fdarg *fda ); /* Sets or updates settings for a descriptor */
void fdman_unset( struct fdman *fdm, int fd ); /* Unsets the descriptor */
int fdman_select( struct fdman *fdm, struct timeval *to ); /* A front to select(), however it performs all the callbacks ... a negative return reflects an error */

Example

This is a simple example that uses two descriptors.  One for the keyboard, and one for an arbitrary TCP/IP connection.

Code: [Select]
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sysexits.h>
#include <fcntl.h>
#include "fdman.h"

struct chat {
int fd;
struct fdman *fdm;
};

void kbdcb( struct fdarg *fda ) {
struct chat *ch = (struct chat *)(fda->arg);
/* Read from keyboard here */
}

void botcb( struct fdarg *fda ) {
uint8_t opt = fda->opt;
ctruct chat *ch = (struct chat *)(fda->arg);
if ( opt & FDMAN_WRITE ) {
printf( "Connected!\n" );
fda->opt = FDMAN_READ;
fdman_set( ch->fdm, fda );
}
if ( opt & FDMAN_READ ) {
/* Read from socket here */
}
}

int main( int argc, char **argv ) {
int arg;
struct fdman fdm;
struct fdarg fda;
struct chat ch;

fdman_init( &fdm );

fda.fd = STDIN_FILENO;
fda.arg = &ch;
fda.opt = FDMAN_READ;
fda.cb = kbdcb;

fdman_set( &fdm, &fda );

ch.fdm = &fdm;
ch.fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( ch.fd < 0 ) {
perror( "socket()" );
exit( EX_OSERR );
}
arg = fcntl( ch.fd, F_GETFL );
fcntl( ch.fd, F_SETFL, arg | O_NONBLOCK );

fda.fd = ch.fd;
fda.arg = &ch;
fda.cb = botcb;
fda.opt = FDMAN_READ | FDMAN_WRITE;

fdman_set( &fdm, &fda );

/* Connect and other stuff here */

while ( fdman_select( &fdm, NULL ) >= 0 );

return 0;
}
An adorable giant isopod!

Offline AntiVirus

  • Legendary
  • x86
  • Hero Member
  • *****
  • Posts: 2521
  • Best
    • View Profile
Re: [C] fdman
« Reply #1 on: December 10, 2006, 10:48:04 pm »
What is uint8_t opt; ?
The once grove of splendor,
Aforetime crowned by lilac and lily,
Lay now forevermore slender;
And all winds that liven
Silhouette a lone existence;
A leafless oak grasping at eternity.


"They say that I must learn to kill before I can feel safe, but I rather kill myself then turn into their slave."
- The Rasmus

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Re: [C] fdman
« Reply #2 on: December 11, 2006, 02:47:36 pm »
What is uint8_t opt; ?

uint8_t opt is an 8 bit bit mask.
An adorable giant isopod!

Offline AntiVirus

  • Legendary
  • x86
  • Hero Member
  • *****
  • Posts: 2521
  • Best
    • View Profile
Re: [C] fdman
« Reply #3 on: December 11, 2006, 05:30:38 pm »
Is it just for C or does C++ have that, too?
The once grove of splendor,
Aforetime crowned by lilac and lily,
Lay now forevermore slender;
And all winds that liven
Silhouette a lone existence;
A leafless oak grasping at eternity.


"They say that I must learn to kill before I can feel safe, but I rather kill myself then turn into their slave."
- The Rasmus

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Re: [C] fdman
« Reply #4 on: December 11, 2006, 06:09:19 pm »
Is it just for C or does C++ have that, too?

uint#_t variants are typedef'd to match the platform's type sizes.  They are defined in sys/types.h.  Both C and C++ can use them.
uint8_t always guarantees an 8 bit unsigned integer
uint16_t always guarantees a 16 bit unsigned integer
int8_t always guarantees an 8 bit signed integer
and so forth ...
An adorable giant isopod!

Offline AntiVirus

  • Legendary
  • x86
  • Hero Member
  • *****
  • Posts: 2521
  • Best
    • View Profile
Re: [C] fdman
« Reply #5 on: December 12, 2006, 04:27:00 pm »
Ooh, that's something I never knew!  Thanks. :D
The once grove of splendor,
Aforetime crowned by lilac and lily,
Lay now forevermore slender;
And all winds that liven
Silhouette a lone existence;
A leafless oak grasping at eternity.


"They say that I must learn to kill before I can feel safe, but I rather kill myself then turn into their slave."
- The Rasmus

Offline Rule

  • x86
  • Hero Member
  • *****
  • Posts: 1588
    • View Profile
Re: [C] fdman
« Reply #6 on: December 24, 2006, 03:43:38 pm »
Nearly any C code will also compile in C++...



Offline AntiVirus

  • Legendary
  • x86
  • Hero Member
  • *****
  • Posts: 2521
  • Best
    • View Profile
Re: [C] fdman
« Reply #7 on: December 25, 2006, 01:37:50 am »
Nearly any C code will also compile in C++...



Yeah, that makes sense. :P
The once grove of splendor,
Aforetime crowned by lilac and lily,
Lay now forevermore slender;
And all winds that liven
Silhouette a lone existence;
A leafless oak grasping at eternity.


"They say that I must learn to kill before I can feel safe, but I rather kill myself then turn into their slave."
- The Rasmus

Offline nslay

  • Hero Member
  • *****
  • Posts: 786
  • Giraffe meat, mmm
    • View Profile
Re: [C] fdman
« Reply #8 on: December 29, 2006, 05:00:18 am »
I improved fdman minimally over the vacation.  It now supports a timer manager so it can adjust the timeout value for select().  This is extremely handy!  I made these modifications to the secure UDP library I wrote and removed the awful sudp_timeout() function.  It now can set its own timer.
The timer manager is implemented with a doubly linked list ... the assumption is that there aren't very many timers to manage (small number = hundreds). 
An adorable giant isopod!