r3183: moved the unlink of the messaging unixdom socket to the messaging destructor
[gd/samba-autobuild/.git] / source4 / lib / socket / socket_unix.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    unix domain socket functions
5
6    Copyright (C) Stefan Metzmacher 2004
7    Copyright (C) Andrew Tridgell 2004
8    
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 2 of the License, or
12    (at your option) any later version.
13    
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.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26
27
28 /*
29   approximate errno mapping
30 */
31 static NTSTATUS unixdom_error(int ernum)
32 {
33         switch (ernum) {
34         case EBADF:
35         case ENOTCONN:
36         case ENOTSOCK:
37         case EFAULT:
38         case EINVAL:
39                 return NT_STATUS_INVALID_PARAMETER;
40         case EAGAIN:
41         case EINTR:
42                 return STATUS_MORE_ENTRIES;
43         case ECONNREFUSED:
44                 return NT_STATUS_CONNECTION_REFUSED;
45         case ENOBUFS:
46         case ENOMEM:
47                 return NT_STATUS_NO_MEMORY;
48         case ENFILE:
49         case EMFILE:
50                 return NT_STATUS_INSUFFICIENT_RESOURCES;
51         case EPIPE:
52                 return NT_STATUS_CONNECTION_DISCONNECTED;
53         case EMSGSIZE:
54                 return NT_STATUS_INVALID_BUFFER_SIZE;
55         }
56         
57         return NT_STATUS_UNSUCCESSFUL;
58 }
59
60 static NTSTATUS unixdom_init(struct socket_context *sock)
61 {
62         sock->fd = socket(PF_UNIX, SOCK_STREAM, 0);
63         if (sock->fd == -1) {
64                 return NT_STATUS_INSUFFICIENT_RESOURCES;
65         }
66         sock->private_data = NULL;
67
68         return NT_STATUS_OK;
69 }
70
71 static void unixdom_close(struct socket_context *sock)
72 {
73         close(sock->fd);
74 }
75
76 static NTSTATUS unixdom_connect(struct socket_context *sock,
77                                 const char *my_address, int my_port,
78                                 const char *srv_address, int srv_port,
79                                 uint32_t flags)
80 {
81         struct sockaddr_un srv_addr;
82         int ret;
83
84         if (strlen(srv_address)+1 > sizeof(srv_addr.sun_path)) {
85                 return NT_STATUS_INVALID_PARAMETER;
86         }
87
88         ZERO_STRUCT(srv_addr);
89         srv_addr.sun_family = AF_UNIX;
90         strncpy(srv_addr.sun_path, srv_address, sizeof(srv_addr.sun_path));
91
92         if (!(flags & SOCKET_FLAG_BLOCK)) {
93                 ret = set_blocking(sock->fd, False);
94                 if (ret == -1) {
95                         return NT_STATUS_INVALID_PARAMETER;
96                 }
97         }
98
99         ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
100         if (ret == -1) {
101                 return unixdom_error(errno);
102         }
103
104         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
105
106         return NT_STATUS_OK;
107 }
108
109 static NTSTATUS unixdom_listen(struct socket_context *sock,
110                                const char *my_address, int port,
111                                int queue_size, uint32_t flags)
112 {
113         struct sockaddr_un my_addr;
114         int ret;
115
116         if (strlen(my_address)+1 > sizeof(my_addr.sun_path)) {
117                 return NT_STATUS_INVALID_PARAMETER;
118         }
119
120         /* delete if it already exists */
121         unlink(my_address);
122
123         ZERO_STRUCT(my_addr);
124         my_addr.sun_family = AF_UNIX;
125         strncpy(my_addr.sun_path, my_address, sizeof(my_addr.sun_path));
126
127         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
128         if (ret == -1) {
129                 return unixdom_error(errno);
130         }
131
132         ret = listen(sock->fd, queue_size);
133         if (ret == -1) {
134                 return unixdom_error(errno);
135         }
136
137         if (!(flags & SOCKET_FLAG_BLOCK)) {
138                 ret = set_blocking(sock->fd, False);
139                 if (ret == -1) {
140                         return unixdom_error(errno);
141                 }
142         }
143
144         sock->state = SOCKET_STATE_SERVER_LISTEN;
145         sock->private_data = (void *)talloc_strdup(sock, my_address);
146
147         return NT_STATUS_OK;
148 }
149
150 static NTSTATUS unixdom_accept(struct socket_context *sock, 
151                                struct socket_context **new_sock, 
152                                uint32_t flags)
153 {
154         struct sockaddr_un cli_addr;
155         socklen_t cli_addr_len = sizeof(cli_addr);
156         int new_fd;
157
158         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
159         if (new_fd == -1) {
160                 return unixdom_error(errno);
161         }
162
163         (*new_sock) = talloc_p(NULL, struct socket_context);
164         if (!(*new_sock)) {
165                 close(new_fd);
166                 return NT_STATUS_NO_MEMORY;
167         }
168
169         /* copy the socket_context */
170         (*new_sock)->type               = sock->type;
171         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
172         (*new_sock)->flags              = flags;
173
174         (*new_sock)->fd                 = new_fd;
175
176         (*new_sock)->private_data       = NULL;
177         (*new_sock)->ops                = sock->ops;
178
179         return NT_STATUS_OK;
180 }
181
182 static NTSTATUS unixdom_recv(struct socket_context *sock, TALLOC_CTX *mem_ctx,
183                              DATA_BLOB *blob, size_t wantlen, uint32_t flags)
184 {
185         ssize_t gotlen;
186         void *buf;
187         int flgs = 0;
188
189         buf = talloc(mem_ctx, wantlen);
190         if (!buf) {
191                 return NT_STATUS_NO_MEMORY;
192         }
193
194         /* TODO: we need to map all flags here */
195         if (flags & SOCKET_FLAG_PEEK) {
196                 flgs |= MSG_PEEK;
197         }
198
199         if (!(flags & SOCKET_FLAG_BLOCK)) {
200                 flgs |= MSG_DONTWAIT;
201         }
202
203         if (flags & SOCKET_FLAG_BLOCK) {
204                 flgs |= MSG_WAITALL;
205         }
206
207         gotlen = recv(sock->fd, buf, wantlen, flgs);
208         if (gotlen == 0) {
209                 talloc_free(buf);
210                 return NT_STATUS_END_OF_FILE;
211         } else if (gotlen == -1) {
212                 NTSTATUS status = unixdom_error(errno);
213                 talloc_free(buf);
214                 return status;
215         }
216
217         blob->length = gotlen;
218         blob->data = talloc_realloc(mem_ctx, buf, gotlen);
219         if (!blob->data) {
220                 return NT_STATUS_NO_MEMORY;
221         }
222
223         return NT_STATUS_OK;
224 }
225
226 static NTSTATUS unixdom_send(struct socket_context *sock, TALLOC_CTX *mem_ctx,
227                              const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
228 {
229         ssize_t len;
230         int flgs = 0;
231
232         *sendlen = 0;
233
234         /* TODO: we need to map all flags here */
235         if (!(flags & SOCKET_FLAG_BLOCK)) {
236                 flgs |= MSG_DONTWAIT;
237         }
238
239         len = send(sock->fd, blob->data, blob->length, flgs);
240         if (len == -1) {
241                 return unixdom_error(errno);
242         }       
243
244         *sendlen = len;
245
246         return NT_STATUS_OK;
247 }
248
249 static NTSTATUS unixdom_set_option(struct socket_context *sock, 
250                                    const char *option, const char *val)
251 {
252         set_socket_options(sock->fd, option);
253         return NT_STATUS_OK;
254 }
255
256 static char *unixdom_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
257 {
258         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
259 }
260
261 static char *unixdom_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
262 {
263         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
264 }
265
266 static int unixdom_get_peer_port(struct socket_context *sock)
267 {
268         return 0;
269 }
270
271 static char *unixdom_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
272 {
273         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
274 }
275
276 static int unixdom_get_my_port(struct socket_context *sock)
277 {
278         return 0;
279 }
280
281 static int unixdom_get_fd(struct socket_context *sock)
282 {
283         return sock->fd;
284 }
285
286 static const struct socket_ops unixdom_ops = {
287         .name           = "unix",
288         .type           = SOCKET_TYPE_STREAM,
289
290         .init           = unixdom_init,
291         .connect        = unixdom_connect,
292         .listen         = unixdom_listen,
293         .accept         = unixdom_accept,
294         .recv           = unixdom_recv,
295         .send           = unixdom_send,
296         .close          = unixdom_close,
297
298         .set_option     = unixdom_set_option,
299
300         .get_peer_name  = unixdom_get_peer_name,
301         .get_peer_addr  = unixdom_get_peer_addr,
302         .get_peer_port  = unixdom_get_peer_port,
303         .get_my_addr    = unixdom_get_my_addr,
304         .get_my_port    = unixdom_get_my_port,
305
306         .get_fd         = unixdom_get_fd
307 };
308
309 const struct socket_ops *socket_unixdom_ops(void)
310 {
311         return &unixdom_ops;
312 }
313
314 NTSTATUS socket_unixdom_init(void)
315 {
316         return NT_STATUS_OK;
317 }