/src/samba/source4/lib/socket/socket.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Socket functions |
4 | | Copyright (C) Andrew Tridgell 1992-1998 |
5 | | Copyright (C) Tim Potter 2000-2001 |
6 | | Copyright (C) Stefan Metzmacher 2004 |
7 | | |
8 | | This program is free software; you can redistribute it and/or modify |
9 | | it under the terms of the GNU General Public License as published by |
10 | | the Free Software Foundation; either version 3 of the License, or |
11 | | (at your option) any later version. |
12 | | |
13 | | This program is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU General Public License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | | */ |
21 | | |
22 | | #include "includes.h" |
23 | | #include "lib/socket/socket.h" |
24 | | #include "system/filesys.h" |
25 | | #include "system/network.h" |
26 | | #include "param/param.h" |
27 | | #include "../lib/tsocket/tsocket.h" |
28 | | #include "lib/util/util_net.h" |
29 | | |
30 | | /* |
31 | | auto-close sockets on free |
32 | | */ |
33 | | static int socket_destructor(struct socket_context *sock) |
34 | 0 | { |
35 | 0 | if (sock->ops->fn_close && |
36 | 0 | !(sock->flags & SOCKET_FLAG_NOCLOSE)) { |
37 | 0 | sock->ops->fn_close(sock); |
38 | 0 | } |
39 | 0 | return 0; |
40 | 0 | } |
41 | | |
42 | | _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev, |
43 | | struct tevent_fd *fde, |
44 | | int fd, |
45 | | void *private_data) |
46 | 0 | { |
47 | | /* this might be the socket_wrapper swrap_close() */ |
48 | 0 | close(fd); |
49 | 0 | } |
50 | | |
51 | | _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops, |
52 | | struct socket_context **new_sock, |
53 | | enum socket_type type, uint32_t flags) |
54 | 0 | { |
55 | 0 | NTSTATUS status; |
56 | |
|
57 | 0 | (*new_sock) = talloc(mem_ctx, struct socket_context); |
58 | 0 | if (!(*new_sock)) { |
59 | 0 | return NT_STATUS_NO_MEMORY; |
60 | 0 | } |
61 | | |
62 | 0 | (*new_sock)->type = type; |
63 | 0 | (*new_sock)->state = SOCKET_STATE_UNDEFINED; |
64 | 0 | (*new_sock)->flags = flags; |
65 | |
|
66 | 0 | (*new_sock)->fd = -1; |
67 | |
|
68 | 0 | (*new_sock)->private_data = NULL; |
69 | 0 | (*new_sock)->ops = ops; |
70 | 0 | (*new_sock)->backend_name = NULL; |
71 | |
|
72 | 0 | status = (*new_sock)->ops->fn_init((*new_sock)); |
73 | 0 | if (!NT_STATUS_IS_OK(status)) { |
74 | 0 | talloc_free(*new_sock); |
75 | 0 | return status; |
76 | 0 | } |
77 | | |
78 | | /* by enabling "testnonblock" mode, all socket receive and |
79 | | send calls on non-blocking sockets will randomly recv/send |
80 | | less data than requested */ |
81 | | |
82 | 0 | if (type == SOCKET_TYPE_STREAM && |
83 | 0 | getenv("SOCKET_TESTNONBLOCK") != NULL) { |
84 | 0 | (*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK; |
85 | 0 | } |
86 | | |
87 | | /* we don't do a connect() on dgram sockets, so need to set |
88 | | non-blocking at socket create time */ |
89 | 0 | if (type == SOCKET_TYPE_DGRAM) { |
90 | 0 | set_blocking(socket_get_fd(*new_sock), false); |
91 | 0 | } |
92 | |
|
93 | 0 | talloc_set_destructor(*new_sock, socket_destructor); |
94 | |
|
95 | 0 | return NT_STATUS_OK; |
96 | 0 | } |
97 | | |
98 | | _PUBLIC_ NTSTATUS socket_create(TALLOC_CTX *mem_ctx, |
99 | | const char *name, enum socket_type type, |
100 | | struct socket_context **new_sock, uint32_t flags) |
101 | 0 | { |
102 | 0 | const struct socket_ops *ops; |
103 | |
|
104 | 0 | ops = socket_getops_byname(name, type); |
105 | 0 | if (!ops) { |
106 | 0 | return NT_STATUS_INVALID_PARAMETER; |
107 | 0 | } |
108 | | |
109 | 0 | return socket_create_with_ops(mem_ctx, ops, new_sock, type, flags); |
110 | 0 | } |
111 | | |
112 | | _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock, |
113 | | const struct socket_address *my_address, |
114 | | const struct socket_address *server_address, |
115 | | uint32_t flags) |
116 | 0 | { |
117 | 0 | if (sock == NULL) { |
118 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
119 | 0 | } |
120 | 0 | if (sock->state != SOCKET_STATE_UNDEFINED) { |
121 | 0 | return NT_STATUS_INVALID_PARAMETER; |
122 | 0 | } |
123 | | |
124 | 0 | if (!sock->ops->fn_connect) { |
125 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
126 | 0 | } |
127 | | |
128 | 0 | return sock->ops->fn_connect(sock, my_address, server_address, flags); |
129 | 0 | } |
130 | | |
131 | | _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags) |
132 | 0 | { |
133 | 0 | if (!sock->ops->fn_connect_complete) { |
134 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
135 | 0 | } |
136 | 0 | return sock->ops->fn_connect_complete(sock, flags); |
137 | 0 | } |
138 | | |
139 | | _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock, |
140 | | const struct socket_address *my_address, |
141 | | int queue_size, uint32_t flags) |
142 | 0 | { |
143 | 0 | if (sock == NULL) { |
144 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
145 | 0 | } |
146 | 0 | if (sock->state != SOCKET_STATE_UNDEFINED) { |
147 | 0 | return NT_STATUS_INVALID_PARAMETER; |
148 | 0 | } |
149 | | |
150 | 0 | if (!sock->ops->fn_listen) { |
151 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
152 | 0 | } |
153 | | |
154 | 0 | return sock->ops->fn_listen(sock, my_address, queue_size, flags); |
155 | 0 | } |
156 | | |
157 | | _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock) |
158 | 0 | { |
159 | 0 | NTSTATUS status; |
160 | |
|
161 | 0 | if (sock == NULL) { |
162 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
163 | 0 | } |
164 | 0 | if (sock->type != SOCKET_TYPE_STREAM) { |
165 | 0 | return NT_STATUS_INVALID_PARAMETER; |
166 | 0 | } |
167 | | |
168 | 0 | if (sock->state != SOCKET_STATE_SERVER_LISTEN) { |
169 | 0 | return NT_STATUS_INVALID_PARAMETER; |
170 | 0 | } |
171 | | |
172 | 0 | if (!sock->ops->fn_accept) { |
173 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
174 | 0 | } |
175 | | |
176 | 0 | status = sock->ops->fn_accept(sock, new_sock); |
177 | |
|
178 | 0 | if (NT_STATUS_IS_OK(status)) { |
179 | 0 | talloc_set_destructor(*new_sock, socket_destructor); |
180 | 0 | (*new_sock)->flags = 0; |
181 | 0 | } |
182 | |
|
183 | 0 | return status; |
184 | 0 | } |
185 | | |
186 | | _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf, |
187 | | size_t wantlen, size_t *nread) |
188 | 0 | { |
189 | 0 | if (sock == NULL) { |
190 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
191 | 0 | } |
192 | 0 | if (sock->state != SOCKET_STATE_CLIENT_CONNECTED && |
193 | 0 | sock->state != SOCKET_STATE_SERVER_CONNECTED && |
194 | 0 | sock->type != SOCKET_TYPE_DGRAM) { |
195 | 0 | return NT_STATUS_INVALID_PARAMETER; |
196 | 0 | } |
197 | | |
198 | 0 | if (!sock->ops->fn_recv) { |
199 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
200 | 0 | } |
201 | | |
202 | 0 | if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) |
203 | 0 | && wantlen > 1) { |
204 | |
|
205 | 0 | if (random() % 10 == 0) { |
206 | 0 | *nread = 0; |
207 | 0 | return STATUS_MORE_ENTRIES; |
208 | 0 | } |
209 | 0 | return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread); |
210 | 0 | } |
211 | 0 | return sock->ops->fn_recv(sock, buf, wantlen, nread); |
212 | 0 | } |
213 | | |
214 | | _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf, |
215 | | size_t wantlen, size_t *nread, |
216 | | TALLOC_CTX *mem_ctx, struct socket_address **src_addr) |
217 | 0 | { |
218 | 0 | if (sock == NULL) { |
219 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
220 | 0 | } |
221 | 0 | if (sock->type != SOCKET_TYPE_DGRAM) { |
222 | 0 | return NT_STATUS_INVALID_PARAMETER; |
223 | 0 | } |
224 | | |
225 | 0 | if (!sock->ops->fn_recvfrom) { |
226 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
227 | 0 | } |
228 | | |
229 | 0 | return sock->ops->fn_recvfrom(sock, buf, wantlen, nread, |
230 | 0 | mem_ctx, src_addr); |
231 | 0 | } |
232 | | |
233 | | _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock, |
234 | | const DATA_BLOB *blob, size_t *sendlen) |
235 | 0 | { |
236 | 0 | if (sock == NULL) { |
237 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
238 | 0 | } |
239 | 0 | if (sock->state != SOCKET_STATE_CLIENT_CONNECTED && |
240 | 0 | sock->state != SOCKET_STATE_SERVER_CONNECTED) { |
241 | 0 | return NT_STATUS_INVALID_PARAMETER; |
242 | 0 | } |
243 | | |
244 | 0 | if (!sock->ops->fn_send) { |
245 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
246 | 0 | } |
247 | | |
248 | 0 | if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) |
249 | 0 | && blob->length > 1) { |
250 | 0 | DATA_BLOB blob2 = *blob; |
251 | 0 | if (random() % 10 == 0) { |
252 | 0 | *sendlen = 0; |
253 | 0 | return STATUS_MORE_ENTRIES; |
254 | 0 | } |
255 | | /* The random size sends are incompatible with TLS and SASL |
256 | | * sockets, which require re-sends to be consistent */ |
257 | 0 | if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) { |
258 | 0 | blob2.length = 1+(random() % blob2.length); |
259 | 0 | } else { |
260 | | /* This is particularly stressful on buggy |
261 | | * LDAP clients, that don't expect on LDAP |
262 | | * packet in many SASL packets */ |
263 | 0 | blob2.length = 1 + blob2.length/2; |
264 | 0 | } |
265 | 0 | return sock->ops->fn_send(sock, &blob2, sendlen); |
266 | 0 | } |
267 | 0 | return sock->ops->fn_send(sock, blob, sendlen); |
268 | 0 | } |
269 | | |
270 | | |
271 | | _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock, |
272 | | const DATA_BLOB *blob, size_t *sendlen, |
273 | | const struct socket_address *dest_addr) |
274 | 0 | { |
275 | 0 | if (sock == NULL) { |
276 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
277 | 0 | } |
278 | 0 | if (sock->type != SOCKET_TYPE_DGRAM) { |
279 | 0 | return NT_STATUS_INVALID_PARAMETER; |
280 | 0 | } |
281 | | |
282 | 0 | if (sock->state == SOCKET_STATE_CLIENT_CONNECTED || |
283 | 0 | sock->state == SOCKET_STATE_SERVER_CONNECTED) { |
284 | 0 | return NT_STATUS_INVALID_PARAMETER; |
285 | 0 | } |
286 | | |
287 | 0 | if (!sock->ops->fn_sendto) { |
288 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
289 | 0 | } |
290 | | |
291 | 0 | return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr); |
292 | 0 | } |
293 | | |
294 | | |
295 | | /* |
296 | | ask for the number of bytes in a pending incoming packet |
297 | | */ |
298 | | _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending) |
299 | 0 | { |
300 | 0 | if (sock == NULL) { |
301 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
302 | 0 | } |
303 | 0 | if (!sock->ops->fn_pending) { |
304 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
305 | 0 | } |
306 | 0 | return sock->ops->fn_pending(sock, npending); |
307 | 0 | } |
308 | | |
309 | | |
310 | | _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val) |
311 | 0 | { |
312 | 0 | if (sock == NULL) { |
313 | 0 | return NT_STATUS_CONNECTION_DISCONNECTED; |
314 | 0 | } |
315 | 0 | if (!sock->ops->fn_set_option) { |
316 | 0 | return NT_STATUS_NOT_IMPLEMENTED; |
317 | 0 | } |
318 | | |
319 | 0 | return sock->ops->fn_set_option(sock, option, val); |
320 | 0 | } |
321 | | |
322 | | _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx) |
323 | 0 | { |
324 | 0 | if (!sock->ops->fn_get_peer_name) { |
325 | 0 | return NULL; |
326 | 0 | } |
327 | | |
328 | 0 | return sock->ops->fn_get_peer_name(sock, mem_ctx); |
329 | 0 | } |
330 | | |
331 | | _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) |
332 | 0 | { |
333 | 0 | if (!sock->ops->fn_get_peer_addr) { |
334 | 0 | return NULL; |
335 | 0 | } |
336 | | |
337 | 0 | return sock->ops->fn_get_peer_addr(sock, mem_ctx); |
338 | 0 | } |
339 | | |
340 | | _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) |
341 | 0 | { |
342 | 0 | if (!sock->ops->fn_get_my_addr) { |
343 | 0 | return NULL; |
344 | 0 | } |
345 | | |
346 | 0 | return sock->ops->fn_get_my_addr(sock, mem_ctx); |
347 | 0 | } |
348 | | |
349 | | _PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx, |
350 | | const struct socket_address *a) |
351 | 0 | { |
352 | 0 | struct tsocket_address *r; |
353 | 0 | int ret; |
354 | |
|
355 | 0 | if (!a) { |
356 | 0 | return NULL; |
357 | 0 | } |
358 | 0 | if (a->sockaddr) { |
359 | 0 | ret = tsocket_address_bsd_from_sockaddr(mem_ctx, |
360 | 0 | a->sockaddr, |
361 | 0 | a->sockaddrlen, |
362 | 0 | &r); |
363 | 0 | } else { |
364 | 0 | ret = tsocket_address_inet_from_strings(mem_ctx, |
365 | 0 | a->family, |
366 | 0 | a->addr, |
367 | 0 | a->port, |
368 | 0 | &r); |
369 | 0 | } |
370 | |
|
371 | 0 | if (ret != 0) { |
372 | 0 | return NULL; |
373 | 0 | } |
374 | | |
375 | 0 | return r; |
376 | 0 | } |
377 | | |
378 | | _PUBLIC_ void socket_address_set_port(struct socket_address *a, |
379 | | uint16_t port) |
380 | 0 | { |
381 | 0 | if (a->sockaddr) { |
382 | 0 | set_sockaddr_port(a->sockaddr, port); |
383 | 0 | } else { |
384 | 0 | a->port = port; |
385 | 0 | } |
386 | |
|
387 | 0 | } |
388 | | |
389 | | _PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx, |
390 | | const struct tsocket_address *a) |
391 | 0 | { |
392 | 0 | ssize_t ret; |
393 | 0 | struct sockaddr_storage ss; |
394 | 0 | size_t sslen = sizeof(ss); |
395 | |
|
396 | 0 | ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen); |
397 | 0 | if (ret < 0) { |
398 | 0 | return NULL; |
399 | 0 | } |
400 | | |
401 | 0 | return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret); |
402 | 0 | } |
403 | | |
404 | | _PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) |
405 | 0 | { |
406 | 0 | struct socket_address *a; |
407 | 0 | struct tsocket_address *r; |
408 | |
|
409 | 0 | a = socket_get_peer_addr(sock, mem_ctx); |
410 | 0 | if (a == NULL) { |
411 | 0 | return NULL; |
412 | 0 | } |
413 | | |
414 | 0 | r = socket_address_to_tsocket_address(mem_ctx, a); |
415 | 0 | talloc_free(a); |
416 | 0 | return r; |
417 | 0 | } |
418 | | |
419 | | _PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) |
420 | 0 | { |
421 | 0 | struct socket_address *a; |
422 | 0 | struct tsocket_address *r; |
423 | |
|
424 | 0 | a = socket_get_my_addr(sock, mem_ctx); |
425 | 0 | if (a == NULL) { |
426 | 0 | return NULL; |
427 | 0 | } |
428 | | |
429 | 0 | r = socket_address_to_tsocket_address(mem_ctx, a); |
430 | 0 | talloc_free(a); |
431 | 0 | return r; |
432 | 0 | } |
433 | | |
434 | | _PUBLIC_ int socket_get_fd(struct socket_context *sock) |
435 | 0 | { |
436 | 0 | if (!sock->ops->fn_get_fd) { |
437 | 0 | return -1; |
438 | 0 | } |
439 | | |
440 | 0 | return sock->ops->fn_get_fd(sock); |
441 | 0 | } |
442 | | |
443 | | /* |
444 | | call dup() on a socket, and close the old fd. This is used to change |
445 | | the fd to the lowest available number, to make select() more |
446 | | efficient (select speed depends on the maximum fd number passed to |
447 | | it) |
448 | | */ |
449 | | _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock) |
450 | 0 | { |
451 | 0 | int fd; |
452 | 0 | if (sock->fd == -1) { |
453 | 0 | return NT_STATUS_INVALID_HANDLE; |
454 | 0 | } |
455 | 0 | fd = dup(sock->fd); |
456 | 0 | if (fd == -1) { |
457 | 0 | return map_nt_error_from_unix_common(errno); |
458 | 0 | } |
459 | 0 | close(sock->fd); |
460 | 0 | sock->fd = fd; |
461 | 0 | return NT_STATUS_OK; |
462 | | |
463 | 0 | } |
464 | | |
465 | | /* Create a new socket_address. The type must match the socket type. |
466 | | * The host parameter may be an IP or a hostname |
467 | | */ |
468 | | |
469 | | _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx, |
470 | | const char *family, |
471 | | const char *host, |
472 | | int port) |
473 | 0 | { |
474 | 0 | struct socket_address *addr = talloc(mem_ctx, struct socket_address); |
475 | 0 | if (!addr) { |
476 | 0 | return NULL; |
477 | 0 | } |
478 | | |
479 | 0 | if (strcmp(family, "ip") == 0 && is_ipaddress_v6(host)) { |
480 | | /* leaving as "ip" would force IPv4 */ |
481 | 0 | family = "ipv6"; |
482 | 0 | } |
483 | |
|
484 | 0 | addr->family = family; |
485 | 0 | addr->addr = talloc_strdup(addr, host); |
486 | 0 | if (!addr->addr) { |
487 | 0 | talloc_free(addr); |
488 | 0 | return NULL; |
489 | 0 | } |
490 | 0 | addr->port = port; |
491 | 0 | addr->sockaddr = NULL; |
492 | 0 | addr->sockaddrlen = 0; |
493 | |
|
494 | 0 | return addr; |
495 | 0 | } |
496 | | |
497 | | /* Create a new socket_address. Copy the struct sockaddr into the new |
498 | | * structure. Used for hooks in the kerberos libraries, where they |
499 | | * supply only a struct sockaddr */ |
500 | | |
501 | | _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx, |
502 | | struct sockaddr *sockaddr, |
503 | | size_t sockaddrlen) |
504 | 0 | { |
505 | 0 | struct socket_address *addr = talloc(mem_ctx, struct socket_address); |
506 | 0 | if (!addr) { |
507 | 0 | return NULL; |
508 | 0 | } |
509 | 0 | switch (sockaddr->sa_family) { |
510 | 0 | case AF_INET: |
511 | 0 | addr->family = "ipv4"; |
512 | 0 | break; |
513 | 0 | #ifdef HAVE_IPV6 |
514 | 0 | case AF_INET6: |
515 | 0 | addr->family = "ipv6"; |
516 | 0 | break; |
517 | 0 | #endif |
518 | 0 | case AF_UNIX: |
519 | 0 | addr->family = "unix"; |
520 | 0 | break; |
521 | 0 | } |
522 | 0 | addr->addr = NULL; |
523 | 0 | addr->port = 0; |
524 | 0 | addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen); |
525 | 0 | if (!addr->sockaddr) { |
526 | 0 | talloc_free(addr); |
527 | 0 | return NULL; |
528 | 0 | } |
529 | 0 | addr->sockaddrlen = sockaddrlen; |
530 | 0 | return addr; |
531 | 0 | } |
532 | | |
533 | | |
534 | | /* |
535 | | Create a new socket_address from sockaddr_storage |
536 | | */ |
537 | | _PUBLIC_ struct socket_address *socket_address_from_sockaddr_storage(TALLOC_CTX *mem_ctx, |
538 | | const struct sockaddr_storage *sockaddr, |
539 | | uint16_t port) |
540 | 0 | { |
541 | 0 | struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address); |
542 | 0 | char addr_str[INET6_ADDRSTRLEN+1]; |
543 | 0 | const char *str; |
544 | |
|
545 | 0 | if (!addr) { |
546 | 0 | return NULL; |
547 | 0 | } |
548 | 0 | addr->port = port; |
549 | 0 | switch (sockaddr->ss_family) { |
550 | 0 | case AF_INET: |
551 | 0 | addr->family = "ipv4"; |
552 | 0 | break; |
553 | 0 | #ifdef HAVE_IPV6 |
554 | 0 | case AF_INET6: |
555 | 0 | addr->family = "ipv6"; |
556 | 0 | break; |
557 | 0 | #endif |
558 | 0 | default: |
559 | 0 | talloc_free(addr); |
560 | 0 | return NULL; |
561 | 0 | } |
562 | | |
563 | 0 | str = print_sockaddr(addr_str, sizeof(addr_str), sockaddr); |
564 | 0 | if (str == NULL) { |
565 | 0 | talloc_free(addr); |
566 | 0 | return NULL; |
567 | 0 | } |
568 | 0 | addr->addr = talloc_strdup(addr, str); |
569 | 0 | if (addr->addr == NULL) { |
570 | 0 | talloc_free(addr); |
571 | 0 | return NULL; |
572 | 0 | } |
573 | | |
574 | 0 | return addr; |
575 | 0 | } |
576 | | |
577 | | /* Copy a socket_address structure */ |
578 | | struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx, |
579 | | const struct socket_address *oaddr) |
580 | 0 | { |
581 | 0 | struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address); |
582 | 0 | if (!addr) { |
583 | 0 | return NULL; |
584 | 0 | } |
585 | 0 | addr->family = oaddr->family; |
586 | 0 | if (oaddr->addr) { |
587 | 0 | addr->addr = talloc_strdup(addr, oaddr->addr); |
588 | 0 | if (!addr->addr) { |
589 | 0 | goto nomem; |
590 | 0 | } |
591 | 0 | } |
592 | 0 | addr->port = oaddr->port; |
593 | 0 | if (oaddr->sockaddr) { |
594 | 0 | addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, |
595 | 0 | oaddr->sockaddr, |
596 | 0 | oaddr->sockaddrlen); |
597 | 0 | if (!addr->sockaddr) { |
598 | 0 | goto nomem; |
599 | 0 | } |
600 | 0 | addr->sockaddrlen = oaddr->sockaddrlen; |
601 | 0 | } |
602 | | |
603 | 0 | return addr; |
604 | | |
605 | 0 | nomem: |
606 | 0 | talloc_free(addr); |
607 | 0 | return NULL; |
608 | 0 | } |
609 | | |
610 | | _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type) |
611 | 0 | { |
612 | 0 | extern const struct socket_ops *socket_ipv4_ops(enum socket_type); |
613 | 0 | extern const struct socket_ops *socket_ipv6_ops(enum socket_type); |
614 | 0 | extern const struct socket_ops *socket_unixdom_ops(enum socket_type); |
615 | |
|
616 | 0 | if (strcmp("ip", family) == 0 || |
617 | 0 | strcmp("ipv4", family) == 0) { |
618 | 0 | return socket_ipv4_ops(type); |
619 | 0 | } |
620 | | |
621 | 0 | #ifdef HAVE_IPV6 |
622 | 0 | if (strcmp("ipv6", family) == 0) { |
623 | 0 | return socket_ipv6_ops(type); |
624 | 0 | } |
625 | 0 | #endif |
626 | | |
627 | 0 | if (strcmp("unix", family) == 0) { |
628 | 0 | return socket_unixdom_ops(type); |
629 | 0 | } |
630 | | |
631 | 0 | return NULL; |
632 | 0 | } |
633 | | |
634 | | /* |
635 | | set some flags on a socket |
636 | | */ |
637 | | void socket_set_flags(struct socket_context *sock, unsigned flags) |
638 | 0 | { |
639 | 0 | sock->flags |= flags; |
640 | 0 | } |