summaryrefslogtreecommitdiff
path: root/source4/lib/socket/socket_ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/socket/socket_ipv6.c')
-rw-r--r--source4/lib/socket/socket_ipv6.c102
1 files changed, 99 insertions, 3 deletions
diff --git a/source4/lib/socket/socket_ipv6.c b/source4/lib/socket/socket_ipv6.c
index 538420f568..2ea04d9661 100644
--- a/source4/lib/socket/socket_ipv6.c
+++ b/source4/lib/socket/socket_ipv6.c
@@ -190,6 +190,11 @@ static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_conte
struct sockaddr_in cli_addr;
socklen_t cli_addr_len = sizeof(cli_addr);
int new_fd;
+
+ if (sock->type != SOCKET_TYPE_STREAM) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
if (new_fd == -1) {
@@ -249,6 +254,62 @@ static NTSTATUS ipv6_tcp_recv(struct socket_context *sock, void *buf,
return NT_STATUS_OK;
}
+static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf,
+ size_t wantlen, size_t *nread,
+ TALLOC_CTX *addr_ctx, struct socket_address **_src)
+{
+ ssize_t gotlen;
+ struct sockaddr_in6 *from_addr;
+ socklen_t from_len = sizeof(*from_addr);
+ struct socket_address *src;
+ struct hostent *he;
+
+ src = talloc(addr_ctx, struct socket_address);
+ if (!src) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ src->family = sock->backend_name;
+
+ from_addr = talloc(src, struct sockaddr_in6);
+ if (!from_addr) {
+ talloc_free(src);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ src->sockaddr = (struct sockaddr *)from_addr;
+
+ *nread = 0;
+
+ gotlen = recvfrom(sock->fd, buf, wantlen, 0,
+ src->sockaddr, &from_len);
+ if (gotlen == 0) {
+ talloc_free(src);
+ return NT_STATUS_END_OF_FILE;
+ } else if (gotlen == -1) {
+ talloc_free(src);
+ return map_nt_error_from_unix(errno);
+ }
+
+ src->sockaddrlen = from_len;
+
+ he = gethostbyaddr((void *)&from_addr->sin6_addr, sizeof(from_addr->sin6_addr), AF_INET6);
+ if (he == NULL) {
+ talloc_free(src);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ src->addr = talloc_strdup(src, he->h_name);
+ if (src->addr == NULL) {
+ talloc_free(src);
+ return NT_STATUS_NO_MEMORY;
+ }
+ src->port = ntohs(from_addr->sin6_port);
+
+ *nread = gotlen;
+ *_src = src;
+ return NT_STATUS_OK;
+}
+
static NTSTATUS ipv6_tcp_send(struct socket_context *sock,
const DATA_BLOB *blob, size_t *sendlen)
{
@@ -266,6 +327,42 @@ static NTSTATUS ipv6_tcp_send(struct socket_context *sock,
return NT_STATUS_OK;
}
+static NTSTATUS ipv6_sendto(struct socket_context *sock,
+ const DATA_BLOB *blob, size_t *sendlen,
+ const struct socket_address *dest_addr)
+{
+ ssize_t len;
+
+ if (dest_addr->sockaddr) {
+ len = sendto(sock->fd, blob->data, blob->length, 0,
+ dest_addr->sockaddr, dest_addr->sockaddrlen);
+ } else {
+ struct sockaddr_in6 srv_addr;
+ struct in6_addr addr;
+
+ ZERO_STRUCT(srv_addr);
+ addr = interpret_addr6(dest_addr->addr);
+ if (addr.s6_addr == 0) {
+ return NT_STATUS_HOST_UNREACHABLE;
+ }
+ srv_addr.sin6_addr = addr;
+ srv_addr.sin6_port = htons(dest_addr->port);
+ srv_addr.sin6_family = PF_INET6;
+
+ *sendlen = 0;
+
+ len = sendto(sock->fd, blob->data, blob->length, 0,
+ (struct sockaddr *)&srv_addr, sizeof(srv_addr));
+ }
+ if (len == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ *sendlen = len;
+
+ return NT_STATUS_OK;
+}
+
static NTSTATUS ipv6_tcp_set_option(struct socket_context *sock, const char *option, const char *val)
{
set_socket_options(sock->fd, option);
@@ -410,6 +507,8 @@ static const struct socket_ops ipv6_tcp_ops = {
.fn_listen = ipv6_tcp_listen,
.fn_accept = ipv6_tcp_accept,
.fn_recv = ipv6_tcp_recv,
+ .fn_recvfrom = ipv6_recvfrom,
+ .fn_sendto = ipv6_sendto,
.fn_send = ipv6_tcp_send,
.fn_close = ipv6_tcp_close,
.fn_pending = ipv6_pending,
@@ -425,8 +524,5 @@ static const struct socket_ops ipv6_tcp_ops = {
const struct socket_ops *socket_ipv6_ops(enum socket_type type)
{
- if (type != SOCKET_TYPE_STREAM) {
- return NULL;
- }
return &ipv6_tcp_ops;
}