libcli/smb: smb-dd client API
authorRalph Boehme <slow@samba.org>
Tue, 27 Sep 2016 17:54:46 +0000 (10:54 -0700)
committerStefan Metzmacher <metze@samba.org>
Fri, 1 Jun 2018 12:35:04 +0000 (14:35 +0200)
libcli/smb/smb_direct_client.c [new file with mode: 0644]
libcli/smb/smb_direct_client.h [new file with mode: 0644]
libcli/smb/wscript

diff --git a/libcli/smb/smb_direct_client.c b/libcli/smb/smb_direct_client.c
new file mode 100644 (file)
index 0000000..ecfcdf8
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Ralph Boehme 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/blocking.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/debug.h"
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/smb_direct_daemon.h"
+#include "librpc/gen_ndr/ndr_smb_direct_daemon.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/util/tstream.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/msghdr.h"
+#include "lib/util/sys_rw_data.h"
+#include "smb_direct.h"
+#include "smb_direct_client.h"
+#include "smb_direct_util.h"
+
+struct smb_direct_socket {
+       int fd;
+       bool listening;
+};
+
+struct smb_direct_interface *smb_direct_get_interfaces(
+       struct smb_direct_socket *socket)
+{
+       return NULL;
+}
+
+static int smb_direct_socket_destructor(struct smb_direct_socket *s)
+{
+       if (s->fd != -1) {
+               close(s->fd);
+               s->fd = -1;
+       }
+       return 0;
+}
+
+struct smb_direct_socket *smb_direct_socket(TALLOC_CTX *mem_ctx)
+{
+       struct smb_direct_socket *s = NULL;
+       char *socket_path = NULL;
+       union {
+               struct sockaddr_un su;
+               struct sockaddr sa;
+       } addr;
+       int result;
+
+       s = talloc_zero(mem_ctx, struct smb_direct_socket);
+       if (s == NULL) {
+               return NULL;
+       }
+
+       *s = (struct smb_direct_socket) {
+               .fd = -1,
+       };
+
+       socket_path = smb_direct_socket_path(s);
+       if (socket_path == NULL) {
+               TALLOC_FREE(s);
+               return NULL;
+       }
+
+       ZERO_STRUCT(addr);
+       addr.su.sun_family = AF_UNIX;
+       strncpy(addr.su.sun_path, socket_path, sizeof(addr.su.sun_path) - 1);
+       TALLOC_FREE(socket_path);
+
+       s->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s->fd == -1) {
+               TALLOC_FREE(s);
+               return NULL;
+       }
+
+       result = connect(s->fd, &addr.sa, sizeof(addr.su));
+       if (result != 0) {
+               TALLOC_FREE(s);
+               return NULL;
+       }
+
+       talloc_set_destructor(s, smb_direct_socket_destructor);
+
+       return s;
+}
+
+int smb_direct_socket_get_fd(struct smb_direct_socket *socket)
+{
+       return socket->fd;
+}
+
+static bool smb_direct_msg_send(struct smb_direct_socket *s,
+                               struct sdd_packetB *packet)
+{
+       DATA_BLOB out_data = data_blob_null;
+       enum ndr_err_code ndr_err;
+       ssize_t nwritten;
+
+       ndr_err = ndr_push_struct_blob(
+               &out_data, s, packet,
+               (ndr_push_flags_fn_t)ndr_push_sdd_packetB);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DBG_ERR("ndr_push_struct_blob failed\n");
+               return false;
+       }
+
+       SIVAL(&out_data.data[0], 0, out_data.length);
+
+       nwritten = write_data(s->fd, out_data.data, out_data.length);
+       if (nwritten != out_data.length) {
+               DBG_ERR("sendmsg failed nwritten [%zd] out_data.length [%zu] [%s]\n",
+                       nwritten, out_data.length, strerror(errno));
+               TALLOC_FREE(out_data.data);
+               return false;
+       }
+
+       TALLOC_FREE(out_data.data);
+       return true;
+}
+
+static bool smb_direct_msg_recv(TALLOC_CTX *mem_ctx,
+                               struct smb_direct_socket *s,
+                               struct sdd_packetB *packet)
+{
+       uint8_t packet_buf[4];
+       ssize_t nread;
+       size_t packet_len;
+       DATA_BLOB response_data;
+       enum ndr_err_code ndr_err;
+
+       nread = read_data(s->fd, packet_buf, 4);
+       if (nread != 4) {
+               DBG_ERR("read failed nread [%zd] [%s] errno [%d]\n",
+                       nread, strerror(errno), errno);
+               return false;
+       }
+
+       packet_len = IVAL(packet_buf, 0);
+       if (packet_len < 5 || packet_len > 0x1000) {
+               DBG_ERR("invalid packet length [%zu]\n", packet_len);
+               return false;
+       }
+
+       response_data.length = packet_len;
+
+       response_data.data = talloc_array(mem_ctx, uint8_t, packet_len);
+       if (response_data.data == NULL) {
+               DBG_ERR("talloc_array failed\n");
+               return false;
+       }
+
+       memcpy(response_data.data, packet_buf, 4);
+
+       nread = read_data(s->fd, response_data.data + 4, packet_len - 4);
+       if (nread != packet_len - 4) {
+               DBG_ERR("read failed nread [%zd] [%s] errno [%d]\n",
+                       nread, strerror(errno), errno);
+               TALLOC_FREE(response_data.data);
+               return false;
+       }
+
+       ndr_err = ndr_pull_struct_blob_all(
+               &response_data,
+               mem_ctx,
+               packet,
+               (ndr_pull_flags_fn_t)ndr_pull_sdd_packetB);
+
+       TALLOC_FREE(response_data.data);
+
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DBG_ERR("ndr_pull_struct_blob_all failed\n");
+               return false;
+       }
+
+       return true;
+}
+
+int smb_direct_bind(struct smb_direct_socket *socket,
+                   struct smb_direct_interface *interfaces)
+{
+       return 0;
+}
+
+struct smb_direct_socket *smb_direct_listen(struct smb_direct_socket *socket,
+                                           struct sdd_listen_params *params)
+{
+       struct smb_direct_socket *listen_socket = NULL;
+       struct sdd_packetB request;
+       struct sdd_packetB *response = NULL;
+       struct sdd_packet_listen_request listen_request;
+       bool ok;
+
+       listen_socket = smb_direct_socket(socket);
+       if (listen_socket == NULL) {
+               return NULL;
+       }
+
+       listen_socket->listening = true;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(listen_request);
+
+       listen_request.params = *params;
+       request.command = SDD_LISTEN_REQUEST;
+       request.packet.listen_request = listen_request;
+
+       ok = smb_direct_msg_send(listen_socket, &request);
+       if (!ok) {
+               DBG_ERR("smb_direct_listen failed\n");
+               return false;
+       }
+
+       response = talloc_zero(listen_socket, struct sdd_packetB);
+       if (response == NULL) {
+               return false;
+       }
+
+       ok = smb_direct_msg_recv(response, listen_socket, response);
+       if (!ok) {
+               DBG_ERR("smb_direct_msg_recv failed\n");
+               TALLOC_FREE(response);
+               return false;
+       }
+
+       if (response->packet.listen_response.status != 0) {
+               DBG_ERR("smb_direct_listen returned status [%" PRIu32 "]\n",
+                       response->packet.listen_response.status);
+               return NULL;
+       }
+
+       return listen_socket;
+}
+
+int smb_direct_accept(struct smb_direct_socket *socket)
+{
+       struct msghdr msg = { 0 };
+       int fd;
+       size_t num_fds;
+       size_t fdlen;
+       int result;
+
+       if (!socket->listening) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       fdlen = msghdr_prep_recv_fds(&msg, NULL, 0, 1);
+
+       {
+               uint8_t buf[fdlen];
+
+               msghdr_prep_recv_fds(&msg, buf, fdlen, 1);
+
+               result = recvmsg(socket->fd, &msg, 0);
+               if (result == -1) {
+                       DBG_ERR("recvmsg failed [%s]\n", strerror(errno));
+                       return -1;
+               }
+       }
+
+       num_fds = msghdr_extract_fds(&msg, &fd, 1);
+       if (num_fds != 1) {
+               DBG_ERR("msghdr_extract_fds failed\n");
+               return -1;
+       }
+
+       return fd;
+}
+
+bool smb_direct_ping(struct smb_direct_socket *s,
+                    uint32_t in_data,
+                    uint32_t *out_data)
+{
+       struct sdd_packetB request;
+       struct sdd_packetB *response = NULL;
+       struct sdd_packet_ping_request ping_request;
+       bool ok;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(ping_request);
+
+       ping_request.data = in_data;
+       request.command = SDD_PING_REQUEST;
+       request.packet.ping_request = ping_request;
+
+       ok = smb_direct_msg_send(s, &request);
+       if (!ok) {
+               DBG_ERR("smb_direct_ping failed\n");
+               return false;
+       }
+
+       response = talloc_zero(s, struct sdd_packetB);
+       if (response == NULL) {
+               return false;
+       }
+
+       ok = smb_direct_msg_recv(response, s, response);
+       if (!ok) {
+               DBG_ERR("smb_direct_msg_recv failed\n");
+               TALLOC_FREE(response);
+               return false;
+       }
+
+       *out_data = response->packet.ping_response.data;
+       return true;
+}
diff --git a/libcli/smb/smb_direct_client.h b/libcli/smb/smb_direct_client.h
new file mode 100644 (file)
index 0000000..9331695
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Ralph Boehme 2016
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "librpc/gen_ndr/smb_direct_daemon.h"
+
+struct smb_direct_socket;
+struct smb_direct_interface;
+
+/**
+ * @brief Get a list of RDMA capabable network interfaces
+ **/
+struct smb_direct_interface *smb_direct_get_interfaces(struct smb_direct_socket *socket);
+
+/**
+ * @brief Create a smb_direct_socket
+ *
+ * This prepares an abstract socket type that can be used for
+ * accepting RDMA sessions via smb_direct_bind(), smb_direct_listen()
+ * and smb_direct_accept().
+ *
+ * Additionally it provides an IPC channel for a small set RPC-like
+ * functions like smb_direct_get_interfaces().
+ *
+ * @param[in] mem_ctx  The talloc memory context to use.
+ *
+ * @return             The smb_direct_socket.
+ **/
+struct smb_direct_socket *smb_direct_socket(TALLOC_CTX *mem_ctx);
+
+int smb_direct_socket_get_fd(struct smb_direct_socket *socket);
+int smb_direct_bind(struct smb_direct_socket *socket,
+                   struct smb_direct_interface *interfaces);
+struct smb_direct_socket *smb_direct_listen(struct smb_direct_socket *socket,
+                                           struct sdd_listen_params *params);
+int smb_direct_accept(struct smb_direct_socket *socket);
+
+bool smb_direct_ping(struct smb_direct_socket *s,
+                    uint32_t in_data,
+                    uint32_t *out_data);
index 339cbfb3370935b30f792d4830856a0753fb4a27..0d85a5f30984c4e280300c7741ca7d623465ee92 100644 (file)
@@ -32,6 +32,7 @@ def build(bld):
                        source='''
                             smb_direct_util.c
                             smb_direct_daemon.c
+                            smb_direct_client.c
                         ''',
                         deps='rdmacm ibverbs',
                         public_deps='''
@@ -42,6 +43,7 @@ def build(bld):
                             LIBTSOCKET
                             LIBSAMBA_TSOCKET
                             NDR_SMB_DIRECT_DAEMON
+                            msghdr
                         ''')
 
     bld.SAMBA_LIBRARY('smb_transport',