diff options
author | Stefan Metzmacher <metze@samba.org> | 2004-09-13 14:17:41 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:58:44 -0500 |
commit | ce694e7051dca90cdb5700e3865315d16931c3c1 (patch) | |
tree | c6c00e86d187bfda340e03559d3561cd434bd39c /source4/lib/socket | |
parent | 360f125f255fd7d5a172d012c00b3cfbff5a6989 (diff) | |
download | samba-ce694e7051dca90cdb5700e3865315d16931c3c1.tar.gz samba-ce694e7051dca90cdb5700e3865315d16931c3c1.tar.bz2 samba-ce694e7051dca90cdb5700e3865315d16931c3c1.zip |
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)
Diffstat (limited to 'source4/lib/socket')
-rw-r--r-- | source4/lib/socket/config.m4 | 4 | ||||
-rw-r--r-- | source4/lib/socket/config.mk | 16 | ||||
-rw-r--r-- | source4/lib/socket/socket.c | 215 | ||||
-rw-r--r-- | source4/lib/socket/socket.h | 93 | ||||
-rw-r--r-- | source4/lib/socket/socket_ipv4.c | 293 |
5 files changed, 621 insertions, 0 deletions
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; +} |