Home | History | Annotate | Download | only in splice
      1 /*
      2  * Copyright (c) 2017 Red Hat, Inc.
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  *
     17  * Author: Boyang Xue <bxue (at) redhat.com>
     18  */
     19 
     20 /*
     21  * Functional test for splice(2): pipe <-> socket
     22  *
     23  * This test case tests splice(2) from a pipe to a socket and vice versa
     24  */
     25 
     26 #define _GNU_SOURCE
     27 #include <errno.h>
     28 #include <sys/types.h>
     29 #include <sys/socket.h>
     30 #include <sys/stat.h>
     31 #include <sys/wait.h>
     32 #include <fcntl.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 #include "tst_test.h"
     36 #include "lapi/splice.h"
     37 #include "splice.h"
     38 
     39 #define PIPE_MAX (64*1024)
     40 
     41 static char *str_len_data;
     42 static int num_len_data = PIPE_MAX;
     43 static char *arr_in, *arr_out;
     44 
     45 static struct tst_option options[] = {
     46 	{"l:", &str_len_data, "-l <num> Length of test data (in bytes)"},
     47 	{NULL, NULL, NULL},
     48 };
     49 
     50 static void setup(void)
     51 {
     52 	int i, pipe_limit;
     53 
     54 	pipe_limit = get_max_limit(num_len_data);
     55 	num_len_data = pipe_limit;
     56 
     57 	if (tst_parse_int(str_len_data, &num_len_data, 1, pipe_limit)) {
     58 		tst_brk(TBROK, "Invalid length of data: '%s', "
     59 			"valid value: [1, %d]", str_len_data, pipe_limit);
     60 	}
     61 	tst_res(TINFO, "splice size = %d", num_len_data);
     62 	arr_in = SAFE_MALLOC(num_len_data);
     63 	arr_out = SAFE_MALLOC(num_len_data);
     64 	for (i = 0; i < num_len_data; i++)
     65 		arr_in[i] = i & 0xff;
     66 
     67 }
     68 
     69 static void cleanup(void)
     70 {
     71 	free(arr_in);
     72 	free(arr_out);
     73 }
     74 
     75 static void pipe_socket(void)
     76 {
     77 	int pp1[2], pp2[2], sv[2], i, ret;
     78 
     79 	SAFE_PIPE(pp1);
     80 	SAFE_PIPE(pp2);
     81 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
     82 		tst_brk(TBROK | TERRNO, "fail to create socket pair.");
     83 
     84 	SAFE_WRITE(1, pp1[1], arr_in, num_len_data);
     85 	for (i = num_len_data; i > 0; i = i - ret) {
     86 		ret = splice(pp1[0], NULL, sv[0], 0, i, 0);
     87 		if (ret == -1) {
     88 			tst_res(TFAIL | TERRNO, "splice error");
     89 			goto exit;
     90 		}
     91 	}
     92 	for (i = num_len_data; i > 0; i = i - ret) {
     93 		ret = splice(sv[1], 0, pp2[1], NULL, i, 0);
     94 		if (ret == -1) {
     95 			if (errno == EINVAL) {
     96 				tst_res(TCONF, "splice does not support "
     97 					"af_unix sockets");
     98 			} else {
     99 				tst_res(TFAIL | TERRNO, "splice error");
    100 			}
    101 			goto exit;
    102 		}
    103 		SAFE_READ(1, pp2[0], arr_out + num_len_data - i, ret);
    104 	}
    105 
    106 	for (i = 0; i < num_len_data; i++) {
    107 		if (arr_in[i] != arr_out[i]) {
    108 			tst_res(TFAIL, "wrong data at %d: expected: %d, "
    109 				"actual: %d", i, arr_in[i], arr_out[i]);
    110 			goto exit;
    111 		}
    112 	}
    113 	tst_res(TPASS, "splice(2): pipe <-> socket run pass.");
    114 exit:
    115 	for (i = 0; i < 2; i++) {
    116 		SAFE_CLOSE(pp1[i]);
    117 		SAFE_CLOSE(pp2[i]);
    118 		SAFE_CLOSE(sv[i]);
    119 	}
    120 }
    121 
    122 static struct tst_test test = {
    123 	.test_all = pipe_socket,
    124 	.setup = setup,
    125 	.cleanup = cleanup,
    126 	.options = options,
    127 	.min_kver = "2.6.17"
    128 };
    129