1*bc36442eSArseniy Krasnov // SPDX-License-Identifier: GPL-2.0-only
2*bc36442eSArseniy Krasnov /* Some common code for MSG_ZEROCOPY logic
3*bc36442eSArseniy Krasnov  *
4*bc36442eSArseniy Krasnov  * Copyright (C) 2023 SberDevices.
5*bc36442eSArseniy Krasnov  *
6*bc36442eSArseniy Krasnov  * Author: Arseniy Krasnov <[email protected]>
7*bc36442eSArseniy Krasnov  */
8*bc36442eSArseniy Krasnov 
9*bc36442eSArseniy Krasnov #include <stdio.h>
10*bc36442eSArseniy Krasnov #include <stdlib.h>
11*bc36442eSArseniy Krasnov #include <sys/types.h>
12*bc36442eSArseniy Krasnov #include <sys/socket.h>
13*bc36442eSArseniy Krasnov #include <linux/errqueue.h>
14*bc36442eSArseniy Krasnov 
15*bc36442eSArseniy Krasnov #include "msg_zerocopy_common.h"
16*bc36442eSArseniy Krasnov 
vsock_recv_completion(int fd,const bool * zerocopied)17*bc36442eSArseniy Krasnov void vsock_recv_completion(int fd, const bool *zerocopied)
18*bc36442eSArseniy Krasnov {
19*bc36442eSArseniy Krasnov 	struct sock_extended_err *serr;
20*bc36442eSArseniy Krasnov 	struct msghdr msg = { 0 };
21*bc36442eSArseniy Krasnov 	char cmsg_data[128];
22*bc36442eSArseniy Krasnov 	struct cmsghdr *cm;
23*bc36442eSArseniy Krasnov 	ssize_t res;
24*bc36442eSArseniy Krasnov 
25*bc36442eSArseniy Krasnov 	msg.msg_control = cmsg_data;
26*bc36442eSArseniy Krasnov 	msg.msg_controllen = sizeof(cmsg_data);
27*bc36442eSArseniy Krasnov 
28*bc36442eSArseniy Krasnov 	res = recvmsg(fd, &msg, MSG_ERRQUEUE);
29*bc36442eSArseniy Krasnov 	if (res) {
30*bc36442eSArseniy Krasnov 		fprintf(stderr, "failed to read error queue: %zi\n", res);
31*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
32*bc36442eSArseniy Krasnov 	}
33*bc36442eSArseniy Krasnov 
34*bc36442eSArseniy Krasnov 	cm = CMSG_FIRSTHDR(&msg);
35*bc36442eSArseniy Krasnov 	if (!cm) {
36*bc36442eSArseniy Krasnov 		fprintf(stderr, "cmsg: no cmsg\n");
37*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
38*bc36442eSArseniy Krasnov 	}
39*bc36442eSArseniy Krasnov 
40*bc36442eSArseniy Krasnov 	if (cm->cmsg_level != SOL_VSOCK) {
41*bc36442eSArseniy Krasnov 		fprintf(stderr, "cmsg: unexpected 'cmsg_level'\n");
42*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
43*bc36442eSArseniy Krasnov 	}
44*bc36442eSArseniy Krasnov 
45*bc36442eSArseniy Krasnov 	if (cm->cmsg_type != VSOCK_RECVERR) {
46*bc36442eSArseniy Krasnov 		fprintf(stderr, "cmsg: unexpected 'cmsg_type'\n");
47*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
48*bc36442eSArseniy Krasnov 	}
49*bc36442eSArseniy Krasnov 
50*bc36442eSArseniy Krasnov 	serr = (void *)CMSG_DATA(cm);
51*bc36442eSArseniy Krasnov 	if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) {
52*bc36442eSArseniy Krasnov 		fprintf(stderr, "serr: wrong origin: %u\n", serr->ee_origin);
53*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
54*bc36442eSArseniy Krasnov 	}
55*bc36442eSArseniy Krasnov 
56*bc36442eSArseniy Krasnov 	if (serr->ee_errno) {
57*bc36442eSArseniy Krasnov 		fprintf(stderr, "serr: wrong error code: %u\n", serr->ee_errno);
58*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
59*bc36442eSArseniy Krasnov 	}
60*bc36442eSArseniy Krasnov 
61*bc36442eSArseniy Krasnov 	/* This flag is used for tests, to check that transmission was
62*bc36442eSArseniy Krasnov 	 * performed as expected: zerocopy or fallback to copy. If NULL
63*bc36442eSArseniy Krasnov 	 * - don't care.
64*bc36442eSArseniy Krasnov 	 */
65*bc36442eSArseniy Krasnov 	if (!zerocopied)
66*bc36442eSArseniy Krasnov 		return;
67*bc36442eSArseniy Krasnov 
68*bc36442eSArseniy Krasnov 	if (*zerocopied && (serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED)) {
69*bc36442eSArseniy Krasnov 		fprintf(stderr, "serr: was copy instead of zerocopy\n");
70*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
71*bc36442eSArseniy Krasnov 	}
72*bc36442eSArseniy Krasnov 
73*bc36442eSArseniy Krasnov 	if (!*zerocopied && !(serr->ee_code & SO_EE_CODE_ZEROCOPY_COPIED)) {
74*bc36442eSArseniy Krasnov 		fprintf(stderr, "serr: was zerocopy instead of copy\n");
75*bc36442eSArseniy Krasnov 		exit(EXIT_FAILURE);
76*bc36442eSArseniy Krasnov 	}
77*bc36442eSArseniy Krasnov }
78