From b366e59c87aa03c0a9c63625a4df922ac70abc94 Mon Sep 17 00:00:00 2001
From: Oleg Hahm <oleg@hobbykeller.org>
Date: Wed, 2 Dec 2015 14:20:44 +0100
Subject: [PATCH] conn: add function to find the best source address

...and use it in POSIX sendto() function.
---
 sys/include/net/conn.h            | 14 ++++++++++++++
 sys/net/gnrc/conn/gnrc_conn.c     |  8 ++++++++
 sys/posix/sockets/posix_sockets.c | 14 ++++++++++----
 3 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/sys/include/net/conn.h b/sys/include/net/conn.h
index bd03991973..8e5a45a776 100644
--- a/sys/include/net/conn.h
+++ b/sys/include/net/conn.h
@@ -31,6 +31,7 @@
  * @brief   Application connection API definitions
  *
  * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ * @author  Oliver Hahm <oliver.hahm@inria.fr>
  */
 #ifndef NET_CONN_H_
 #define NET_CONN_H_
@@ -38,11 +39,24 @@
 #include "net/conn/ip.h"
 #include "net/conn/tcp.h"
 #include "net/conn/udp.h"
+#include "net/ipv6/addr.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/**
+ * @brief   Find the best matching source address for a given prefix
+ *
+ * @param[in] dst   Pointer to the IPv6 address to find a match for
+ *                  Must not be NULL
+ *
+ * @return NULL if no matching address on any interface could be found
+ * @return pointer to an IPv6 address configured on an interface with the best
+ *         match to @p dst
+ */
+ipv6_addr_t *conn_find_best_source(const ipv6_addr_t *dst);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sys/net/gnrc/conn/gnrc_conn.c b/sys/net/gnrc/conn/gnrc_conn.c
index 9a835965bb..80fe1c9481 100644
--- a/sys/net/gnrc/conn/gnrc_conn.c
+++ b/sys/net/gnrc/conn/gnrc_conn.c
@@ -11,6 +11,7 @@
  *
  * @file
  * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ * @author  Oliver Hahm <oliver.hahm@inria.fr>
  */
 
 #include "net/conn.h"
@@ -85,6 +86,13 @@ bool gnrc_conn6_set_local_addr(uint8_t *conn_addr, const ipv6_addr_t *addr)
     }
     return true;
 }
+
+ipv6_addr_t *conn_find_best_source(const ipv6_addr_t *dst)
+{
+    ipv6_addr_t *local = NULL;
+    gnrc_ipv6_netif_find_by_prefix(&local, dst);
+    return local;
+}
 #endif
 
 /** @} */
diff --git a/sys/posix/sockets/posix_sockets.c b/sys/posix/sockets/posix_sockets.c
index 623283e636..d01466dc90 100644
--- a/sys/posix/sockets/posix_sockets.c
+++ b/sys/posix/sockets/posix_sockets.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Freie Universität Berlin
+ * Copyright (C) 2015 INRIA
  *
  * This file is subject to the terms and conditions of the GNU Lesser
  * General Public License v2.1. See the file LICENSE in the top level
@@ -11,6 +12,7 @@
  * @file
  * @brief   Providing implementation for POSIX socket wrapper.
  * @author  Martine Lenders <mlenders@inf.fu-berlin.de>
+ * @author  Oliver Hahm <oliver.hahm@inria.fr>
  * @todo
  */
 
@@ -862,11 +864,15 @@ ssize_t sendto(int socket, const void *buffer, size_t length, int flags,
                                       sport, byteorder_ntohs(port));
             }
             else if (address != NULL) {
-                ipv6_addr_t local;
+                ipv6_addr_t unspec;
+                ipv6_addr_t *best_match;
                 s->src_port = (uint16_t)genrand_uint32_range(1LU << 10U, 1LU << 16U);
-                /* implicitly bind the socket here */
-                ipv6_addr_set_unspecified(&local);
-                if ((res = conn_udp_create(&s->conn.udp, &local, sizeof(local),
+                /* find the best matching source address */
+                if ((best_match = conn_find_best_source(addr)) == NULL) {
+                    ipv6_addr_set_unspecified(&unspec);
+                    best_match = &unspec;
+                }
+                if ((res = conn_udp_create(&s->conn.udp, best_match, sizeof(unspec),
                                            s->domain, s->src_port)) < 0) {
                     errno = -res;
                     return -1;
-- 
GitLab