rdesktop (1.6.0): add addin support
authorOtavio Salvador <otavio@ossystems.com.br>
Mon, 8 Jun 2009 19:19:47 +0000 (16:19 -0300)
committerOtavio Salvador <otavio@ossystems.com.br>
Fri, 10 Jul 2009 17:25:44 +0000 (14:25 -0300)
Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
recipes/rdesktop/rdesktop-1.6.0/rdesktop-addin.patch [new file with mode: 0644]
recipes/rdesktop/rdesktop_1.6.0.bb

diff --git a/recipes/rdesktop/rdesktop-1.6.0/rdesktop-addin.patch b/recipes/rdesktop/rdesktop-1.6.0/rdesktop-addin.patch
new file mode 100644 (file)
index 0000000..ffd942a
--- /dev/null
@@ -0,0 +1,534 @@
+diff -ur rdesktop-1.6.0-orig/channels.c rdesktop-1.6.0/channels.c
+--- rdesktop-1.6.0-orig/channels.c     2007-01-08 07:47:05.000000000 +0300
++++ rdesktop-1.6.0/channels.c  2008-12-05 18:58:00.000000000 +0300
+@@ -19,6 +19,9 @@
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <unistd.h>
+ #include "rdesktop.h"
+ #define MAX_CHANNELS                  6
+@@ -44,7 +47,7 @@
+ */
+ VCHANNEL *
+-channel_register(char *name, uint32 flags, void (*callback) (STREAM))
++channel_register(char *name, uint32 flags, void (*callback) (STREAM,char*))
+ {
+       VCHANNEL *channel;
+@@ -159,7 +162,7 @@
+       if ((flags & CHANNEL_FLAG_FIRST) && (flags & CHANNEL_FLAG_LAST))
+       {
+               /* single fragment - pass straight up */
+-              channel->process(s);
++              channel->process(s, channel->name);
+       }
+       else
+       {
+@@ -183,7 +186,109 @@
+               {
+                       in->end = in->p;
+                       in->p = in->data;
+-                      channel->process(in);
++                      channel->process(in, channel->name);
+               }
+       }
+ }
++
++/* Generic callback for delivering data to third party add-ins */
++void addin_callback(STREAM s, char *name)
++{
++      pid_t pid;
++      int pipe_read;
++      int pipe_write;
++      uint32 blocksize;
++
++      blocksize = s->end - s->p;
++
++      lookup_addin(name, &pid, &pipe_read, &pipe_write);
++      if (pid > 0) {
++              /* Prepend the block with the block size so the
++                   add-in can identify blocks */
++              write(pipe_write, &blocksize, sizeof(uint32));
++              write(pipe_write, s->p, blocksize);
++      }
++}
++
++void addin_add_fds(int *n, fd_set *rfds, fd_set *wfds, struct timeval *tv)
++{
++      extern ADDIN_DATA addin_data[];
++      extern int addin_count;
++      int i;
++
++      for (i = 0; i < addin_count; i++) {
++              /* Take in account only live addins. */
++              if (addin_data[i].pid > 0) {
++                      int addin_fd = addin_data[i].pipe_read;
++
++                      FD_SET(addin_fd, rfds);
++                      if (*n < addin_fd)
++                              *n = addin_fd;
++              }
++      }
++}
++
++/* Process outgoing addin data */
++void addin_check_fds(fd_set *rfds, fd_set *wfds)
++{
++      extern ADDIN_DATA addin_data[];
++      extern int addin_count;
++      int i;
++      unsigned int block_len;
++      ssize_t bytes_read;
++      STREAM s;
++
++      for (i = 0; i < addin_count; i++) {
++              int addin_fd = addin_data[i].pipe_read;
++
++              if (!FD_ISSET(addin_fd, rfds)) {
++                      continue;
++              }
++
++              bytes_read = read(addin_fd, &block_len, sizeof(block_len));
++              if (bytes_read <= 0) {
++                      addin_check_terminated(&addin_data[i]);
++                      continue;
++              }
++
++              if (block_len > 0xffff) {
++                      warning("received too much data (%d) from addin %s\n",
++                              block_len, addin_data[i].name);
++                      addin_check_terminated(&addin_data[i]);
++                      continue;
++              }
++
++              if (block_len > addin_data[i].buf_len) {
++                      addin_data[i].buf = (unsigned char *)xrealloc(
++                                                      addin_data[i].buf,
++                                                      block_len);
++                      addin_data[i].buf_len = block_len;
++              }
++
++              bytes_read = read(addin_fd, addin_data[i].buf, block_len);
++              if (bytes_read > 0) {
++                      s = channel_init(addin_data[i].vchannel, bytes_read);
++                      memcpy(s->p, addin_data[i].buf, bytes_read);
++                      s->p += bytes_read;
++                      s->end = s->p;
++
++                      channel_send(s, addin_data[i].vchannel);
++              }
++      }
++}
++
++void addin_check_terminated(ADDIN_DATA *addin)
++{
++      int status = 0;
++
++      pid_t result = waitpid(addin->pid, &status, WNOHANG);
++      if (result <= 0)
++              return;
++
++      if (WIFEXITED(status) || WIFSIGNALED(status)) {
++              warning("Addin %s is suddenly terminated\n", addin->name);
++              /* Mark this addin as terminated to exclude
++                 it from processing. */
++              addin->pid = 0;
++      }
++}
+diff -ur rdesktop-1.6.0-orig/cliprdr.c rdesktop-1.6.0/cliprdr.c
+--- rdesktop-1.6.0-orig/cliprdr.c      2007-01-08 07:47:05.000000000 +0300
++++ rdesktop-1.6.0/cliprdr.c   2008-12-05 18:42:40.000000000 +0300
+@@ -111,7 +111,7 @@
+ }
+ static void
+-cliprdr_process(STREAM s)
++cliprdr_process(STREAM s, char *name)
+ {
+       uint16 type, status;
+       uint32 length, format;
+Only in rdesktop-1.6.0/doc: .svn
+Only in rdesktop-1.6.0/keymaps: .svn
+diff -ur rdesktop-1.6.0-orig/lspci.c rdesktop-1.6.0/lspci.c
+--- rdesktop-1.6.0-orig/lspci.c        2007-01-08 07:47:05.000000000 +0300
++++ rdesktop-1.6.0/lspci.c     2008-12-05 18:42:40.000000000 +0300
+@@ -128,7 +128,7 @@
+ /* Process new data from the virtual channel */
+ static void
+-lspci_process(STREAM s)
++lspci_process(STREAM s, char *name)
+ {
+       unsigned int pkglen;
+       static char *rest = NULL;
+diff -ur rdesktop-1.6.0-orig/proto.h rdesktop-1.6.0/proto.h
+--- rdesktop-1.6.0-orig/proto.h        2008-04-02 15:13:22.000000000 +0400
++++ rdesktop-1.6.0/proto.h     2008-12-05 18:58:00.000000000 +0300
+@@ -45,7 +45,7 @@
+ RD_HCURSOR cache_get_cursor(uint16 cache_idx);
+ void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor);
+ /* channels.c */
+-VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM));
++VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM,char *));
+ STREAM channel_init(VCHANNEL * channel, uint32 length);
+ void channel_send(STREAM s, VCHANNEL * channel);
+ void channel_process(STREAM s, uint16 mcs_channel);
+@@ -314,6 +314,21 @@
+ void scard_lock(int lock);
+ void scard_unlock(int lock);
++/* External addins */
++void init_external_addin(char * addin_name, char * addin_path, char * args, ADDIN_DATA * addin_data);
++
++/* Generic callback for delivering data to third party add-ins */
++void addin_callback(STREAM s, char *name);
++
++/* Find an external add-in registration by virtual channel name */
++void lookup_addin(char *name, pid_t * pid, int * pipe_read, int * pipe_write);
++
++void addin_add_fds(int *n, fd_set *rfds, fd_set *wfds, struct timeval *tv);
++
++void addin_check_fds(fd_set *rfds, fd_set *wfds);
++
++void addin_check_terminated(ADDIN_DATA *addin);
++
+ /* *INDENT-OFF* */
+ #ifdef __cplusplus
+ }
+diff -ur rdesktop-1.6.0-orig/rdesktop.c rdesktop-1.6.0/rdesktop.c
+--- rdesktop-1.6.0-orig/rdesktop.c     2008-04-05 09:22:26.000000000 +0400
++++ rdesktop-1.6.0/rdesktop.c  2008-12-05 18:58:00.000000000 +0300
+@@ -28,6 +28,7 @@
+ #include <sys/times.h>                /* times */
+ #include <ctype.h>            /* toupper */
+ #include <errno.h>
++#include <signal.h>           /* kill */
+ #include "rdesktop.h"
+ #ifdef HAVE_LOCALE_H
+@@ -115,6 +116,9 @@
+ extern uint32 g_num_devices;
+ extern char *g_rdpdr_clientname;
++ADDIN_DATA addin_data[MAX_ADDINS];
++int addin_count = 0;
++
+ #ifdef RDP2VNC
+ extern int rfb_port;
+ extern int defer_time;
+@@ -208,6 +212,9 @@
+       fprintf(stderr,
+               "                   \"AKS\"              -> Device vendor name                 \n");
+ #endif
++      fprintf(stderr,
++                "         '-r addin:<channelname>:</path/to/executable>[:arg1[:arg2:]...]': enable third\n");
++        fprintf(stderr, "                      party virtual channel add-in.\n");
+       fprintf(stderr, "   -0: attach to console\n");
+       fprintf(stderr, "   -4: use RDP version 4\n");
+       fprintf(stderr, "   -5: use RDP version 5 (default)\n");
+@@ -417,6 +424,8 @@
+       struct passwd *pw;
+       uint32 flags, ext_disc_reason = 0;
+       char *p;
++      char *addin_name;
++      char *addin_path;
+       int c;
+       char *locale = NULL;
+       int username_option = 0;
+@@ -672,8 +681,58 @@
+                               break;
+                       case 'r':
++                              if (str_startswith(optarg, "addin"))
++                              {
++                                      if (addin_count >= MAX_ADDINS)
++                                      {
++                                              error("Add-ins data table full, increase MAX_ADDINS\n");
++                                              return 1;
++                                      }
++
++                                      optarg += 5;
+-                              if (str_startswith(optarg, "sound"))
++                                      if (*optarg == ':')
++                                        {
++                                                addin_name = optarg + 1;
++                                                if (*addin_name != '\0')
++                                                {
++                                                        addin_path = next_arg(addin_name, ':');
++                                                }
++                                                else
++                                                {
++                                                        addin_path = 0;
++                                                }
++                                                if (addin_path != 0)
++                                                {
++                                                        p = next_arg(addin_path, ':');
++                                                }
++                                                if (*addin_name != '\0' && addin_path != 0 && *addin_path != '\0')
++                                                {
++                                                        init_external_addin(addin_name, addin_path,
++                                                                        p, &addin_data[addin_count]);
++                                                        if (addin_data[addin_count].pid != 0)
++                                                        {
++                                                                addin_count++;
++                                                        }
++                                                        else
++                                                        {
++                                                                error("Failed to initialise add-in [%s]\n", addin_name);
++                                                                return 1;
++                                                        }
++                                                }
++                                                else
++                                                {
++                                                        usage(argv[0]);
++                                                        return(1);
++                                                }
++                                        }
++                                        else
++                                        {
++                                                usage(argv[0]);
++                                                return(1);
++                                        }
++                                }
++                              else if (str_startswith(optarg, "sound"))
+                               {
+                                       optarg += 5;
+@@ -982,6 +1041,17 @@
+       cache_save_state();
+       ui_deinit();
++      /* Send a SIGUSR1 to all addins to close and sleep for a couple of secs
++         to give them a chance to stop */
++      for (c = 0; c < addin_count; c++)
++      {
++              if (addin_data[c].pid != 0)
++              {
++                      kill(addin_data[c].pid,SIGUSR1);
++                      sleep(2);
++              }
++      }
++
+       if (ext_disc_reason >= 2)
+               print_disconnect_reason(ext_disc_reason);
+@@ -1625,3 +1695,105 @@
+               return False;
+       return True;
+ }
++
++/* Initialise external addin */
++void init_external_addin(char * addin_name, char * addin_path, char * args, ADDIN_DATA * addin_data)
++{
++      char *p;
++      char *current_arg;
++      char * argv[256];
++      char argv_buffer[256][256];
++      int i;
++      int readpipe[2],writepipe[2];
++      pid_t child;
++
++      /* Initialise addin structure */
++      memset(addin_data, 0, sizeof(ADDIN_DATA));
++      /* Go through the list of args, adding each to argv */
++      argv[0] = addin_path;
++      i = 1;
++      p=current_arg=args;
++      while (current_arg != 0 && current_arg[0] != '\0')
++      {
++              p=next_arg(p, ':');;
++              if (p != 0 && *p != '\0')
++                      *(p - 1) = '\0';
++              strcpy(argv_buffer[i], current_arg);
++              argv[i]=argv_buffer[i];
++              i++;
++              current_arg=p;
++      }
++      argv[i] = NULL;
++
++
++      /* Create pipes */
++      if (pipe(readpipe) < 0 || pipe(writepipe) < 0)
++      {
++              perror("pipes for addin");
++              return;
++      }
++
++      /* Fork process */
++      if ((child = fork()) < 0)
++      {
++              perror("fork for addin");
++              return;
++      }
++
++      /* Child */
++      if (child == 0)
++      {
++              /* Set stdin and stdout of child to relevant pipe ends */
++              dup2(writepipe[0],0);
++              dup2(readpipe[1],1);
++
++              /* Close all fds as they are not needed now */
++              close(readpipe[0]);
++              close(readpipe[1]);
++              close(writepipe[0]);
++              close(writepipe[1]);
++              execvp((char *)argv[0], (char **)argv);
++              perror("Error executing child");
++              _exit(128);
++      }
++      else
++      {
++              strcpy(addin_data->name, addin_name);
++              /* Close child end fd's */
++              close(readpipe[1]);
++              close(writepipe[0]);
++              addin_data->pipe_read=readpipe[0];
++              addin_data->pipe_write=writepipe[1];
++              addin_data->vchannel=channel_register(addin_name,
++                                              CHANNEL_OPTION_INITIALIZED |
++                                              CHANNEL_OPTION_ENCRYPT_RDP |    
++                                              CHANNEL_OPTION_COMPRESS_RDP,
++                                              addin_callback);
++              if (!addin_data->vchannel)
++              {
++                      perror("Channel register failed");
++                      return;
++              }
++              else
++                      addin_data->pid=child;
++                      
++      }
++
++}
++
++/* Find an external add-in registration by virtual channel name */
++void lookup_addin(char *name, pid_t * pid, int * pipe_read, int * pipe_write)
++{
++      int i;
++
++      *pid = 0;
++
++      for (i = 0; i < addin_count; i++) {
++              if (!strcmp(name,addin_data[i].name)) {
++                      *pid=addin_data[i].pid;
++                      *pipe_read=addin_data[i].pipe_read;
++                      *pipe_write=addin_data[i].pipe_write;
++                      break;
++              }
++      }
++}
+diff -ur rdesktop-1.6.0-orig/rdesktop.h rdesktop-1.6.0/rdesktop.h
+--- rdesktop-1.6.0-orig/rdesktop.h     2008-04-05 08:54:10.000000000 +0400
++++ rdesktop-1.6.0/rdesktop.h  2008-12-05 18:42:40.000000000 +0300
+@@ -41,6 +41,8 @@
+ #define VERSION "1.6.0"
++#define MAX_ADDINS 20
++
+ #ifdef WITH_DEBUG
+ #define DEBUG(args)   printf args;
+ #else
+diff -ur rdesktop-1.6.0-orig/rdpdr.c rdesktop-1.6.0/rdpdr.c
+--- rdesktop-1.6.0-orig/rdpdr.c        2008-02-14 14:37:17.000000000 +0300
++++ rdesktop-1.6.0/rdpdr.c     2008-12-05 18:42:40.000000000 +0300
+@@ -781,7 +781,7 @@
+ }
+ static void
+-rdpdr_process(STREAM s)
++rdpdr_process(STREAM s, char *name)
+ {
+       uint32 handle;
+       uint8 *magic;
+diff -ur rdesktop-1.6.0-orig/rdpsnd.c rdesktop-1.6.0/rdpsnd.c
+--- rdesktop-1.6.0-orig/rdpsnd.c       2008-02-14 14:37:17.000000000 +0300
++++ rdesktop-1.6.0/rdpsnd.c    2008-12-05 18:42:40.000000000 +0300
+@@ -544,7 +544,7 @@
+ }
+ static void
+-rdpsnd_process(STREAM s)
++rdpsnd_process(STREAM s, char *name)
+ {
+       uint16 len;
+@@ -611,7 +611,7 @@
+ }
+ static void
+-rdpsnddbg_process(STREAM s)
++rdpsnddbg_process(STREAM s, char *name)
+ {
+       unsigned int pkglen;
+       static char *rest = NULL;
+diff -ur rdesktop-1.6.0-orig/seamless.c rdesktop-1.6.0/seamless.c
+--- rdesktop-1.6.0-orig/seamless.c     2008-04-02 15:13:22.000000000 +0400
++++ rdesktop-1.6.0/seamless.c  2008-12-05 18:42:40.000000000 +0300
+@@ -370,7 +370,7 @@
+ static void
+-seamless_process(STREAM s)
++seamless_process(STREAM s, char *name)
+ {
+       unsigned int pkglen;
+       static char *rest = NULL;
+Only in rdesktop-1.6.0: .svn
+diff -ur rdesktop-1.6.0-orig/types.h rdesktop-1.6.0/types.h
+--- rdesktop-1.6.0-orig/types.h        2007-01-08 07:47:06.000000000 +0300
++++ rdesktop-1.6.0/types.h     2008-12-05 18:42:40.000000000 +0300
+@@ -125,7 +125,7 @@
+       char name[8];
+       uint32 flags;
+       struct stream in;
+-      void (*process) (STREAM);
++      void (*process) (STREAM,char *);
+ }
+ VCHANNEL;
+@@ -265,4 +265,15 @@
+ }
+ FILEINFO;
++typedef struct _ADDIN_DATA
++{
++      char name[255];
++      unsigned char *buf;
++      unsigned int buf_len;
++      pid_t pid;
++      int pipe_read;
++      int pipe_write;
++      VCHANNEL *vchannel;
++} ADDIN_DATA;
++
+ typedef RD_BOOL(*str_handle_lines_t) (const char *line, void *data);
+diff -ur rdesktop-1.6.0-orig/xwin.c rdesktop-1.6.0/xwin.c
+--- rdesktop-1.6.0-orig/xwin.c 2008-05-11 10:14:38.000000000 +0400
++++ rdesktop-1.6.0/xwin.c      2008-12-05 18:42:40.000000000 +0300
+@@ -2620,6 +2620,9 @@
+               rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
+               seamless_select_timeout(&tv);
++              /* add addins handles */
++              addin_add_fds(&n, &rfds, &wfds, &tv);
++
+               n++;
+               switch (select(n, &rfds, &wfds, NULL, &tv))
+@@ -2642,6 +2645,8 @@
+               rdpsnd_check_fds(&rfds, &wfds);
+ #endif
++              addin_check_fds(&rfds, &wfds);
++
+               rdpdr_check_fds(&rfds, &wfds, (RD_BOOL) False);
+               if (FD_ISSET(rdp_socket, &rfds))
index 08ec0fc..0f39e78 100644 (file)
@@ -1,8 +1,9 @@
 require rdesktop.inc
 
-PR = "${INC_PR}.1"
+PR = "${INC_PR}.2"
 
 SRC_URI += " file://audio-2008.patch;patch=1"
+SRC_URI_append_ossystems = " file://rdesktop-addin.patch;patch=1"
 
 SRC_URI += " file://audio-2008.patch;patch=1"