2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2004
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 auto-close sockets on free
26 static int socket_destructor(void *ptr)
28 struct socket_context *sock = ptr;
29 if (sock->ops->fn_close) {
30 sock->ops->fn_close(sock);
35 NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops, struct socket_context **new_sock, uint32_t flags)
39 (*new_sock) = talloc(mem_ctx, struct socket_context);
41 return NT_STATUS_NO_MEMORY;
44 (*new_sock)->type = ops->type;
45 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
46 (*new_sock)->flags = flags;
50 (*new_sock)->private_data = NULL;
51 (*new_sock)->ops = ops;
53 status = (*new_sock)->ops->fn_init((*new_sock));
54 if (!NT_STATUS_IS_OK(status)) {
55 talloc_free(*new_sock);
59 /* by enabling "testnonblock" mode, all socket receive and
60 send calls on non-blocking sockets will randomly recv/send
61 less data than requested */
62 if (!(flags & SOCKET_FLAG_BLOCK) &&
63 lp_parm_bool(-1, "socket", "testnonblock", False)) {
64 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
67 talloc_set_destructor(*new_sock, socket_destructor);
72 NTSTATUS socket_create(const char *name, enum socket_type type, struct socket_context **new_sock, uint32_t flags)
74 const struct socket_ops *ops;
76 ops = socket_getops_byname(name, type);
78 return NT_STATUS_INVALID_PARAMETER;
81 return socket_create_with_ops(NULL, ops, new_sock, flags);
84 void socket_destroy(struct socket_context *sock)
86 /* the close is handled by the destructor */
90 NTSTATUS socket_connect(struct socket_context *sock,
91 const char *my_address, int my_port,
92 const char *server_address, int server_port,
95 if (sock->type != SOCKET_TYPE_STREAM) {
96 return NT_STATUS_INVALID_PARAMETER;
99 if (sock->state != SOCKET_STATE_UNDEFINED) {
100 return NT_STATUS_INVALID_PARAMETER;
103 if (!sock->ops->fn_connect) {
104 return NT_STATUS_NOT_IMPLEMENTED;
107 return sock->ops->fn_connect(sock, my_address, my_port, server_address, server_port, flags);
110 NTSTATUS socket_listen(struct socket_context *sock, const char *my_address, int port, int queue_size, uint32_t flags)
112 if (sock->type != SOCKET_TYPE_STREAM) {
113 return NT_STATUS_INVALID_PARAMETER;
116 if (sock->state != SOCKET_STATE_UNDEFINED) {
117 return NT_STATUS_INVALID_PARAMETER;
120 if (!sock->ops->fn_listen) {
121 return NT_STATUS_NOT_IMPLEMENTED;
124 return sock->ops->fn_listen(sock, my_address, port, queue_size, flags);
127 NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
131 if (sock->type != SOCKET_TYPE_STREAM) {
132 return NT_STATUS_INVALID_PARAMETER;
135 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
136 return NT_STATUS_INVALID_PARAMETER;
139 if (!sock->ops->fn_accept) {
140 return NT_STATUS_NOT_IMPLEMENTED;
143 status = sock->ops->fn_accept(sock, new_sock);
145 if (NT_STATUS_IS_OK(status)) {
146 talloc_set_destructor(*new_sock, socket_destructor);
152 NTSTATUS socket_recv(struct socket_context *sock, void *buf,
153 size_t wantlen, size_t *nread, uint32_t flags)
155 if (sock->type != SOCKET_TYPE_STREAM) {
156 return NT_STATUS_INVALID_PARAMETER;
159 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
160 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
161 return NT_STATUS_INVALID_PARAMETER;
164 if (!sock->ops->fn_recv) {
165 return NT_STATUS_NOT_IMPLEMENTED;
168 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && wantlen > 1) {
169 if (random() % 10 == 0) {
171 return STATUS_MORE_ENTRIES;
173 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread, flags);
176 return sock->ops->fn_recv(sock, buf, wantlen, nread, flags);
179 NTSTATUS socket_send(struct socket_context *sock,
180 const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
182 if (sock->type != SOCKET_TYPE_STREAM) {
183 return NT_STATUS_INVALID_PARAMETER;
186 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
187 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
188 return NT_STATUS_INVALID_PARAMETER;
191 if (!sock->ops->fn_send) {
192 return NT_STATUS_NOT_IMPLEMENTED;
195 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && blob->length > 1) {
196 DATA_BLOB blob2 = *blob;
197 if (random() % 10 == 0) {
199 return STATUS_MORE_ENTRIES;
201 blob2.length = 1+(random() % blob2.length);
202 return sock->ops->fn_send(sock, &blob2, sendlen, flags);
205 return sock->ops->fn_send(sock, blob, sendlen, flags);
208 NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
210 if (!sock->ops->fn_set_option) {
211 return NT_STATUS_NOT_IMPLEMENTED;
214 return sock->ops->fn_set_option(sock, option, val);
217 char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
219 if (!sock->ops->fn_get_peer_name) {
223 return sock->ops->fn_get_peer_name(sock, mem_ctx);
226 char *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
228 if (!sock->ops->fn_get_peer_addr) {
232 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
235 int socket_get_peer_port(struct socket_context *sock)
237 if (!sock->ops->fn_get_peer_port) {
241 return sock->ops->fn_get_peer_port(sock);
244 char *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
246 if (!sock->ops->fn_get_my_addr) {
250 return sock->ops->fn_get_my_addr(sock, mem_ctx);
253 int socket_get_my_port(struct socket_context *sock)
255 if (!sock->ops->fn_get_my_port) {
259 return sock->ops->fn_get_my_port(sock);
262 int socket_get_fd(struct socket_context *sock)
264 if (!sock->ops->fn_get_fd) {
268 return sock->ops->fn_get_fd(sock);
272 call dup() on a socket, and close the old fd. This is used to change
273 the fd to the lowest available number, to make select() more
274 efficient (select speed depends on the maxiumum fd number passed to
277 NTSTATUS socket_dup(struct socket_context *sock)
280 if (sock->fd == -1) {
281 return NT_STATUS_INVALID_HANDLE;
285 return map_nt_error_from_unix(errno);
293 const struct socket_ops *socket_getops_byname(const char *name, enum socket_type type)
295 if (strcmp("ip", name) == 0 ||
296 strcmp("ipv4", name) == 0) {
297 return socket_ipv4_ops();
301 if (strcmp("ipv6", name) == 0) {
302 if (lp_parm_bool(-1, "socket", "noipv6", False)) {
303 DEBUG(3, ("IPv6 support was disabled in smb.conf"));
306 return socket_ipv6_ops();
310 if (strcmp("unix", name) == 0) {
311 return socket_unixdom_ops();