udp (closure => comm closure)
udp: dict argument
- address (string list): IPv6 or IPv4 addresses to listen and send on
- port (integer): UDP port to listen and send on
+ address (string list): IPv6 or IPv4 addresses to listen and send on;
+ default is all local addresses
+ port (integer): UDP port to listen and send on; optional if you
+ don't need to have a stable address for your peers to talk to
+ (in which case your site ought probably to have `local-mobile true').
buffer (buffer closure): buffer for incoming packets
authbind (string): optional, path to authbind-helper program
bool_t udp_make_socket(struct udpcommon *uc, struct udpsock *us,
int failmsgclass);
- /* Fills in us->fd. Logs any errors with lg_[v]perror. */
+ /* Caller should have filled in ->addr. Fills in us->fd,
+ ->experienced; updates ->addr. Logs any errors with lg_[v]perror. */
+bool_t udp_import_socket(struct udpcommon *uc, struct udpsock *us,
+ int failmsgclass, int fd);
+ /* Like udp_make_socket, but caller provides fd. fd is not closed
+ on error */
void udp_destroy_socket(struct udpcommon *uc, struct udpsock *us);
/* Idempotent. No errors are possible. */
#define UDP_APPLY_STANDARD(st,uc,desc) \
(uc)->use_proxy=False; \
(uc)->authbind=dict_read_string(d,"authbind",False,"udp",(uc)->cc.loc); \
- (uc)->port=dict_read_number(d,"port",True,"udp",(uc)->cc.loc,0)
+ (uc)->port=dict_read_number(d,"port",False,"udp",(uc)->cc.loc,0)
/* void UDP_APPLY_STANDARD(SOMETHING *st, struct udpcommon *uc,
* const char *desc);
* // Expects in scope: dict_t *d=...; as from COMM_APPLY_STANDARD
bool_t ok=polypath_make_socket(st,bad,badctx, us,ifname);
if (!ok) goto out;
} else {
- FILLZERO(us->experienced);
- us->fd=fd;
+ bool_t ok=udp_import_socket(uc,us,M_WARNING,fd);
+ if (!ok) goto out;
fd=-1;
}
interf->socks.n_socks++;
+ lg_perror(LG,M_INFO,0,"using %s %s",ifname,
+ iaddr_to_string(&us->addr));
us=0; /* do not destroy this socket during `out' */
- lg_perror(LG,M_INFO,0,"using %s %s",ifname,ifaddr);
} else {
int i;
for (i=0; i<interf->socks.n_socks; i++)
- if (!memcmp(&interf->socks.socks[i].addr,ia,sizeof(*ia)))
+ if (iaddr_equal(&interf->socks.socks[i].addr,ia,True))
goto address_remove_found;
BAD("address to remove not found");
address_remove_found:
- lg_perror(LG,M_INFO,0,"removed %s %s",ifname,ifaddr);
+ lg_perror(LG,M_INFO,0,"removed %s %s",ifname,
+ iaddr_to_string(&interf->socks.socks[i].addr));
udp_destroy_socket(&st->uc,&interf->socks.socks[i]);
interf->socks.socks[i]=
interf->socks.socks[--interf->socks.n_socks];
comm_addr_to_string_fn *addr_to_string;
};
-bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib);
+bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib,
+ bool_t ignoreport);
static inline const char *comm_addr_to_string(const struct comm_addr *ca)
{
static inline bool_t comm_addr_equal(const struct comm_addr *a,
const struct comm_addr *b)
{
- return a->comm==b->comm && iaddr_equal(&a->ia,&b->ia);
+ return a->comm==b->comm && iaddr_equal(&a->ia,&b->ia,False);
}
/* LOG interface */
/* Check that the packet came from our poxy server;
we shouldn't be contacted directly by anybody else
(since they can trivially forge source addresses) */
- if (!iaddr_equal(&from,&uc->proxy)) {
+ if (!iaddr_equal(&from,&uc->proxy,False)) {
Message(M_INFO,"udp: received packet that's not "
"from the proxy\n");
BUF_FREE(cc->rbuf);
}
}
+#define FAIL_LG 0, cc->cl.description, &cc->loc, failmsgclass
+#define FAIL(...) do{ \
+ lg_perror(FAIL_LG,errno,__VA_ARGS__); \
+ goto failed; \
+ }while(0)
+
+static bool_t record_socket_gotaddr(struct udpcommon *uc, struct udpsock *us,
+ int failmsgclass)
+{
+ struct commcommon *cc=&uc->cc;
+ socklen_t salen=sizeof(us->addr);
+ int r=getsockname(us->fd,&us->addr.sa,&salen);
+ if (r) FAIL("getsockname()");
+ if (salen>sizeof(us->addr)) { errno=0; FAIL("getsockname() length"); }
+ return True;
+
+ failed:
+ return False;
+}
+
+bool_t udp_import_socket(struct udpcommon *uc, struct udpsock *us,
+ int failmsgclass, int fd)
+{
+ FILLZERO(us->experienced);
+ us->fd=fd;
+ return record_socket_gotaddr(uc,us,failmsgclass);
+}
+
bool_t udp_make_socket(struct udpcommon *uc, struct udpsock *us,
int failmsgclass)
{
struct commcommon *cc=&uc->cc;
us->fd=-1;
-#define FAIL_LG 0, cc->cl.description, &cc->loc, failmsgclass
-#define FAIL(...) do{ \
- lg_perror(FAIL_LG,errno,__VA_ARGS__); \
- goto failed; \
- }while(0)
-
FILLZERO(us->experienced);
us->fd=socket(addr->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
if (us->fd<0) FAIL("socket");
if (bind(us->fd, &addr->sa, iaddr_socklen(addr))!=0)
FAIL("bind (%s)",iaddr_to_string(addr));
}
+
+ bool_t ok=record_socket_gotaddr(uc,us,failmsgclass);
+ if (!ok) goto failed;
+
return True;
failed:
udp_destroy_socket(uc,us);
return False;
+}
#undef FAIL
-}
void udp_socks_register(struct udpcommon *uc, struct udpsocks *socks)
{
return bufs[b];
}
-bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib)
+bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib,
+ bool_t ignoreport)
{
if (ia->sa.sa_family != ib->sa.sa_family)
return 0;
switch (ia->sa.sa_family) {
case AF_INET:
return ia->sin.sin_addr.s_addr == ib->sin.sin_addr.s_addr
- && ia->sin.sin_port == ib->sin.sin_port;
+ && (ignoreport ||
+ ia->sin.sin_port == ib->sin.sin_port);
#ifdef CONFIG_IPV6
case AF_INET6:
return !memcmp(&ia->sin6.sin6_addr, &ib->sin6.sin6_addr, 16)
- && ia->sin6.sin6_scope_id == ib->sin6.sin6_scope_id
- && ia->sin6.sin6_port == ib->sin6.sin6_port
+ && ia->sin6.sin6_scope_id == ib->sin6.sin6_scope_id
+ && (ignoreport ||
+ ia->sin6.sin6_port == ib->sin6.sin6_port)
/* we ignore the flowinfo field */;
#endif /* CONFIG_IPV6 */
default: