xref: /freebsd/contrib/ofed/librdmacm/examples/rcopy.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky  * Copyright (c) 2011 Intel Corporation.  All rights reserved.
3*d6b92ffaSHans Petter Selasky  *
4*d6b92ffaSHans Petter Selasky  * This software is available to you under the OpenIB.org BSD license
5*d6b92ffaSHans Petter Selasky  * below:
6*d6b92ffaSHans Petter Selasky  *
7*d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
8*d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
9*d6b92ffaSHans Petter Selasky  *     conditions are met:
10*d6b92ffaSHans Petter Selasky  *
11*d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
12*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
13*d6b92ffaSHans Petter Selasky  *        disclaimer.
14*d6b92ffaSHans Petter Selasky  *
15*d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
16*d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
17*d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
18*d6b92ffaSHans Petter Selasky  *        provided with the distribution.
19*d6b92ffaSHans Petter Selasky  *
20*d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21*d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22*d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
23*d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24*d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25*d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26*d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27*d6b92ffaSHans Petter Selasky  * SOFTWARE.
28*d6b92ffaSHans Petter Selasky  */
29*d6b92ffaSHans Petter Selasky 
30*d6b92ffaSHans Petter Selasky #include <stdio.h>
31*d6b92ffaSHans Petter Selasky #include <stdlib.h>
32*d6b92ffaSHans Petter Selasky #include <string.h>
33*d6b92ffaSHans Petter Selasky #include <strings.h>
34*d6b92ffaSHans Petter Selasky #include <errno.h>
35*d6b92ffaSHans Petter Selasky #include <getopt.h>
36*d6b92ffaSHans Petter Selasky #include <arpa/inet.h>
37*d6b92ffaSHans Petter Selasky #include <sys/mman.h>
38*d6b92ffaSHans Petter Selasky #include <sys/types.h>
39*d6b92ffaSHans Petter Selasky #include <sys/socket.h>
40*d6b92ffaSHans Petter Selasky #include <sys/time.h>
41*d6b92ffaSHans Petter Selasky #include <sys/stat.h>
42*d6b92ffaSHans Petter Selasky #include <fcntl.h>
43*d6b92ffaSHans Petter Selasky #include <netdb.h>
44*d6b92ffaSHans Petter Selasky #include <unistd.h>
45*d6b92ffaSHans Petter Selasky 
46*d6b92ffaSHans Petter Selasky #include <rdma/rsocket.h>
47*d6b92ffaSHans Petter Selasky 
48*d6b92ffaSHans Petter Selasky union rsocket_address {
49*d6b92ffaSHans Petter Selasky 	struct sockaddr		sa;
50*d6b92ffaSHans Petter Selasky 	struct sockaddr_in	sin;
51*d6b92ffaSHans Petter Selasky 	struct sockaddr_in6	sin6;
52*d6b92ffaSHans Petter Selasky 	struct sockaddr_storage storage;
53*d6b92ffaSHans Petter Selasky };
54*d6b92ffaSHans Petter Selasky 
55*d6b92ffaSHans Petter Selasky static const char *port = "7427";
56*d6b92ffaSHans Petter Selasky static char *dst_addr;
57*d6b92ffaSHans Petter Selasky static char *dst_file;
58*d6b92ffaSHans Petter Selasky static char *src_file;
59*d6b92ffaSHans Petter Selasky static struct timeval start, end;
60*d6b92ffaSHans Petter Selasky //static void buf[1024 * 1024];
61*d6b92ffaSHans Petter Selasky static uint64_t bytes;
62*d6b92ffaSHans Petter Selasky static int fd;
63*d6b92ffaSHans Petter Selasky static void *file_addr;
64*d6b92ffaSHans Petter Selasky 
65*d6b92ffaSHans Petter Selasky enum {
66*d6b92ffaSHans Petter Selasky 	CMD_NOOP,
67*d6b92ffaSHans Petter Selasky 	CMD_OPEN,
68*d6b92ffaSHans Petter Selasky 	CMD_CLOSE,
69*d6b92ffaSHans Petter Selasky 	CMD_WRITE,
70*d6b92ffaSHans Petter Selasky 	CMD_RESP = 0x80,
71*d6b92ffaSHans Petter Selasky };
72*d6b92ffaSHans Petter Selasky 
73*d6b92ffaSHans Petter Selasky /* TODO: handle byte swapping */
74*d6b92ffaSHans Petter Selasky struct msg_hdr {
75*d6b92ffaSHans Petter Selasky 	uint8_t  version;
76*d6b92ffaSHans Petter Selasky 	uint8_t  command;
77*d6b92ffaSHans Petter Selasky 	uint16_t len;
78*d6b92ffaSHans Petter Selasky 	uint32_t data;
79*d6b92ffaSHans Petter Selasky 	uint64_t id;
80*d6b92ffaSHans Petter Selasky };
81*d6b92ffaSHans Petter Selasky 
82*d6b92ffaSHans Petter Selasky struct msg_open {
83*d6b92ffaSHans Petter Selasky 	struct msg_hdr hdr;
84*d6b92ffaSHans Petter Selasky 	char path[0];
85*d6b92ffaSHans Petter Selasky };
86*d6b92ffaSHans Petter Selasky 
87*d6b92ffaSHans Petter Selasky struct msg_write {
88*d6b92ffaSHans Petter Selasky 	struct msg_hdr hdr;
89*d6b92ffaSHans Petter Selasky 	uint64_t size;
90*d6b92ffaSHans Petter Selasky };
91*d6b92ffaSHans Petter Selasky 
show_perf(void)92*d6b92ffaSHans Petter Selasky static void show_perf(void)
93*d6b92ffaSHans Petter Selasky {
94*d6b92ffaSHans Petter Selasky 	float usec;
95*d6b92ffaSHans Petter Selasky 
96*d6b92ffaSHans Petter Selasky 	usec = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
97*d6b92ffaSHans Petter Selasky 
98*d6b92ffaSHans Petter Selasky 	printf("%lld bytes in %.2f seconds = %.2f Gb/sec\n",
99*d6b92ffaSHans Petter Selasky 	       (long long) bytes, usec / 1000000., (bytes * 8) / (1000. * usec));
100*d6b92ffaSHans Petter Selasky }
101*d6b92ffaSHans Petter Selasky 
_ntop(union rsocket_address * rsa)102*d6b92ffaSHans Petter Selasky static char *_ntop(union rsocket_address *rsa)
103*d6b92ffaSHans Petter Selasky {
104*d6b92ffaSHans Petter Selasky 	static char addr[32];
105*d6b92ffaSHans Petter Selasky 
106*d6b92ffaSHans Petter Selasky 	switch (rsa->sa.sa_family) {
107*d6b92ffaSHans Petter Selasky 	case AF_INET:
108*d6b92ffaSHans Petter Selasky 		inet_ntop(AF_INET, &rsa->sin.sin_addr, addr, sizeof addr);
109*d6b92ffaSHans Petter Selasky 		break;
110*d6b92ffaSHans Petter Selasky 	case AF_INET6:
111*d6b92ffaSHans Petter Selasky 		inet_ntop(AF_INET6, &rsa->sin6.sin6_addr, addr, sizeof addr);
112*d6b92ffaSHans Petter Selasky 		break;
113*d6b92ffaSHans Petter Selasky 	default:
114*d6b92ffaSHans Petter Selasky 		addr[0] = '\0';
115*d6b92ffaSHans Petter Selasky 		break;
116*d6b92ffaSHans Petter Selasky 	}
117*d6b92ffaSHans Petter Selasky 
118*d6b92ffaSHans Petter Selasky 	return addr;
119*d6b92ffaSHans Petter Selasky }
120*d6b92ffaSHans Petter Selasky 
_recv(int rs,char * msg,size_t len)121*d6b92ffaSHans Petter Selasky static size_t _recv(int rs, char *msg, size_t len)
122*d6b92ffaSHans Petter Selasky {
123*d6b92ffaSHans Petter Selasky 	size_t ret, offset;
124*d6b92ffaSHans Petter Selasky 
125*d6b92ffaSHans Petter Selasky 	for (offset = 0; offset < len; offset += ret) {
126*d6b92ffaSHans Petter Selasky 		ret = rrecv(rs, msg + offset, len - offset, 0);
127*d6b92ffaSHans Petter Selasky 		if (ret <= 0)
128*d6b92ffaSHans Petter Selasky 			return ret;
129*d6b92ffaSHans Petter Selasky 	}
130*d6b92ffaSHans Petter Selasky 
131*d6b92ffaSHans Petter Selasky 	return len;
132*d6b92ffaSHans Petter Selasky }
133*d6b92ffaSHans Petter Selasky 
msg_recv_hdr(int rs,struct msg_hdr * hdr)134*d6b92ffaSHans Petter Selasky static int msg_recv_hdr(int rs, struct msg_hdr *hdr)
135*d6b92ffaSHans Petter Selasky {
136*d6b92ffaSHans Petter Selasky 	int ret;
137*d6b92ffaSHans Petter Selasky 
138*d6b92ffaSHans Petter Selasky 	ret = _recv(rs, (char *) hdr, sizeof *hdr);
139*d6b92ffaSHans Petter Selasky 	if (ret != sizeof *hdr)
140*d6b92ffaSHans Petter Selasky 		return -1;
141*d6b92ffaSHans Petter Selasky 
142*d6b92ffaSHans Petter Selasky 	if (hdr->version || hdr->len < sizeof *hdr) {
143*d6b92ffaSHans Petter Selasky 		printf("invalid version %d or length %d\n",
144*d6b92ffaSHans Petter Selasky 		       hdr->version, hdr->len);
145*d6b92ffaSHans Petter Selasky 		return -1;
146*d6b92ffaSHans Petter Selasky 	}
147*d6b92ffaSHans Petter Selasky 
148*d6b92ffaSHans Petter Selasky 	return sizeof *hdr;
149*d6b92ffaSHans Petter Selasky }
150*d6b92ffaSHans Petter Selasky 
msg_get_resp(int rs,struct msg_hdr * msg,uint8_t cmd)151*d6b92ffaSHans Petter Selasky static int msg_get_resp(int rs, struct msg_hdr *msg, uint8_t cmd)
152*d6b92ffaSHans Petter Selasky {
153*d6b92ffaSHans Petter Selasky 	int ret;
154*d6b92ffaSHans Petter Selasky 
155*d6b92ffaSHans Petter Selasky 	ret = msg_recv_hdr(rs, msg);
156*d6b92ffaSHans Petter Selasky 	if (ret != sizeof *msg)
157*d6b92ffaSHans Petter Selasky 		return ret;
158*d6b92ffaSHans Petter Selasky 
159*d6b92ffaSHans Petter Selasky 	if ((msg->len != sizeof *msg) || (msg->command != (cmd | CMD_RESP))) {
160*d6b92ffaSHans Petter Selasky 		printf("invalid length %d or bad command response %x:%x\n",
161*d6b92ffaSHans Petter Selasky 		       msg->len, msg->command, cmd | CMD_RESP);
162*d6b92ffaSHans Petter Selasky 		return -1;
163*d6b92ffaSHans Petter Selasky 	}
164*d6b92ffaSHans Petter Selasky 
165*d6b92ffaSHans Petter Selasky 	return msg->data;
166*d6b92ffaSHans Petter Selasky }
167*d6b92ffaSHans Petter Selasky 
msg_send_resp(int rs,struct msg_hdr * msg,uint32_t status)168*d6b92ffaSHans Petter Selasky static void msg_send_resp(int rs, struct msg_hdr *msg, uint32_t status)
169*d6b92ffaSHans Petter Selasky {
170*d6b92ffaSHans Petter Selasky 	struct msg_hdr resp;
171*d6b92ffaSHans Petter Selasky 
172*d6b92ffaSHans Petter Selasky 	resp.version = 0;
173*d6b92ffaSHans Petter Selasky 	resp.command = msg->command | CMD_RESP;
174*d6b92ffaSHans Petter Selasky 	resp.len = sizeof resp;
175*d6b92ffaSHans Petter Selasky 	resp.data = status;
176*d6b92ffaSHans Petter Selasky 	resp.id = msg->id;
177*d6b92ffaSHans Petter Selasky 	rsend(rs, (char *) &resp, sizeof resp, 0);
178*d6b92ffaSHans Petter Selasky }
179*d6b92ffaSHans Petter Selasky 
server_listen(void)180*d6b92ffaSHans Petter Selasky static int server_listen(void)
181*d6b92ffaSHans Petter Selasky {
182*d6b92ffaSHans Petter Selasky 	struct addrinfo hints, *res;
183*d6b92ffaSHans Petter Selasky 	int ret, rs;
184*d6b92ffaSHans Petter Selasky 
185*d6b92ffaSHans Petter Selasky 	memset(&hints, 0, sizeof hints);
186*d6b92ffaSHans Petter Selasky 	hints.ai_flags = RAI_PASSIVE;
187*d6b92ffaSHans Petter Selasky  	ret = getaddrinfo(NULL, port, &hints, &res);
188*d6b92ffaSHans Petter Selasky 	if (ret) {
189*d6b92ffaSHans Petter Selasky 		printf("getaddrinfo failed: %s\n", gai_strerror(ret));
190*d6b92ffaSHans Petter Selasky 		return ret;
191*d6b92ffaSHans Petter Selasky 	}
192*d6b92ffaSHans Petter Selasky 
193*d6b92ffaSHans Petter Selasky 	rs = rsocket(res->ai_family, res->ai_socktype, res->ai_protocol);
194*d6b92ffaSHans Petter Selasky 	if (rs < 0) {
195*d6b92ffaSHans Petter Selasky 		perror("rsocket failed\n");
196*d6b92ffaSHans Petter Selasky 		ret = rs;
197*d6b92ffaSHans Petter Selasky 		goto free;
198*d6b92ffaSHans Petter Selasky 	}
199*d6b92ffaSHans Petter Selasky 
200*d6b92ffaSHans Petter Selasky 	ret = 1;
201*d6b92ffaSHans Petter Selasky 	ret = rsetsockopt(rs, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof ret);
202*d6b92ffaSHans Petter Selasky 	if (ret) {
203*d6b92ffaSHans Petter Selasky 		perror("rsetsockopt failed");
204*d6b92ffaSHans Petter Selasky 		goto close;
205*d6b92ffaSHans Petter Selasky 	}
206*d6b92ffaSHans Petter Selasky 
207*d6b92ffaSHans Petter Selasky 	ret = rbind(rs, res->ai_addr, res->ai_addrlen);
208*d6b92ffaSHans Petter Selasky 	if (ret) {
209*d6b92ffaSHans Petter Selasky 		perror("rbind failed");
210*d6b92ffaSHans Petter Selasky 		goto close;
211*d6b92ffaSHans Petter Selasky 	}
212*d6b92ffaSHans Petter Selasky 
213*d6b92ffaSHans Petter Selasky 	ret = rlisten(rs, 1);
214*d6b92ffaSHans Petter Selasky 	if (ret) {
215*d6b92ffaSHans Petter Selasky 		perror("rlisten failed");
216*d6b92ffaSHans Petter Selasky 		goto close;
217*d6b92ffaSHans Petter Selasky 	}
218*d6b92ffaSHans Petter Selasky 
219*d6b92ffaSHans Petter Selasky 	ret = rs;
220*d6b92ffaSHans Petter Selasky 	goto free;
221*d6b92ffaSHans Petter Selasky 
222*d6b92ffaSHans Petter Selasky close:
223*d6b92ffaSHans Petter Selasky 	rclose(rs);
224*d6b92ffaSHans Petter Selasky free:
225*d6b92ffaSHans Petter Selasky 	freeaddrinfo(res);
226*d6b92ffaSHans Petter Selasky 	return ret;
227*d6b92ffaSHans Petter Selasky }
228*d6b92ffaSHans Petter Selasky 
server_open(int rs,struct msg_hdr * msg)229*d6b92ffaSHans Petter Selasky static int server_open(int rs, struct msg_hdr *msg)
230*d6b92ffaSHans Petter Selasky {
231*d6b92ffaSHans Petter Selasky 	char *path = NULL;
232*d6b92ffaSHans Petter Selasky 	int ret, len;
233*d6b92ffaSHans Petter Selasky 
234*d6b92ffaSHans Petter Selasky 	printf("opening: ");
235*d6b92ffaSHans Petter Selasky 	fflush(NULL);
236*d6b92ffaSHans Petter Selasky 	if (file_addr || fd > 0) {
237*d6b92ffaSHans Petter Selasky 		printf("cannot open another file\n");
238*d6b92ffaSHans Petter Selasky 		ret = EBUSY;
239*d6b92ffaSHans Petter Selasky 		goto out;
240*d6b92ffaSHans Petter Selasky 	}
241*d6b92ffaSHans Petter Selasky 
242*d6b92ffaSHans Petter Selasky 	len = msg->len - sizeof *msg;
243*d6b92ffaSHans Petter Selasky 	path = malloc(len);
244*d6b92ffaSHans Petter Selasky 	if (!path) {
245*d6b92ffaSHans Petter Selasky 		printf("cannot allocate path name\n");
246*d6b92ffaSHans Petter Selasky 		ret = ENOMEM;
247*d6b92ffaSHans Petter Selasky 		goto out;
248*d6b92ffaSHans Petter Selasky 	}
249*d6b92ffaSHans Petter Selasky 
250*d6b92ffaSHans Petter Selasky 	ret = _recv(rs, path, len);
251*d6b92ffaSHans Petter Selasky 	if (ret != len) {
252*d6b92ffaSHans Petter Selasky 		printf("error receiving path\n");
253*d6b92ffaSHans Petter Selasky 		goto out;
254*d6b92ffaSHans Petter Selasky 	}
255*d6b92ffaSHans Petter Selasky 
256*d6b92ffaSHans Petter Selasky 	printf("%s, ", path);
257*d6b92ffaSHans Petter Selasky 	fflush(NULL);
258*d6b92ffaSHans Petter Selasky 	fd = open(path, O_RDWR | O_CREAT | O_TRUNC, msg->data);
259*d6b92ffaSHans Petter Selasky 	if (fd < 0) {
260*d6b92ffaSHans Petter Selasky 		printf("unable to open destination file\n");
261*d6b92ffaSHans Petter Selasky 		ret = errno;
262*d6b92ffaSHans Petter Selasky 	}
263*d6b92ffaSHans Petter Selasky 
264*d6b92ffaSHans Petter Selasky 	ret = 0;
265*d6b92ffaSHans Petter Selasky out:
266*d6b92ffaSHans Petter Selasky 	if (path)
267*d6b92ffaSHans Petter Selasky 		free(path);
268*d6b92ffaSHans Petter Selasky 
269*d6b92ffaSHans Petter Selasky 	msg_send_resp(rs, msg, ret);
270*d6b92ffaSHans Petter Selasky 	return ret;
271*d6b92ffaSHans Petter Selasky }
272*d6b92ffaSHans Petter Selasky 
server_close(int rs,struct msg_hdr * msg)273*d6b92ffaSHans Petter Selasky static void server_close(int rs, struct msg_hdr *msg)
274*d6b92ffaSHans Petter Selasky {
275*d6b92ffaSHans Petter Selasky 	printf("closing...");
276*d6b92ffaSHans Petter Selasky 	fflush(NULL);
277*d6b92ffaSHans Petter Selasky 	msg_send_resp(rs, msg, 0);
278*d6b92ffaSHans Petter Selasky 
279*d6b92ffaSHans Petter Selasky 	if (file_addr) {
280*d6b92ffaSHans Petter Selasky 		munmap(file_addr, bytes);
281*d6b92ffaSHans Petter Selasky 		file_addr = NULL;
282*d6b92ffaSHans Petter Selasky 	}
283*d6b92ffaSHans Petter Selasky 
284*d6b92ffaSHans Petter Selasky 	if (fd > 0) {
285*d6b92ffaSHans Petter Selasky 		close(fd);
286*d6b92ffaSHans Petter Selasky 		fd = 0;
287*d6b92ffaSHans Petter Selasky 	}
288*d6b92ffaSHans Petter Selasky 	printf("done\n");
289*d6b92ffaSHans Petter Selasky }
290*d6b92ffaSHans Petter Selasky 
server_write(int rs,struct msg_hdr * msg)291*d6b92ffaSHans Petter Selasky static int server_write(int rs, struct msg_hdr *msg)
292*d6b92ffaSHans Petter Selasky {
293*d6b92ffaSHans Petter Selasky 	size_t len;
294*d6b92ffaSHans Petter Selasky 	int ret;
295*d6b92ffaSHans Petter Selasky 
296*d6b92ffaSHans Petter Selasky 	printf("transferring");
297*d6b92ffaSHans Petter Selasky 	fflush(NULL);
298*d6b92ffaSHans Petter Selasky 	if (fd <= 0) {
299*d6b92ffaSHans Petter Selasky 		printf("...file not opened\n");
300*d6b92ffaSHans Petter Selasky 		ret = EINVAL;
301*d6b92ffaSHans Petter Selasky 		goto out;
302*d6b92ffaSHans Petter Selasky 	}
303*d6b92ffaSHans Petter Selasky 
304*d6b92ffaSHans Petter Selasky 	if (msg->len != sizeof(struct msg_write)) {
305*d6b92ffaSHans Petter Selasky 		printf("...invalid message length %d\n", msg->len);
306*d6b92ffaSHans Petter Selasky 		ret = EINVAL;
307*d6b92ffaSHans Petter Selasky 		goto out;
308*d6b92ffaSHans Petter Selasky 	}
309*d6b92ffaSHans Petter Selasky 
310*d6b92ffaSHans Petter Selasky 	ret = _recv(rs, (char *) &bytes, sizeof bytes);
311*d6b92ffaSHans Petter Selasky 	if (ret != sizeof bytes)
312*d6b92ffaSHans Petter Selasky 		goto out;
313*d6b92ffaSHans Petter Selasky 
314*d6b92ffaSHans Petter Selasky 	ret = ftruncate(fd, bytes);
315*d6b92ffaSHans Petter Selasky 	if (ret)
316*d6b92ffaSHans Petter Selasky 		goto out;
317*d6b92ffaSHans Petter Selasky 
318*d6b92ffaSHans Petter Selasky 	file_addr = mmap(NULL, bytes, PROT_WRITE, MAP_SHARED, fd, 0);
319*d6b92ffaSHans Petter Selasky 	if (file_addr == (void *) -1) {
320*d6b92ffaSHans Petter Selasky 		printf("...error mapping file\n");
321*d6b92ffaSHans Petter Selasky 		ret = errno;
322*d6b92ffaSHans Petter Selasky 		goto out;
323*d6b92ffaSHans Petter Selasky 	}
324*d6b92ffaSHans Petter Selasky 
325*d6b92ffaSHans Petter Selasky 	printf("...%lld bytes...", (long long) bytes);
326*d6b92ffaSHans Petter Selasky 	fflush(NULL);
327*d6b92ffaSHans Petter Selasky 	len = _recv(rs, file_addr, bytes);
328*d6b92ffaSHans Petter Selasky 	if (len != bytes) {
329*d6b92ffaSHans Petter Selasky 		printf("...error receiving data\n");
330*d6b92ffaSHans Petter Selasky 		ret = (int) len;
331*d6b92ffaSHans Petter Selasky 	}
332*d6b92ffaSHans Petter Selasky out:
333*d6b92ffaSHans Petter Selasky 	msg_send_resp(rs, msg, ret);
334*d6b92ffaSHans Petter Selasky 	return ret;
335*d6b92ffaSHans Petter Selasky }
336*d6b92ffaSHans Petter Selasky 
server_process(int rs)337*d6b92ffaSHans Petter Selasky static void server_process(int rs)
338*d6b92ffaSHans Petter Selasky {
339*d6b92ffaSHans Petter Selasky 	struct msg_hdr msg;
340*d6b92ffaSHans Petter Selasky 	int ret;
341*d6b92ffaSHans Petter Selasky 
342*d6b92ffaSHans Petter Selasky 	do {
343*d6b92ffaSHans Petter Selasky 		ret = msg_recv_hdr(rs, &msg);
344*d6b92ffaSHans Petter Selasky 		if (ret != sizeof msg)
345*d6b92ffaSHans Petter Selasky 			break;
346*d6b92ffaSHans Petter Selasky 
347*d6b92ffaSHans Petter Selasky 		switch (msg.command) {
348*d6b92ffaSHans Petter Selasky 		case CMD_OPEN:
349*d6b92ffaSHans Petter Selasky 			ret = server_open(rs, &msg);
350*d6b92ffaSHans Petter Selasky 			break;
351*d6b92ffaSHans Petter Selasky 		case CMD_CLOSE:
352*d6b92ffaSHans Petter Selasky 			server_close(rs, &msg);
353*d6b92ffaSHans Petter Selasky 			ret = 0;
354*d6b92ffaSHans Petter Selasky 			break;
355*d6b92ffaSHans Petter Selasky 		case CMD_WRITE:
356*d6b92ffaSHans Petter Selasky 			ret = server_write(rs, &msg);
357*d6b92ffaSHans Petter Selasky 			break;
358*d6b92ffaSHans Petter Selasky 		default:
359*d6b92ffaSHans Petter Selasky 			msg_send_resp(rs, &msg, EINVAL);
360*d6b92ffaSHans Petter Selasky 			ret = -1;
361*d6b92ffaSHans Petter Selasky 			break;
362*d6b92ffaSHans Petter Selasky 		}
363*d6b92ffaSHans Petter Selasky 
364*d6b92ffaSHans Petter Selasky 	} while (!ret);
365*d6b92ffaSHans Petter Selasky }
366*d6b92ffaSHans Petter Selasky 
server_run(void)367*d6b92ffaSHans Petter Selasky static int server_run(void)
368*d6b92ffaSHans Petter Selasky {
369*d6b92ffaSHans Petter Selasky 	int lrs, rs;
370*d6b92ffaSHans Petter Selasky 	union rsocket_address rsa;
371*d6b92ffaSHans Petter Selasky 	socklen_t len;
372*d6b92ffaSHans Petter Selasky 
373*d6b92ffaSHans Petter Selasky 	lrs = server_listen();
374*d6b92ffaSHans Petter Selasky 	if (lrs < 0)
375*d6b92ffaSHans Petter Selasky 		return lrs;
376*d6b92ffaSHans Petter Selasky 
377*d6b92ffaSHans Petter Selasky 	while (1) {
378*d6b92ffaSHans Petter Selasky 		len = sizeof rsa;
379*d6b92ffaSHans Petter Selasky 		printf("waiting for connection...");
380*d6b92ffaSHans Petter Selasky 		fflush(NULL);
381*d6b92ffaSHans Petter Selasky 		rs = raccept(lrs, &rsa.sa, &len);
382*d6b92ffaSHans Petter Selasky 
383*d6b92ffaSHans Petter Selasky 		printf("client: %s\n", _ntop(&rsa));
384*d6b92ffaSHans Petter Selasky 		server_process(rs);
385*d6b92ffaSHans Petter Selasky 
386*d6b92ffaSHans Petter Selasky 		rshutdown(rs, SHUT_RDWR);
387*d6b92ffaSHans Petter Selasky 		rclose(rs);
388*d6b92ffaSHans Petter Selasky 	}
389*d6b92ffaSHans Petter Selasky 	return 0;
390*d6b92ffaSHans Petter Selasky }
391*d6b92ffaSHans Petter Selasky 
client_connect(void)392*d6b92ffaSHans Petter Selasky static int client_connect(void)
393*d6b92ffaSHans Petter Selasky {
394*d6b92ffaSHans Petter Selasky 	struct addrinfo *res;
395*d6b92ffaSHans Petter Selasky 	int ret, rs;
396*d6b92ffaSHans Petter Selasky 
397*d6b92ffaSHans Petter Selasky  	ret = getaddrinfo(dst_addr, port, NULL, &res);
398*d6b92ffaSHans Petter Selasky 	if (ret) {
399*d6b92ffaSHans Petter Selasky 		printf("getaddrinfo failed: %s\n", gai_strerror(ret));
400*d6b92ffaSHans Petter Selasky 		return ret;
401*d6b92ffaSHans Petter Selasky 	}
402*d6b92ffaSHans Petter Selasky 
403*d6b92ffaSHans Petter Selasky 	rs = rsocket(res->ai_family, res->ai_socktype, res->ai_protocol);
404*d6b92ffaSHans Petter Selasky 	if (rs < 0) {
405*d6b92ffaSHans Petter Selasky 		perror("rsocket failed\n");
406*d6b92ffaSHans Petter Selasky 		goto free;
407*d6b92ffaSHans Petter Selasky 	}
408*d6b92ffaSHans Petter Selasky 
409*d6b92ffaSHans Petter Selasky 	ret = rconnect(rs, res->ai_addr, res->ai_addrlen);
410*d6b92ffaSHans Petter Selasky 	if (ret) {
411*d6b92ffaSHans Petter Selasky 		perror("rconnect failed\n");
412*d6b92ffaSHans Petter Selasky 		rclose(rs);
413*d6b92ffaSHans Petter Selasky 		rs = ret;
414*d6b92ffaSHans Petter Selasky 	}
415*d6b92ffaSHans Petter Selasky 
416*d6b92ffaSHans Petter Selasky free:
417*d6b92ffaSHans Petter Selasky 	freeaddrinfo(res);
418*d6b92ffaSHans Petter Selasky 	return rs;
419*d6b92ffaSHans Petter Selasky }
420*d6b92ffaSHans Petter Selasky 
client_open(int rs)421*d6b92ffaSHans Petter Selasky static int client_open(int rs)
422*d6b92ffaSHans Petter Selasky {
423*d6b92ffaSHans Petter Selasky 	struct msg_open *msg;
424*d6b92ffaSHans Petter Selasky 	struct stat stats;
425*d6b92ffaSHans Petter Selasky 	uint32_t len;
426*d6b92ffaSHans Petter Selasky 	int ret;
427*d6b92ffaSHans Petter Selasky 
428*d6b92ffaSHans Petter Selasky 	printf("opening...");
429*d6b92ffaSHans Petter Selasky 	fflush(NULL);
430*d6b92ffaSHans Petter Selasky 	fd = open(src_file, O_RDONLY);
431*d6b92ffaSHans Petter Selasky 	if (fd < 0)
432*d6b92ffaSHans Petter Selasky 		return fd;
433*d6b92ffaSHans Petter Selasky 
434*d6b92ffaSHans Petter Selasky 	ret = fstat(fd, &stats);
435*d6b92ffaSHans Petter Selasky 	if (ret < 0)
436*d6b92ffaSHans Petter Selasky 		goto err1;
437*d6b92ffaSHans Petter Selasky 
438*d6b92ffaSHans Petter Selasky 	bytes = (uint64_t) stats.st_size;
439*d6b92ffaSHans Petter Selasky 	file_addr = mmap(NULL, bytes, PROT_READ, MAP_SHARED, fd, 0);
440*d6b92ffaSHans Petter Selasky 	if (file_addr == (void *) -1) {
441*d6b92ffaSHans Petter Selasky 		ret = errno;
442*d6b92ffaSHans Petter Selasky 		goto err1;
443*d6b92ffaSHans Petter Selasky 	}
444*d6b92ffaSHans Petter Selasky 
445*d6b92ffaSHans Petter Selasky 	len = (((uint32_t) strlen(dst_file)) + 8) & 0xFFFFFFF8;
446*d6b92ffaSHans Petter Selasky 	msg = calloc(1, sizeof(*msg) + len);
447*d6b92ffaSHans Petter Selasky 	if (!msg) {
448*d6b92ffaSHans Petter Selasky 		ret = -1;
449*d6b92ffaSHans Petter Selasky 		goto err2;
450*d6b92ffaSHans Petter Selasky 	}
451*d6b92ffaSHans Petter Selasky 
452*d6b92ffaSHans Petter Selasky 	msg->hdr.command = CMD_OPEN;
453*d6b92ffaSHans Petter Selasky 	msg->hdr.len = sizeof(*msg) + len;
454*d6b92ffaSHans Petter Selasky 	msg->hdr.data = (uint32_t) stats.st_mode;
455*d6b92ffaSHans Petter Selasky 	strcpy(msg->path, dst_file);
456*d6b92ffaSHans Petter Selasky 	ret = rsend(rs, msg, msg->hdr.len, 0);
457*d6b92ffaSHans Petter Selasky 	if (ret != msg->hdr.len)
458*d6b92ffaSHans Petter Selasky 		goto err3;
459*d6b92ffaSHans Petter Selasky 
460*d6b92ffaSHans Petter Selasky 	ret = msg_get_resp(rs, &msg->hdr, CMD_OPEN);
461*d6b92ffaSHans Petter Selasky 	if (ret)
462*d6b92ffaSHans Petter Selasky 		goto err3;
463*d6b92ffaSHans Petter Selasky 
464*d6b92ffaSHans Petter Selasky 	return 0;
465*d6b92ffaSHans Petter Selasky 
466*d6b92ffaSHans Petter Selasky err3:
467*d6b92ffaSHans Petter Selasky 	free(msg);
468*d6b92ffaSHans Petter Selasky err2:
469*d6b92ffaSHans Petter Selasky 	munmap(file_addr, bytes);
470*d6b92ffaSHans Petter Selasky err1:
471*d6b92ffaSHans Petter Selasky 	close(fd);
472*d6b92ffaSHans Petter Selasky 	return ret;
473*d6b92ffaSHans Petter Selasky }
474*d6b92ffaSHans Petter Selasky 
client_start_write(int rs)475*d6b92ffaSHans Petter Selasky static int client_start_write(int rs)
476*d6b92ffaSHans Petter Selasky {
477*d6b92ffaSHans Petter Selasky 	struct msg_write msg;
478*d6b92ffaSHans Petter Selasky 	int ret;
479*d6b92ffaSHans Petter Selasky 
480*d6b92ffaSHans Petter Selasky 	printf("transferring");
481*d6b92ffaSHans Petter Selasky 	fflush(NULL);
482*d6b92ffaSHans Petter Selasky 	memset(&msg, 0, sizeof msg);
483*d6b92ffaSHans Petter Selasky 	msg.hdr.command = CMD_WRITE;
484*d6b92ffaSHans Petter Selasky 	msg.hdr.len = sizeof(msg);
485*d6b92ffaSHans Petter Selasky 	msg.size = bytes;
486*d6b92ffaSHans Petter Selasky 
487*d6b92ffaSHans Petter Selasky 	ret = rsend(rs, &msg, sizeof msg, 0);
488*d6b92ffaSHans Petter Selasky 	if (ret != msg.hdr.len)
489*d6b92ffaSHans Petter Selasky 		return ret;
490*d6b92ffaSHans Petter Selasky 
491*d6b92ffaSHans Petter Selasky 	return 0;
492*d6b92ffaSHans Petter Selasky }
493*d6b92ffaSHans Petter Selasky 
client_close(int rs)494*d6b92ffaSHans Petter Selasky static int client_close(int rs)
495*d6b92ffaSHans Petter Selasky {
496*d6b92ffaSHans Petter Selasky 	struct msg_hdr msg;
497*d6b92ffaSHans Petter Selasky 	int ret;
498*d6b92ffaSHans Petter Selasky 
499*d6b92ffaSHans Petter Selasky 	printf("closing...");
500*d6b92ffaSHans Petter Selasky 	fflush(NULL);
501*d6b92ffaSHans Petter Selasky 	memset(&msg, 0, sizeof msg);
502*d6b92ffaSHans Petter Selasky 	msg.command = CMD_CLOSE;
503*d6b92ffaSHans Petter Selasky 	msg.len = sizeof msg;
504*d6b92ffaSHans Petter Selasky 	ret = rsend(rs, (char *) &msg, msg.len, 0);
505*d6b92ffaSHans Petter Selasky 	if (ret != msg.len)
506*d6b92ffaSHans Petter Selasky 		goto out;
507*d6b92ffaSHans Petter Selasky 
508*d6b92ffaSHans Petter Selasky 	ret = msg_get_resp(rs, &msg, CMD_CLOSE);
509*d6b92ffaSHans Petter Selasky 	if (ret)
510*d6b92ffaSHans Petter Selasky 		goto out;
511*d6b92ffaSHans Petter Selasky 
512*d6b92ffaSHans Petter Selasky 	printf("done\n");
513*d6b92ffaSHans Petter Selasky out:
514*d6b92ffaSHans Petter Selasky 	munmap(file_addr, bytes);
515*d6b92ffaSHans Petter Selasky 	close(fd);
516*d6b92ffaSHans Petter Selasky 	return ret;
517*d6b92ffaSHans Petter Selasky }
518*d6b92ffaSHans Petter Selasky 
client_run(void)519*d6b92ffaSHans Petter Selasky static int client_run(void)
520*d6b92ffaSHans Petter Selasky {
521*d6b92ffaSHans Petter Selasky 	struct msg_hdr ack;
522*d6b92ffaSHans Petter Selasky 	int ret, rs;
523*d6b92ffaSHans Petter Selasky 	size_t len;
524*d6b92ffaSHans Petter Selasky 
525*d6b92ffaSHans Petter Selasky 	rs = client_connect();
526*d6b92ffaSHans Petter Selasky 	if (rs < 0)
527*d6b92ffaSHans Petter Selasky 		return rs;
528*d6b92ffaSHans Petter Selasky 
529*d6b92ffaSHans Petter Selasky 	ret = client_open(rs);
530*d6b92ffaSHans Petter Selasky 	if (ret)
531*d6b92ffaSHans Petter Selasky 		goto shutdown;
532*d6b92ffaSHans Petter Selasky 
533*d6b92ffaSHans Petter Selasky 	ret = client_start_write(rs);
534*d6b92ffaSHans Petter Selasky 	if (ret)
535*d6b92ffaSHans Petter Selasky 		goto close;
536*d6b92ffaSHans Petter Selasky 
537*d6b92ffaSHans Petter Selasky 	printf("...");
538*d6b92ffaSHans Petter Selasky 	fflush(NULL);
539*d6b92ffaSHans Petter Selasky 	gettimeofday(&start, NULL);
540*d6b92ffaSHans Petter Selasky 	len = rsend(rs, file_addr, bytes, 0);
541*d6b92ffaSHans Petter Selasky 	if (len == bytes)
542*d6b92ffaSHans Petter Selasky 		ret = msg_get_resp(rs, &ack, CMD_WRITE);
543*d6b92ffaSHans Petter Selasky 	else
544*d6b92ffaSHans Petter Selasky 		ret = (int) len;
545*d6b92ffaSHans Petter Selasky 
546*d6b92ffaSHans Petter Selasky 	gettimeofday(&end, NULL);
547*d6b92ffaSHans Petter Selasky 
548*d6b92ffaSHans Petter Selasky close:
549*d6b92ffaSHans Petter Selasky 	client_close(rs);
550*d6b92ffaSHans Petter Selasky shutdown:
551*d6b92ffaSHans Petter Selasky 	rshutdown(rs, SHUT_RDWR);
552*d6b92ffaSHans Petter Selasky 	rclose(rs);
553*d6b92ffaSHans Petter Selasky 	if (!ret)
554*d6b92ffaSHans Petter Selasky 		show_perf();
555*d6b92ffaSHans Petter Selasky 	return ret;
556*d6b92ffaSHans Petter Selasky }
557*d6b92ffaSHans Petter Selasky 
show_usage(char * program)558*d6b92ffaSHans Petter Selasky static void show_usage(char *program)
559*d6b92ffaSHans Petter Selasky {
560*d6b92ffaSHans Petter Selasky 	printf("usage 1: %s [options]\n", program);
561*d6b92ffaSHans Petter Selasky 	printf("\t     starts the server application\n");
562*d6b92ffaSHans Petter Selasky 	printf("\t[-p  port_number]\n");
563*d6b92ffaSHans Petter Selasky 	printf("usage 2: %s source server[:destination] [options]\n", program);
564*d6b92ffaSHans Petter Selasky 	printf("\t     source - file name and path\n");
565*d6b92ffaSHans Petter Selasky 	printf("\t     server - name or address\n");
566*d6b92ffaSHans Petter Selasky 	printf("\t     destination - file name and path\n");
567*d6b92ffaSHans Petter Selasky 	printf("\t[-p  port_number]\n");
568*d6b92ffaSHans Petter Selasky 	exit(1);
569*d6b92ffaSHans Petter Selasky }
570*d6b92ffaSHans Petter Selasky 
server_opts(int argc,char ** argv)571*d6b92ffaSHans Petter Selasky static void server_opts(int argc, char **argv)
572*d6b92ffaSHans Petter Selasky {
573*d6b92ffaSHans Petter Selasky 	int op;
574*d6b92ffaSHans Petter Selasky 
575*d6b92ffaSHans Petter Selasky 	while ((op = getopt(argc, argv, "p:")) != -1) {
576*d6b92ffaSHans Petter Selasky 		switch (op) {
577*d6b92ffaSHans Petter Selasky 		case 'p':
578*d6b92ffaSHans Petter Selasky 			port = optarg;
579*d6b92ffaSHans Petter Selasky 			break;
580*d6b92ffaSHans Petter Selasky 		default:
581*d6b92ffaSHans Petter Selasky 			show_usage(argv[0]);
582*d6b92ffaSHans Petter Selasky 		}
583*d6b92ffaSHans Petter Selasky 	}
584*d6b92ffaSHans Petter Selasky }
585*d6b92ffaSHans Petter Selasky 
client_opts(int argc,char ** argv)586*d6b92ffaSHans Petter Selasky static void client_opts(int argc, char **argv)
587*d6b92ffaSHans Petter Selasky {
588*d6b92ffaSHans Petter Selasky 	int op;
589*d6b92ffaSHans Petter Selasky 
590*d6b92ffaSHans Petter Selasky 	if (argc < 3)
591*d6b92ffaSHans Petter Selasky 		show_usage(argv[0]);
592*d6b92ffaSHans Petter Selasky 
593*d6b92ffaSHans Petter Selasky 	src_file = argv[1];
594*d6b92ffaSHans Petter Selasky 	dst_addr = argv[2];
595*d6b92ffaSHans Petter Selasky 	dst_file = strchr(dst_addr, ':');
596*d6b92ffaSHans Petter Selasky 	if (dst_file) {
597*d6b92ffaSHans Petter Selasky 		*dst_file = '\0';
598*d6b92ffaSHans Petter Selasky 		dst_file++;
599*d6b92ffaSHans Petter Selasky 	}
600*d6b92ffaSHans Petter Selasky 	if (!dst_file)
601*d6b92ffaSHans Petter Selasky 		dst_file = src_file;
602*d6b92ffaSHans Petter Selasky 
603*d6b92ffaSHans Petter Selasky 	while ((op = getopt(argc, argv, "p:")) != -1) {
604*d6b92ffaSHans Petter Selasky 		switch (op) {
605*d6b92ffaSHans Petter Selasky 		case 'p':
606*d6b92ffaSHans Petter Selasky 			port = optarg;
607*d6b92ffaSHans Petter Selasky 			break;
608*d6b92ffaSHans Petter Selasky 		default:
609*d6b92ffaSHans Petter Selasky 			show_usage(argv[0]);
610*d6b92ffaSHans Petter Selasky 		}
611*d6b92ffaSHans Petter Selasky 	}
612*d6b92ffaSHans Petter Selasky 
613*d6b92ffaSHans Petter Selasky }
614*d6b92ffaSHans Petter Selasky 
main(int argc,char ** argv)615*d6b92ffaSHans Petter Selasky int main(int argc, char **argv)
616*d6b92ffaSHans Petter Selasky {
617*d6b92ffaSHans Petter Selasky 	int ret;
618*d6b92ffaSHans Petter Selasky 
619*d6b92ffaSHans Petter Selasky 	if (argc == 1 || argv[1][0] == '-') {
620*d6b92ffaSHans Petter Selasky 		server_opts(argc, argv);
621*d6b92ffaSHans Petter Selasky 		ret = server_run();
622*d6b92ffaSHans Petter Selasky 	} else {
623*d6b92ffaSHans Petter Selasky 		client_opts(argc, argv);
624*d6b92ffaSHans Petter Selasky 		ret = client_run();
625*d6b92ffaSHans Petter Selasky 	}
626*d6b92ffaSHans Petter Selasky 
627*d6b92ffaSHans Petter Selasky 	return ret;
628*d6b92ffaSHans Petter Selasky }
629