r5298: - got rid of pstring.h from includes.h. This at least makes it a bit
[bbaumbach/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-2005
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 #include "system/network.h"
26 #include "system/filesys.h"
27
28
29
30 /*
31   approximate errno mapping
32 */
33 static NTSTATUS unixdom_error(int ernum)
34 {
35         return map_nt_error_from_unix(ernum);
36 }
37
38 static NTSTATUS unixdom_init(struct socket_context *sock)
39 {
40         sock->fd = socket(PF_UNIX, SOCK_STREAM, 0);
41         if (sock->fd == -1) {
42                 return NT_STATUS_INSUFFICIENT_RESOURCES;
43         }
44         sock->private_data = NULL;
45
46         return NT_STATUS_OK;
47 }
48
49 static void unixdom_close(struct socket_context *sock)
50 {
51         close(sock->fd);
52 }
53
54 static NTSTATUS unixdom_connect_complete(struct socket_context *sock, uint32_t flags)
55 {
56         int error=0, ret;
57         socklen_t len = sizeof(error);
58
59         /* check for any errors that may have occurred - this is needed
60            for non-blocking connect */
61         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
62         if (ret == -1) {
63                 return map_nt_error_from_unix(errno);
64         }
65         if (error != 0) {
66                 return map_nt_error_from_unix(error);
67         }
68
69         if (!(flags & SOCKET_FLAG_BLOCK)) {
70                 ret = set_blocking(sock->fd, False);
71                 if (ret == -1) {
72                         return map_nt_error_from_unix(errno);
73                 }
74         }
75
76         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
77
78         return NT_STATUS_OK;
79 }
80
81 static NTSTATUS unixdom_connect(struct socket_context *sock,
82                                 const char *my_address, int my_port,
83                                 const char *srv_address, int srv_port,
84                                 uint32_t flags)
85 {
86         struct sockaddr_un srv_addr;
87         int ret;
88
89         if (strlen(srv_address)+1 > sizeof(srv_addr.sun_path)) {
90                 return NT_STATUS_INVALID_PARAMETER;
91         }
92
93         ZERO_STRUCT(srv_addr);
94         srv_addr.sun_family = AF_UNIX;
95         strncpy(srv_addr.sun_path, srv_address, sizeof(srv_addr.sun_path));
96
97         ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
98         if (ret == -1) {
99                 return unixdom_error(errno);
100         }
101
102         return unixdom_connect_complete(sock, flags);
103 }
104
105 static NTSTATUS unixdom_listen(struct socket_context *sock,
106                                const char *my_address, int port,
107                                int queue_size, uint32_t flags)
108 {
109         struct sockaddr_un my_addr;
110         int ret;
111
112         if (strlen(my_address)+1 > sizeof(my_addr.sun_path)) {
113                 return NT_STATUS_INVALID_PARAMETER;
114         }
115
116         /* delete if it already exists */
117         unlink(my_address);
118
119         ZERO_STRUCT(my_addr);
120         my_addr.sun_family = AF_UNIX;
121         strncpy(my_addr.sun_path, my_address, sizeof(my_addr.sun_path));
122
123         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
124         if (ret == -1) {
125                 return unixdom_error(errno);
126         }
127
128         ret = listen(sock->fd, queue_size);
129         if (ret == -1) {
130                 return unixdom_error(errno);
131         }
132
133         if (!(flags & SOCKET_FLAG_BLOCK)) {
134                 ret = set_blocking(sock->fd, False);
135                 if (ret == -1) {
136                         return unixdom_error(errno);
137                 }
138         }
139
140         sock->state = SOCKET_STATE_SERVER_LISTEN;
141         sock->private_data = (void *)talloc_strdup(sock, my_address);
142
143         return NT_STATUS_OK;
144 }
145
146 static NTSTATUS unixdom_accept(struct socket_context *sock, 
147                                struct socket_context **new_sock)
148 {
149         struct sockaddr_un cli_addr;
150         socklen_t cli_addr_len = sizeof(cli_addr);
151         int new_fd;
152
153         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
154         if (new_fd == -1) {
155                 return unixdom_error(errno);
156         }
157
158         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
159                 int ret = set_blocking(new_fd, False);
160                 if (ret == -1) {
161                         close(new_fd);
162                         return map_nt_error_from_unix(errno);
163                 }
164         }
165
166         (*new_sock) = talloc(NULL, struct socket_context);
167         if (!(*new_sock)) {
168                 close(new_fd);
169                 return NT_STATUS_NO_MEMORY;
170         }
171
172         /* copy the socket_context */
173         (*new_sock)->type               = sock->type;
174         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
175         (*new_sock)->flags              = sock->flags;
176
177         (*new_sock)->fd                 = new_fd;
178
179         (*new_sock)->private_data       = NULL;
180         (*new_sock)->ops                = sock->ops;
181
182         return NT_STATUS_OK;
183 }
184
185 static NTSTATUS unixdom_recv(struct socket_context *sock, void *buf, 
186                              size_t wantlen, size_t *nread, uint32_t flags)
187 {
188         ssize_t gotlen;
189         int flgs = 0;
190
191         /* TODO: we need to map all flags here */
192         if (flags & SOCKET_FLAG_PEEK) {
193                 flgs |= MSG_PEEK;
194         }
195
196         if (flags & SOCKET_FLAG_BLOCK) {
197                 flgs |= MSG_WAITALL;
198         }
199
200         *nread = 0;
201
202         gotlen = recv(sock->fd, buf, wantlen, flgs);
203         if (gotlen == 0) {
204                 return NT_STATUS_END_OF_FILE;
205         } else if (gotlen == -1) {
206                 return unixdom_error(errno);
207         }
208
209         *nread = gotlen;
210
211         return NT_STATUS_OK;
212 }
213
214 static NTSTATUS unixdom_send(struct socket_context *sock,
215                              const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
216 {
217         ssize_t len;
218         int flgs = 0;
219
220         *sendlen = 0;
221
222         len = send(sock->fd, blob->data, blob->length, flgs);
223         if (len == -1) {
224                 return unixdom_error(errno);
225         }       
226
227         *sendlen = len;
228
229         return NT_STATUS_OK;
230 }
231
232 static NTSTATUS unixdom_set_option(struct socket_context *sock, 
233                                    const char *option, const char *val)
234 {
235         return NT_STATUS_OK;
236 }
237
238 static char *unixdom_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
239 {
240         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
241 }
242
243 static char *unixdom_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
244 {
245         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
246 }
247
248 static int unixdom_get_peer_port(struct socket_context *sock)
249 {
250         return 0;
251 }
252
253 static char *unixdom_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
254 {
255         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
256 }
257
258 static int unixdom_get_my_port(struct socket_context *sock)
259 {
260         return 0;
261 }
262
263 static int unixdom_get_fd(struct socket_context *sock)
264 {
265         return sock->fd;
266 }
267
268 static const struct socket_ops unixdom_ops = {
269         .name                   = "unix",
270         .fn_init                = unixdom_init,
271         .fn_connect             = unixdom_connect,
272         .fn_connect_complete    = unixdom_connect_complete,
273         .fn_listen              = unixdom_listen,
274         .fn_accept              = unixdom_accept,
275         .fn_recv                = unixdom_recv,
276         .fn_send                = unixdom_send,
277         .fn_close               = unixdom_close,
278
279         .fn_set_option          = unixdom_set_option,
280
281         .fn_get_peer_name       = unixdom_get_peer_name,
282         .fn_get_peer_addr       = unixdom_get_peer_addr,
283         .fn_get_peer_port       = unixdom_get_peer_port,
284         .fn_get_my_addr         = unixdom_get_my_addr,
285         .fn_get_my_port         = unixdom_get_my_port,
286
287         .fn_get_fd              = unixdom_get_fd
288 };
289
290 const struct socket_ops *socket_unixdom_ops(enum socket_type type)
291 {
292         if (type != SOCKET_TYPE_STREAM) {
293                 return NULL;
294         }
295         return &unixdom_ops;
296 }