]> git.ipfire.org Git - thirdparty/lldpd.git/blobdiff - src/lib/connection.c
lib: stricly-prevent use of a connection used to watch events
[thirdparty/lldpd.git] / src / lib / connection.c
index 729ee092b339fa6dcf48728b1fa05b17369e6422..191d7c6a02f04aaf6c5c5d681e638ee68cf99aa0 100644 (file)
 #include <sys/un.h>
 
 #include "lldpctl.h"
-#include "private.h"
+#include "atom.h"
 #include "../compat/compat.h"
 #include "../ctl.h"
 #include "../log.h"
-#include "../lldpd-structs.h"
 
 const char*
 lldpctl_get_default_transport(void)
@@ -36,9 +35,9 @@ lldpctl_get_default_transport(void)
 
 /* Connect to the remote end */
 static int
-sync_connect()
+sync_connect(lldpctl_conn_t *lldpctl)
 {
-       return ctl_connect(LLDPD_CTL_SOCKET);
+       return ctl_connect(lldpctl->ctlname);
 }
 
 /* Synchronously send data to remote end. */
@@ -47,10 +46,10 @@ sync_send(lldpctl_conn_t *lldpctl,
     const uint8_t *data, size_t length, void *user_data)
 {
        struct lldpctl_conn_sync_t *conn = user_data;
-       size_t nb;
+       ssize_t nb;
 
        if (conn->fd == -1 &&
-           ((conn->fd = sync_connect()) == -1)) {
+           ((conn->fd = sync_connect(lldpctl)) == -1)) {
                return LLDPCTL_ERR_CANNOT_CONNECT;
        }
 
@@ -61,31 +60,42 @@ sync_send(lldpctl_conn_t *lldpctl,
        return nb;
 }
 
-/* Statiscally receive data from remote end. */
+/* Statically receive data from remote end. */
 static ssize_t
 sync_recv(lldpctl_conn_t *lldpctl,
     const uint8_t *data, size_t length, void *user_data)
 {
        struct lldpctl_conn_sync_t *conn = user_data;
-       size_t nb;
+       ssize_t nb;
+       size_t remain, offset = 0;
 
        if (conn->fd == -1 &&
-           ((conn->fd = sync_connect()) == -1)) {
+           ((conn->fd = sync_connect(lldpctl)) == -1)) {
                lldpctl->error = LLDPCTL_ERR_CANNOT_CONNECT;
                return LLDPCTL_ERR_CANNOT_CONNECT;
        }
 
-       while ((nb = read(conn->fd, (void*)data, length)) == -1) {
-               if (errno == EAGAIN || errno == EINTR) continue;
-               return LLDPCTL_ERR_CALLBACK_FAILURE;
-       }
-       return nb;
+       remain = length;
+       do {
+               if ((nb = read(conn->fd, (unsigned char*)data + offset, remain)) == -1) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+                       return LLDPCTL_ERR_CALLBACK_FAILURE;
+               }
+               remain -= nb;
+               offset += nb;
+       } while (remain > 0 && nb != 0);
+       return offset;
 }
 
-
-
 lldpctl_conn_t*
 lldpctl_new(lldpctl_send_callback send, lldpctl_recv_callback recv, void *user_data)
+{
+       return lldpctl_new_name(lldpctl_get_default_transport(), send, recv, user_data);
+}
+
+lldpctl_conn_t*
+lldpctl_new_name(const char *ctlname, lldpctl_send_callback send, lldpctl_recv_callback recv, void *user_data)
 {
        lldpctl_conn_t *conn = NULL;
        struct lldpctl_conn_sync_t *data = NULL;
@@ -97,8 +107,14 @@ lldpctl_new(lldpctl_send_callback send, lldpctl_recv_callback recv, void *user_d
        if ((conn = calloc(1, sizeof(lldpctl_conn_t))) == NULL)
                return NULL;
 
+       conn->ctlname = strdup(ctlname);
+       if (conn->ctlname == NULL) {
+               free(conn);
+               return NULL;
+       }
        if (!send && !recv) {
                if ((data = malloc(sizeof(struct lldpctl_conn_sync_t))) == NULL) {
+                       free(conn->ctlname);
                        free(conn);
                        return NULL;
                }
@@ -119,6 +135,7 @@ int
 lldpctl_release(lldpctl_conn_t *conn)
 {
        if (conn == NULL) return 0;
+       free(conn->ctlname);
        if (conn->send == sync_send) {
                struct lldpctl_conn_sync_t *data = conn->user_data;
                if (data->fd != -1) close(data->fd);
@@ -142,7 +159,6 @@ _lldpctl_needs(lldpctl_conn_t *conn, size_t length)
 {
        uint8_t *buffer = NULL;
        ssize_t  rc;
-       if (conn->input_buffer_len >= length) return 0;
 
        if ((buffer = malloc(length)) == NULL)
                return SET_ERROR(conn, LLDPCTL_ERR_NOMEM);
@@ -163,7 +179,7 @@ _lldpctl_needs(lldpctl_conn_t *conn, size_t length)
        return rc;
 }
 
-static void
+static int
 check_for_notification(lldpctl_conn_t *conn)
 {
        struct lldpd_neighbor_change *change;
@@ -176,7 +192,7 @@ check_for_notification(lldpctl_conn_t *conn)
            NOTIFICATION,
            &p,
            &MARSHAL_INFO(lldpd_neighbor_change));
-       if (rc != 0) return;
+       if (rc != 0) return rc;
        change = p;
 
        /* We have a notification, call the callback */
@@ -193,7 +209,7 @@ check_for_notification(lldpctl_conn_t *conn)
                interface = _lldpctl_new_atom(conn, atom_interface,
                    change->ifname);
                if (interface == NULL) goto end;
-               neighbor = _lldpctl_new_atom(conn, atom_port,
+               neighbor = _lldpctl_new_atom(conn, atom_port, 0,
                    NULL, change->neighbor, NULL);
                if (neighbor == NULL) goto end;
                conn->watch_cb(conn, type, interface, neighbor, conn->watch_data);
@@ -211,6 +227,9 @@ end:
        }
        free(change->ifname);
        free(change);
+
+       /* Indicate if more data remains in the buffer for processing */
+       return (rc);
 }
 
 ssize_t
@@ -235,14 +254,26 @@ lldpctl_recv(lldpctl_conn_t *conn, const uint8_t *data, size_t length)
        memcpy(conn->input_buffer + conn->input_buffer_len, data, length);
        conn->input_buffer_len += length;
 
-       /* Is it a notification? */
-       check_for_notification(conn);
+       /* Read all notifications */
+       while(!check_for_notification(conn));
 
        RESET_ERROR(conn);
 
        return conn->input_buffer_len;
 }
 
+int
+lldpctl_process_conn_buffer(lldpctl_conn_t *conn)
+{
+       int rc;
+
+       rc = check_for_notification(conn);
+
+       RESET_ERROR(conn);
+
+       return rc;
+}
+
 ssize_t
 lldpctl_send(lldpctl_conn_t *conn)
 {