<div dir="ltr"><br><br><div class="gmail_quote">On Tue, Dec 4, 2012 at 2:14 AM, Rusty Russell <span dir="ltr"><<a href="mailto:rusty@rustcorp.com.au" target="_blank">rusty@rustcorp.com.au</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">Allan Ference <<a href="mailto:f.fallen45@gmail.com">f.fallen45@gmail.com</a>> writes:<br>
> Hey Rusty,<br>
><br>
> Good day, I've done the changes needed and pushed to branch named `net'<br>
> which you can view on my fork here:<br>
> <a href="https://github.com/allanference/ccan/tree/net" target="_blank">https://github.com/allanference/ccan/tree/net</a><br>
<br>
</div>Hi Allan,<br>
<br>
        Please CC the list in future.<br>
<br></blockquote><div>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. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

I looked at the net changes, and initially I thought it was a bad idea<br>
to rename net_client_lookup to net_lookup.  But I thought harder, and I<br>
now agree (we should probably add a net_wildcard() function if we want a<br>
convenient way of getting a v4/v6 address to bind to).  Similarly with<br>
exporting set_nonblock, though it seems that your version handling<br>
windows would be better?<br>
<br></blockquote><div>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?)</div>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Your interface to socket is fairly incoherent, however.  As I'm sure you<br>
know by now writing a socket library is *hard*.  If I were you, I'd<br>
think what interface you'd want to use, and then implement that.<br>
<br>
For example, if you're trying to write a server, I've always wanted an<br>
interface like:<br>
<br>
        /* Listeners create connections. */<br>
        struct listener;<br>
<br></blockquote><div>I don't quite get this one, you never use this variable \/ </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
        /* One connection per client. */<br>
        struct conn;<br>
<br></blockquote><div>Nor this one >_> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
        /* Create a new listener; fn gets called when it gets a connection */<br>
        bool new_listener(const char *service,<br>
                          bool (*fn)(struct conn *, void *arg), void *arg);<br>
<br>
        /* To create a connection. */<br>
        bool new_conn(const char *node, const char *service,<br>
                      bool (*fn)(struct conn *, void *arg), void *arg);<br>
<br>
        /* In case you want to create a connection manually. */<br>
        struct conn *new_conn_fd(int fd,<br>
                            bool (*fn)(struct conn *, void *arg),<br>
                            void *arg);<br>
<br>
        /* Queue some data to be written.  Fails on OOM or closed fd. */<br>
        bool conn_write(struct conn *conn, const void *data, size_t len);<br>
<br>
        /* Queue a request to read into a buffer.  Fails on OOM or closed fd. */<br>
        bool conn_read(struct conn *conn, void *data, size_t len);<br>
<br>
        /* Queue a partial request to read into a buffer. */<br>
        bool conn_read_partial(struct conn *conn, void *data, size_t *len);<br>
<br>
        /* Queue a partial write request. */<br>
        bool conn_write_partial(struct conn *conn, const void *data, size_t *len);<br>
<br>
        /* Your function must return this value. */<br>
        bool conn_next(struct conn *conn,<br>
                       bool (*next)(struct conn *, void *arg), void *arg);<br>
<br>
        /* Useful next functions. */<br>
        /* Close the connection, we're done. */<br>
        void next_close(struct conn *, void *arg));<br>
<br>
        /* Exit the loop, returning this (non-NULL) arg. */<br>
        void next_break(struct conn *, void *arg);<br>
<br>
        /* This is the main loop. */<br>
        void *conn_loop(void);<br>
<br>
Now to use this would be really nice, eg:<br>
        #define BUFFER_SIZE 1024<br>
<br>
        struct buf {<br>
                char bytes[BUFFER_SIZE];<br>
                size_t used;<br>
        };<br>
<br>
        static bool echo_write(struct conn *conn, struct buf *buf)<br>
        {<br>
                if (!conn_write(conn, buf->bytes, buf->used)) {<br>
                        free(buf);<br>
                        return false;<br>
                }<br>
                return conn_next(conn, echo_read, buf);<br>
        }<br>
<br>
        static bool echo_read(struct conn *conn, struct buf *buf)<br>
        {<br>
                buf->used = BUFFER_SIZE;<br>
                if (!conn_read_partial(conn, buf->bytes, &buf->used)) {<br>
                        free(buf);<br>
                        return false;<br>
                }<br>
                return conn_next(conn, echo_write, buf);<br>
        }<br>
<br>
        static bool echo_start(struct conn *conn, void *unused)<br>
        {<br>
                struct buf *buf = malloc(sizeof(buf));<br>
                if (!buf)<br>
                        return false;<br>
<br>
                return conn_next(conn, buf, echo_read, buf);<br>
        }<br>
<br>
        int main(int argc, char *argv[])<br>
        {<br>
                if (!new_listener(argv[1], echo_start, NULL))<br>
                        err(1, "Creating listener");<br>
<br>
                conn_loop();<br>
        }<br>
<br></blockquote><div>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. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

The implementation can be done completely without threads, yet be fully<br>
async.  Or another variant could use a thread per connection, so the<br>
only user-visible synchronization would be for anything shared between<br>
threads.<br></blockquote><div>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:</div>
<div><br></div><div>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())</div><div><br></div>
<div>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.</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
The best thing is that you could force the implementation into a<br>
debugging sychronous mode, where conn_read_* and conn_write_* worked<br>
synchonously, and conn_next immediately called the next function.  This<br>
gives you a nice call-chain to see exactly what occurred.<br>
<br></blockquote><div>Ah!  This is what I was thinking about just few days ago but I was too lazy to implement it, thanks for reminding me! </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Of course, the names might need work, and the callbacks should be made<br>
typesafe using ccan/typesafe_cb, but I'd love to use such a module!<br>
<br>
Cheers,<br>
Rusty.<br>
</blockquote></div><div><br></div>I'll do my best do improve it in the near future.<br><br clear="all"><div>Thanks,</div><div>Allan</div>
</div>