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