1321936Shselasky/*
2321936Shselasky * Copyright (c) 2011 Intel Corporation.  All rights reserved.
3321936Shselasky *
4321936Shselasky * This software is available to you under the OpenIB.org BSD license
5321936Shselasky * below:
6321936Shselasky *
7321936Shselasky *     Redistribution and use in source and binary forms, with or
8321936Shselasky *     without modification, are permitted provided that the following
9321936Shselasky *     conditions are met:
10321936Shselasky *
11321936Shselasky *      - Redistributions of source code must retain the above
12321936Shselasky *        copyright notice, this list of conditions and the following
13321936Shselasky *        disclaimer.
14321936Shselasky *
15321936Shselasky *      - Redistributions in binary form must reproduce the above
16321936Shselasky *        copyright notice, this list of conditions and the following
17321936Shselasky *        disclaimer in the documentation and/or other materials
18321936Shselasky *        provided with the distribution.
19321936Shselasky *
20321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
23321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27321936Shselasky * SOFTWARE.
28321936Shselasky */
29321936Shselasky
30321936Shselasky#include <stdio.h>
31321936Shselasky#include <stdlib.h>
32321936Shselasky#include <string.h>
33321936Shselasky#include <strings.h>
34321936Shselasky#include <errno.h>
35321936Shselasky#include <getopt.h>
36321936Shselasky#include <arpa/inet.h>
37321936Shselasky#include <sys/mman.h>
38321936Shselasky#include <sys/types.h>
39321936Shselasky#include <sys/socket.h>
40321936Shselasky#include <sys/time.h>
41321936Shselasky#include <sys/stat.h>
42321936Shselasky#include <fcntl.h>
43321936Shselasky#include <netdb.h>
44321936Shselasky#include <unistd.h>
45321936Shselasky
46321936Shselasky#include <rdma/rsocket.h>
47321936Shselasky
48321936Shselaskyunion rsocket_address {
49321936Shselasky	struct sockaddr		sa;
50321936Shselasky	struct sockaddr_in	sin;
51321936Shselasky	struct sockaddr_in6	sin6;
52321936Shselasky	struct sockaddr_storage storage;
53321936Shselasky};
54321936Shselasky
55321936Shselaskystatic const char *port = "7427";
56321936Shselaskystatic char *dst_addr;
57321936Shselaskystatic char *dst_file;
58321936Shselaskystatic char *src_file;
59321936Shselaskystatic struct timeval start, end;
60321936Shselasky//static void buf[1024 * 1024];
61321936Shselaskystatic uint64_t bytes;
62321936Shselaskystatic int fd;
63321936Shselaskystatic void *file_addr;
64321936Shselasky
65321936Shselaskyenum {
66321936Shselasky	CMD_NOOP,
67321936Shselasky	CMD_OPEN,
68321936Shselasky	CMD_CLOSE,
69321936Shselasky	CMD_WRITE,
70321936Shselasky	CMD_RESP = 0x80,
71321936Shselasky};
72321936Shselasky
73321936Shselasky/* TODO: handle byte swapping */
74321936Shselaskystruct msg_hdr {
75321936Shselasky	uint8_t  version;
76321936Shselasky	uint8_t  command;
77321936Shselasky	uint16_t len;
78321936Shselasky	uint32_t data;
79321936Shselasky	uint64_t id;
80321936Shselasky};
81321936Shselasky
82321936Shselaskystruct msg_open {
83321936Shselasky	struct msg_hdr hdr;
84321936Shselasky	char path[0];
85321936Shselasky};
86321936Shselasky
87321936Shselaskystruct msg_write {
88321936Shselasky	struct msg_hdr hdr;
89321936Shselasky	uint64_t size;
90321936Shselasky};
91321936Shselasky
92321936Shselaskystatic void show_perf(void)
93321936Shselasky{
94321936Shselasky	float usec;
95321936Shselasky
96321936Shselasky	usec = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
97321936Shselasky
98321936Shselasky	printf("%lld bytes in %.2f seconds = %.2f Gb/sec\n",
99321936Shselasky	       (long long) bytes, usec / 1000000., (bytes * 8) / (1000. * usec));
100321936Shselasky}
101321936Shselasky
102321936Shselaskystatic char *_ntop(union rsocket_address *rsa)
103321936Shselasky{
104321936Shselasky	static char addr[32];
105321936Shselasky
106321936Shselasky	switch (rsa->sa.sa_family) {
107321936Shselasky	case AF_INET:
108321936Shselasky		inet_ntop(AF_INET, &rsa->sin.sin_addr, addr, sizeof addr);
109321936Shselasky		break;
110321936Shselasky	case AF_INET6:
111321936Shselasky		inet_ntop(AF_INET6, &rsa->sin6.sin6_addr, addr, sizeof addr);
112321936Shselasky		break;
113321936Shselasky	default:
114321936Shselasky		addr[0] = '\0';
115321936Shselasky		break;
116321936Shselasky	}
117321936Shselasky
118321936Shselasky	return addr;
119321936Shselasky}
120321936Shselasky
121321936Shselaskystatic size_t _recv(int rs, char *msg, size_t len)
122321936Shselasky{
123321936Shselasky	size_t ret, offset;
124321936Shselasky
125321936Shselasky	for (offset = 0; offset < len; offset += ret) {
126321936Shselasky		ret = rrecv(rs, msg + offset, len - offset, 0);
127321936Shselasky		if (ret <= 0)
128321936Shselasky			return ret;
129321936Shselasky	}
130321936Shselasky
131321936Shselasky	return len;
132321936Shselasky}
133321936Shselasky
134321936Shselaskystatic int msg_recv_hdr(int rs, struct msg_hdr *hdr)
135321936Shselasky{
136321936Shselasky	int ret;
137321936Shselasky
138321936Shselasky	ret = _recv(rs, (char *) hdr, sizeof *hdr);
139321936Shselasky	if (ret != sizeof *hdr)
140321936Shselasky		return -1;
141321936Shselasky
142321936Shselasky	if (hdr->version || hdr->len < sizeof *hdr) {
143321936Shselasky		printf("invalid version %d or length %d\n",
144321936Shselasky		       hdr->version, hdr->len);
145321936Shselasky		return -1;
146321936Shselasky	}
147321936Shselasky
148321936Shselasky	return sizeof *hdr;
149321936Shselasky}
150321936Shselasky
151321936Shselaskystatic int msg_get_resp(int rs, struct msg_hdr *msg, uint8_t cmd)
152321936Shselasky{
153321936Shselasky	int ret;
154321936Shselasky
155321936Shselasky	ret = msg_recv_hdr(rs, msg);
156321936Shselasky	if (ret != sizeof *msg)
157321936Shselasky		return ret;
158321936Shselasky
159321936Shselasky	if ((msg->len != sizeof *msg) || (msg->command != (cmd | CMD_RESP))) {
160321936Shselasky		printf("invalid length %d or bad command response %x:%x\n",
161321936Shselasky		       msg->len, msg->command, cmd | CMD_RESP);
162321936Shselasky		return -1;
163321936Shselasky	}
164321936Shselasky
165321936Shselasky	return msg->data;
166321936Shselasky}
167321936Shselasky
168321936Shselaskystatic void msg_send_resp(int rs, struct msg_hdr *msg, uint32_t status)
169321936Shselasky{
170321936Shselasky	struct msg_hdr resp;
171321936Shselasky
172321936Shselasky	resp.version = 0;
173321936Shselasky	resp.command = msg->command | CMD_RESP;
174321936Shselasky	resp.len = sizeof resp;
175321936Shselasky	resp.data = status;
176321936Shselasky	resp.id = msg->id;
177321936Shselasky	rsend(rs, (char *) &resp, sizeof resp, 0);
178321936Shselasky}
179321936Shselasky
180321936Shselaskystatic int server_listen(void)
181321936Shselasky{
182321936Shselasky	struct addrinfo hints, *res;
183321936Shselasky	int ret, rs;
184321936Shselasky
185321936Shselasky	memset(&hints, 0, sizeof hints);
186321936Shselasky	hints.ai_flags = RAI_PASSIVE;
187321936Shselasky 	ret = getaddrinfo(NULL, port, &hints, &res);
188321936Shselasky	if (ret) {
189321936Shselasky		printf("getaddrinfo failed: %s\n", gai_strerror(ret));
190321936Shselasky		return ret;
191321936Shselasky	}
192321936Shselasky
193321936Shselasky	rs = rsocket(res->ai_family, res->ai_socktype, res->ai_protocol);
194321936Shselasky	if (rs < 0) {
195321936Shselasky		perror("rsocket failed\n");
196321936Shselasky		ret = rs;
197321936Shselasky		goto free;
198321936Shselasky	}
199321936Shselasky
200321936Shselasky	ret = 1;
201321936Shselasky	ret = rsetsockopt(rs, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof ret);
202321936Shselasky	if (ret) {
203321936Shselasky		perror("rsetsockopt failed");
204321936Shselasky		goto close;
205321936Shselasky	}
206321936Shselasky
207321936Shselasky	ret = rbind(rs, res->ai_addr, res->ai_addrlen);
208321936Shselasky	if (ret) {
209321936Shselasky		perror("rbind failed");
210321936Shselasky		goto close;
211321936Shselasky	}
212321936Shselasky
213321936Shselasky	ret = rlisten(rs, 1);
214321936Shselasky	if (ret) {
215321936Shselasky		perror("rlisten failed");
216321936Shselasky		goto close;
217321936Shselasky	}
218321936Shselasky
219321936Shselasky	ret = rs;
220321936Shselasky	goto free;
221321936Shselasky
222321936Shselaskyclose:
223321936Shselasky	rclose(rs);
224321936Shselaskyfree:
225321936Shselasky	freeaddrinfo(res);
226321936Shselasky	return ret;
227321936Shselasky}
228321936Shselasky
229321936Shselaskystatic int server_open(int rs, struct msg_hdr *msg)
230321936Shselasky{
231321936Shselasky	char *path = NULL;
232321936Shselasky	int ret, len;
233321936Shselasky
234321936Shselasky	printf("opening: ");
235321936Shselasky	fflush(NULL);
236321936Shselasky	if (file_addr || fd > 0) {
237321936Shselasky		printf("cannot open another file\n");
238321936Shselasky		ret = EBUSY;
239321936Shselasky		goto out;
240321936Shselasky	}
241321936Shselasky
242321936Shselasky	len = msg->len - sizeof *msg;
243321936Shselasky	path = malloc(len);
244321936Shselasky	if (!path) {
245321936Shselasky		printf("cannot allocate path name\n");
246321936Shselasky		ret = ENOMEM;
247321936Shselasky		goto out;
248321936Shselasky	}
249321936Shselasky
250321936Shselasky	ret = _recv(rs, path, len);
251321936Shselasky	if (ret != len) {
252321936Shselasky		printf("error receiving path\n");
253321936Shselasky		goto out;
254321936Shselasky	}
255321936Shselasky
256321936Shselasky	printf("%s, ", path);
257321936Shselasky	fflush(NULL);
258321936Shselasky	fd = open(path, O_RDWR | O_CREAT | O_TRUNC, msg->data);
259321936Shselasky	if (fd < 0) {
260321936Shselasky		printf("unable to open destination file\n");
261321936Shselasky		ret = errno;
262321936Shselasky	}
263321936Shselasky
264321936Shselasky	ret = 0;
265321936Shselaskyout:
266321936Shselasky	if (path)
267321936Shselasky		free(path);
268321936Shselasky
269321936Shselasky	msg_send_resp(rs, msg, ret);
270321936Shselasky	return ret;
271321936Shselasky}
272321936Shselasky
273321936Shselaskystatic void server_close(int rs, struct msg_hdr *msg)
274321936Shselasky{
275321936Shselasky	printf("closing...");
276321936Shselasky	fflush(NULL);
277321936Shselasky	msg_send_resp(rs, msg, 0);
278321936Shselasky
279321936Shselasky	if (file_addr) {
280321936Shselasky		munmap(file_addr, bytes);
281321936Shselasky		file_addr = NULL;
282321936Shselasky	}
283321936Shselasky
284321936Shselasky	if (fd > 0) {
285321936Shselasky		close(fd);
286321936Shselasky		fd = 0;
287321936Shselasky	}
288321936Shselasky	printf("done\n");
289321936Shselasky}
290321936Shselasky
291321936Shselaskystatic int server_write(int rs, struct msg_hdr *msg)
292321936Shselasky{
293321936Shselasky	size_t len;
294321936Shselasky	int ret;
295321936Shselasky
296321936Shselasky	printf("transferring");
297321936Shselasky	fflush(NULL);
298321936Shselasky	if (fd <= 0) {
299321936Shselasky		printf("...file not opened\n");
300321936Shselasky		ret = EINVAL;
301321936Shselasky		goto out;
302321936Shselasky	}
303321936Shselasky
304321936Shselasky	if (msg->len != sizeof(struct msg_write)) {
305321936Shselasky		printf("...invalid message length %d\n", msg->len);
306321936Shselasky		ret = EINVAL;
307321936Shselasky		goto out;
308321936Shselasky	}
309321936Shselasky
310321936Shselasky	ret = _recv(rs, (char *) &bytes, sizeof bytes);
311321936Shselasky	if (ret != sizeof bytes)
312321936Shselasky		goto out;
313321936Shselasky
314321936Shselasky	ret = ftruncate(fd, bytes);
315321936Shselasky	if (ret)
316321936Shselasky		goto out;
317321936Shselasky
318321936Shselasky	file_addr = mmap(NULL, bytes, PROT_WRITE, MAP_SHARED, fd, 0);
319321936Shselasky	if (file_addr == (void *) -1) {
320321936Shselasky		printf("...error mapping file\n");
321321936Shselasky		ret = errno;
322321936Shselasky		goto out;
323321936Shselasky	}
324321936Shselasky
325321936Shselasky	printf("...%lld bytes...", (long long) bytes);
326321936Shselasky	fflush(NULL);
327321936Shselasky	len = _recv(rs, file_addr, bytes);
328321936Shselasky	if (len != bytes) {
329321936Shselasky		printf("...error receiving data\n");
330321936Shselasky		ret = (int) len;
331321936Shselasky	}
332321936Shselaskyout:
333321936Shselasky	msg_send_resp(rs, msg, ret);
334321936Shselasky	return ret;
335321936Shselasky}
336321936Shselasky
337321936Shselaskystatic void server_process(int rs)
338321936Shselasky{
339321936Shselasky	struct msg_hdr msg;
340321936Shselasky	int ret;
341321936Shselasky
342321936Shselasky	do {
343321936Shselasky		ret = msg_recv_hdr(rs, &msg);
344321936Shselasky		if (ret != sizeof msg)
345321936Shselasky			break;
346321936Shselasky
347321936Shselasky		switch (msg.command) {
348321936Shselasky		case CMD_OPEN:
349321936Shselasky			ret = server_open(rs, &msg);
350321936Shselasky			break;
351321936Shselasky		case CMD_CLOSE:
352321936Shselasky			server_close(rs, &msg);
353321936Shselasky			ret = 0;
354321936Shselasky			break;
355321936Shselasky		case CMD_WRITE:
356321936Shselasky			ret = server_write(rs, &msg);
357321936Shselasky			break;
358321936Shselasky		default:
359321936Shselasky			msg_send_resp(rs, &msg, EINVAL);
360321936Shselasky			ret = -1;
361321936Shselasky			break;
362321936Shselasky		}
363321936Shselasky
364321936Shselasky	} while (!ret);
365321936Shselasky}
366321936Shselasky
367321936Shselaskystatic int server_run(void)
368321936Shselasky{
369321936Shselasky	int lrs, rs;
370321936Shselasky	union rsocket_address rsa;
371321936Shselasky	socklen_t len;
372321936Shselasky
373321936Shselasky	lrs = server_listen();
374321936Shselasky	if (lrs < 0)
375321936Shselasky		return lrs;
376321936Shselasky
377321936Shselasky	while (1) {
378321936Shselasky		len = sizeof rsa;
379321936Shselasky		printf("waiting for connection...");
380321936Shselasky		fflush(NULL);
381321936Shselasky		rs = raccept(lrs, &rsa.sa, &len);
382321936Shselasky
383321936Shselasky		printf("client: %s\n", _ntop(&rsa));
384321936Shselasky		server_process(rs);
385321936Shselasky
386321936Shselasky		rshutdown(rs, SHUT_RDWR);
387321936Shselasky		rclose(rs);
388321936Shselasky	}
389321936Shselasky	return 0;
390321936Shselasky}
391321936Shselasky
392321936Shselaskystatic int client_connect(void)
393321936Shselasky{
394321936Shselasky	struct addrinfo *res;
395321936Shselasky	int ret, rs;
396321936Shselasky
397321936Shselasky 	ret = getaddrinfo(dst_addr, port, NULL, &res);
398321936Shselasky	if (ret) {
399321936Shselasky		printf("getaddrinfo failed: %s\n", gai_strerror(ret));
400321936Shselasky		return ret;
401321936Shselasky	}
402321936Shselasky
403321936Shselasky	rs = rsocket(res->ai_family, res->ai_socktype, res->ai_protocol);
404321936Shselasky	if (rs < 0) {
405321936Shselasky		perror("rsocket failed\n");
406321936Shselasky		goto free;
407321936Shselasky	}
408321936Shselasky
409321936Shselasky	ret = rconnect(rs, res->ai_addr, res->ai_addrlen);
410321936Shselasky	if (ret) {
411321936Shselasky		perror("rconnect failed\n");
412321936Shselasky		rclose(rs);
413321936Shselasky		rs = ret;
414321936Shselasky	}
415321936Shselasky
416321936Shselaskyfree:
417321936Shselasky	freeaddrinfo(res);
418321936Shselasky	return rs;
419321936Shselasky}
420321936Shselasky
421321936Shselaskystatic int client_open(int rs)
422321936Shselasky{
423321936Shselasky	struct msg_open *msg;
424321936Shselasky	struct stat stats;
425321936Shselasky	uint32_t len;
426321936Shselasky	int ret;
427321936Shselasky
428321936Shselasky	printf("opening...");
429321936Shselasky	fflush(NULL);
430321936Shselasky	fd = open(src_file, O_RDONLY);
431321936Shselasky	if (fd < 0)
432321936Shselasky		return fd;
433321936Shselasky
434321936Shselasky	ret = fstat(fd, &stats);
435321936Shselasky	if (ret < 0)
436321936Shselasky		goto err1;
437321936Shselasky
438321936Shselasky	bytes = (uint64_t) stats.st_size;
439321936Shselasky	file_addr = mmap(NULL, bytes, PROT_READ, MAP_SHARED, fd, 0);
440321936Shselasky	if (file_addr == (void *) -1) {
441321936Shselasky		ret = errno;
442321936Shselasky		goto err1;
443321936Shselasky	}
444321936Shselasky
445321936Shselasky	len = (((uint32_t) strlen(dst_file)) + 8) & 0xFFFFFFF8;
446321936Shselasky	msg = calloc(1, sizeof(*msg) + len);
447321936Shselasky	if (!msg) {
448321936Shselasky		ret = -1;
449321936Shselasky		goto err2;
450321936Shselasky	}
451321936Shselasky
452321936Shselasky	msg->hdr.command = CMD_OPEN;
453321936Shselasky	msg->hdr.len = sizeof(*msg) + len;
454321936Shselasky	msg->hdr.data = (uint32_t) stats.st_mode;
455321936Shselasky	strcpy(msg->path, dst_file);
456321936Shselasky	ret = rsend(rs, msg, msg->hdr.len, 0);
457321936Shselasky	if (ret != msg->hdr.len)
458321936Shselasky		goto err3;
459321936Shselasky
460321936Shselasky	ret = msg_get_resp(rs, &msg->hdr, CMD_OPEN);
461321936Shselasky	if (ret)
462321936Shselasky		goto err3;
463321936Shselasky
464321936Shselasky	return 0;
465321936Shselasky
466321936Shselaskyerr3:
467321936Shselasky	free(msg);
468321936Shselaskyerr2:
469321936Shselasky	munmap(file_addr, bytes);
470321936Shselaskyerr1:
471321936Shselasky	close(fd);
472321936Shselasky	return ret;
473321936Shselasky}
474321936Shselasky
475321936Shselaskystatic int client_start_write(int rs)
476321936Shselasky{
477321936Shselasky	struct msg_write msg;
478321936Shselasky	int ret;
479321936Shselasky
480321936Shselasky	printf("transferring");
481321936Shselasky	fflush(NULL);
482321936Shselasky	memset(&msg, 0, sizeof msg);
483321936Shselasky	msg.hdr.command = CMD_WRITE;
484321936Shselasky	msg.hdr.len = sizeof(msg);
485321936Shselasky	msg.size = bytes;
486321936Shselasky
487321936Shselasky	ret = rsend(rs, &msg, sizeof msg, 0);
488321936Shselasky	if (ret != msg.hdr.len)
489321936Shselasky		return ret;
490321936Shselasky
491321936Shselasky	return 0;
492321936Shselasky}
493321936Shselasky
494321936Shselaskystatic int client_close(int rs)
495321936Shselasky{
496321936Shselasky	struct msg_hdr msg;
497321936Shselasky	int ret;
498321936Shselasky
499321936Shselasky	printf("closing...");
500321936Shselasky	fflush(NULL);
501321936Shselasky	memset(&msg, 0, sizeof msg);
502321936Shselasky	msg.command = CMD_CLOSE;
503321936Shselasky	msg.len = sizeof msg;
504321936Shselasky	ret = rsend(rs, (char *) &msg, msg.len, 0);
505321936Shselasky	if (ret != msg.len)
506321936Shselasky		goto out;
507321936Shselasky
508321936Shselasky	ret = msg_get_resp(rs, &msg, CMD_CLOSE);
509321936Shselasky	if (ret)
510321936Shselasky		goto out;
511321936Shselasky
512321936Shselasky	printf("done\n");
513321936Shselaskyout:
514321936Shselasky	munmap(file_addr, bytes);
515321936Shselasky	close(fd);
516321936Shselasky	return ret;
517321936Shselasky}
518321936Shselasky
519321936Shselaskystatic int client_run(void)
520321936Shselasky{
521321936Shselasky	struct msg_hdr ack;
522321936Shselasky	int ret, rs;
523321936Shselasky	size_t len;
524321936Shselasky
525321936Shselasky	rs = client_connect();
526321936Shselasky	if (rs < 0)
527321936Shselasky		return rs;
528321936Shselasky
529321936Shselasky	ret = client_open(rs);
530321936Shselasky	if (ret)
531321936Shselasky		goto shutdown;
532321936Shselasky
533321936Shselasky	ret = client_start_write(rs);
534321936Shselasky	if (ret)
535321936Shselasky		goto close;
536321936Shselasky
537321936Shselasky	printf("...");
538321936Shselasky	fflush(NULL);
539321936Shselasky	gettimeofday(&start, NULL);
540321936Shselasky	len = rsend(rs, file_addr, bytes, 0);
541321936Shselasky	if (len == bytes)
542321936Shselasky		ret = msg_get_resp(rs, &ack, CMD_WRITE);
543321936Shselasky	else
544321936Shselasky		ret = (int) len;
545321936Shselasky
546321936Shselasky	gettimeofday(&end, NULL);
547321936Shselasky
548321936Shselaskyclose:
549321936Shselasky	client_close(rs);
550321936Shselaskyshutdown:
551321936Shselasky	rshutdown(rs, SHUT_RDWR);
552321936Shselasky	rclose(rs);
553321936Shselasky	if (!ret)
554321936Shselasky		show_perf();
555321936Shselasky	return ret;
556321936Shselasky}
557321936Shselasky
558321936Shselaskystatic void show_usage(char *program)
559321936Shselasky{
560321936Shselasky	printf("usage 1: %s [options]\n", program);
561321936Shselasky	printf("\t     starts the server application\n");
562321936Shselasky	printf("\t[-p  port_number]\n");
563321936Shselasky	printf("usage 2: %s source server[:destination] [options]\n", program);
564321936Shselasky	printf("\t     source - file name and path\n");
565321936Shselasky	printf("\t     server - name or address\n");
566321936Shselasky	printf("\t     destination - file name and path\n");
567321936Shselasky	printf("\t[-p  port_number]\n");
568321936Shselasky	exit(1);
569321936Shselasky}
570321936Shselasky
571321936Shselaskystatic void server_opts(int argc, char **argv)
572321936Shselasky{
573321936Shselasky	int op;
574321936Shselasky
575321936Shselasky	while ((op = getopt(argc, argv, "p:")) != -1) {
576321936Shselasky		switch (op) {
577321936Shselasky		case 'p':
578321936Shselasky			port = optarg;
579321936Shselasky			break;
580321936Shselasky		default:
581321936Shselasky			show_usage(argv[0]);
582321936Shselasky		}
583321936Shselasky	}
584321936Shselasky}
585321936Shselasky
586321936Shselaskystatic void client_opts(int argc, char **argv)
587321936Shselasky{
588321936Shselasky	int op;
589321936Shselasky
590321936Shselasky	if (argc < 3)
591321936Shselasky		show_usage(argv[0]);
592321936Shselasky
593321936Shselasky	src_file = argv[1];
594321936Shselasky	dst_addr = argv[2];
595321936Shselasky	dst_file = strchr(dst_addr, ':');
596321936Shselasky	if (dst_file) {
597321936Shselasky		*dst_file = '\0';
598321936Shselasky		dst_file++;
599321936Shselasky	}
600321936Shselasky	if (!dst_file)
601321936Shselasky		dst_file = src_file;
602321936Shselasky
603321936Shselasky	while ((op = getopt(argc, argv, "p:")) != -1) {
604321936Shselasky		switch (op) {
605321936Shselasky		case 'p':
606321936Shselasky			port = optarg;
607321936Shselasky			break;
608321936Shselasky		default:
609321936Shselasky			show_usage(argv[0]);
610321936Shselasky		}
611321936Shselasky	}
612321936Shselasky
613321936Shselasky}
614321936Shselasky
615321936Shselaskyint main(int argc, char **argv)
616321936Shselasky{
617321936Shselasky	int ret;
618321936Shselasky
619321936Shselasky	if (argc == 1 || argv[1][0] == '-') {
620321936Shselasky		server_opts(argc, argv);
621321936Shselasky		ret = server_run();
622321936Shselasky	} else {
623321936Shselasky		client_opts(argc, argv);
624321936Shselasky		ret = client_run();
625321936Shselasky	}
626321936Shselasky
627321936Shselasky	return ret;
628321936Shselasky}
629