BRL-CAD
if_remote.c
Go to the documentation of this file.
1 /* I F _ R E M O T E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1986-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup if */
21 /** @{ */
22 /** @file if_remote.c
23  *
24  * Remote libfb interface.
25  *
26  * Duplicates the functions in libfb via communication with a remote
27  * server (fbserv).
28  *
29  * Note that internal errors are returned as -2 and below, because
30  * most remote errors (unpacked by ntohl) will be -1 (although they
31  * could be anything).
32  *
33  */
34 /** @} */
35 
36 #include "common.h"
37 
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 
42 #ifdef HAVE_SYS_TYPES_H
43 # include <sys/types.h>
44 #endif
45 #ifdef HAVE_WRITEV
46 # include <sys/uio.h> /* for struct iovec */
47 #endif
48 #ifdef HAVE_NETINET_IN_H
49 # include <netinet/in.h> /* for htons(), etc. */
50 #endif
51 #ifdef HAVE_SYS_SOCKET_H
52 # include <sys/socket.h>
53 #endif
54 
55 #include "bu/color.h"
56 #include "bu/str.h"
57 #include "bu/log.h"
58 #include "pkg.h"
59 #include "fb_private.h"
60 #include "fb.h"
61 #include "fbmsg.h"
62 
63 
64 #define NET_LONG_LEN 4 /* # bytes to network long */
65 
66 #define MAX_HOSTNAME 128
67 #define PCP(ptr) ((struct pkg_conn *)((ptr)->u1.p))
68 #define PCPL(ptr) ((ptr)->u1.p) /* left hand side version */
69 
70 /* Package Handlers. */
71 static void pkgerror(struct pkg_conn *pcpp, char *buf); /* error message handler */
72 static struct pkg_switch pkgswitch[] = {
73  { MSG_ERROR, pkgerror, "Error Message", NULL },
74  { 0, NULL, NULL, NULL }
75 };
76 
77 
78 /* True if the non-null string s is all digits */
79 HIDDEN int
80 numeric(const char *s)
81 {
82  if (s == (char *)0 || *s == 0)
83  return 0;
84 
85  while (*s) {
86  if (*s < '0' || *s > '9')
87  return 0;
88  s++;
89  }
90 
91  return 1;
92 }
93 
94 
95 /*
96  * Break up a file specification into its component parts. We try to
97  * be infinitely flexible here which makes this complicated. Handle
98  * any of the following:
99  *
100  * File Host Port Dev
101  * 0 localhost 0 NULL
102  * 0:[dev] localhost 0 dev
103  * :0 localhost 0 NULL
104  * host:[dev] host remotefb dev
105  * host:0 host 0 NULL
106  * host:0:[dev] host 0 dev
107  *
108  * Return -1 on error, else 0.
109  */
110 static int
111 parse_file(const char *file, char *host, int *portp, char *device, int length)
112 /* input file spec */
113 /* host part */
114 /* port number */
115 /* device part */
116 {
117  int port;
118  char prefix[256];
119  const char *rest;
120  const char *dev;
121  const char *colon;
122 
123  if (numeric(file)) {
124  /* 0 */
125  port = atoi(file);
126  bu_strlcpy(host, "localhost", length);
127  dev = "";
128  goto done;
129  }
130  if ((colon = strchr(file, ':')) != NULL) {
131  bu_strlcpy(prefix, file, colon - file + 1);
132  rest = colon+1;
133  if (numeric(prefix)) {
134  /* 0:[dev] */
135  port = atoi(prefix);
136  bu_strlcpy(host, "localhost", length);
137  dev = rest;
138  goto done;
139  } else {
140  /* :[dev] or host:[dev] */
141  bu_strlcpy(host, prefix, length);
142  if (numeric(rest)) {
143  /* :0 or host:0 */
144  port = atoi(rest);
145  dev = "";
146  goto done;
147  } else {
148  /* check for [host]:0:[dev] */
149  if ((colon = strchr(rest, ':')) != NULL) {
150  bu_strlcpy(prefix, rest, colon - rest + 1);
151  if (numeric(prefix)) {
152  port = atoi(prefix);
153  dev = colon+1;
154  goto done;
155  } else {
156  /* No port given! */
157  dev = rest;
158  port = 5558; /*XXX*/
159  goto done;
160  }
161  } else {
162  /* No port given */
163  dev = rest;
164  port = 5558; /*XXX*/
165  goto done;
166  }
167  }
168  }
169  }
170  /* bad file spec */
171  return -1;
172 
173 done:
174  /* Default hostname */
175  if (strlen(host) == 0) {
176  bu_strlcpy(host, "localhost", length);
177  }
178  /* Magic port number mapping */
179  if (port < 0)
180  return -1;
181  if (port < 1024)
182  port += 5559;
183  /*
184  * In the spirit of X, let "unix" be an alias for the "localhost".
185  * Eventually this may invoke UNIX Domain PKG (if we can figure
186  * out what to do about socket pathnames).
187  */
188  if (BU_STR_EQUAL(host, "unix"))
189  bu_strlcpy(host, "localhost", length);
190 
191  /* copy out port and device */
192  *portp = port;
193  bu_strlcpy(device, dev, length);
194 
195  return 0;
196 }
197 
198 
199 HIDDEN void
200 rem_log(const char *msg)
201 {
202  fb_log("%s", msg);
203 }
204 
205 
206 /*
207  * Open a connection to the remotefb.
208  *
209  * We send NET_LONG_LEN bytes of mode, NET_LONG_LEN bytes of size,
210  * then the devname (or NULL if default).
211  */
212 HIDDEN int
213 rem_open(register fb *ifp, const char *file, int width, int height)
214 {
215  size_t i;
216  struct pkg_conn *pc;
217  char buf[128] = {0};
218  char hostname[MAX_HOSTNAME] = {0};
219  char portname[MAX_HOSTNAME] = {0};
220  char device[MAX_HOSTNAME] = {0};
221  int port = 0;
222 
223  FB_CK_FB(ifp);
224 
225  if (file == NULL || parse_file(file, hostname, &port, device, MAX_HOSTNAME) < 0) {
226  /* too wild for our tastes */
227  fb_log("rem_open: bad device name \"%s\"\n", file == NULL ? "(null)" : file);
228  return -2;
229  }
230  /*printf("hostname = \"%s\", port = %d, device = \"%s\"\n", hostname, port, device);*/
231 
232  if (port != 5558) {
233  sprintf(portname, "%d", port);
234  if ((pc = pkg_open(hostname, portname, 0, 0, 0, pkgswitch, rem_log)) == PKC_ERROR) {
235  fb_log("rem_open: can't connect to fb server on host \"%s\", port \"%s\".\n", hostname, portname);
236  return -3;
237  }
238  } else {
239  pc = pkg_open(hostname, "remotefb", 0, 0, 0, pkgswitch, rem_log);
240  if (pc == PKC_ERROR) {
241  pc = pkg_open(hostname, "5558", 0, 0, 0, pkgswitch, rem_log);
242  if (pc == PKC_ERROR) {
243  fb_log("rem_open: can't connect to remotefb server on host \"%s\".\n", hostname);
244  return -4;
245  }
246  }
247  }
248  PCPL(ifp) = (char *)pc; /* stash in u1 */
249  ifp->if_fd = pc->pkc_fd; /* unused */
250 
251 #ifdef HAVE_SYS_SOCKET_H
252  {
253  int n;
254  int val;
255  val = 32767;
256  n = setsockopt(pc->pkc_fd, SOL_SOCKET, SO_SNDBUF, (char *)&val, sizeof(val));
257  if (n < 0)
258  perror("setsockopt: SO_SNDBUF");
259 
260  val = 32767;
261  n = setsockopt(pc->pkc_fd, SOL_SOCKET, SO_RCVBUF, (char *)&val, sizeof(val));
262  if (n < 0)
263  perror("setsockopt: SO_RCVBUF");
264  }
265 #endif
266 
267  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(width);
268  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(height);
269  bu_strlcpy(&buf[2*NET_LONG_LEN], device, 128-2*NET_LONG_LEN);
270 
271  i = strlen(device)+2*NET_LONG_LEN;
272  if ((size_t)pkg_send(MSG_FBOPEN, buf, i, pc) != i)
273  return -5;
274 
275  /* return code, max_width, max_height, width, height as longs */
276  if (pkg_waitfor (MSG_RETURN, buf, sizeof(buf), pc) < 5*NET_LONG_LEN)
277  return -6;
278 
279  ifp->if_max_width = ntohl(*(uint32_t *)&buf[1*NET_LONG_LEN]);
280  ifp->if_max_height = ntohl(*(uint32_t *)&buf[2*NET_LONG_LEN]);
281  ifp->if_width = ntohl(*(uint32_t *)&buf[3*NET_LONG_LEN]);
282  ifp->if_height = ntohl(*(uint32_t *)&buf[4*NET_LONG_LEN]);
283 
284  if (ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]) != 0)
285  return -7; /* fail */
286 
287  return 0; /* OK */
288 }
289 
292 {
293  return NULL;
294 }
295 
296 
297 HIDDEN void
299 {
300  return;
301 }
302 
303 HIDDEN int
304 rem_open_existing(fb *UNUSED(ifp), int UNUSED(width), int UNUSED(height), struct fb_platform_specific *UNUSED(fb_p))
305 {
306  return 0;
307 }
308 
309 HIDDEN int
311 {
312  return 0;
313 }
314 
315 HIDDEN int
316 rem_configure_window(fb *UNUSED(ifp), int UNUSED(width), int UNUSED(height))
317 {
318  return 0;
319 }
320 
321 HIDDEN int
322 rem_refresh(fb *UNUSED(ifp), int UNUSED(x), int UNUSED(y), int UNUSED(w), int UNUSED(h))
323 {
324  return 0;
325 }
326 
327 
328 HIDDEN int
330 {
331  unsigned char buf[NET_LONG_LEN+1];
332 
333  /* send a close package to remote */
334  if (pkg_send(MSG_FBCLOSE, (const char *)0, 0, PCP(ifp)) < 0)
335  return -2;
336  /*
337  * When some libfb interfaces with a "linger mode" window gets
338  * its fb_close() call here, it closes down the network file
339  * descriptor, and so the PKG connection is terminated at this
340  * point. If there was no transmission error noted in the
341  * pkg_send() above, but the pkg_waitfor () here gets an error,
342  * clean up and declare this a successful close() operation.
343  */
344  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN) {
345  pkg_close(PCP(ifp));
346  return 0;
347  }
348  pkg_close(PCP(ifp));
349  return ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]);
350 }
351 
352 
353 HIDDEN int
355 {
356  unsigned char buf[NET_LONG_LEN+1];
357 
358  /* send a free package to remote */
359  if (pkg_send(MSG_FBFREE, (const char *)0, 0, PCP(ifp)) < 0)
360  return -2;
361  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
362  return -3;
363  pkg_close(PCP(ifp));
364  return ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]);
365 }
366 
367 
368 HIDDEN int
369 rem_clear(fb *ifp, unsigned char *bgpp)
370 {
371  unsigned char buf[NET_LONG_LEN+1];
372 
373  /* send a clear package to remote */
374  if (bgpp == PIXEL_NULL) {
375  buf[0] = buf[1] = buf[2] = 0; /* black */
376  } else {
377  buf[0] = (bgpp)[RED];
378  buf[1] = (bgpp)[GRN];
379  buf[2] = (bgpp)[BLU];
380  }
381  if (pkg_send(MSG_FBCLEAR, (const char *)buf, 3, PCP(ifp)) < 3)
382  return -2;
383  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
384  return -3;
385  return ntohl(*(uint32_t *)buf);
386 }
387 
388 
389 /*
390  * Send as longs: x, y, num
391  */
393 rem_read(register fb *ifp, int x, int y, unsigned char *pixelp, size_t num)
394 {
395  ssize_t ret;
396  unsigned char buf[3*NET_LONG_LEN+1];
397 
398  if (num == 0)
399  return 0;
400  /* Send Read Command */
401  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(x);
402  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(y);
403  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl((long)num);
404  if (pkg_send(MSG_FBREAD, (const char *)buf, 3*NET_LONG_LEN, PCP(ifp)) < 3*NET_LONG_LEN)
405  return -2;
406 
407  /* Get response; 0 len means failure */
408  ret = pkg_waitfor(MSG_RETURN, (char *)pixelp, num*sizeof(RGBpixel), PCP(ifp));
409  if (ret <= 0) {
410  fb_log("rem_read: read %lu at <%d, %d> failed, ret=%ld.\n",
411  num, x, y, ret);
412  return -3;
413  }
414  return ret/sizeof(RGBpixel);
415 }
416 
417 
418 /*
419  * As longs, x, y, num
420  */
422 rem_write(register fb *ifp, int x, int y, const unsigned char *pixelp, size_t num)
423 {
424  ssize_t ret;
425  unsigned char buf[3*NET_LONG_LEN+1];
426 
427  if (num <= 0) return num;
428 
429  /* Send Write Command */
430  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(x);
431  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(y);
432  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl((long)num);
433  ret = pkg_2send(MSG_FBWRITE+MSG_NORETURN,
434  (const char *)buf, 3*NET_LONG_LEN,
435  (const char *)pixelp, num*sizeof(RGBpixel),
436  PCP(ifp));
437  ret -= 3*NET_LONG_LEN;
438  if (ret < 0)
439  return -1; /* Error from libpkg */
440  return ret/sizeof(RGBpixel);
441  /* No reading an error return package, sacrificed for speed. */
442 }
443 
444 
445 HIDDEN int
446 rem_readrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned char *pp)
447 {
448  int num;
449  int ret;
450  unsigned char buf[4*NET_LONG_LEN+1];
451 
452  num = width*height;
453  if (num <= 0)
454  return 0;
455  /* Send Read Command */
456  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(xmin);
457  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(ymin);
458  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl(width);
459  *(uint32_t *)&buf[3*NET_LONG_LEN] = htonl(height);
460  if (pkg_send(MSG_FBREADRECT, (const char *)buf, 4*NET_LONG_LEN, PCP(ifp)) < 4*NET_LONG_LEN)
461  return -2;
462 
463  /* Get response; 0 len means failure */
464  ret = pkg_waitfor (MSG_RETURN, (char *)pp,
465  num*sizeof(RGBpixel), PCP(ifp));
466  if (ret <= 0) {
467  fb_log("rem_rectread: read %d at <%d, %d> failed, ret=%d.\n",
468  num, xmin, ymin, ret);
469  return -3;
470  }
471  return ret/sizeof(RGBpixel);
472 }
473 
474 
475 HIDDEN int
476 rem_writerect(fb *ifp, int xmin, int ymin, int width, int height, const unsigned char *pp)
477 {
478  int num;
479  int ret;
480  unsigned char buf[4*NET_LONG_LEN+1];
481 
482  num = width*height;
483  if (num <= 0)
484  return 0;
485 
486  /* Send Write Command */
487  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(xmin);
488  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(ymin);
489  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl(width);
490  *(uint32_t *)&buf[3*NET_LONG_LEN] = htonl(height);
491  ret = pkg_2send(MSG_FBWRITERECT+MSG_NORETURN,
492  (const char *)buf, 4*NET_LONG_LEN,
493  (const char *)pp, num*sizeof(RGBpixel),
494  PCP(ifp));
495  ret -= 4*NET_LONG_LEN;
496  if (ret < 0)
497  return -4; /* Error from libpkg */
498  return ret/sizeof(RGBpixel);
499  /* No reading an error return package, sacrificed for speed. */
500 }
501 
502 
503 /*
504  * Issue: Determining if other end has support for this yet.
505  */
506 HIDDEN int
507 rem_bwreadrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned char *pp)
508 {
509  int num;
510  int ret;
511  unsigned char buf[4*NET_LONG_LEN+1];
512 
513  num = width*height;
514  if (num <= 0)
515  return 0;
516  /* Send Read Command */
517  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(xmin);
518  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(ymin);
519  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl(width);
520  *(uint32_t *)&buf[3*NET_LONG_LEN] = htonl(height);
521  if (pkg_send(MSG_FBBWREADRECT, (const char *)buf, 4*NET_LONG_LEN, PCP(ifp)) < 4*NET_LONG_LEN)
522  return -2;
523 
524  /* Get response; 0 len means failure */
525  ret = pkg_waitfor (MSG_RETURN, (char *)pp, num, PCP(ifp));
526  if (ret <= 0) {
527  fb_log("rem_bwrectread: read %d at <%d, %d> failed, ret=%d.\n",
528  num, xmin, ymin, ret);
529  return -3;
530  }
531  return ret;
532 }
533 
534 
535 HIDDEN int
536 rem_bwwriterect(fb *ifp, int xmin, int ymin, int width, int height, const unsigned char *pp)
537 {
538  int num;
539  int ret;
540  unsigned char buf[4*NET_LONG_LEN+1];
541 
542  num = width*height;
543  if (num <= 0)
544  return 0;
545 
546  /* Send Write Command */
547  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(xmin);
548  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(ymin);
549  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl(width);
550  *(uint32_t *)&buf[3*NET_LONG_LEN] = htonl(height);
551  ret = pkg_2send(MSG_FBBWWRITERECT+MSG_NORETURN,
552  (const char *)buf, 4*NET_LONG_LEN,
553  (const char *)pp, num,
554  PCP(ifp));
555  ret -= 4*NET_LONG_LEN;
556  if (ret < 0)
557  return -4; /* Error from libpkg */
558  return ret;
559  /* No reading an error return package, sacrificed for speed. */
560 }
561 
562 
563 /*
564  * 32-bit longs: mode, x, y
565  */
566 HIDDEN int
567 rem_cursor(fb *ifp, int mode, int x, int y)
568 {
569  unsigned char buf[3*NET_LONG_LEN+1];
570 
571  /* Send Command */
572  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(mode);
573  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(x);
574  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl(y);
575  if (pkg_send(MSG_FBCURSOR, (const char *)buf, 3*NET_LONG_LEN, PCP(ifp)) < 3*NET_LONG_LEN)
576  return -2;
577  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
578  return -3;
579  return ntohl(*(uint32_t *)buf);
580 }
581 
582 
583 HIDDEN int
584 rem_getcursor(fb *ifp, int *mode, int *x, int *y)
585 {
586  unsigned char buf[4*NET_LONG_LEN+1];
587 
588  /* Send Command */
589  if (pkg_send(MSG_FBGETCURSOR, (char *)0, 0, PCP(ifp)) < 0)
590  return -2;
591 
592  /* return code, xcenter, ycenter, xzoom, yzoom as longs */
593  if (pkg_waitfor (MSG_RETURN, (char *)buf, sizeof(buf), PCP(ifp)) < 4*NET_LONG_LEN)
594  return -3;
595  *mode = ntohl(*(uint32_t *)&buf[1*NET_LONG_LEN]);
596  *x = ntohl(*(uint32_t *)&buf[2*NET_LONG_LEN]);
597  *y = ntohl(*(uint32_t *)&buf[3*NET_LONG_LEN]);
598  if (ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]) != 0)
599  return -4; /* fail */
600  return 0; /* OK */
601 }
602 
603 
604 /*
605  * Program the "shape" of the cursor.
606  *
607  * bits[] has xbits*ybits bits in it, rounded up to next largest byte.
608  *
609  * Do not confuse this routine with the old fb_scursor() call.
610  */
611 HIDDEN int
612 rem_setcursor(fb *ifp, const unsigned char *bits, int xbits, int ybits, int xorig, int yorig)
613 {
614  unsigned char buf[4*NET_LONG_LEN+1];
615  int ret;
616 
617  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(xbits);
618  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(ybits);
619  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl(xorig);
620  *(uint32_t *)&buf[3*NET_LONG_LEN] = htonl(yorig);
621 
622  ret = pkg_2send(MSG_FBSETCURSOR+MSG_NORETURN,
623  (const char *)buf, 4*NET_LONG_LEN,
624  (const char *)bits, (xbits*ybits+7)>>3,
625  PCP(ifp));
626  ret -= 4*NET_LONG_LEN;
627  if (ret < 0)
628  return -1; /* Error from libpkg */
629 
630  /* Since this call got somehow overlooked until Release 4.3, older
631  * 'fbserv' programs won't have support for this request. Rather
632  * than dooming LGT users to endless frustration, simply launch
633  * off the request and tell our caller that all is well. LGT
634  * never actually checks the return code of this routine anyway.
635  */
636  return 0;
637 }
638 
639 
640 HIDDEN int
641 rem_view(fb *ifp, int xcenter, int ycenter, int xzoom, int yzoom)
642 {
643  unsigned char buf[4*NET_LONG_LEN+1];
644 
645  /* Send Command */
646  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(xcenter);
647  *(uint32_t *)&buf[1*NET_LONG_LEN] = htonl(ycenter);
648  *(uint32_t *)&buf[2*NET_LONG_LEN] = htonl(xzoom);
649  *(uint32_t *)&buf[3*NET_LONG_LEN] = htonl(yzoom);
650  if (pkg_send(MSG_FBVIEW, (const char *)buf, 4*NET_LONG_LEN, PCP(ifp)) < 4*NET_LONG_LEN)
651  return -2;
652  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
653  return -3;
654  return ntohl(*(uint32_t *)buf);
655 }
656 
657 
658 HIDDEN int
659 rem_getview(fb *ifp, int *xcenter, int *ycenter, int *xzoom, int *yzoom)
660 {
661  unsigned char buf[5*NET_LONG_LEN+1];
662 
663  /* Send Command */
664  if (pkg_send(MSG_FBGETVIEW, (char *)0, 0, PCP(ifp)) < 0)
665  return -2;
666 
667  /* return code, xcenter, ycenter, xzoom, yzoom as longs */
668  if (pkg_waitfor (MSG_RETURN, (char *)buf, sizeof(buf), PCP(ifp)) < 5*NET_LONG_LEN)
669  return -3;
670  *xcenter = ntohl(*(uint32_t *)&buf[1*NET_LONG_LEN]);
671  *ycenter = ntohl(*(uint32_t *)&buf[2*NET_LONG_LEN]);
672  *xzoom = ntohl(*(uint32_t *)&buf[3*NET_LONG_LEN]);
673  *yzoom = ntohl(*(uint32_t *)&buf[4*NET_LONG_LEN]);
674  if (ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]) != 0)
675  return -4; /* fail */
676  return 0; /* OK */
677 }
678 
679 
680 #define REM_CMAP_BYTES (256*3*2)
681 
682 HIDDEN int
683 rem_rmap(register fb *ifp, register ColorMap *cmap)
684 {
685  register int i;
686  unsigned char buf[NET_LONG_LEN+1];
687  unsigned char cm[REM_CMAP_BYTES+4];
688 
689  if (pkg_send(MSG_FBRMAP, (const char *)0, 0, PCP(ifp)) < 0)
690  return -2;
691  if (pkg_waitfor (MSG_DATA, (char *)cm, REM_CMAP_BYTES, PCP(ifp)) < REM_CMAP_BYTES)
692  return -3;
693  for (i = 0; i < 256; i++) {
694  cmap->cm_red[i] = ntohs(*(uint32_t *)(cm+2*(0+i)));
695  cmap->cm_green[i] = ntohs(*(uint32_t *)(cm+2*(256+i)));
696  cmap->cm_blue[i] = ntohs(*(uint16_t *)(cm+2*(512+i)));
697  }
698  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
699  return -4;
700  return ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]);
701 }
702 
703 
704 HIDDEN int
705 rem_wmap(register fb *ifp, const ColorMap *cmap)
706 {
707  register int i;
708  unsigned char buf[NET_LONG_LEN+1];
709  unsigned char cm[REM_CMAP_BYTES+4];
710 
711  if (cmap == COLORMAP_NULL) {
712  if (pkg_send(MSG_FBWMAP, (const char *)0, 0, PCP(ifp)) < 0)
713  return -2;
714  } else {
715  for (i = 0; i < 256; i++) {
716  *(uint16_t *)(cm+2*(0+i)) = htons(cmap->cm_red[i]);
717  *(uint16_t *)(cm+2*(256+i)) = htons(cmap->cm_green[i]);
718  *(uint16_t *)(cm+2*(512+i)) = htons(cmap->cm_blue[i]);
719  }
720  if (pkg_send(MSG_FBWMAP, (const char *)cm, REM_CMAP_BYTES, PCP(ifp)) < REM_CMAP_BYTES)
721  return -3;
722  }
723  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
724  return -4;
725  return ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]);
726 }
727 
728 
729 /*
730  * Poll tells the remote end to handle input events. There is no need
731  * to wait for a reply (FLUSH can be used for synchronization. In
732  * fact, we may not want to send polls at all....
733  */
734 HIDDEN int
736 {
737  /* send a poll package to remote */
738  if (pkg_send(MSG_FBPOLL, (char *)0, 0, PCP(ifp)) < 0)
739  return -1;
740  return 0;
741 }
742 
743 
744 HIDDEN int
746 {
747  unsigned char buf[NET_LONG_LEN+1];
748 
749  /* send a flush package to remote */
750  if (pkg_send(MSG_FBFLUSH, (const char *)0, 0, PCP(ifp)) < 0)
751  return -2;
752  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
753  return -3;
754  return ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]);
755 }
756 
757 
758 HIDDEN int
760 {
761  unsigned char buf[1*NET_LONG_LEN+1];
762 
763  fb_log("Remote Interface:\n");
764 
765  /* Send Command */
766  *(uint32_t *)&buf[0*NET_LONG_LEN] = htonl(0L);
767  if (pkg_send(MSG_FBHELP, (const char *)buf, 1*NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
768  return -2;
769  if (pkg_waitfor (MSG_RETURN, (char *)buf, NET_LONG_LEN, PCP(ifp)) < 1*NET_LONG_LEN)
770  return -3;
771  return ntohl(*(uint32_t *)&buf[0*NET_LONG_LEN]);
772 }
773 
774 
775 /*
776  * This is where we come on asynchronous error or log messages. We
777  * are counting on the remote machine now to prefix his own name to
778  * messages, so we don't touch them ourselves.
779  */
780 HIDDEN void
781 pkgerror(struct pkg_conn *UNUSED(pcpp), char *buf)
782 {
783  fb_log("%s", buf);
784  free(buf);
785 }
786 
787 
789  0,
791  rem_open,
794  rem_get_fbps,
795  rem_put_fbps,
796  rem_close,
797  rem_clear,
798  rem_read,
799  rem_write,
800  rem_rmap,
801  rem_wmap,
802  rem_view,
803  rem_getview,
805  rem_cursor,
807  rem_readrect,
812  rem_refresh,
813  rem_poll,
814  rem_flush,
815  rem_free,
816  rem_help,
817  "Remote Device Interface", /* should be filled in */
818  32*1024, /* " */
819  32*1024, /* " */
820  "host:[dev]",
821  512,
822  512,
823  -1, /* select fd */
824  -1,
825  1, 1, /* zoom */
826  256, 256, /* window center */
827  0, 0, 0, /* cursor */
828  PIXEL_NULL,
829  PIXEL_NULL,
830  PIXEL_NULL,
831  -1,
832  0,
833  0L,
834  0L,
835  0, /* debug */
836  0, /* refresh rate */
837  {0}, /* u1 */
838  {0}, /* u2 */
839  {0}, /* u3 */
840  {0}, /* u4 */
841  {0}, /* u5 */
842  {0} /* u6 */
843 };
844 
845 
846 /*
847  * Local Variables:
848  * mode: C
849  * tab-width: 8
850  * indent-tabs-mode: t
851  * c-file-style: "stroustrup"
852  * End:
853  * ex: shiftwidth=4 tabstop=8
854  */
HIDDEN int rem_wmap(register fb *ifp, const ColorMap *cmap)
Definition: if_remote.c:705
Definition: db_flip.c:35
ptrdiff_t ssize_t
Definition: common.h:119
#define COLORMAP_NULL
Definition: fb.h:91
unsigned char RGBpixel[3]
Definition: fb.h:73
void pkg_close(struct pkg_conn *pc)
Definition: pkg.c:800
void fb_log(const char *fmt,...) _BU_ATTR_PRINTF12
Definition: fb_log.c:42
int if_fd
internal file descriptor
Definition: fb_private.h:119
unsigned short cm_green[256]
Definition: fb.h:84
HIDDEN int rem_setcursor(fb *ifp, const unsigned char *bits, int xbits, int ybits, int xorig, int yorig)
Definition: if_remote.c:612
HIDDEN int numeric(const char *s)
Definition: if_remote.c:80
if lu s
Definition: nmg_mod.c:3860
HIDDEN int rem_getview(fb *ifp, int *xcenter, int *ycenter, int *xzoom, int *yzoom)
Definition: if_remote.c:659
HIDDEN int rem_close_existing(fb *ifp)
Definition: if_remote.c:310
HIDDEN int rem_poll(fb *ifp)
Definition: if_remote.c:735
HIDDEN void rem_put_fbps(struct fb_platform_specific *fbps)
Definition: if_remote.c:298
#define RED
Definition: color.h:39
HIDDEN int rem_refresh(fb *ifp, int x, int y, int w, int h)
Definition: if_remote.c:322
#define PCPL(ptr)
Definition: if_remote.c:68
#define PIXEL_NULL
Definition: fb.h:89
HIDDEN int rem_rmap(register fb *ifp, register ColorMap *cmap)
Definition: if_remote.c:683
Header file for the BRL-CAD common definitions.
int if_max_width
max device width
Definition: fb_private.h:111
HIDDEN int rem_free(fb *ifp)
Definition: if_remote.c:354
HIDDEN int rem_open_existing(fb *ifp, int width, int height, struct fb_platform_specific *fb_p)
Definition: if_remote.c:304
#define BLU
Definition: color.h:41
HIDDEN int rem_flush(fb *ifp)
Definition: if_remote.c:745
ustring width
int pkc_fd
TCP connection fd.
Definition: pkg.h:80
#define HIDDEN
Definition: common.h:86
HIDDEN int rem_bwwriterect(fb *ifp, int xmin, int ymin, int width, int height, const unsigned char *pp)
Definition: if_remote.c:536
struct pkg_conn * pkg_open(const char *host, const char *service, const char *protocol, const char *username, const char *passwd, const struct pkg_switch *switchp, pkg_errlog errlog)
HIDDEN int rem_getcursor(fb *ifp, int *mode, int *x, int *y)
Definition: if_remote.c:584
char * strchr(const char *sp, int c)
#define FB_REMOTE_MAGIC
Definition: magic.h:190
int pkg_send(int type, const char *buf, size_t len, struct pkg_conn *pc)
Definition: pkg.c:934
#define FB_CK_FB(_p)
Definition: fb.h:100
#define NET_LONG_LEN
Definition: if_remote.c:64
HIDDEN ssize_t rem_write(register fb *ifp, int x, int y, const unsigned char *pixelp, size_t num)
Definition: if_remote.c:422
#define bu_strlcpy(dst, src, size)
Definition: str.h:60
unsigned short cm_red[256]
Definition: fb.h:83
HIDDEN struct fb_platform_specific * rem_get_fbps(uint32_t magic)
Definition: if_remote.c:291
HIDDEN int rem_writerect(fb *ifp, int xmin, int ymin, int width, int height, const unsigned char *pp)
Definition: if_remote.c:476
int if_max_height
max device height
Definition: fb_private.h:112
oldeumate l2 magic
Definition: nmg_mod.c:3843
#define UNUSED(parameter)
Definition: common.h:239
HIDDEN ssize_t rem_read(register fb *ifp, int x, int y, unsigned char *pixelp, size_t num)
Definition: if_remote.c:393
HIDDEN int rem_help(fb *ifp)
Definition: if_remote.c:759
int pkg_waitfor(int type, char *buf, size_t len, struct pkg_conn *pc)
Definition: pkg.c:1355
#define REM_CMAP_BYTES
Definition: if_remote.c:680
Definition: pkg.h:57
Definition: fb.h:82
HIDDEN int rem_readrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned char *pp)
Definition: if_remote.c:446
HIDDEN int rem_view(fb *ifp, int xcenter, int ycenter, int xzoom, int yzoom)
Definition: if_remote.c:641
HIDDEN int rem_clear(fb *ifp, unsigned char *bgpp)
Definition: if_remote.c:369
HIDDEN int rem_close(fb *ifp)
Definition: if_remote.c:329
HIDDEN int rem_open(register fb *ifp, const char *file, int width, int height)
Definition: if_remote.c:213
fb remote_interface
Definition: if_remote.c:788
Definition: pkg.h:79
HIDDEN int rem_bwreadrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned char *pp)
Definition: if_remote.c:507
A frame-buffer IO structure.
Definition: fb_private.h:80
int pkg_2send(int type, const char *buf1, size_t len1, const char *buf2, size_t len2, struct pkg_conn *pc)
Definition: pkg.c:1061
int if_width
current values
Definition: fb_private.h:115
HIDDEN void rem_log(const char *msg)
Definition: if_remote.c:200
unsigned short cm_blue[256]
Definition: fb.h:85
#define GRN
Definition: color.h:40
#define MSG_DATA
Definition: ntp.h:34
HIDDEN int rem_cursor(fb *ifp, int mode, int x, int y)
Definition: if_remote.c:567
#define MAX_HOSTNAME
Definition: if_remote.c:66
HIDDEN int rem_configure_window(fb *ifp, int width, int height)
Definition: if_remote.c:316
#define PCP(ptr)
Definition: if_remote.c:67
#define PKC_ERROR
Definition: pkg.h:104
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126