[ccan] ccan: the psuedo "networking" module.

Allan Ference f.fallen45 at gmail.com
Tue Dec 4 13:43:20 EST 2012


On Tue, Dec 4, 2012 at 2:14 AM, Rusty Russell <rusty at rustcorp.com.au> wrote:

> Allan Ference <f.fallen45 at gmail.com> writes:
> > Hey Rusty,
> >
> > Good day, I've done the changes needed and pushed to branch named `net'
> > which you can view on my fork here:
> > https://github.com/allanference/ccan/tree/net
>
> Hi Allan,
>
>         Please CC the list in future.
>
> Okay, though it seems to be kind of dead so Cc'ing it may not be of use
but I've guessed it may be that you don't like checking e-mails.

> I looked at the net changes, and initially I thought it was a bad idea
> to rename net_client_lookup to net_lookup.  But I thought harder, and I
> now agree (we should probably add a net_wildcard() function if we want a
> convenient way of getting a v4/v6 address to bind to).  Similarly with
> exporting set_nonblock, though it seems that your version handling
> windows would be better?
>
> It does handle windows better, I could put the windows compatibility
better but I thought I would wait until we would make the config generator
to detect windows (like you said on the mailing list before, remember?)

> Your interface to socket is fairly incoherent, however.  As I'm sure you
> know by now writing a socket library is *hard*.  If I were you, I'd
> think what interface you'd want to use, and then implement that.
>
> For example, if you're trying to write a server, I've always wanted an
> interface like:
>
>         /* Listeners create connections. */
>         struct listener;
>
> I don't quite get this one, you never use this variable \/

>         /* One connection per client. */
>         struct conn;
>
> Nor this one >_>

>         /* Create a new listener; fn gets called when it gets a connection
> */
>         bool new_listener(const char *service,
>                           bool (*fn)(struct conn *, void *arg), void *arg);
>
>         /* To create a connection. */
>         bool new_conn(const char *node, const char *service,
>                       bool (*fn)(struct conn *, void *arg), void *arg);
>
>         /* In case you want to create a connection manually. */
>         struct conn *new_conn_fd(int fd,
>                             bool (*fn)(struct conn *, void *arg),
>                             void *arg);
>
>         /* Queue some data to be written.  Fails on OOM or closed fd. */
>         bool conn_write(struct conn *conn, const void *data, size_t len);
>
>         /* Queue a request to read into a buffer.  Fails on OOM or closed
> fd. */
>         bool conn_read(struct conn *conn, void *data, size_t len);
>
>         /* Queue a partial request to read into a buffer. */
>         bool conn_read_partial(struct conn *conn, void *data, size_t *len);
>
>         /* Queue a partial write request. */
>         bool conn_write_partial(struct conn *conn, const void *data,
> size_t *len);
>
>         /* Your function must return this value. */
>         bool conn_next(struct conn *conn,
>                        bool (*next)(struct conn *, void *arg), void *arg);
>
>         /* Useful next functions. */
>         /* Close the connection, we're done. */
>         void next_close(struct conn *, void *arg));
>
>         /* Exit the loop, returning this (non-NULL) arg. */
>         void next_break(struct conn *, void *arg);
>
>         /* This is the main loop. */
>         void *conn_loop(void);
>
> Now to use this would be really nice, eg:
>         #define BUFFER_SIZE 1024
>
>         struct buf {
>                 char bytes[BUFFER_SIZE];
>                 size_t used;
>         };
>
>         static bool echo_write(struct conn *conn, struct buf *buf)
>         {
>                 if (!conn_write(conn, buf->bytes, buf->used)) {
>                         free(buf);
>                         return false;
>                 }
>                 return conn_next(conn, echo_read, buf);
>         }
>
>         static bool echo_read(struct conn *conn, struct buf *buf)
>         {
>                 buf->used = BUFFER_SIZE;
>                 if (!conn_read_partial(conn, buf->bytes, &buf->used)) {
>                         free(buf);
>                         return false;
>                 }
>                 return conn_next(conn, echo_write, buf);
>         }
>
>         static bool echo_start(struct conn *conn, void *unused)
>         {
>                 struct buf *buf = malloc(sizeof(buf));
>                 if (!buf)
>                         return false;
>
>                 return conn_next(conn, buf, echo_read, buf);
>         }
>
>         int main(int argc, char *argv[])
>         {
>                 if (!new_listener(argv[1], echo_start, NULL))
>                         err(1, "Creating listener");
>
>                 conn_loop();
>         }
>
> Your idea is nice, and I tottaly agree with you to be honest, I will try
to rewrite it soon, just need some more time.

> The implementation can be done completely without threads, yet be fully
> async.  Or another variant could use a thread per connection, so the
> only user-visible synchronization would be for anything shared between
> threads.
>
I don't think creating a thread per connection would be nice, the
asynchronous methods do good job, however, for the server part sure we
could leave that as a loop but consider something like so:

A graphical application (say a game or a chat client) want to handle GUI
events (take something like gtk or Qt as an example, they require a
gtk_main() and return application.exec())

But for a server it's nice, why? because if we would want to make something
like a chat server it would be good since we only care about connections,
etc.

>
> The best thing is that you could force the implementation into a
> debugging sychronous mode, where conn_read_* and conn_write_* worked
> synchonously, and conn_next immediately called the next function.  This
> gives you a nice call-chain to see exactly what occurred.
>
> Ah!  This is what I was thinking about just few days ago but I was too
lazy to implement it, thanks for reminding me!

> Of course, the names might need work, and the callbacks should be made
> typesafe using ccan/typesafe_cb, but I'd love to use such a module!
>
> Cheers,
> Rusty.
>

I'll do my best do improve it in the near future.

Thanks,
Allan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/ccan/attachments/20121204/ab6ebe48/attachment.html>


More information about the ccan mailing list