90f289a1e0952262e9adbeab9f33791c88c450f8
[kai/samba-autobuild/.git] / source4 / lib / socket / socket_ipv4.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Socket IPv4 functions
4    Copyright (C) Stefan Metzmacher 2004
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 static NTSTATUS ipv4_tcp_init(struct socket_context *sock)
24 {
25         sock->fd = socket(PF_INET, SOCK_STREAM, 0);
26         if (sock->fd == -1) {
27                 /* TODO: we need to map from errno to NTSTATUS here! */ 
28                 return NT_STATUS_FOOBAR;
29         }
30
31         return NT_STATUS_OK;
32 }
33
34 static void ipv4_tcp_close(struct socket_context *sock)
35 {
36         close(sock->fd);
37 }
38
39 static NTSTATUS ipv4_tcp_connect(struct socket_context *sock,
40                                         const char *my_address, int my_port,
41                                         const char *srv_address, int srv_port,
42                                         uint32_t flags)
43 {
44         struct sockaddr_in my_addr;
45         struct sockaddr_in srv_addr;
46         struct in_addr my_ip;
47         struct in_addr srv_ip;
48         int ret;
49
50         ret = inet_aton(my_address, &my_ip);
51         if (ret == 0) {
52                 /* not a valid ipv4 address */
53                 return NT_STATUS_FOOBAR;
54         }
55
56         ZERO_STRUCT(my_addr);
57 #ifdef HAVE_SOCK_SIN_LEN
58         my_addr.sin_len         = sizeof(my_addr);
59 #endif
60         my_addr.sin_addr        = my_ip;
61         my_addr.sin_port        = htons(my_port);
62         my_addr.sin_family      = PF_INET;
63
64         ret = inet_aton(srv_address, &srv_ip);
65         if (ret == 0) {
66                 /* not a valid ipv4 address */
67                 return NT_STATUS_FOOBAR;
68         }
69
70         ret = bind(sock->fd, &my_addr, sizeof(my_addr));
71         if (ret == -1) {
72                 /* TODO: we need to map from errno to NTSTATUS here! */
73                 return NT_STATUS_FOOBAR;
74         }
75
76         ZERO_STRUCT(srv_addr);
77 #ifdef HAVE_SOCK_SIN_LEN
78         srv_addr.sin_len        = sizeof(srv_addr);
79 #endif
80         srv_addr.sin_addr       = srv_ip;
81         srv_addr.sin_port       = htons(srv_port);
82         srv_addr.sin_family     = PF_INET;
83
84         if (!(flags & SOCKET_OPTION_BLOCK)) {
85                 ret = set_blocking(sock->fd, False);
86                 if (ret == -1) {
87                         /* TODO: we need to map from errno to NTSTATUS here! */
88                         return NT_STATUS_FOOBAR;
89                 }
90         }
91
92
93         ret = connect(sock->fd, &srv_addr, sizeof(srv_addr));
94         if (ret == -1) {
95                 /* TODO: we need to map from errno to NTSTATUS here! */
96                 return NT_STATUS_FOOBAR;
97         }
98
99         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
100
101         return NT_STATUS_OK;
102 }
103
104 static NTSTATUS ipv4_tcp_listen(struct socket_context *sock,
105                                         const char *my_address, int port,
106                                         int queue_size, uint32_t flags)
107 {
108         struct sockaddr_in my_addr;
109         struct in_addr ip_addr;
110         int ret;
111
112         ZERO_STRUCT(my_addr);
113
114         ret = inet_aton(my_address, &ip_addr);
115         if (ret == 0) {
116                 /* not a valid ipv4 address */
117                 return NT_STATUS_FOOBAR;
118         }
119
120 #ifdef HAVE_SOCK_SIN_LEN
121         my_addr.sin_len         = sizeof(my_addr);
122 #endif
123         my_addr.sin_addr        = ip_addr;
124         my_addr.sin_port        = htons(port);
125         my_addr.sin_family      = PF_INET;
126
127         ret = bind(sock->fd, &my_addr, sizeof(my_addr));
128         if (ret == -1) {
129                 /* TODO: we need to map from errno to NTSTATUS here! */
130                 return NT_STATUS_FOOBAR;
131         }
132
133         ret = listen(sock->fd, queue_size);
134         if (ret == -1) {
135                 /* TODO: we need to map from errno to NTSTATUS here! */
136                 return NT_STATUS_FOOBAR;
137         }
138
139         return NT_STATUS_NOT_IMPLEMENTED;
140 }
141
142 static NTSTATUS ipv4_tcp_accept(struct socket_context *sock, struct socket_context **new_sock, uint32_t flags)
143 {
144         struct sockaddr_in cli_addr;
145         socklen_t cli_addr_len = 0;
146         int new_fd;
147         int ret;
148
149         new_fd = accept(sock->fd, &cli_addr, &cli_addr_len);
150         if (new_fd == -1) {
151                 /* TODO: we need to map from errno to NTSTATUS here! */
152                 return NT_STATUS_FOOBAR;
153         }
154
155         if (!(flags & SOCKET_OPTION_BLOCK)) {
156                 ret = set_blocking(sock->fd, False);
157                 if (ret == -1) {
158                         /* TODO: we need to map from errno to NTSTATUS here! */
159                         return NT_STATUS_FOOBAR;
160                 }
161         }
162
163         /* TODO: we could add a 'accept_check' hook here
164          *       which get the black/white lists via socket_set_accept_filter()
165          *       or something like that
166          *       --metze
167          */
168
169         (*new_sock) = talloc_p(NULL, struct socket_context);
170         if (!(*new_sock)) {
171                 return NT_STATUS_NO_MEMORY;
172         }
173
174         /* copy the socket_context */
175         (*new_sock)->type               = sock->type;
176         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
177         (*new_sock)->flags              = flags;
178
179         (*new_sock)->fd                 = new_fd;
180
181         (*new_sock)->private_data       = NULL;
182         (*new_sock)->ops                = sock->ops;
183
184         return NT_STATUS_NOT_IMPLEMENTED;
185 }
186
187 static NTSTATUS ipv4_tcp_recv(struct socket_context *sock, TALLOC_CTX *mem_ctx,
188                                         DATA_BLOB *blob, size_t wantlen, uint32_t flags)
189 {
190         ssize_t gotlen;
191         void *buf;
192         int flgs = 0;
193
194         buf = talloc(mem_ctx, wantlen);
195         if (!buf) {
196                 return NT_STATUS_NO_MEMORY;
197         }
198
199         /* TODO: we need to map the flags here */
200
201         gotlen = recv(sock->fd, buf, wantlen, flgs);
202         if (gotlen == -1) {
203                 talloc_free(buf);
204                 /* TODO: we need to map from errno to NTSTATUS here! */
205                 return NT_STATUS_FOOBAR;
206         }
207
208         blob->length = gotlen;
209         blob->data = buf;
210
211         return NT_STATUS_OK;
212 }
213
214 static NTSTATUS ipv4_tcp_send(struct socket_context *sock, TALLOC_CTX *mem_ctx,
215                                         const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
216 {
217         ssize_t len;
218         int flgs = 0;
219
220         /* TODO: we need to map the flags here */
221
222         len = send(sock->fd, blob->data, blob->length, flgs);
223         if (len == -1) {
224                 /* TODO: we need to map from errno to NTSTATUS here! */
225                 return NT_STATUS_FOOBAR;
226         }       
227
228         *sendlen = len;
229
230         return NT_STATUS_OK;
231 }
232
233 static NTSTATUS ipv4_tcp_set_option(struct socket_context *sock, const char *option, const char *val)
234 {
235         return NT_STATUS_NOT_SUPPORTED;
236 }
237
238 static const char *ipv4_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
239 {
240         return NULL;
241 }
242
243 static int ipv4_tcp_get_peer_port(struct socket_context *sock, TALLOC_CTX *mem_ctx)
244 {
245         return -1;
246 }
247
248 static const char *ipv4_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
249 {
250         return NULL;
251 }
252
253 static int ipv4_tcp_get_my_port(struct socket_context *sock, TALLOC_CTX *mem_ctx)
254 {
255         return -1;
256 }
257
258 static int ipv4_tcp_get_fd(struct socket_context *sock, TALLOC_CTX *mem_ctx)
259 {
260         return sock->fd;
261 }
262
263 static const struct socket_ops ipv4_tcp_ops = {
264         .name           = "ipv4",
265         .type           = SOCKET_TYPE_STREAM,
266
267         .init           = ipv4_tcp_init,
268         .connect        = ipv4_tcp_connect,
269         .listen         = ipv4_tcp_listen,
270         .accept         = ipv4_tcp_accept,
271         .recv           = ipv4_tcp_recv,
272         .send           = ipv4_tcp_send,
273         .close          = ipv4_tcp_close,
274
275         .set_option     = ipv4_tcp_set_option,
276
277         .get_peer_addr  = ipv4_tcp_get_peer_addr,
278         .get_peer_port  = ipv4_tcp_get_peer_port,
279         .get_my_addr    = ipv4_tcp_get_my_addr,
280         .get_my_port    = ipv4_tcp_get_my_port,
281
282         .get_fd         = ipv4_tcp_get_fd
283 };
284
285 const struct socket_ops *socket_ipv4_ops(void)
286 {
287         return &ipv4_tcp_ops;
288 }
289
290 NTSTATUS socket_ipv4_init(void)
291 {
292         return NT_STATUS_OK;
293 }