[12/12] unix: Add a method for choosing sender of packet in promiscous DGRAM queue

Submitted by Kirill Tkhai on April 29, 2016, 2:37 p.m.

Details

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

Commit Message

Kirill Tkhai April 29, 2016, 2:37 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 |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

Patch hide | download patch | download mbox

diff --git a/criu/sk-unix.c b/criu/sk-unix.c
index 048d778..0ae0e61 100644
--- a/criu/sk-unix.c
+++ b/criu/sk-unix.c
@@ -908,6 +908,75 @@  static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd)
 	return 0;
 }
 
+static int unix_get_fd(int *fds, int num, SkPacketEntry *pkt, struct sockaddr **addr,
+		       socklen_t *addrlen, void *data)
+{
+	struct unix_sk_info *send, *recv = (struct unix_sk_info *)data;
+	struct sockaddr_un *un;
+	int i, ret;
+
+	*addr = xmalloc(sizeof(struct sockaddr_un));
+	if (!*addr)
+		return -1;
+	un = (struct sockaddr_un *)*addr;
+
+	if (!pkt->has_sender_ino) {
+		ret = -1;
+		goto populate;
+	}
+
+	send = find_unix_sk_by_ino(pkt->sender_ino);
+	if (!send) {
+		pr_err("Can't find socket with ino=%d\n", pkt->sender_ino);
+		goto free;
+	}
+	/*
+	 * Since foreign fd is sent after it's bound,
+	 * we don't have to wait send->prepared here.
+	 */
+	for (i = 0; i < num; i++) {
+		*addrlen = sizeof(struct sockaddr_un);
+		ret = getsockname(fds[i], *addr, addrlen);
+		if (ret < 0) {
+			pr_err("Can't get socket name\n");
+			goto free;
+		}
+		*addrlen -= sizeof(un->sun_family);
+
+		if (*addrlen == send->ue->name.len &&
+		    memcmp(un->sun_path, send->ue->name.data, *addrlen) == 0) {
+			ret = fds[i];
+populate:
+			/* Reuse *addr to return receiver address */
+			*addrlen = recv->ue->name.len + sizeof(un->sun_family);
+			memcpy(un->sun_path, recv->ue->name.data, recv->ue->name.len);
+			un->sun_family = AF_UNIX;
+			return ret;
+		}
+	}
+
+	pr_err("Do not owe socket with ino=%u\n", pkt->sender_ino);
+free:
+	xfree(*addr);
+	*addr = NULL;
+	return -1;
+}
+
+static int restore_promisc_queue(struct unix_sk_info *ui, int fd)
+{
+	int *ffds = ui->foreign_fds, i;
+
+	if (restore_sk_queue(ffds, ui->nr_senders, unix_get_fd, ui->ue->id, ui) < 0) {
+		pr_err("Can't restore rcv queue\n");
+		return -1;
+	}
+
+	for (i = 0; i < ui->nr_senders; i++)
+		close(ffds[i]);
+
+	return 0;
+}
+
 static int post_open_unix_sk(struct file_desc *d, int fd)
 {
 	struct unix_sk_info *ui;
@@ -919,6 +988,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)

Comments

Andrey Vagin May 16, 2016, 7:46 p.m.
On Fri, Apr 29, 2016 at 05:37:48PM +0300, Kirill Tkhai wrote:
> 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 |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 72 insertions(+)
> 
> diff --git a/criu/sk-unix.c b/criu/sk-unix.c
> index 048d778..0ae0e61 100644
> --- a/criu/sk-unix.c
> +++ b/criu/sk-unix.c
> @@ -908,6 +908,75 @@ static int prep_unix_sk_cwd(struct unix_sk_info *ui, int *prev_cwd_fd)
>  	return 0;
>  }
>  
> +static int unix_get_fd(int *fds, int num, SkPacketEntry *pkt, struct sockaddr **addr,
> +		       socklen_t *addrlen, void *data)
> +{
> +	struct unix_sk_info *send, *recv = (struct unix_sk_info *)data;
> +	struct sockaddr_un *un;
> +	int i, ret;
> +
> +	*addr = xmalloc(sizeof(struct sockaddr_un));
> +	if (!*addr)
> +		return -1;
> +	un = (struct sockaddr_un *)*addr;
> +
> +	if (!pkt->has_sender_ino) {
> +		ret = -1;
> +		goto populate;
> +	}
> +
> +	send = find_unix_sk_by_ino(pkt->sender_ino);
> +	if (!send) {
> +		pr_err("Can't find socket with ino=%d\n", pkt->sender_ino);
> +		goto free;
> +	}
> +	/*
> +	 * Since foreign fd is sent after it's bound,
> +	 * we don't have to wait send->prepared here.
> +	 */
> +	for (i = 0; i < num; i++) {
> +		*addrlen = sizeof(struct sockaddr_un);
> +		ret = getsockname(fds[i], *addr, addrlen);

I think it should be optimized. getsockname() should not be called more
to restore each message.

> +		if (ret < 0) {
> +			pr_err("Can't get socket name\n");
> +			goto free;
> +		}
> +		*addrlen -= sizeof(un->sun_family);
> +
> +		if (*addrlen == send->ue->name.len &&
> +		    memcmp(un->sun_path, send->ue->name.data, *addrlen) == 0) {
> +			ret = fds[i];
> +populate:
> +			/* Reuse *addr to return receiver address */
> +			*addrlen = recv->ue->name.len + sizeof(un->sun_family);
> +			memcpy(un->sun_path, recv->ue->name.data, recv->ue->name.len);
> +			un->sun_family = AF_UNIX;
> +			return ret;
> +		}
> +	}
> +
> +	pr_err("Do not owe socket with ino=%u\n", pkt->sender_ino);
> +free:
> +	xfree(*addr);
> +	*addr = NULL;
> +	return -1;
> +}
> +
> +static int restore_promisc_queue(struct unix_sk_info *ui, int fd)
> +{
> +	int *ffds = ui->foreign_fds, i;
> +
> +	if (restore_sk_queue(ffds, ui->nr_senders, unix_get_fd, ui->ue->id, ui) < 0) {
> +		pr_err("Can't restore rcv queue\n");
> +		return -1;
> +	}
> +
> +	for (i = 0; i < ui->nr_senders; i++)
> +		close(ffds[i]);
> +
> +	return 0;
> +}
> +
>  static int post_open_unix_sk(struct file_desc *d, int fd)
>  {
>  	struct unix_sk_info *ui;
> @@ -919,6 +988,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)
> 
> _______________________________________________
> CRIU mailing list
> CRIU@openvz.org
> https://lists.openvz.org/mailman/listinfo/criu