1 /*-
2  *  Copyright (c) 2002, 2003  Peter Pentchev
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions
7  *  are met:
8  *  1. Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
RawVideoTypeToCommonVideoVideoType(RawVideoType type)24  *  SUCH DAMAGE.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/select.h>
30 
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "urelay.h"
39 #include "ur_err.h"
40 
41 __RINGID("$Ringlet: c/net/urelay/urelay.c,v 1.3 2003/07/16 10:21:04 roam Exp $");
42 
43 int		verbose, quiet;
44 
45 char		ur_verstr[64] = "urelay";
46 char		*msgsrc, *msgdst;
47 char		*ignsrc, *igndst;
48 
49 static ur_err_t	ur_init(int, char *[]);
50 static ur_err_t	ur_close(void);
51 static ur_err_t	ur_doit(int, char *[]);
52 
53 static void	usage(void);
54 static ur_err_t	version(void);
55 
56 /*
57  * Function:
58  *         ur_makeversion()                - generate version string
59  * Inputs:
AlignInt(int value,int alignment)60  *         none
61  * Returns:
62  *         ur_err_t
63  * Modifies:
64  *         ur_verstr
65  */
66 
67 static ur_err_t
68 ur_makeversion(void) {
69 
70 	snprintf(ur_verstr, sizeof(ur_verstr), "urelay v%d.%d"
71 #if UR_VER_PRE
72 	    "-pre%d"
73 #endif /* UR_VER_PRE */
74 #if UR_VER_PATCH
75 	    "p%d"
76 #endif /* UR_VER_PATCH */
77 	    ,
78 	    UR_VER_MAJ, UR_VER_MIN
79 #if UR_VER_PRE
80 	    , UR_VER_PRE
81 #endif /* UR_VER_PRE */
82 #if UR_VER_PATCH
83 	    , UR_VER_PATCH
84 #endif /* UR_VER_PATCH */
85 		);
86 
87 	return (UR_ERR_NONE);
88 }
89 
90 static ur_err_t
91 ur_nonblock(int fd) {
92 	int flags;
93 
94 	if (fcntl(fd, F_GETFL, &flags) == -1)
95 		return (UR_ERR_FCNTL_GET);
96 	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
97 		return (UR_ERR_FCNTL_SET);
98 	return (UR_ERR_NONE);
99 }
100 
101 /*
102  * Function:
103  * 	ur_init				- general-purpose init function
104  * Inputs:
105  * 	argc, argv			- main() args for option processing
106  * Returns:
107  * 	ur_err_t
108  * 	CMDLINE
109  * Modifies:
110  * 	verbose, quiet
111  */
112 
113 static ur_err_t
114 ur_init(int argc, char *argv[]) {
115 	int ch, helpq, versq;
116 	ur_err_t err;
PrintI420VideoFrame(const I420VideoFrame & frame,FILE * file)117 
118 	helpq = versq = 0;
119 	ur_makeversion();
120 
121 	/* Process cmdline options */
122 
123 	opterr = 0;
124 	while (ch = getopt(argc, argv, UR_OPTSTR), ch != EOF)
125 		switch (ch) {
126 			case 'h':
127 				helpq = 1;
128 				break;
129 			case 'M':
130 				msgsrc = optarg;
131 				break;
132 			case 'm':
133 				msgdst = optarg;
134 				break;
135 			case 'S':
136 				ignsrc = optarg;
137 				break;
ExtractBuffer(const I420VideoFrame & input_frame,size_t size,uint8_t * buffer)138 			case 's':
139 				igndst = optarg;
140 				break;
141 			case 'q':
142 				quiet++;
143 				break;
144 			case 'V':
145 				versq = 1;
146 				break;
147 			case 'v':
148 				verbose++;
149 				break;
150 			case '?':
151 			default:
152 				usage();
153 				/* NOTREACHED */
154 		}
155 
156 	argc -= optind; argv += optind;
157 
158 	if (versq)
159 		version();
160 	if (helpq)
161 		usage();
162 	if (versq)
163 		/* no need for "|| helpq": usage() never returns */
164 		exit(UR_ERR_NONE);
165 
166 	if ((err = ur_nonblock(0)) != UR_ERR_NONE)
167 		return (err);
168 	if ((err = ur_nonblock(6)) != UR_ERR_NONE)
ConvertNV12ToRGB565(const uint8_t * src_frame,uint8_t * dst_frame,int width,int height)169 		return (err);
170 	return (UR_ERR_NONE);
171 }
172 
173 /*
174  * Function:
175  * 	ur_close			- general-purpose shutdown function
176  * Inputs:
177  * 	none
178  * Returns:
179  * 	ur_err_t
180  * 	nothing for the present (FIXME)
181  * Modifies:
ConvertRGB24ToARGB(const uint8_t * src_frame,uint8_t * dst_frame,int width,int height,int dst_stride)182  * 	nothing for the present (FIXME)
183  */
184 
185 static ur_err_t
186 ur_close(void) {
187 
188 	return (UR_ERR_NONE);
189 }
190 
ConvertRotationMode(VideoRotation rotation)191 /*
192  * Function:
193  * 	usage			- startup help info
194  * Inputs:
195  * 	none
196  * Returns:
197  * 	nothing
198  * Modifies:
199  * 	nothing, writes to stdout and exits
200  */
201 
202 void
203 usage(void) {
204 	static const char *msg[] = {
205 	    "usage: urelay [-hqVv]",
206 	    "\t-h\tprint this help text and exit;",
207 	    "\t-q\tquiet operation; multiple -q's make it even more quiet;",
208 	    "\t-V\tprint version information and exit;",
209 	    "\t-v\tverbose operation; multiple -v's increase verbosity level.",
210 	    NULL
211 	};
212 	unsigned i;
213 
214 	for (i = 0; msg[i] != NULL; i++)
215 		fprintf(stderr, "%s\n", msg[i]);
216 	exit(UR_ERR_CMDLINE);
217 }
218 
219 /*
220  * function:
221  * 	ur_version		- output version info
222  * Inputs:
223  * 	none
224  * Returns:
225  * 	UR_ERR_NONE
226  * Modifies:
227  * 	nothing, writes to stdout
228  */
229 
230 ur_err_t
231 version(void) {
232 
233 	printf("%s\n", ur_verstr);
234 
235 	if (verbose) {
236 		printf("%s\n", "Built on " __DATE__ ", " __TIME__);
237 #ifdef __GNUC__
238 		if (verbose > 1)
239 			printf("%s\n", "Compiler: GNU C " __VERSION__
240 			    " on " UR_OS " " UR_OSREL ": " UR_OSHOST);
241 #endif /* __GNUC__ */
242 	}
243 
ConvertToI420(VideoType src_video_type,const uint8_t * src_frame,int crop_x,int crop_y,int src_width,int src_height,size_t sample_size,VideoRotation rotation,I420VideoFrame * dst_frame)244 	return (UR_ERR_NONE);
245 }
246 
247 static ur_err_t
248 ur_write(int fd, char *buf, size_t len) {
249 	int n;
250 
251 	while (len > 0) {
252 		if ((n = write(fd, buf, len)) == -1)
253 			return (UR_ERR_WRITE);
254 		len -= n;
255 		buf += n;
256 	}
257 	return (UR_ERR_NONE);
258 }
259 
260 static ur_err_t
261 ur_xfer(int in, int out) {
262 	char buf[512];
263 	int n;
264 	ur_err_t err;
265 
266 	RDBG(("xfer, in = %d, out = %d\n", in, out));
267 
268 	while ((n = read(in, buf, sizeof(buf))) > 0) {
269 		RDBG(("xfer: read %d\n", n));
270 		if ((err = ur_write(out, buf, n)) != UR_ERR_NONE)
271 			return (err);
272 	}
273 	RDBG(("xfer: out of the loop, n = %d\n", n));
274 	if (n == -1) {
275 		if (errno == EAGAIN)
276 			return (UR_ERR_NONE);
277 		return (UR_ERR_READ);
278 	}
279 	if (n == 0)
280 		return (UR_ERR_NOREAD);
281 	return (UR_ERR_NONE);
282 }
283 
284 static ur_err_t
285 ur_swallow(int fd, char *str, size_t len) {
286 	char *buf;
287 	int n;
288 
289 	if ((buf = malloc(len)) == NULL)
290 		return (UR_ERR_NOMEM);
291 	while (len > 0) {
292 		if ((n = read(fd, buf, len)) == -1) {
293 			if (errno == EAGAIN)
294 				continue;
295 			free(buf);
296 			return (UR_ERR_READ);
ConvertFromI420(const I420VideoFrame & src_frame,VideoType dst_video_type,int dst_sample_size,uint8_t * dst_frame)297 		}
298 		if (n == 0)
299 			continue;
300 
301 		if (memcmp(str, buf, n)) {
302 			free(buf);
303 			return (UR_ERR_DIFF);
304 		}
305 		str += n;
306 		len -= n;
307 	}
308 	free(buf);
309 	return (UR_ERR_NONE);
310 }
311 
ConvertFromYV12(const I420VideoFrame & src_frame,VideoType dst_video_type,int dst_sample_size,uint8_t * dst_frame)312 /*
313  * Function:
314  * 	ur_selloop			- do the actual connection proxying.
315  * Inputs:
316  * 	src				- the source file descriptor array
317  * 	dst				- the destination file desc array
318  * Returns:
319  * 	ur_err_t
320  * 	UR_ERR_SELECT			- select() error
321  * 	Error codes from ur_swallow(), ur_write(), ur_xfer().
322  * Modifies:
323  *	nothing by itself; does a select() on the file descriptors and
324  * 	invokes ur_swallow(), ur_write(), or ur_xfer() as needed.
325  */
326 
327 static ur_err_t
328 ur_selloop(int src[2], int dst[2]) {
329 	fd_set fdr;
330 	int maxfd, left, n;
331 	ur_err_t err;
332 
333 	RDBG(("selloop, src=(%d, %d), dst = (%d, %d)\n",
334 	    src[0], src[1], dst[0], dst[1]));
335 
336 	if ((msgsrc != NULL) &&
337 	    ((err = ur_write(src[1], msgsrc, strlen(msgsrc))) != UR_ERR_NONE))
338 		return (err);
339 	if ((msgdst != NULL) &&
340 	    ((err = ur_write(dst[1], msgdst, strlen(msgdst))) != UR_ERR_NONE))
341 		return (err);
342 	if ((ignsrc != NULL) &&
343 	    ((err = ur_swallow(src[0], ignsrc, strlen(ignsrc))) != UR_ERR_NONE))
344 		return (err);
345 	if ((igndst != NULL) &&
346 	    ((err = ur_swallow(dst[0], igndst, strlen(igndst))) != UR_ERR_NONE))
347 		return (err);
348 
349 	left = 2;
350 
351 	maxfd = src[0];
352 	if (src[1] > maxfd)
353 		maxfd = src[1];
354 	if (dst[0] > maxfd)
355 		maxfd = dst[0];
356 	if (dst[1] > maxfd)
357 		maxfd = dst[1];
358 
359 	while (left > 0) {
360 		RDBG(("selloop: loop, left = %d\n", left));
361 
362 		FD_ZERO(&fdr);
363 		FD_SET(src[0], &fdr);
364 		FD_SET(dst[0], &fdr);
365 
366 		if ((n = select(maxfd, &fdr, NULL, NULL, NULL)) == -1)
367 			return (UR_ERR_SELECT);
368 		RDBG(("selloop: select() returned %d\n", n));
369 		if (n == 0)
370 			continue;
371 
372 		if (FD_ISSET(src[0], &fdr))
373 			if ((err = ur_xfer(src[0], dst[1])) != UR_ERR_NONE) {
374 				if (err == UR_ERR_NOREAD) {
375 					shutdown(dst[1], SHUT_WR);
376 					left--;
377 				} else {
378 					return (err);
379 				}
380 			}
381 		if (FD_ISSET(dst[0], &fdr))
382 			if ((err = ur_xfer(dst[0], src[1])) != UR_ERR_NONE) {
383 				if (err == UR_ERR_NOREAD) {
384 					shutdown(src[1], SHUT_WR);
385 					left--;
386 				} else {
387 					return (err);
388 				}
389 			}
390 	}
391 	return (UR_ERR_NONE);
392 }
393 
394 /*
395  * Function:
396  * 	ur_doit				- perform the actual work
397  * Inputs:
398  * 	argc, argv			- main() args
399  * Returns:
400  * 	The error code from ur_selloop().
401  * Modifies:
402  *	nothing by itself; invokes ur_selloop().
403  */
404 
405 static ur_err_t
406 ur_doit(int argc __unused, char *argv[] __unused) {
407 	int fdin[2] = {0, 1}, fdout[2] = {6, 7};
408 	ur_err_t err;
409 
410 	if ((err = ur_selloop(fdin, fdout)) != UR_ERR_NONE)
411 		return (err);
412 	return (UR_ERR_NONE);
413 }
414 
415 /*
416  *   M A I N   F U N C T I O N
417  */
418 
419 int
420 main(int argc, char *argv[]) {
421 	ur_err_t r, cr;
422 
423 	if (r = ur_init(argc, argv), r)
424 		return (ur_prerror("init", r));
425 
426 	argc -= optind;
427 	argv += optind;
428 	if (r = ur_doit(argc, argv), r)
429 		ur_prerror("doit", r);
430 
431 	if (cr = ur_close(), cr)
432 		ur_prerror("close", cr);
433 
434 	return (r? r: cr);
435 }
436