add psmb_destroy()
[psmb.git] / src / psmb_socket.c
index a7c42efa9a6177443264731eff064ad6fe9bfcc4..28344a7a65c04138712f1dc5922a37e167a3b2e7 100644 (file)
@@ -8,6 +8,8 @@
 #include <psmb.h>
 #include "psmb_priv.h"
 
+static void dummy_log(void *log_priv, int priority, const char *format, ...) {}
+
 psmb_ctx_t *psmb_new(void)
 {
        return psmb_new_mm(malloc, free, realloc);
@@ -18,21 +20,43 @@ psmb_ctx_t *psmb_new_mm(void *(*malloc)(size_t size),
                        void *(*realloc)(void *ptr, size_t size))
 {
        psmb_ctx_t *ctx = (*malloc)(sizeof(psmb_ctx_t));
-       if (!ctx)
+       if (!ctx) {
+               int sverr = errno;
+               LOG(ctx, LOG_ERR, "failed to allocate psmb_ctx: %m");
+               errno = sverr;
                return NULL;
+       }
        *ctx = (psmb_ctx_t){
                .fd = -1,
                .malloc = malloc, .free = free, .realloc = realloc,
-               .pmtu = PSMB_DEFAULT_PMTU, .port = PSMB_DEFAULT_PORT};
+               .logf = dummy_log,
+               .pmtu = PSMB_DEFAULT_PMTU,
+               .port = PSMB_DEFAULT_PORT};
        return ctx;
 }
 
+psmb_result_t psmb_set_logf(psmb_ctx_t *ctx,
+       void (*logf)(void *log_priv, int priority, const char *format, ...),
+       void *log_priv)
+{
+       if (ctx->fd == -1) {
+               ctx->logf = logf;
+               ctx->log_priv = log_priv;
+               return (psmb_result_t){PSMB_OK};
+       } else {
+               LOG(ctx, LOG_ERR, "psmb_set_...() used after psmb_open()");
+               errno = EBUSY;
+               return (psmb_result_t){PSMB_ERROR};
+       }
+}
+
 psmb_result_t psmb_set_pmtu(psmb_ctx_t *ctx, unsigned int pmtu)
 {
        if (ctx->fd == -1) {
                ctx->pmtu = pmtu;
                return (psmb_result_t){PSMB_OK};
        } else {
+               LOG(ctx, LOG_ERR, "psmb_set_...() used after psmb_open()");
                errno = EBUSY;
                return (psmb_result_t){PSMB_ERROR};
        }
@@ -44,6 +68,21 @@ psmb_result_t psmb_set_port(psmb_ctx_t *ctx, unsigned short port)
                ctx->port = port;
                return (psmb_result_t){PSMB_OK};
        } else {
+               LOG(ctx, LOG_ERR, "psmb_set_...() used after psmb_open()");
+               errno = EBUSY;
+               return (psmb_result_t){PSMB_ERROR};
+       }
+}
+
+psmb_result_t psmb_set_mgrp(psmb_ctx_t *ctx, struct in6_addr prefix,
+       unsigned char prefixlen)
+{
+       if (ctx->fd == -1) {
+               ctx->prefix = prefix;
+               ctx->prefixlen = prefixlen;
+               return (psmb_result_t){PSMB_OK};
+       } else {
+               LOG(ctx, LOG_ERR, "psmb_set_...() used after psmb_open()");
                errno = EBUSY;
                return (psmb_result_t){PSMB_ERROR};
        }
@@ -59,30 +98,55 @@ psmb_result_t psmb_open(psmb_ctx_t *ctx)
        };
 
        if (ctx->fd != -1) {
+               LOG(ctx, LOG_ERR, "redundant call to psmb_open()");
                errno = EBUSY;
                return (psmb_result_t){PSMB_ERROR};
        }
        ctx->fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
        if (ctx->fd == -1) {
+               int sverr = errno;
+               LOG(ctx, LOG_ERR, "socket: %m");
+               errno = sverr;
                return (psmb_result_t){PSMB_ERROR};
        }
        if (setsockopt(ctx->fd, SOL_SOCKET, SO_REUSEADDR,
                        &on, sizeof(on)) < 0) {
+               int sverr = errno;
+               LOG(ctx, LOG_ERR, "setsockopt(..., SO_REUSEADDR, ...): %m");
                close(ctx->fd);
                ctx->fd = -1;
+               errno = sverr;
                return (psmb_result_t){PSMB_ERROR};
        }
        if (setsockopt(ctx->fd, IPPROTO_IPV6, IPV6_PKTINFO,
                        &on, sizeof(on)) < 0) {
+               int sverr = errno;
+               LOG(ctx, LOG_ERR, "setsockopt(..., IPV6_PKTINFO, ...): %m");
                close(ctx->fd);
                ctx->fd = -1;
+               errno = sverr;
                return (psmb_result_t){PSMB_ERROR};
        }
        if (bind(ctx->fd, (struct sockaddr *)&addr,
                        sizeof(struct sockaddr)) == -1) {
+               int sverr = errno;
+               LOG(ctx, LOG_ERR, "bind(): %m");
                close(ctx->fd);
                ctx->fd = -1;
+               errno = sverr;
                return (psmb_result_t){PSMB_ERROR};
        }
        return (psmb_result_t){PSMB_OK};
 }
+
+void psmb_destroy(psmb_ctx_t *ctx)
+{
+       if (ctx->fd == -1) {
+               LOG(ctx, LOG_ERR, "psmb_ctx is not open");
+       } else {
+               if (close(ctx->fd) == -1)
+                       LOG(ctx, LOG_ERR, "close(): %m");
+       }
+       /* clean up the rest */
+       (*ctx->free)(ctx);
+}