|
@@ -904,6 +904,88 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m,
|
|
|
return rc ? rc : dlen;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tipc_send_group_anycast - send message to any member with given identity
|
|
|
+ * @sock: socket structure
|
|
|
+ * @m: message to send
|
|
|
+ * @dlen: total length of message data
|
|
|
+ * @timeout: timeout to wait for wakeup
|
|
|
+ *
|
|
|
+ * Called from function tipc_sendmsg(), which has done all sanity checks
|
|
|
+ * Returns the number of bytes sent on success, or errno
|
|
|
+ */
|
|
|
+static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,
|
|
|
+ int dlen, long timeout)
|
|
|
+{
|
|
|
+ DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
|
|
|
+ struct sock *sk = sock->sk;
|
|
|
+ struct tipc_sock *tsk = tipc_sk(sk);
|
|
|
+ struct list_head *cong_links = &tsk->cong_links;
|
|
|
+ int blks = tsk_blocks(GROUP_H_SIZE + dlen);
|
|
|
+ struct tipc_group *grp = tsk->group;
|
|
|
+ struct tipc_member *first = NULL;
|
|
|
+ struct tipc_member *mbr = NULL;
|
|
|
+ struct net *net = sock_net(sk);
|
|
|
+ u32 node, port, exclude;
|
|
|
+ u32 type, inst, domain;
|
|
|
+ struct list_head dsts;
|
|
|
+ int lookups = 0;
|
|
|
+ int dstcnt, rc;
|
|
|
+ bool cong;
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&dsts);
|
|
|
+
|
|
|
+ type = dest->addr.name.name.type;
|
|
|
+ inst = dest->addr.name.name.instance;
|
|
|
+ domain = addr_domain(net, dest->scope);
|
|
|
+ exclude = tipc_group_exclude(grp);
|
|
|
+
|
|
|
+ while (++lookups < 4) {
|
|
|
+ first = NULL;
|
|
|
+
|
|
|
+ /* Look for a non-congested destination member, if any */
|
|
|
+ while (1) {
|
|
|
+ if (!tipc_nametbl_lookup(net, type, inst, domain, &dsts,
|
|
|
+ &dstcnt, exclude, false))
|
|
|
+ return -EHOSTUNREACH;
|
|
|
+ tipc_dest_pop(&dsts, &node, &port);
|
|
|
+ cong = tipc_group_cong(grp, node, port, blks, &mbr);
|
|
|
+ if (!cong)
|
|
|
+ break;
|
|
|
+ if (mbr == first)
|
|
|
+ break;
|
|
|
+ if (!first)
|
|
|
+ first = mbr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Start over if destination was not in member list */
|
|
|
+ if (unlikely(!mbr))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (likely(!cong && !tipc_dest_find(cong_links, node, 0)))
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* Block or return if destination link or member is congested */
|
|
|
+ rc = tipc_wait_for_cond(sock, &timeout,
|
|
|
+ !tipc_dest_find(cong_links, node, 0) &&
|
|
|
+ !tipc_group_cong(grp, node, port,
|
|
|
+ blks, &mbr));
|
|
|
+ if (unlikely(rc))
|
|
|
+ return rc;
|
|
|
+
|
|
|
+ /* Send, unless destination disappeared while waiting */
|
|
|
+ if (likely(mbr))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (unlikely(lookups >= 4))
|
|
|
+ return -EHOSTUNREACH;
|
|
|
+
|
|
|
+ rc = tipc_send_group_msg(net, tsk, m, mbr, node, port, dlen);
|
|
|
+
|
|
|
+ return rc ? rc : dlen;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* tipc_send_group_bcast - send message to all members in communication group
|
|
|
* @sk: socket structure
|
|
@@ -1127,6 +1209,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
|
|
|
if (grp) {
|
|
|
if (!dest)
|
|
|
return tipc_send_group_bcast(sock, m, dlen, timeout);
|
|
|
+ if (dest->addrtype == TIPC_ADDR_NAME)
|
|
|
+ return tipc_send_group_anycast(sock, m, dlen, timeout);
|
|
|
if (dest->addrtype == TIPC_ADDR_ID)
|
|
|
return tipc_send_group_unicast(sock, m, dlen, timeout);
|
|
|
return -EINVAL;
|