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.
22 #include "lib/socket/socket.h"
23 #include "system/filesys.h"
26 auto-close sockets on free
28 static int socket_destructor(void *ptr)
30 struct socket_context *sock = ptr;
31 if (sock->ops->fn_close) {
32 sock->ops->fn_close(sock);
37 static NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
38 struct socket_context **new_sock,
39 enum socket_type type, uint32_t flags)
43 (*new_sock) = talloc(mem_ctx, struct socket_context);
45 return NT_STATUS_NO_MEMORY;
48 (*new_sock)->type = type;
49 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
50 (*new_sock)->flags = flags;
54 (*new_sock)->private_data = NULL;
55 (*new_sock)->ops = ops;
56 (*new_sock)->backend_name = NULL;
58 status = (*new_sock)->ops->fn_init((*new_sock));
59 if (!NT_STATUS_IS_OK(status)) {
60 talloc_free(*new_sock);
64 /* by enabling "testnonblock" mode, all socket receive and
65 send calls on non-blocking sockets will randomly recv/send
66 less data than requested */
67 if (!(flags & SOCKET_FLAG_BLOCK) &&
68 type == SOCKET_TYPE_STREAM &&
69 lp_parm_bool(-1, "socket", "testnonblock", False)) {
70 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
73 /* we don't do a connect() on dgram sockets, so need to set
74 non-blocking at socket create time */
75 if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
76 set_blocking(socket_get_fd(*new_sock), False);
79 talloc_set_destructor(*new_sock, socket_destructor);
84 NTSTATUS socket_create(const char *name, enum socket_type type,
85 struct socket_context **new_sock, uint32_t flags)
87 const struct socket_ops *ops;
89 ops = socket_getops_byname(name, type);
91 return NT_STATUS_INVALID_PARAMETER;
94 return socket_create_with_ops(NULL, ops, new_sock, type, flags);
97 NTSTATUS socket_connect(struct socket_context *sock,
98 const char *my_address, int my_port,
99 const char *server_address, int server_port,
103 return NT_STATUS_CONNECTION_DISCONNECTED;
105 if (sock->state != SOCKET_STATE_UNDEFINED) {
106 return NT_STATUS_INVALID_PARAMETER;
109 if (!sock->ops->fn_connect) {
110 return NT_STATUS_NOT_IMPLEMENTED;
113 return sock->ops->fn_connect(sock, my_address, my_port, server_address, server_port, flags);
116 NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
118 if (!sock->ops->fn_connect_complete) {
119 return NT_STATUS_NOT_IMPLEMENTED;
121 return sock->ops->fn_connect_complete(sock, flags);
124 NTSTATUS socket_listen(struct socket_context *sock, const char *my_address, int port, int queue_size, uint32_t flags)
127 return NT_STATUS_CONNECTION_DISCONNECTED;
129 if (sock->state != SOCKET_STATE_UNDEFINED) {
130 return NT_STATUS_INVALID_PARAMETER;
133 if (!sock->ops->fn_listen) {
134 return NT_STATUS_NOT_IMPLEMENTED;
137 return sock->ops->fn_listen(sock, my_address, port, queue_size, flags);
140 NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
145 return NT_STATUS_CONNECTION_DISCONNECTED;
147 if (sock->type != SOCKET_TYPE_STREAM) {
148 return NT_STATUS_INVALID_PARAMETER;
151 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
152 return NT_STATUS_INVALID_PARAMETER;
155 if (!sock->ops->fn_accept) {
156 return NT_STATUS_NOT_IMPLEMENTED;
159 status = sock->ops->fn_accept(sock, new_sock);
161 if (NT_STATUS_IS_OK(status)) {
162 talloc_set_destructor(*new_sock, socket_destructor);
168 NTSTATUS socket_recv(struct socket_context *sock, void *buf,
169 size_t wantlen, size_t *nread, uint32_t flags)
172 return NT_STATUS_CONNECTION_DISCONNECTED;
174 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
175 sock->state != SOCKET_STATE_SERVER_CONNECTED &&
176 sock->type != SOCKET_TYPE_DGRAM) {
177 return NT_STATUS_INVALID_PARAMETER;
180 if (!sock->ops->fn_recv) {
181 return NT_STATUS_NOT_IMPLEMENTED;
184 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && wantlen > 1) {
185 if (random() % 10 == 0) {
187 return STATUS_MORE_ENTRIES;
189 return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread, flags);
192 return sock->ops->fn_recv(sock, buf, wantlen, nread, flags);
195 NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
196 size_t wantlen, size_t *nread, uint32_t flags,
197 const char **src_addr, int *src_port)
200 return NT_STATUS_CONNECTION_DISCONNECTED;
202 if (sock->type != SOCKET_TYPE_DGRAM) {
203 return NT_STATUS_INVALID_PARAMETER;
206 if (!sock->ops->fn_recvfrom) {
207 return NT_STATUS_NOT_IMPLEMENTED;
210 return sock->ops->fn_recvfrom(sock, buf, wantlen, nread, flags,
214 NTSTATUS socket_send(struct socket_context *sock,
215 const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
218 return NT_STATUS_CONNECTION_DISCONNECTED;
220 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
221 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
222 return NT_STATUS_INVALID_PARAMETER;
225 if (!sock->ops->fn_send) {
226 return NT_STATUS_NOT_IMPLEMENTED;
229 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && blob->length > 1) {
230 DATA_BLOB blob2 = *blob;
231 if (random() % 10 == 0) {
233 return STATUS_MORE_ENTRIES;
235 blob2.length = 1+(random() % blob2.length);
236 return sock->ops->fn_send(sock, &blob2, sendlen, flags);
239 return sock->ops->fn_send(sock, blob, sendlen, flags);
243 NTSTATUS socket_sendto(struct socket_context *sock,
244 const DATA_BLOB *blob, size_t *sendlen, uint32_t flags,
245 const char *dest_addr, int dest_port)
248 return NT_STATUS_CONNECTION_DISCONNECTED;
250 if (sock->type != SOCKET_TYPE_DGRAM) {
251 return NT_STATUS_INVALID_PARAMETER;
254 if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
255 sock->state == SOCKET_STATE_SERVER_CONNECTED) {
256 return NT_STATUS_INVALID_PARAMETER;
259 if (!sock->ops->fn_sendto) {
260 return NT_STATUS_NOT_IMPLEMENTED;
263 return sock->ops->fn_sendto(sock, blob, sendlen, flags, dest_addr, dest_port);
268 ask for the number of bytes in a pending incoming packet
270 NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
273 return NT_STATUS_CONNECTION_DISCONNECTED;
275 if (!sock->ops->fn_pending) {
276 return NT_STATUS_NOT_IMPLEMENTED;
278 return sock->ops->fn_pending(sock, npending);
282 NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
285 return NT_STATUS_CONNECTION_DISCONNECTED;
287 if (!sock->ops->fn_set_option) {
288 return NT_STATUS_NOT_IMPLEMENTED;
291 return sock->ops->fn_set_option(sock, option, val);
294 char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
296 if (!sock->ops->fn_get_peer_name) {
300 return sock->ops->fn_get_peer_name(sock, mem_ctx);
303 char *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
305 if (!sock->ops->fn_get_peer_addr) {
309 return sock->ops->fn_get_peer_addr(sock, mem_ctx);
312 int socket_get_peer_port(struct socket_context *sock)
314 if (!sock->ops->fn_get_peer_port) {
318 return sock->ops->fn_get_peer_port(sock);
321 char *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
323 if (!sock->ops->fn_get_my_addr) {
327 return sock->ops->fn_get_my_addr(sock, mem_ctx);
330 int socket_get_my_port(struct socket_context *sock)
332 if (!sock->ops->fn_get_my_port) {
336 return sock->ops->fn_get_my_port(sock);
339 int socket_get_fd(struct socket_context *sock)
341 if (!sock->ops->fn_get_fd) {
345 return sock->ops->fn_get_fd(sock);
349 call dup() on a socket, and close the old fd. This is used to change
350 the fd to the lowest available number, to make select() more
351 efficient (select speed depends on the maxiumum fd number passed to
354 NTSTATUS socket_dup(struct socket_context *sock)
357 if (sock->fd == -1) {
358 return NT_STATUS_INVALID_HANDLE;
362 return map_nt_error_from_unix(errno);
370 const struct socket_ops *socket_getops_byname(const char *name, enum socket_type type)
372 extern const struct socket_ops *socket_ipv4_ops(enum socket_type );
373 extern const struct socket_ops *socket_ipv6_ops(enum socket_type );
374 extern const struct socket_ops *socket_unixdom_ops(enum socket_type );
376 if (strcmp("ip", name) == 0 ||
377 strcmp("ipv4", name) == 0) {
378 return socket_ipv4_ops(type);
382 if (strcmp("ipv6", name) == 0) {
383 if (lp_parm_bool(-1, "socket", "noipv6", False)) {
384 DEBUG(3, ("IPv6 support was disabled in smb.conf"));
387 return socket_ipv6_ops(type);
391 if (strcmp("unix", name) == 0) {
392 return socket_unixdom_ops(type);