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"
31 approximate errno mapping
33 static NTSTATUS
unixdom_error(int ernum
)
35 return map_nt_error_from_unix(ernum
);
38 static NTSTATUS
unixdom_init(struct socket_context
*sock
)
43 case SOCKET_TYPE_STREAM
:
46 case SOCKET_TYPE_DGRAM
:
50 return NT_STATUS_INVALID_PARAMETER
;
53 sock
->fd
= socket(PF_UNIX
, type
, 0);
55 return map_nt_error_from_unix(errno
);
57 sock
->private_data
= NULL
;
59 sock
->backend_name
= "unix";
64 static void unixdom_close(struct socket_context
*sock
)
69 static NTSTATUS
unixdom_connect_complete(struct socket_context
*sock
, uint32_t flags
)
72 socklen_t len
= sizeof(error
);
74 /* check for any errors that may have occurred - this is needed
75 for non-blocking connect */
76 ret
= getsockopt(sock
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
78 return map_nt_error_from_unix(errno
);
81 return map_nt_error_from_unix(error
);
84 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
85 ret
= set_blocking(sock
->fd
, false);
87 return map_nt_error_from_unix(errno
);
91 sock
->state
= SOCKET_STATE_CLIENT_CONNECTED
;
96 static NTSTATUS
unixdom_connect(struct socket_context
*sock
,
97 const struct socket_address
*my_address
,
98 const struct socket_address
*srv_address
,
103 if (srv_address
->sockaddr
) {
104 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
106 struct sockaddr_un srv_addr
;
107 if (strlen(srv_address
->addr
)+1 > sizeof(srv_addr
.sun_path
)) {
108 return NT_STATUS_OBJECT_PATH_INVALID
;
111 ZERO_STRUCT(srv_addr
);
112 srv_addr
.sun_family
= AF_UNIX
;
113 strncpy(srv_addr
.sun_path
, srv_address
->addr
, sizeof(srv_addr
.sun_path
));
115 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
118 return unixdom_error(errno
);
121 return unixdom_connect_complete(sock
, flags
);
124 static NTSTATUS
unixdom_listen(struct socket_context
*sock
,
125 const struct socket_address
*my_address
,
126 int queue_size
, uint32_t flags
)
128 struct sockaddr_un my_addr
;
131 /* delete if it already exists */
132 if (my_address
->addr
) {
133 unlink(my_address
->addr
);
136 if (my_address
->sockaddr
) {
137 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
138 } else if (my_address
->addr
== NULL
) {
139 return NT_STATUS_INVALID_PARAMETER
;
141 if (strlen(my_address
->addr
)+1 > sizeof(my_addr
.sun_path
)) {
142 return NT_STATUS_OBJECT_PATH_INVALID
;
146 ZERO_STRUCT(my_addr
);
147 my_addr
.sun_family
= AF_UNIX
;
148 strncpy(my_addr
.sun_path
, my_address
->addr
, sizeof(my_addr
.sun_path
));
150 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
153 return unixdom_error(errno
);
156 if (sock
->type
== SOCKET_TYPE_STREAM
) {
157 ret
= listen(sock
->fd
, queue_size
);
159 return unixdom_error(errno
);
163 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
164 ret
= set_blocking(sock
->fd
, false);
166 return unixdom_error(errno
);
170 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
171 sock
->private_data
= (void *)talloc_strdup(sock
, my_address
->addr
);
176 static NTSTATUS
unixdom_accept(struct socket_context
*sock
,
177 struct socket_context
**new_sock
)
179 struct sockaddr_un cli_addr
;
180 socklen_t cli_addr_len
= sizeof(cli_addr
);
183 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
184 return NT_STATUS_INVALID_PARAMETER
;
187 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
189 return unixdom_error(errno
);
192 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
193 int ret
= set_blocking(new_fd
, false);
196 return map_nt_error_from_unix(errno
);
200 (*new_sock
) = talloc(NULL
, struct socket_context
);
203 return NT_STATUS_NO_MEMORY
;
206 /* copy the socket_context */
207 (*new_sock
)->type
= sock
->type
;
208 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
209 (*new_sock
)->flags
= sock
->flags
;
211 (*new_sock
)->fd
= new_fd
;
213 (*new_sock
)->private_data
= NULL
;
214 (*new_sock
)->ops
= sock
->ops
;
215 (*new_sock
)->backend_name
= sock
->backend_name
;
220 static NTSTATUS
unixdom_recv(struct socket_context
*sock
, void *buf
,
221 size_t wantlen
, size_t *nread
)
227 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
229 return NT_STATUS_END_OF_FILE
;
230 } else if (gotlen
== -1) {
231 return unixdom_error(errno
);
239 static NTSTATUS
unixdom_send(struct socket_context
*sock
,
240 const DATA_BLOB
*blob
, size_t *sendlen
)
246 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
248 return unixdom_error(errno
);
257 static NTSTATUS
unixdom_sendto(struct socket_context
*sock
,
258 const DATA_BLOB
*blob
, size_t *sendlen
,
259 const struct socket_address
*dest
)
264 if (dest
->sockaddr
) {
265 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
266 dest
->sockaddr
, dest
->sockaddrlen
);
268 struct sockaddr_un srv_addr
;
270 if (strlen(dest
->addr
)+1 > sizeof(srv_addr
.sun_path
)) {
271 return NT_STATUS_OBJECT_PATH_INVALID
;
274 ZERO_STRUCT(srv_addr
);
275 srv_addr
.sun_family
= AF_UNIX
;
276 strncpy(srv_addr
.sun_path
, dest
->addr
, sizeof(srv_addr
.sun_path
));
278 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
279 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
282 return map_nt_error_from_unix(errno
);
291 static NTSTATUS
unixdom_set_option(struct socket_context
*sock
,
292 const char *option
, const char *val
)
297 static char *unixdom_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
299 return talloc_strdup(mem_ctx
, "LOCAL/unixdom");
302 static struct socket_address
*unixdom_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
304 struct sockaddr_in
*peer_addr
;
305 socklen_t len
= sizeof(*peer_addr
);
306 struct socket_address
*peer
;
309 peer
= talloc(mem_ctx
, struct socket_address
);
314 peer
->family
= sock
->backend_name
;
315 peer_addr
= talloc(peer
, struct sockaddr_in
);
321 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
323 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
329 peer
->sockaddrlen
= len
;
332 peer
->addr
= talloc_strdup(peer
, "LOCAL/unixdom");
341 static struct socket_address
*unixdom_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
343 struct sockaddr_in
*local_addr
;
344 socklen_t len
= sizeof(*local_addr
);
345 struct socket_address
*local
;
348 local
= talloc(mem_ctx
, struct socket_address
);
353 local
->family
= sock
->backend_name
;
354 local_addr
= talloc(local
, struct sockaddr_in
);
360 local
->sockaddr
= (struct sockaddr
*)local_addr
;
362 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
368 local
->sockaddrlen
= len
;
371 local
->addr
= talloc_strdup(local
, "LOCAL/unixdom");
380 static int unixdom_get_fd(struct socket_context
*sock
)
385 static NTSTATUS
unixdom_pending(struct socket_context
*sock
, size_t *npending
)
388 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
392 return map_nt_error_from_unix(errno
);
395 static const struct socket_ops unixdom_ops
= {
397 .fn_init
= unixdom_init
,
398 .fn_connect
= unixdom_connect
,
399 .fn_connect_complete
= unixdom_connect_complete
,
400 .fn_listen
= unixdom_listen
,
401 .fn_accept
= unixdom_accept
,
402 .fn_recv
= unixdom_recv
,
403 .fn_send
= unixdom_send
,
404 .fn_sendto
= unixdom_sendto
,
405 .fn_close
= unixdom_close
,
406 .fn_pending
= unixdom_pending
,
408 .fn_set_option
= unixdom_set_option
,
410 .fn_get_peer_name
= unixdom_get_peer_name
,
411 .fn_get_peer_addr
= unixdom_get_peer_addr
,
412 .fn_get_my_addr
= unixdom_get_my_addr
,
414 .fn_get_fd
= unixdom_get_fd
417 _PUBLIC_
const struct socket_ops
*socket_unixdom_ops(enum socket_type type
)