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(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(errno
);
58 sock
->private_data
= NULL
;
60 sock
->backend_name
= "unix";
65 static void unixdom_close(struct socket_context
*sock
)
70 static NTSTATUS
unixdom_connect_complete(struct socket_context
*sock
, uint32_t flags
)
73 socklen_t len
= sizeof(error
);
75 /* check for any errors that may have occurred - this is needed
76 for non-blocking connect */
77 ret
= getsockopt(sock
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
79 return map_nt_error_from_unix(errno
);
82 return map_nt_error_from_unix(error
);
85 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
86 ret
= set_blocking(sock
->fd
, false);
88 return map_nt_error_from_unix(errno
);
92 sock
->state
= SOCKET_STATE_CLIENT_CONNECTED
;
97 static NTSTATUS
unixdom_connect(struct socket_context
*sock
,
98 const struct socket_address
*my_address
,
99 const struct socket_address
*srv_address
,
104 if (srv_address
->sockaddr
) {
105 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
107 struct sockaddr_un srv_addr
;
108 if (strlen(srv_address
->addr
)+1 > sizeof(srv_addr
.sun_path
)) {
109 return NT_STATUS_OBJECT_PATH_INVALID
;
112 ZERO_STRUCT(srv_addr
);
113 srv_addr
.sun_family
= AF_UNIX
;
114 strncpy(srv_addr
.sun_path
, srv_address
->addr
, sizeof(srv_addr
.sun_path
));
116 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
119 return unixdom_error(errno
);
122 return unixdom_connect_complete(sock
, flags
);
125 static NTSTATUS
unixdom_listen(struct socket_context
*sock
,
126 const struct socket_address
*my_address
,
127 int queue_size
, uint32_t flags
)
129 struct sockaddr_un my_addr
;
132 /* delete if it already exists */
133 if (my_address
->addr
) {
134 unlink(my_address
->addr
);
137 if (my_address
->sockaddr
) {
138 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
139 } else if (my_address
->addr
== NULL
) {
140 return NT_STATUS_INVALID_PARAMETER
;
142 if (strlen(my_address
->addr
)+1 > sizeof(my_addr
.sun_path
)) {
143 return NT_STATUS_OBJECT_PATH_INVALID
;
147 ZERO_STRUCT(my_addr
);
148 my_addr
.sun_family
= AF_UNIX
;
149 strncpy(my_addr
.sun_path
, my_address
->addr
, sizeof(my_addr
.sun_path
));
151 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
154 return unixdom_error(errno
);
157 if (sock
->type
== SOCKET_TYPE_STREAM
) {
158 ret
= listen(sock
->fd
, queue_size
);
160 return unixdom_error(errno
);
164 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
165 ret
= set_blocking(sock
->fd
, false);
167 return unixdom_error(errno
);
171 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
172 sock
->private_data
= (void *)talloc_strdup(sock
, my_address
->addr
);
177 static NTSTATUS
unixdom_accept(struct socket_context
*sock
,
178 struct socket_context
**new_sock
)
180 struct sockaddr_un cli_addr
;
181 socklen_t cli_addr_len
= sizeof(cli_addr
);
184 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
185 return NT_STATUS_INVALID_PARAMETER
;
188 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
190 return unixdom_error(errno
);
193 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
194 int ret
= set_blocking(new_fd
, false);
197 return map_nt_error_from_unix(errno
);
201 (*new_sock
) = talloc(NULL
, struct socket_context
);
204 return NT_STATUS_NO_MEMORY
;
207 /* copy the socket_context */
208 (*new_sock
)->type
= sock
->type
;
209 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
210 (*new_sock
)->flags
= sock
->flags
;
212 (*new_sock
)->fd
= new_fd
;
214 (*new_sock
)->private_data
= NULL
;
215 (*new_sock
)->ops
= sock
->ops
;
216 (*new_sock
)->backend_name
= sock
->backend_name
;
221 static NTSTATUS
unixdom_recv(struct socket_context
*sock
, void *buf
,
222 size_t wantlen
, size_t *nread
)
228 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
230 return NT_STATUS_END_OF_FILE
;
231 } else if (gotlen
== -1) {
232 return unixdom_error(errno
);
240 static NTSTATUS
unixdom_send(struct socket_context
*sock
,
241 const DATA_BLOB
*blob
, size_t *sendlen
)
247 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
249 return unixdom_error(errno
);
258 static NTSTATUS
unixdom_sendto(struct socket_context
*sock
,
259 const DATA_BLOB
*blob
, size_t *sendlen
,
260 const struct socket_address
*dest
)
265 if (dest
->sockaddr
) {
266 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
267 dest
->sockaddr
, dest
->sockaddrlen
);
269 struct sockaddr_un srv_addr
;
271 if (strlen(dest
->addr
)+1 > sizeof(srv_addr
.sun_path
)) {
272 return NT_STATUS_OBJECT_PATH_INVALID
;
275 ZERO_STRUCT(srv_addr
);
276 srv_addr
.sun_family
= AF_UNIX
;
277 strncpy(srv_addr
.sun_path
, dest
->addr
, sizeof(srv_addr
.sun_path
));
279 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
280 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
283 return map_nt_error_from_unix(errno
);
292 static NTSTATUS
unixdom_set_option(struct socket_context
*sock
,
293 const char *option
, const char *val
)
298 static char *unixdom_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
300 return talloc_strdup(mem_ctx
, "LOCAL/unixdom");
303 static struct socket_address
*unixdom_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
305 struct sockaddr_in
*peer_addr
;
306 socklen_t len
= sizeof(*peer_addr
);
307 struct socket_address
*peer
;
310 peer
= talloc(mem_ctx
, struct socket_address
);
315 peer
->family
= sock
->backend_name
;
316 peer_addr
= talloc(peer
, struct sockaddr_in
);
322 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
324 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
330 peer
->sockaddrlen
= len
;
333 peer
->addr
= talloc_strdup(peer
, "LOCAL/unixdom");
342 static struct socket_address
*unixdom_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
344 struct sockaddr_in
*local_addr
;
345 socklen_t len
= sizeof(*local_addr
);
346 struct socket_address
*local
;
349 local
= talloc(mem_ctx
, struct socket_address
);
354 local
->family
= sock
->backend_name
;
355 local_addr
= talloc(local
, struct sockaddr_in
);
361 local
->sockaddr
= (struct sockaddr
*)local_addr
;
363 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
369 local
->sockaddrlen
= len
;
372 local
->addr
= talloc_strdup(local
, "LOCAL/unixdom");
381 static int unixdom_get_fd(struct socket_context
*sock
)
386 static NTSTATUS
unixdom_pending(struct socket_context
*sock
, size_t *npending
)
389 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
393 return map_nt_error_from_unix(errno
);
396 static const struct socket_ops unixdom_ops
= {
398 .fn_init
= unixdom_init
,
399 .fn_connect
= unixdom_connect
,
400 .fn_connect_complete
= unixdom_connect_complete
,
401 .fn_listen
= unixdom_listen
,
402 .fn_accept
= unixdom_accept
,
403 .fn_recv
= unixdom_recv
,
404 .fn_send
= unixdom_send
,
405 .fn_sendto
= unixdom_sendto
,
406 .fn_close
= unixdom_close
,
407 .fn_pending
= unixdom_pending
,
409 .fn_set_option
= unixdom_set_option
,
411 .fn_get_peer_name
= unixdom_get_peer_name
,
412 .fn_get_peer_addr
= unixdom_get_peer_addr
,
413 .fn_get_my_addr
= unixdom_get_my_addr
,
415 .fn_get_fd
= unixdom_get_fd
418 _PUBLIC_
const struct socket_ops
*socket_unixdom_ops(enum socket_type type
)