[v2,14/15] unix: Add a method for choosing sender of packet in promiscous DGRAM queue

Submitted by Kirill Tkhai on May 27, 2016, 1:07 p.m.

Details

Message ID 146435447428.31234.17287479870386190431.stgit@pro
State Rejected
Series "Support for packet's msg_name in receive queue of promiscous DGRAM sockets"
Headers show

Commit Message

Kirill Tkhai May 27, 2016, 1:07 p.m.
Iterate over foreign sockets and find the right one to restore a packet.
This allows to restore promiscous DGRAM queue with correct msg_names.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/sk-unix.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

Patch hide | download patch | download mbox

diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index c14c8c4..a154367 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -927,6 +927,78 @@  static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd)
 	return 0;
 }
 
+static int unix_get_fd(struct sk_fd **sks, SkPacketEntry *pkt)
+{
+	struct unix_sk_info *send;
+	socklen_t addrlen;
+	int i;
+
+	if (!pkt->has_sender_ino)
+		return -1;
+
+	send = find_unix_sk_by_ino(pkt->sender_ino);
+	if (!send) {
+		pr_err("Can't find socket with ino=%d\n", pkt->sender_ino);
+		return -1;
+	}
+
+	for (i = 0; sks[i]; i++) {
+		addrlen = sks[i]->addrlen - offsetof(struct sockaddr_un, sun_path);
+
+		if (addrlen == send->ue->name.len &&
+		    memcmp(&sks[i]->addr->sa_data, send->ue->name.data, addrlen) == 0) {
+			return sks[i]->fd;
+		}
+	}
+
+	pr_err("Do not owe socket with ino=%u\n", pkt->sender_ino);
+	return -1;
+}
+
+static int restore_promisc_queue(struct unix_sk_info *ui, int fd)
+{
+	int *ffds = ui->foreign_fds, i, ret;
+	struct sk_fd **sks, *sk;
+	struct sockaddr_un dst_addr;
+	socklen_t dst_addrlen;
+
+	/* Last sks in array is NULL */
+	sks = xmalloc((ui->nr_senders + 1) * sizeof(struct sk_fd *));
+	for (i = 0; i < ui->nr_senders; i++) {
+		sk = xmalloc(sizeof(struct sk_fd));
+		sk->addr = xmalloc(sizeof(struct sockaddr_un));
+		sk->addrlen = sizeof(struct sockaddr_un);
+		ret = getsockname(ffds[i], sk->addr, &sk->addrlen);
+		if (ret < 0) {
+			pr_err("Can't get socket name\n");
+			return -1;
+		}
+		sk->fd = ffds[i];
+		sks[i] = sk;
+	}
+	sks[ui->nr_senders] = NULL;
+
+	dst_addrlen = ui->ue->name.len + sizeof(dst_addr.sun_family);
+	memcpy(&dst_addr.sun_path, ui->ue->name.data, ui->ue->name.len);
+	dst_addr.sun_family = AF_UNIX;
+
+	if (__restore_sk_queue(sks, unix_get_fd, ui->ue->id,
+			       (struct sockaddr *)&dst_addr, dst_addrlen) < 0) {
+		pr_err("Can't restore rcv queue\n");
+		return -1;
+	}
+
+	for (i = 0; i < ui->nr_senders; i++) {
+		xfree(sks[i]->addr);
+		xfree(sks[i]);
+		close(ffds[i]);
+	}
+	xfree(sks[ui->nr_senders]);
+	xfree(sks);
+
+	return 0;
+}
+
 static int post_open_unix_sk(struct file_desc *d, int fd)
 {
 	struct unix_sk_info *ui;
@@ -938,6 +1010,9 @@  static int post_open_unix_sk(struct file_desc *d, int fd)
 	if (ui->flags & (USK_PAIR_MASTER | USK_PAIR_SLAVE))
 		return 0;
 
+	if (ui->nr_senders && restore_promisc_queue(ui, fd))
+		return -1;
+
 	peer = ui->peer;
 
 	if (peer == NULL)