From ce694e7051dca90cdb5700e3865315d16931c3c1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 13 Sep 2004 14:17:41 +0000 Subject: r2328: add the start of a new system and protocol independent socket library. this is not used, but compiled currently there're maybe some api changes later... metze (This used to be commit de4447d7a57c614b80d0ac00dca900ea7e1c21ea) --- source4/lib/socket/config.m4 | 4 + source4/lib/socket/config.mk | 16 +++ source4/lib/socket/socket.c | 215 ++++++++++++++++++++++++++++ source4/lib/socket/socket.h | 93 +++++++++++++ source4/lib/socket/socket_ipv4.c | 293 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 621 insertions(+) create mode 100644 source4/lib/socket/config.m4 create mode 100644 source4/lib/socket/config.mk create mode 100644 source4/lib/socket/socket.c create mode 100644 source4/lib/socket/socket.h create mode 100644 source4/lib/socket/socket_ipv4.c (limited to 'source4/lib') diff --git a/source4/lib/socket/config.m4 b/source4/lib/socket/config.m4 new file mode 100644 index 0000000000..a5d3d0916e --- /dev/null +++ b/source4/lib/socket/config.m4 @@ -0,0 +1,4 @@ + +SMB_MODULE_MK(socket_ipv4,SOCKET,STATIC,lib/socket/config.mk) + +SMB_SUBSYSTEM_MK(SOCKET,lib/socket/config.mk) diff --git a/source4/lib/socket/config.mk b/source4/lib/socket/config.mk new file mode 100644 index 0000000000..854702a6f8 --- /dev/null +++ b/source4/lib/socket/config.mk @@ -0,0 +1,16 @@ + +################################################ +# Start MODULE socket_ipv4 +[MODULE::socket_ipv4] +INIT_OBJ_FILES = \ + lib/socket/socket_ipv4.o +# End MODULE socket_ipv4 +################################################ + +################################################ +# Start SUBSYSTEM SOCKET +[SUBSYSTEM::SOCKET] +INIT_OBJ_FILES = \ + lib/socket/socket.o +# End SUBSYSTEM SOCKET +################################################ diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c new file mode 100644 index 0000000000..fefd7a14b2 --- /dev/null +++ b/source4/lib/socket/socket.c @@ -0,0 +1,215 @@ +/* + Unix SMB/CIFS implementation. + Socket functions + Copyright (C) Stefan Metzmacher 2004 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +NTSTATUS socket_create(const char *name, enum socket_type type, struct socket_context **new_sock, uint32_t flags) +{ + NTSTATUS status; + + (*new_sock) = talloc_p(NULL, struct socket_context); + if (!(*new_sock)) { + return NT_STATUS_NO_MEMORY; + } + + (*new_sock)->type = type; + (*new_sock)->state = SOCKET_STATE_UNDEFINED; + (*new_sock)->flags = flags; + + (*new_sock)->fd = -1; + + (*new_sock)->private_data = NULL; + (*new_sock)->ops = socket_getops_byname(name, type); + if (!(*new_sock)->ops) { + talloc_free((*new_sock)); + return status; + } + + status = (*new_sock)->ops->init((*new_sock)); + if (!NT_STATUS_IS_OK(status)) { + talloc_free((*new_sock)); + return status; + } + + return NT_STATUS_OK; +} + +void socket_destroy(struct socket_context *sock) +{ + if (sock->ops->close) { + sock->ops->close(sock); + } + talloc_free(sock); +} + +NTSTATUS socket_connect(struct socket_context *sock, + const char *my_address, int my_port, + const char *server_address, int server_port, + uint32_t flags) +{ + if (sock->type != SOCKET_TYPE_STREAM) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (sock->state != SOCKET_STATE_UNDEFINED) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!sock->ops->connect) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return sock->ops->connect(sock, my_address, my_port, server_address, server_port, flags); +} + +NTSTATUS socket_listen(struct socket_context *sock, const char *my_address, int port, int queue_size, uint32_t flags) +{ + if (sock->type != SOCKET_TYPE_STREAM) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (sock->state != SOCKET_STATE_UNDEFINED) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!sock->ops->listen) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return sock->ops->listen(sock, my_address, port, queue_size, flags); +} + +NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock, uint32_t flags) +{ + if (sock->type != SOCKET_TYPE_STREAM) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (sock->state != SOCKET_STATE_SERVER_LISTEN) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!sock->ops->accept) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return sock->ops->accept(sock, new_sock, flags); +} + +NTSTATUS socket_recv(struct socket_context *sock, TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, size_t wantlen, uint32_t flags) +{ + if (sock->type != SOCKET_TYPE_STREAM) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (sock->state != SOCKET_STATE_CLIENT_CONNECTED || + sock->state != SOCKET_STATE_SERVER_CONNECTED) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!sock->ops->recv) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return sock->ops->recv(sock, mem_ctx, blob, wantlen, flags); +} + +NTSTATUS socket_send(struct socket_context *sock, TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, size_t *sendlen, uint32_t flags) +{ + if (sock->type != SOCKET_TYPE_STREAM) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (sock->state != SOCKET_STATE_CLIENT_CONNECTED || + sock->state != SOCKET_STATE_SERVER_CONNECTED) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!sock->ops->send) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return sock->ops->send(sock, mem_ctx, blob, sendlen, flags); +} + +NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val) +{ + if (!sock->ops->set_option) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + return sock->ops->set_option(sock, option, val); +} + +const char *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + if (!sock->ops->get_peer_addr) { + return NULL; + } + + return sock->ops->get_peer_addr(sock, mem_ctx); +} + +int socket_get_peer_port(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + if (!sock->ops->get_peer_port) { + return -1; + } + + return sock->ops->get_peer_port(sock, mem_ctx); +} + +const char *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + if (!sock->ops->get_my_addr) { + return NULL; + } + + return sock->ops->get_my_addr(sock, mem_ctx); +} + +int socket_get_my_port(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + if (!sock->ops->get_my_port) { + return -1; + } + + return sock->ops->get_my_port(sock, mem_ctx); +} + +int socket_get_fd(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + if (!sock->ops->get_fd) { + return -1; + } + + return sock->ops->get_fd(sock, mem_ctx); +} + +const struct socket_ops *socket_getops_byname(const char *name, enum socket_type type) +{ + if (strequal("ip", name) || strequal("ipv4", name)) { + return socket_ipv4_ops(); + } + + return NULL; +} diff --git a/source4/lib/socket/socket.h b/source4/lib/socket/socket.h new file mode 100644 index 0000000000..dfc964b741 --- /dev/null +++ b/source4/lib/socket/socket.h @@ -0,0 +1,93 @@ +/* + Unix SMB/CIFS implementation. + Socket functions + Copyright (C) Stefan Metzmacher 2004 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _SAMBA_SOCKET_H +#define _SAMBA_SOCKET_H + +struct socket_context; + +enum socket_type { + SOCKET_TYPE_STREAM +}; + +struct socket_ops { + const char *name; + enum socket_type type; + + NTSTATUS (*init)(struct socket_context *sock); + + /* client ops */ + NTSTATUS (*connect)(struct socket_context *sock, + const char *my_address, int my_port, + const char *server_address, int server_port, + uint32_t flags); + + /* server ops */ + NTSTATUS (*listen)(struct socket_context *sock, + const char *my_address, int port, int queue_size, uint32_t flags); + NTSTATUS (*accept)(struct socket_context *sock, + struct socket_context **new_sock, uint32_t flags); + + /* general ops */ + NTSTATUS (*recv)(struct socket_context *sock, TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, size_t wantlen, uint32_t flags); + NTSTATUS (*send)(struct socket_context *sock, TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, size_t *sendlen, uint32_t flags); + + void (*close)(struct socket_context *sock); + + NTSTATUS (*set_option)(struct socket_context *sock, const char *option, const char *val); + + const char *(*get_peer_addr)(struct socket_context *sock, TALLOC_CTX *mem_ctx); + int (*get_peer_port)(struct socket_context *sock, TALLOC_CTX *mem_ctx); + const char *(*get_my_addr)(struct socket_context *sock, TALLOC_CTX *mem_ctx); + int (*get_my_port)(struct socket_context *sock, TALLOC_CTX *mem_ctx); + + int (*get_fd)(struct socket_context *sock, TALLOC_CTX *mem_ctx); +}; + +enum socket_state { + SOCKET_STATE_UNDEFINED, + + SOCKET_STATE_CLIENT_START, + SOCKET_STATE_CLIENT_CONNECTED, + SOCKET_STATE_CLIENT_STARTTLS, + SOCKET_STATE_CLIENT_ERROR, + + SOCKET_STATE_SERVER_LISTEN, + SOCKET_STATE_SERVER_CONNECTED, + SOCKET_STATE_SERVER_STARTTLS, + SOCKET_STATE_SERVER_ERROR +}; + +#define SOCKET_OPTION_BLOCK 0x00000001 + +struct socket_context { + enum socket_type type; + enum socket_state state; + uint32_t flags; + + int fd; + + void *private_data; + const struct socket_ops *ops; +}; + +#endif /* _SAMBA_SOCKET_H */ diff --git a/source4/lib/socket/socket_ipv4.c b/source4/lib/socket/socket_ipv4.c new file mode 100644 index 0000000000..90f289a1e0 --- /dev/null +++ b/source4/lib/socket/socket_ipv4.c @@ -0,0 +1,293 @@ +/* + Unix SMB/CIFS implementation. + Socket IPv4 functions + Copyright (C) Stefan Metzmacher 2004 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +static NTSTATUS ipv4_tcp_init(struct socket_context *sock) +{ + sock->fd = socket(PF_INET, SOCK_STREAM, 0); + if (sock->fd == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + return NT_STATUS_OK; +} + +static void ipv4_tcp_close(struct socket_context *sock) +{ + close(sock->fd); +} + +static NTSTATUS ipv4_tcp_connect(struct socket_context *sock, + const char *my_address, int my_port, + const char *srv_address, int srv_port, + uint32_t flags) +{ + struct sockaddr_in my_addr; + struct sockaddr_in srv_addr; + struct in_addr my_ip; + struct in_addr srv_ip; + int ret; + + ret = inet_aton(my_address, &my_ip); + if (ret == 0) { + /* not a valid ipv4 address */ + return NT_STATUS_FOOBAR; + } + + ZERO_STRUCT(my_addr); +#ifdef HAVE_SOCK_SIN_LEN + my_addr.sin_len = sizeof(my_addr); +#endif + my_addr.sin_addr = my_ip; + my_addr.sin_port = htons(my_port); + my_addr.sin_family = PF_INET; + + ret = inet_aton(srv_address, &srv_ip); + if (ret == 0) { + /* not a valid ipv4 address */ + return NT_STATUS_FOOBAR; + } + + ret = bind(sock->fd, &my_addr, sizeof(my_addr)); + if (ret == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + ZERO_STRUCT(srv_addr); +#ifdef HAVE_SOCK_SIN_LEN + srv_addr.sin_len = sizeof(srv_addr); +#endif + srv_addr.sin_addr = srv_ip; + srv_addr.sin_port = htons(srv_port); + srv_addr.sin_family = PF_INET; + + if (!(flags & SOCKET_OPTION_BLOCK)) { + ret = set_blocking(sock->fd, False); + if (ret == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + } + + + ret = connect(sock->fd, &srv_addr, sizeof(srv_addr)); + if (ret == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + sock->state = SOCKET_STATE_CLIENT_CONNECTED; + + return NT_STATUS_OK; +} + +static NTSTATUS ipv4_tcp_listen(struct socket_context *sock, + const char *my_address, int port, + int queue_size, uint32_t flags) +{ + struct sockaddr_in my_addr; + struct in_addr ip_addr; + int ret; + + ZERO_STRUCT(my_addr); + + ret = inet_aton(my_address, &ip_addr); + if (ret == 0) { + /* not a valid ipv4 address */ + return NT_STATUS_FOOBAR; + } + +#ifdef HAVE_SOCK_SIN_LEN + my_addr.sin_len = sizeof(my_addr); +#endif + my_addr.sin_addr = ip_addr; + my_addr.sin_port = htons(port); + my_addr.sin_family = PF_INET; + + ret = bind(sock->fd, &my_addr, sizeof(my_addr)); + if (ret == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + ret = listen(sock->fd, queue_size); + if (ret == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS ipv4_tcp_accept(struct socket_context *sock, struct socket_context **new_sock, uint32_t flags) +{ + struct sockaddr_in cli_addr; + socklen_t cli_addr_len = 0; + int new_fd; + int ret; + + new_fd = accept(sock->fd, &cli_addr, &cli_addr_len); + if (new_fd == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + if (!(flags & SOCKET_OPTION_BLOCK)) { + ret = set_blocking(sock->fd, False); + if (ret == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + } + + /* TODO: we could add a 'accept_check' hook here + * which get the black/white lists via socket_set_accept_filter() + * or something like that + * --metze + */ + + (*new_sock) = talloc_p(NULL, struct socket_context); + if (!(*new_sock)) { + return NT_STATUS_NO_MEMORY; + } + + /* copy the socket_context */ + (*new_sock)->type = sock->type; + (*new_sock)->state = SOCKET_STATE_SERVER_CONNECTED; + (*new_sock)->flags = flags; + + (*new_sock)->fd = new_fd; + + (*new_sock)->private_data = NULL; + (*new_sock)->ops = sock->ops; + + return NT_STATUS_NOT_IMPLEMENTED; +} + +static NTSTATUS ipv4_tcp_recv(struct socket_context *sock, TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, size_t wantlen, uint32_t flags) +{ + ssize_t gotlen; + void *buf; + int flgs = 0; + + buf = talloc(mem_ctx, wantlen); + if (!buf) { + return NT_STATUS_NO_MEMORY; + } + + /* TODO: we need to map the flags here */ + + gotlen = recv(sock->fd, buf, wantlen, flgs); + if (gotlen == -1) { + talloc_free(buf); + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + blob->length = gotlen; + blob->data = buf; + + return NT_STATUS_OK; +} + +static NTSTATUS ipv4_tcp_send(struct socket_context *sock, TALLOC_CTX *mem_ctx, + const DATA_BLOB *blob, size_t *sendlen, uint32_t flags) +{ + ssize_t len; + int flgs = 0; + + /* TODO: we need to map the flags here */ + + len = send(sock->fd, blob->data, blob->length, flgs); + if (len == -1) { + /* TODO: we need to map from errno to NTSTATUS here! */ + return NT_STATUS_FOOBAR; + } + + *sendlen = len; + + return NT_STATUS_OK; +} + +static NTSTATUS ipv4_tcp_set_option(struct socket_context *sock, const char *option, const char *val) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +static const char *ipv4_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + return NULL; +} + +static int ipv4_tcp_get_peer_port(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + return -1; +} + +static const char *ipv4_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + return NULL; +} + +static int ipv4_tcp_get_my_port(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + return -1; +} + +static int ipv4_tcp_get_fd(struct socket_context *sock, TALLOC_CTX *mem_ctx) +{ + return sock->fd; +} + +static const struct socket_ops ipv4_tcp_ops = { + .name = "ipv4", + .type = SOCKET_TYPE_STREAM, + + .init = ipv4_tcp_init, + .connect = ipv4_tcp_connect, + .listen = ipv4_tcp_listen, + .accept = ipv4_tcp_accept, + .recv = ipv4_tcp_recv, + .send = ipv4_tcp_send, + .close = ipv4_tcp_close, + + .set_option = ipv4_tcp_set_option, + + .get_peer_addr = ipv4_tcp_get_peer_addr, + .get_peer_port = ipv4_tcp_get_peer_port, + .get_my_addr = ipv4_tcp_get_my_addr, + .get_my_port = ipv4_tcp_get_my_port, + + .get_fd = ipv4_tcp_get_fd +}; + +const struct socket_ops *socket_ipv4_ops(void) +{ + return &ipv4_tcp_ops; +} + +NTSTATUS socket_ipv4_init(void) +{ + return NT_STATUS_OK; +} -- cgit