Home | History | Annotate | Download | only in recvmsg
      1 /*
      2  * Copyright (c) 2016 Cyril Hrubis <chrubis (at) suse.cz>
      3  * Copyright (c) 2016 Michal Kubecek <mkubecek (at) suse.cz>
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 /*
     20  * This is a regression test for kernel commit:
     21  *
     22  * 197c949e7798  udp: properly support MSG_PEEK with truncated buffers
     23  *
     24  * NOTE: The testcase will hang on upatched stable kernel.
     25  */
     26 
     27 #include <string.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <unistd.h>
     31 #include <sys/types.h>
     32 #include <sys/socket.h>
     33 #include <netinet/in.h>
     34 
     35 #include "tst_test.h"
     36 #include "lapi/socket.h"
     37 
     38 static const char msg[] = "Michael Gilfix was here\341\210\264\r\n";
     39 static const unsigned msglen = ARRAY_SIZE(msg) - 1;
     40 static unsigned char buff[25];
     41 static const int bufflen = ARRAY_SIZE(buff);
     42 
     43 static int sdr, sdw;
     44 
     45 static void verify_recvmsg(void)
     46 {
     47 	struct sockaddr_in6 addr_init = {
     48 		.sin6_family	= AF_INET6,
     49 		.sin6_port	= htons(0),
     50 		.sin6_addr	= IN6ADDR_LOOPBACK_INIT,
     51 	};
     52 	struct sockaddr_in6 addr_r, addr_w, addr_f;
     53 	socklen_t addrlen_r, addrlen_w;
     54 	struct iovec iov = {
     55 		.iov_base	= buff,
     56 		.iov_len	= sizeof(buff),
     57 	};
     58 	struct msghdr msghdr = {
     59 		.msg_name	= &addr_f,
     60 		.msg_namelen	= sizeof(addr_f),
     61 		.msg_iov	= &iov,
     62 		.msg_iovlen	= 1,
     63 		.msg_control	= NULL,
     64 		.msg_controllen	= 0,
     65 		.msg_flags	= 0,
     66 	};
     67 	int R;
     68 
     69 	sdr = SAFE_SOCKET(PF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP);
     70 	SAFE_BIND(sdr, (struct sockaddr*)&addr_init, sizeof(addr_init));
     71 	addrlen_r = sizeof(addr_r);
     72 	SAFE_GETSOCKNAME(sdr, (struct sockaddr*)&addr_r, &addrlen_r);
     73 	sdw = SAFE_SOCKET(PF_INET6, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP);
     74 	SAFE_BIND(sdw, (struct sockaddr*)&addr_init, sizeof(addr_init));
     75 	addrlen_w = sizeof(addr_w);
     76 	SAFE_GETSOCKNAME(sdw, (struct sockaddr*)&addr_w, &addrlen_w);
     77 
     78 	R = sendto(sdw, msg, msglen, 0, (struct sockaddr*)&addr_r, addrlen_r);
     79 	if (R < 0)
     80 		tst_brk(TBROK | TERRNO, "sendto()");
     81 
     82 	R = recvmsg(sdr, &msghdr, MSG_PEEK);
     83 	if (R < 0) {
     84 		tst_res(TFAIL | TERRNO, "recvmsg(..., MSG_PEEK)");
     85 		return;
     86 	}
     87 
     88 	tst_res(TINFO, "received %d bytes", R);
     89 
     90 	if ((R == bufflen) && !memcmp(msg, buff, R))
     91 		tst_res(TPASS, "recvmsg(..., MSG_PEEK) works fine");
     92 	else
     93 		tst_res(TPASS, "recvmsg(..., MSG_PEEK) failed");
     94 
     95 	SAFE_CLOSE(sdw);
     96 	SAFE_CLOSE(sdr);
     97 }
     98 
     99 static void cleanup(void)
    100 {
    101 	if (sdw > 0)
    102 		SAFE_CLOSE(sdw);
    103 
    104 	if (sdr > 0)
    105 		SAFE_CLOSE(sdr);
    106 }
    107 
    108 static struct tst_test test = {
    109 	.tid = "recvmsg02",
    110 	.min_kver = "2.6.27",
    111 	.test_all = verify_recvmsg,
    112 	.cleanup = cleanup,
    113 };
    114