1 #include <stdio.h>
2 #include <mach/mach.h>
3 #include <mach/message.h>
4 #include <unistd.h>
5 #include <assert.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <bootstrap.h>
9 #include <fcntl.h>
10 #include <sys/errno.h>
11 #include <sys/resource.h>
12 
13 static int
14 connect_to_server(void);
15 
16 typedef struct {
17 	mach_msg_header_t   header;
18 	mach_msg_body_t     body;
19 	mach_msg_port_descriptor_t port_descriptor;
20 	mach_msg_trailer_t  trailer;            // subtract this when sending
21 } ipc_complex_message;
22 
23 static ipc_complex_message icm_request = {};
24 
25 struct args {
26 	const char *progname;
27 	int verbose;
28 	int voucher;
29 	int num_msgs;
30 	const char *server_port_name;
31 	mach_port_t server_port;
32 	mach_port_t reply_port;
33 	int request_msg_size;
34 	void *request_msg;
35 	int reply_msg_size;
36 	void *reply_msg;
37 	uint32_t persona_id;
38 	long client_pid;
39 };
40 
41 static void
parse_args(struct args * args)42 parse_args(struct args *args)
43 {
44 	args->verbose = 0;
45 	args->voucher = 0;
46 	args->server_port_name = "TEST_FD_TABLE_LIMITS";
47 	args->server_port = MACH_PORT_NULL;
48 	args->reply_port = MACH_PORT_NULL;
49 	args->num_msgs = 1;
50 	args->request_msg_size = sizeof(ipc_complex_message) - sizeof(mach_msg_trailer_t);
51 	args->reply_msg_size = sizeof(ipc_complex_message) - sizeof(mach_msg_trailer_t);
52 	args->request_msg = &icm_request;
53 	args->reply_msg = NULL;
54 	args->client_pid = getpid();
55 }
56 
57 static int
connect_to_server(void)58 connect_to_server(void)
59 {
60 	struct args client_args = {};
61 	parse_args(&client_args);
62 
63 	/* Find the bootstrap port */
64 	mach_port_t bsport;
65 	kern_return_t ret = task_get_bootstrap_port(mach_task_self(), &bsport);
66 	if (ret) {
67 		mach_error("client: task_get_bootstrap_port()", ret);
68 		exit(1);
69 	}
70 
71 	printf("client: Look up bootstrap service port\n");
72 	ret = bootstrap_look_up(bsport, client_args.server_port_name,
73 	    &client_args.server_port);
74 	if (ret) {
75 		mach_error("client: bootstrap_look_up()", ret);
76 		exit(1);
77 	}
78 
79 	printf("client: Set service port as the resource notify port\n");
80 	ret = task_set_special_port(mach_task_self(), TASK_RESOURCE_NOTIFY_PORT, client_args.server_port);
81 	if (ret) {
82 		mach_error("client: task_set_special_port()", ret);
83 		exit(1);
84 	}
85 
86 	return 0;
87 }
88 
89 int
main(int argc,char * argv[])90 main(int argc, char *argv[])
91 {
92 	int fd = 0;
93 	int soft_limit = 0;
94 	int hard_limit = 0;
95 	int test_num = 0;
96 	int ret;
97 	if (argc == 4) {
98 		soft_limit = atoi(argv[1]);
99 		hard_limit = atoi(argv[2]);
100 		test_num = atoi(argv[3]);
101 	} else {
102 		printf("Usage: ./fd_table_limits_client <soft limit> <hard limit> <test_num>\n");
103 		goto fail_and_exit;
104 	}
105 
106 	printf("client: soft limit = %d, hard limit = %d, test_num = %d\n", soft_limit, hard_limit, test_num);
107 	if (test_num == 2) {
108 		ret = connect_to_server();
109 		if (ret) {
110 			goto fail_and_exit;
111 		}
112 	}
113 
114 	struct rlimit rl;
115 
116 	ret = getrlimit(RLIMIT_NOFILE, &rl);
117 	if (ret < 0) {
118 		printf("client: getrlimit failed with err = %d\n", errno);
119 		goto fail_and_exit;
120 	}
121 
122 	int new_rlim_max = 2000;
123 	if (rl.rlim_cur < new_rlim_max) {
124 		printf("client: raising file open limit from %llu (max %llu) to %d\n",
125 		    rl.rlim_cur, rl.rlim_max, new_rlim_max);
126 		rl.rlim_cur = new_rlim_max;
127 		rl.rlim_max = new_rlim_max;
128 		ret = setrlimit(RLIMIT_NOFILE, &rl);
129 		if (ret < 0) {
130 			printf("client: setrlimit failed with err = %d\n", errno);
131 			goto fail_and_exit;
132 		}
133 	}
134 
135 
136 	printf("client: Starting the fd allocation loop\n");
137 	int i = 0;
138 	while (i < new_rlim_max) {
139 		fd = open("/bin/ls", O_RDONLY | 0x08000000 /* O_CLOFORK */);
140 		if (fd < 0) {
141 			printf("open(/bin/ls) FD #%d failed with err = %d ", i, errno);
142 			goto fail_and_exit;
143 		}
144 
145 		if ((i % 20) == 0) {
146 			/* Print every port in the multiple of 20 */
147 			printf("client: FD #%d\n", i);
148 			sleep(1);
149 		}
150 
151 		if (i == soft_limit && !hard_limit) {
152 			printf("client: Hit the soft limit \n");
153 			exit(0);
154 		}
155 
156 		if (i == hard_limit) {
157 			printf("client: Hit the hard limit\n");
158 		}
159 
160 		i++;
161 	}
162 
163 fail_and_exit:
164 	exit(91);
165 }
166