2 Unix SMB/CIFS implementation.
4 unix domain socket functions
6 Copyright (C) Stefan Metzmacher 2004
7 Copyright (C) Andrew Tridgell 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/socket/socket.h"
25 #include "system/network.h"
26 #include "system/filesys.h"
28 _PUBLIC_
const struct socket_ops
*socket_unixdom_ops(enum socket_type type
);
32 approximate errno mapping
34 static NTSTATUS
unixdom_error(int ernum
)
36 return map_nt_error_from_unix_common(ernum
);
39 static NTSTATUS
unixdom_init(struct socket_context
*sock
)
44 case SOCKET_TYPE_STREAM
:
47 case SOCKET_TYPE_DGRAM
:
51 return NT_STATUS_INVALID_PARAMETER
;
54 sock
->fd
= socket(PF_UNIX
, type
, 0);
56 return map_nt_error_from_unix_common(errno
);
58 sock
->private_data
= NULL
;
60 sock
->backend_name
= "unix";
62 smb_set_close_on_exec(sock
->fd
);
67 static void unixdom_close(struct socket_context
*sock
)
72 static NTSTATUS
unixdom_connect_complete(struct socket_context
*sock
, uint32_t flags
)
75 socklen_t len
= sizeof(error
);
77 /* check for any errors that may have occurred - this is needed
78 for non-blocking connect */
79 ret
= getsockopt(sock
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
81 return map_nt_error_from_unix_common(errno
);
84 return map_nt_error_from_unix_common(error
);
87 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
88 ret
= set_blocking(sock
->fd
, false);
90 return map_nt_error_from_unix_common(errno
);
94 sock
->state
= SOCKET_STATE_CLIENT_CONNECTED
;
99 static NTSTATUS
unixdom_connect(struct socket_context
*sock
,
100 const struct socket_address
*my_address
,
101 const struct socket_address
*srv_address
,
106 if (srv_address
->sockaddr
) {
107 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
109 struct sockaddr_un srv_addr
;
110 if (strlen(srv_address
->addr
)+1 > sizeof(srv_addr
.sun_path
)) {
111 return NT_STATUS_OBJECT_PATH_INVALID
;
114 ZERO_STRUCT(srv_addr
);
115 srv_addr
.sun_family
= AF_UNIX
;
116 snprintf(srv_addr
.sun_path
, sizeof(srv_addr
.sun_path
), "%s", srv_address
->addr
);
118 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
121 return unixdom_error(errno
);
124 return unixdom_connect_complete(sock
, flags
);
127 static NTSTATUS
unixdom_listen(struct socket_context
*sock
,
128 const struct socket_address
*my_address
,
129 int queue_size
, uint32_t flags
)
131 struct sockaddr_un my_addr
;
134 /* delete if it already exists */
135 if (my_address
->addr
) {
136 unlink(my_address
->addr
);
139 if (my_address
->sockaddr
) {
140 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
141 } else if (my_address
->addr
== NULL
) {
142 return NT_STATUS_INVALID_PARAMETER
;
144 if (strlen(my_address
->addr
)+1 > sizeof(my_addr
.sun_path
)) {
145 return NT_STATUS_OBJECT_PATH_INVALID
;
149 ZERO_STRUCT(my_addr
);
150 my_addr
.sun_family
= AF_UNIX
;
151 snprintf(my_addr
.sun_path
, sizeof(my_addr
.sun_path
), "%s", my_address
->addr
);
153 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
156 return unixdom_error(errno
);
159 if (sock
->type
== SOCKET_TYPE_STREAM
) {
160 ret
= listen(sock
->fd
, queue_size
);
162 return unixdom_error(errno
);
166 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
167 ret
= set_blocking(sock
->fd
, false);
169 return unixdom_error(errno
);
173 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
174 sock
->private_data
= (void *)talloc_strdup(sock
, my_address
->addr
);
179 static NTSTATUS
unixdom_accept(struct socket_context
*sock
,
180 struct socket_context
**new_sock
)
182 struct sockaddr_un cli_addr
;
183 socklen_t cli_addr_len
= sizeof(cli_addr
);
186 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
187 return NT_STATUS_INVALID_PARAMETER
;
190 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
192 return unixdom_error(errno
);
195 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
196 int ret
= set_blocking(new_fd
, false);
199 return map_nt_error_from_unix_common(errno
);
203 smb_set_close_on_exec(new_fd
);
205 (*new_sock
) = talloc(NULL
, struct socket_context
);
208 return NT_STATUS_NO_MEMORY
;
211 /* copy the socket_context */
212 (*new_sock
)->type
= sock
->type
;
213 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
214 (*new_sock
)->flags
= sock
->flags
;
216 (*new_sock
)->fd
= new_fd
;
218 (*new_sock
)->private_data
= NULL
;
219 (*new_sock
)->ops
= sock
->ops
;
220 (*new_sock
)->backend_name
= sock
->backend_name
;
225 static NTSTATUS
unixdom_recv(struct socket_context
*sock
, void *buf
,
226 size_t wantlen
, size_t *nread
)
232 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
234 return NT_STATUS_END_OF_FILE
;
235 } else if (gotlen
== -1) {
236 return unixdom_error(errno
);
244 static NTSTATUS
unixdom_send(struct socket_context
*sock
,
245 const DATA_BLOB
*blob
, size_t *sendlen
)
251 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
253 return unixdom_error(errno
);
262 static NTSTATUS
unixdom_sendto(struct socket_context
*sock
,
263 const DATA_BLOB
*blob
, size_t *sendlen
,
264 const struct socket_address
*dest
)
269 if (dest
->sockaddr
) {
270 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
271 dest
->sockaddr
, dest
->sockaddrlen
);
273 struct sockaddr_un srv_addr
;
275 if (strlen(dest
->addr
)+1 > sizeof(srv_addr
.sun_path
)) {
276 return NT_STATUS_OBJECT_PATH_INVALID
;
279 ZERO_STRUCT(srv_addr
);
280 srv_addr
.sun_family
= AF_UNIX
;
281 snprintf(srv_addr
.sun_path
, sizeof(srv_addr
.sun_path
), "%s", dest
->addr
);
283 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
284 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
287 return map_nt_error_from_unix_common(errno
);
296 static NTSTATUS
unixdom_set_option(struct socket_context
*sock
,
297 const char *option
, const char *val
)
302 static char *unixdom_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
304 return talloc_strdup(mem_ctx
, "LOCAL/unixdom");
307 static struct socket_address
*unixdom_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
309 struct sockaddr_in
*peer_addr
;
310 socklen_t len
= sizeof(*peer_addr
);
311 struct socket_address
*peer
;
314 peer
= talloc(mem_ctx
, struct socket_address
);
319 peer
->family
= sock
->backend_name
;
320 peer_addr
= talloc(peer
, struct sockaddr_in
);
326 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
328 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
334 peer
->sockaddrlen
= len
;
337 peer
->addr
= talloc_strdup(peer
, "LOCAL/unixdom");
346 static struct socket_address
*unixdom_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
348 struct sockaddr_in
*local_addr
;
349 socklen_t len
= sizeof(*local_addr
);
350 struct socket_address
*local
;
353 local
= talloc(mem_ctx
, struct socket_address
);
358 local
->family
= sock
->backend_name
;
359 local_addr
= talloc(local
, struct sockaddr_in
);
365 local
->sockaddr
= (struct sockaddr
*)local_addr
;
367 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
373 local
->sockaddrlen
= len
;
376 local
->addr
= talloc_strdup(local
, "LOCAL/unixdom");
385 static int unixdom_get_fd(struct socket_context
*sock
)
390 static NTSTATUS
unixdom_pending(struct socket_context
*sock
, size_t *npending
)
393 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
397 return map_nt_error_from_unix_common(errno
);
400 static const struct socket_ops unixdom_ops
= {
402 .fn_init
= unixdom_init
,
403 .fn_connect
= unixdom_connect
,
404 .fn_connect_complete
= unixdom_connect_complete
,
405 .fn_listen
= unixdom_listen
,
406 .fn_accept
= unixdom_accept
,
407 .fn_recv
= unixdom_recv
,
408 .fn_send
= unixdom_send
,
409 .fn_sendto
= unixdom_sendto
,
410 .fn_close
= unixdom_close
,
411 .fn_pending
= unixdom_pending
,
413 .fn_set_option
= unixdom_set_option
,
415 .fn_get_peer_name
= unixdom_get_peer_name
,
416 .fn_get_peer_addr
= unixdom_get_peer_addr
,
417 .fn_get_my_addr
= unixdom_get_my_addr
,
419 .fn_get_fd
= unixdom_get_fd
422 _PUBLIC_
const struct socket_ops
*socket_unixdom_ops(enum socket_type type
)