Example Server Program

Here is a simple synchronous server for the protocol defined in The example.mx File. Note that this server does not use advanced features such as asynchronous operation.

/* Example miniRPC server program */

#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <minirpc/minirpc.h>
#include "example_server.h"

#define die(s, args...) do {fprintf(stderr, s"\n", ##args); abort();} while (0)

struct conn_data {
        struct mrpc_connection *conn;
        char *remote;
        unsigned chosen;
        int count;
};

mrpc_status_t do_choose(void *conn_data, struct mrpc_message *msg,
                        example_color_choice *in)
{
        struct conn_data *data=conn_data;
        unsigned i;
        unsigned new=0;

        /* Save a bitmap of the colors chosen by the client.  For this
           example, we don't actually do anything with the bitmap. */
        for (i=0; i<in->acceptable.acceptable_len; i++)
                new |= 1 << in->acceptable.acceptable_val[i];
        data->chosen=new;
        data->count=i;
        return MINIRPC_OK;
}

mrpc_status_t do_get(void *conn_data, struct mrpc_message *msg,
                        example_count *out)
{
        struct conn_data *data=conn_data;

        *out=data->count;
        return MINIRPC_OK;
}

static const struct example_server_operations ops = {
        .choose_color = do_choose,
        .get_num_colors = do_get,
        .crayon_selected = NULL,  /* not supported */
};

void *do_accept(void *set_data, struct mrpc_connection *conn,
                        struct sockaddr *from, socklen_t from_len)
{
        struct conn_data *data;
        char buf[256];

        if (getnameinfo(from, from_len, buf, sizeof(buf), NULL, 0, 0)) {
                mrpc_conn_close(conn);
                return NULL;
        }
        example_server_set_operations(conn, &ops);
        data=malloc(sizeof(*data));
        memset(data, 0, sizeof(*data));
        data->conn=conn;
        data->remote=strndup(buf, sizeof(buf));
        fprintf(stderr, "New connection from %s\n", data->remote);
        return data;
}

void do_disconnect(void *conn_data, enum mrpc_disc_reason reason)
{
        struct conn_data *data=conn_data;
        const char *reason_str;

        /* If do_accept() rejected the connection and returned NULL, we have
           nothing to free. */
        if (conn_data == NULL)
                return;

        switch (reason) {
        case MRPC_DISC_USER:
                reason_str="by application";
                break;
        case MRPC_DISC_CLOSED:
                reason_str="by remote end";
                break;
        case MRPC_DISC_IOERR:
                reason_str="due to I/O error";
                break;
        default:
                reason_str="for unknown reason";
        }

        fprintf(stderr, "Connection to %s closed %s\n", data->remote,
                                reason_str);
        free(data->remote);
        free(data);
}

int main(int argc, char **argv)
{
        struct mrpc_conn_set *set;
        char *port;
        int ret;

        if (argc != 2) {
                fprintf(stderr, "Usage: %s port\n", argv[0]);
                exit(1);
        }
        port=argv[1];

        if (mrpc_conn_set_create(&set, example_server, NULL))
                die("Couldn't create connection set");
        if (mrpc_set_accept_func(set, do_accept))
                die("Couldn't set accept function");
        if (mrpc_set_disconnect_func(set, do_disconnect))
                die("Couldn't set disconnect function");
        ret=mrpc_listen(set, AF_UNSPEC, NULL, &port);
        if (ret)
                die("Couldn't create listening socket: %s", strerror(ret));

        mrpc_dispatcher_add(set);
        mrpc_dispatch_loop(set);
        /* For this simple example, we don't ever destroy the connection set,
           so mrpc_dispatch_loop() will never return. */
        return 0;
}

miniRPC 0.3.3
Documentation generated by Doxygen 1.5.6