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->close) {
30 sock->ops->close(sock);
35 NTSTATUS socket_create(const char *name, enum socket_type type, struct socket_context **new_sock, uint32_t flags)
39 (*new_sock) = talloc_p(NULL, struct socket_context);
41 return NT_STATUS_NO_MEMORY;
44 (*new_sock)->type = type;
45 (*new_sock)->state = SOCKET_STATE_UNDEFINED;
46 (*new_sock)->flags = flags;
50 (*new_sock)->private_data = NULL;
51 (*new_sock)->ops = socket_getops_byname(name, type);
52 if (!(*new_sock)->ops) {
53 talloc_free(*new_sock);
54 return NT_STATUS_INVALID_PARAMETER;
57 status = (*new_sock)->ops->init((*new_sock));
58 if (!NT_STATUS_IS_OK(status)) {
59 talloc_free(*new_sock);
63 /* by enabling "testnonblock" mode, all socket receive and
64 send calls on non-blocking sockets will randomly recv/send
65 less data than requested */
66 if (!(flags & SOCKET_FLAG_BLOCK) &&
67 lp_parm_bool(-1, "socket", "testnonblock", False)) {
68 (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
71 talloc_set_destructor(*new_sock, socket_destructor);
76 void socket_destroy(struct socket_context *sock)
78 /* the close is handled by the destructor */
82 NTSTATUS socket_connect(struct socket_context *sock,
83 const char *my_address, int my_port,
84 const char *server_address, int server_port,
87 if (sock->type != SOCKET_TYPE_STREAM) {
88 return NT_STATUS_INVALID_PARAMETER;
91 if (sock->state != SOCKET_STATE_UNDEFINED) {
92 return NT_STATUS_INVALID_PARAMETER;
95 if (!sock->ops->connect) {
96 return NT_STATUS_NOT_IMPLEMENTED;
99 return sock->ops->connect(sock, my_address, my_port, server_address, server_port, flags);
102 NTSTATUS socket_listen(struct socket_context *sock, const char *my_address, int port, int queue_size, uint32_t flags)
104 if (sock->type != SOCKET_TYPE_STREAM) {
105 return NT_STATUS_INVALID_PARAMETER;
108 if (sock->state != SOCKET_STATE_UNDEFINED) {
109 return NT_STATUS_INVALID_PARAMETER;
112 if (!sock->ops->listen) {
113 return NT_STATUS_NOT_IMPLEMENTED;
116 return sock->ops->listen(sock, my_address, port, queue_size, flags);
119 NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
123 if (sock->type != SOCKET_TYPE_STREAM) {
124 return NT_STATUS_INVALID_PARAMETER;
127 if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
128 return NT_STATUS_INVALID_PARAMETER;
131 if (!sock->ops->accept) {
132 return NT_STATUS_NOT_IMPLEMENTED;
135 status = sock->ops->accept(sock, new_sock);
137 if (NT_STATUS_IS_OK(status)) {
138 talloc_set_destructor(*new_sock, socket_destructor);
144 NTSTATUS socket_recv(struct socket_context *sock, void *buf,
145 size_t wantlen, size_t *nread, uint32_t flags)
147 if (sock->type != SOCKET_TYPE_STREAM) {
148 return NT_STATUS_INVALID_PARAMETER;
151 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
152 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
153 return NT_STATUS_INVALID_PARAMETER;
156 if (!sock->ops->recv) {
157 return NT_STATUS_NOT_IMPLEMENTED;
160 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && wantlen > 1) {
161 if (random() % 10 == 0) {
163 return STATUS_MORE_ENTRIES;
165 return sock->ops->recv(sock, buf, 1+(random() % wantlen), nread, flags);
168 return sock->ops->recv(sock, buf, wantlen, nread, flags);
171 NTSTATUS socket_send(struct socket_context *sock,
172 const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
174 if (sock->type != SOCKET_TYPE_STREAM) {
175 return NT_STATUS_INVALID_PARAMETER;
178 if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
179 sock->state != SOCKET_STATE_SERVER_CONNECTED) {
180 return NT_STATUS_INVALID_PARAMETER;
183 if (!sock->ops->send) {
184 return NT_STATUS_NOT_IMPLEMENTED;
187 if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) && blob->length > 1) {
188 DATA_BLOB blob2 = *blob;
189 if (random() % 10 == 0) {
191 return STATUS_MORE_ENTRIES;
193 blob2.length = 1+(random() % blob2.length);
194 return sock->ops->send(sock, &blob2, sendlen, flags);
197 return sock->ops->send(sock, blob, sendlen, flags);
200 NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
202 if (!sock->ops->set_option) {
203 return NT_STATUS_NOT_IMPLEMENTED;
206 return sock->ops->set_option(sock, option, val);
209 char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
211 if (!sock->ops->get_peer_name) {
215 return sock->ops->get_peer_name(sock, mem_ctx);
218 char *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
220 if (!sock->ops->get_peer_addr) {
224 return sock->ops->get_peer_addr(sock, mem_ctx);
227 int socket_get_peer_port(struct socket_context *sock)
229 if (!sock->ops->get_peer_port) {
233 return sock->ops->get_peer_port(sock);
236 char *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
238 if (!sock->ops->get_my_addr) {
242 return sock->ops->get_my_addr(sock, mem_ctx);
245 int socket_get_my_port(struct socket_context *sock)
247 if (!sock->ops->get_my_port) {
251 return sock->ops->get_my_port(sock);
254 int socket_get_fd(struct socket_context *sock)
256 if (!sock->ops->get_fd) {
260 return sock->ops->get_fd(sock);
264 call dup() on a socket, and close the old fd. This is used to change
265 the fd to the lowest available number, to make select() more
266 efficient (select speed depends on the maxiumum fd number passed to
269 NTSTATUS socket_dup(struct socket_context *sock)
272 if (sock->fd == -1) {
273 return NT_STATUS_INVALID_HANDLE;
277 return map_nt_error_from_unix(errno);
285 const struct socket_ops *socket_getops_byname(const char *name, enum socket_type type)
287 if (strcmp("ip", name) == 0 ||
288 strcmp("ipv4", name) == 0) {
289 return socket_ipv4_ops();
293 if (strcmp("ipv6", name) == 0) {
294 if (lp_parm_bool(-1, "socket", "noipv6", False)) {
295 DEBUG(3, ("IPv6 support was disabled in smb.conf"));
298 return socket_ipv6_ops();
302 if (strcmp("unix", name) == 0) {
303 return socket_unixdom_ops();