示例#1
0
/* Send data to the server, checking and reporting errors */
int _pg_send(void *data,u32 datasize) {
  if (send(_pgsockfd,data,datasize,0)!=datasize) {
    clienterr("send error");
    return 1;
  }
  return 0;
}
示例#2
0
   /* Malloc wrapper */
void *_pg_malloc(size_t size) {
  void *p;
  p = malloc(size);
  if (!p)
    clienterr("out of memory");
  return p;
}
示例#3
0
/* Receive... */
int _pg_recv(void *data,u32 datasize) {
  while (1) {
    if (recv(_pgsockfd,data,datasize,0) >= 0) break;
    
    /* if we have been interrupted (by a signal for instance), restart
       the reception */
    if (errno != EINTR) {
      clienterr("recv error");
      return 1;
    }
  }
  return 0;
}
示例#4
0
/* Some 'user friendly' default sig handlers */
void _pgsig(int sig) {
  char *a,*b;
  u32 id;
  
  switch (sig) {
    
  case SIGSEGV:
    id = PGRES_STRING_SEGFAULT;
    break;
    
  case SIGFPE:
    id = PGRES_STRING_MATHERR;
    break;
    
  default:
    return;
    
  }
  
  a = pgGetString(pgGetServerRes(id));
  b = alloca(strlen(a)+1);
  strcpy(b,a);
  clienterr(b);
}
示例#5
0
/* Open a connection to the server, parsing PicoGUI commandline options
  if they are present
*/  
void pgInit(int argc, char **argv)
{
  int  numbytes;
  struct pghello ServerInfo;
#ifndef CONFIG_UNIX_SOCKET
  struct hostent *he;
  struct sockaddr_in server_addr; /* connector's address information */
#else
  struct sockaddr_un server_addr; 
#endif
  const char *hostname;
  u16 port = PG_REQUEST_PORT;
  const char *appletparam = NULL;
  int fd,i,j,args_to_shift;
  char *arg;
  volatile int tmp;
#ifdef UCLINUX  
  struct in_addr srv_addr;
#endif
  struct stat st;
  int enable_warning = 1;

  if (_pgsockfd) {
    printf("PicoGUI cli_c: Warning, pgInit called multiple times\n");
    return;
  }

  /* Save the program's name */
  if (argc > 0)
    _pg_appname = argv[0];
   
  /* Set default handlers */
  pgSetErrorHandler(&_pg_defaulterr);
  _pgselect_handler = &select;
  _pgselect_bottomhalf = NULL;
  signal(SIGSEGV,&_pgsig);
  signal(SIGFPE,&_pgsig);
   
  /* Default tunables */
  hostname = getenv("PGSERVER");
  if ((!hostname) || (!*hostname))
     hostname = PG_REQUEST_SERVER;

  /* Handle arguments we recognize, Leave others for the app */
  if (argc > 0) {
    for (i=1;i<argc;i++) {
      arg = argv[i];
      
      /* It's ours if it starts with --pg */
      if (!bcmp(arg,"--pg",4)) {
	arg+=4;
	args_to_shift = 1;
	
	if (!strcmp(arg,"server")) {
	  /* --pgserver : Next argument is the picogui server */
	  args_to_shift = 2;
	  hostname = argv[i+1];
	  setenv("pgserver",hostname,1);    /* Child processes inherit server */
	}
	
	else if (!strcmp(arg,"version")) {
	  /* --pgversion : For now print CVS id */
	  fprintf(stderr,"$Id$\n");
	  exit(1);
	}
	
	else if (!strcmp(arg,"applet")) {
	  /* --pgapplet : Create the app in a public container instead of
	   *              registering a new app.
	   */
	  
	  args_to_shift = 2;
	  appletparam = argv[i+1];
	}
	
	else if (!strcmp(arg,"nowarn")) {
	  enable_warning = 0;
	}
	
	else {
	  /* Other command, print some help */
	  fprintf(stderr,"PicoGUI Client Library\nCommands: --pgserver --pgversion --pgapplet --pgnowarn\n");
	  exit(1);
	}
	
	/* Remove this argument - shuffle all future args back a space */
	argc -= args_to_shift;
	for (j=i;j<argc;j++)
	  argv[j] = argv[j+args_to_shift];
	i -= args_to_shift;
      }
    }
    /* Some programs might rely on this? */
    argv[argc] = NULL;
  }

  /* Separate the display number from the hostname */
  arg = strrchr(hostname,':');
  if (arg) {
    port = PG_REQUEST_PORT + atoi(arg+1);
    *arg = 0;
  }
  /* Only a display? Use default server */
  if (!*hostname)
    hostname = PG_REQUEST_SERVER;
   
#ifndef CONFIG_UNIX_SOCKET
#  ifdef UCLINUX
  /* get the host info.
   * gethostbyname() and gethostbyaddr() not working in uClinux.
   * Using inet_aton()
   * I let the two first in the case of... or for the future.
   */
  if ((he=gethostbyname(hostname)) != NULL) {
    srv_addr = *((struct in_addr *)he->h_addr);
  }
  else if ((he=gethostbyaddr(hostname,strlen(hostname),AF_INET)) != NULL) {
    srv_addr = *((struct in_addr *)he->h_addr);
  }
  else if (inet_aton(hostname, &srv_addr)) {
  }
  else {
    clienterr("Error resolving server hostname");
    return;
  }
#  else
  if ((he=gethostbyname(hostname)) == NULL) {  /* get the host info */
    clienterr("Error resolving server hostname");
    return;
  }
#  endif
#endif


#ifndef CONFIG_UNIX_SOCKET
  if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
#else
  if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
#endif
    clienterr("socket error");
    return;
  }

#ifndef CONFIG_UNIX_SOCKET
  /* Try disabling the "Nagle algorithm" or "tinygram prevention" */
  tmp = 1;
  setsockopt(fd,6 /*PROTO_TCP*/,TCP_NODELAY,(void *)&tmp,sizeof(tmp));
   
  server_addr.sin_family = AF_INET;         /* host byte order */
  server_addr.sin_port = htons(port);       /* short, network byte order */
#ifdef UCLINUX
  server_addr.sin_addr = srv_addr;
#else
  server_addr.sin_addr = *((struct in_addr *)he->h_addr);
#endif
  bzero(&(server_addr.sin_zero), 8);                /* zero the rest of the struct */

  if (connect(fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
#else
  server_addr.sun_family = AF_UNIX;
  strcpy(server_addr.sun_path,hostname);
  i = strlen(server_addr.sun_path) + sizeof(server_addr.sun_family);

  if (connect(fd, (struct sockaddr *)&server_addr, i) == -1) {
#endif
    perror ("connect");
    clienterr("Error connecting to server");
    return;
  }

  /* We're connected */
  _pgsockfd = fd;

  /* Don't let child processes inherit the connection */
  fcntl(fd,F_SETFD,fcntl(fd,F_GETFD,0) | FD_CLOEXEC);

  /* Receive the hello packet and convert byte order */
  if (_pg_recv(&ServerInfo,sizeof(ServerInfo)))
    return;
  ServerInfo.magic = ntohl(ServerInfo.magic);
  ServerInfo.protover = ntohs(ServerInfo.protover);
  
  /* Validate it */
  if(ServerInfo.magic != PG_REQUEST_MAGIC) {
    clienterr("server has bad magic number");
    return;
  }

  if((ServerInfo.protover < PG_PROTOCOL_VER) && enable_warning) {
	 const char *s1, *s2;
	 char * copys1;

         /* Since we know there's a compatibility problem now, it's unsafe
	  * to create a message dialog. We'll try it anyway, but first
	  * print a message to the console.
	  */
         printf("*********** PicoGUI incompatibility ************\n"
		"Server is version %d, require at least version %d\n",
		ServerInfo.protover, PG_PROTOCOL_VER);
     
	 /* We must copy the first string temporarily because the pgGetString
	  * buffer is only valid until the next picogui call */
	 s1 = pgGetString(pgGetServerRes(PGRES_STRING_PGUIWARN));
	 copys1 = alloca(strlen(s1)+1);
	 strcpy(copys1, s1);
	 s2 = pgGetString(pgGetServerRes(PGRES_STRING_PGUICOMPAT)),   
	   pgMessageDialog(copys1,s2,0);
  }

  /* Set up applet handle */
  if (appletparam) {
    /* Is it a number or widget name? */
    if (isdigit(*appletparam))
      _pg_appletbox = atol(appletparam);
    else
      _pg_appletbox = pgFindWidget(appletparam);
  }
}

void pgSetErrorHandler(void (*handler)(u16 errortype,
				       const char *msg)) {
  _pgerrhandler = handler;
}

const char *pgErrortypeString(u16 errortype) {
  switch (errortype) {
  case PG_ERRT_MEMORY:     return "MEMORY";
  case PG_ERRT_IO:         return "IO";
  case PG_ERRT_NETWORK:    return "NETWORK";
  case PG_ERRT_BADPARAM:   return "BADPARAM";
  case PG_ERRT_HANDLE:     return "HANDLE";
  case PG_ERRT_INTERNAL:   return "INTERNAL";
  case PG_ERRT_BUSY:       return "BUSY";
  case PG_ERRT_CLIENT:     return "CLIENT";
  case PG_ERRT_NONE:       return "NONE";
  case PG_ERRT_FILEFMT:    return "FILEFMT";
  }
  return "UNKNOWN";
}

/* Sets an idle handler using nonblocking IO. See details in client_c.h */
pgidlehandler pgSetIdle(s32 t,pgidlehandler handler) {
   pgidlehandler previous = _pgidle_handler;
   if (!handler) t = 0;
   if (!t) handler = 0;
   _pgidle_handler = handler;
   _pgidle_period.tv_sec = t / 1000;
   _pgidle_period.tv_usec = (t % 1000) * 1000;
   return previous;
}

/* Flushes the buffer of packets - if there's only one, it gets sent as is
  More than one packet is wrapped in a batch packet.

  This checks for errors.  If a return value is needed, the API function will
  call FlushRequests directly. If the client calls this it is assumed that they
  don't care about the return value (anything needing a return value would have
  called it explicitly)

  Return data is stored in _pg_return (yes, it's a little messy, but it's more
  efficient than a static variable in the function that must be passed out as
  a pointer) I believe in niceness for APIs and efficiency for the guts 8-)
*/
void pgFlushRequests(void) {

#ifdef DEBUG
  printf("Flushed %d packet(s), %d bytes\n",_pgreqbuffer_count,_pgreqbuffer_size);
#endif

  /* Free the data! */
  if (_pg_return.type == PG_RESPONSE_DATA &&
      _pg_return.e.data.data) {
    free(_pg_return.e.data.data);
    _pg_return.e.data.data = NULL;
  }
  if (_pg_return.type == PG_RESPONSE_EVENT &&
      (_pg_return.e.event.type & PG_EVENTCODINGMASK) == PG_EVENTCODING_DATA &&
      _pg_return.e.event.e.data.pointer) {
    free(_pg_return.e.event.e.data.pointer);
    _pg_return.e.event.e.data.pointer = NULL;
  }

  if (!_pgreqbuffer_count) {
    /* No packets */
    return;
  }
  else if (_pgreqbuffer_count==1) {
    /* One packet- send as is */
    if (_pg_send(_pgreqbuffer,_pgreqbuffer_size))
      return;
  }
  else {
    /* Many packets - use a batch packet */
    struct pgrequest batch_header;
    batch_header.type = htons(PGREQ_BATCH);
    batch_header.id = ++_pgrequestid;    /* Order doesn't matter for id */
    batch_header.size = htonl(_pgreqbuffer_size);
    if (_pg_send(&batch_header,sizeof(batch_header)))
      return;
    if (_pg_send(_pgreqbuffer,_pgreqbuffer_size))
      return;
  }

  /* Reset buffer */
  _pgreqbuffer_size = _pgreqbuffer_count = 0;

  /* Need a response packet back... If the last packet added to the buffer was a 'wait',
   * flag _pg_getresponse that it's ok to run idle handlers and select handlers. */
  _pg_getresponse(_pgreqbuffer_lasttype == PGREQ_WAIT);
}
示例#6
0
void _pg_getresponse(int eventwait) {
  s16 rsp_id = 0;
  int extra_packet = 0;

  /* Read the response type. This is where the client spends almost
   * all it's time waiting (and the only safe place to interrupt)
   * so handle the idling here.
   */

  if ( eventwait && ( ((_pgidle_period.tv_sec + _pgidle_period.tv_usec)&&!_pgidle_lock) ||
		      (_pgselect_handler != &select) ) ) {
     
    /* Use the interruptable wait (only for event waits!) */
    switch (_pg_recvtimeout(&_pg_return.type)) {
    case 2:
      /* There's an extra packet after this one (return code from 'ping')
       * so we'll need to suck that up after we're done processing the
       * actual event packet.
       */
      extra_packet = 1;
      break;
    case 0:
      break;
    default:
      return;
    }
  }
  else {
     /* Normal receive */
     
     if (_pg_recv(&_pg_return.type,sizeof(_pg_return.type)))
       return;
  }

  _pg_return.type = ntohs(_pg_return.type);

  switch (_pg_return.type) {

  case PG_RESPONSE_ERR:
    {
      /* Error */
      struct pgresponse_err pg_err;
      char *msg;

      /* Read the rest of the error (already have response type) */
      pg_err.type = _pg_return.type;
      if (_pg_recv(((char*)&pg_err)+sizeof(_pg_return.type),
		   sizeof(pg_err)-sizeof(_pg_return.type)))
			   return;
      rsp_id = pg_err.id;
      pg_err.errt = ntohs(pg_err.errt);
      pg_err.msglen = ntohs(pg_err.msglen);
      
      /* Dynamically allocated buffer for the error message */ 
      msg = alloca(pg_err.msglen+1);
      if(_pg_recv(msg,pg_err.msglen))
		      return;
      msg[pg_err.msglen] = 0;
       
      (*_pgerrhandler)(pg_err.errt,msg);
    }
    break;

  case PG_RESPONSE_RET:
    {
      /* Return value */
      struct pgresponse_ret pg_ret;
      
      /* Read the rest of the error (already have response type) */
      pg_ret.type = _pg_return.type;
      if (_pg_recv(((char*)&pg_ret)+sizeof(_pg_return.type),
		   sizeof(pg_ret)-sizeof(_pg_return.type)))
	return;
      rsp_id = pg_ret.id;
      _pg_return.e.retdata = ntohl(pg_ret.data);
    }
    break;
    
  case PG_RESPONSE_EVENT:
    {
      /* Event */
      struct pgresponse_event pg_ev;

      /* Read the rest of the event (already have response type) */
      if (_pg_recv(((char*)&pg_ev)+sizeof(_pg_return.type),
		   sizeof(pg_ev)-sizeof(_pg_return.type)))
	return;
      pg_ev.type = _pg_return.type;
      memset(&_pg_return.e.event,0,sizeof(_pg_return.e.event));
      _pg_return.e.event.type = ntohs(pg_ev.event);
      _pg_return.e.event.from = ntohl(pg_ev.from);      
      pg_ev.param = ntohl(pg_ev.param);
       
      /* Decode the event differently based on the type */
      switch (_pg_return.e.event.type & PG_EVENTCODINGMASK) {

	 /* Easy, da? */
       default:
       case PG_EVENTCODING_PARAM:
	 _pg_return.e.event.e.param = pg_ev.param;      
	 break;
       
	 /* On some architectures this isn't necessary due to the layout
	  * of the union. Hope the optimizer notices :) */
       case PG_EVENTCODING_XY:
       case PG_EVENTCODING_KBD:   /* Same thing, just different names */
	 _pg_return.e.event.e.size.w = pg_ev.param >> 16;
	 _pg_return.e.event.e.size.h = pg_ev.param & 0xFFFF;
	 break;
	 
	 /* Decode 'mouse' parameters, sign extend the 12-bit values to 16 bits */
       case PG_EVENTCODING_PNTR:
	 _pg_return.e.event.e.pntr.x     = pg_ev.param & 0x0FFF;
	 if (_pg_return.e.event.e.pntr.x & 0x0800)
	   _pg_return.e.event.e.pntr.x |= 0xF000;
	 _pg_return.e.event.e.pntr.y     = (pg_ev.param>>12) & 0x0FFF;
	 if (_pg_return.e.event.e.pntr.y & 0x0800)
	   _pg_return.e.event.e.pntr.y |= 0xF000;
	 _pg_return.e.event.e.pntr.btn   = pg_ev.param >> 28;
	 _pg_return.e.event.e.pntr.chbtn = (pg_ev.param>>24) & 0x000F;
	 break;
	 
	 /* Transfer extra data */
       case PG_EVENTCODING_DATA:   

	 _pg_return.e.event.e.data.size = pg_ev.param;      
	 if (!(_pg_return.e.event.e.data.pointer = 
	       _pg_malloc(_pg_return.e.event.e.data.size+1)))
	   return;
	 if (_pg_recv(_pg_return.e.event.e.data.pointer,
		      _pg_return.e.event.e.data.size))
	   return;
	 /* Add a null terminator */
	 ((char *)_pg_return.e.event.e.data.pointer)
	   [_pg_return.e.event.e.data.size] = 0;

	 /* If this was a valid PG_NWE_INFILTER event, stick the data in its place */
	 if (pg_ev.param == sizeof(union pg_client_trigger) && 
	     _pg_return.e.event.type == PG_NWE_INFILTER) {
	   int i;

	   _pg_return.e.event.e.data.trigger = (union pg_client_trigger*) _pg_return.e.event.e.data.pointer;
	   
	   for (i=0;i<(sizeof(_pg_return.e.event.e.data.trigger->array)/
		       sizeof(_pg_return.e.event.e.data.trigger->array[0]));i++)
	     _pg_return.e.event.e.data.trigger->array[i] = ntohl(_pg_return.e.event.e.data.trigger->array[i]);
	 }

	 break;

	 /* Decode keyboard event */
	 
      }
	
    }
    break;

  case PG_RESPONSE_DATA:
    {
      /* Something larger- return it in a dynamically allocated buffer */
      struct pgresponse_data pg_data;
      
      /* Read the rest of the response (already have response type) */
      pg_data.type = _pg_return.type;
      if (_pg_recv(((char*)&pg_data)+sizeof(_pg_return.type),
		   sizeof(pg_data)-sizeof(_pg_return.type)))
	return;
      rsp_id = pg_data.id;
      _pg_return.e.data.size = ntohl(pg_data.size);
      
      if (!(_pg_return.e.data.data = 
	    _pg_malloc(_pg_return.e.data.size+1)))
	return;

      if (_pg_return.e.data.size)
      {
	if (_pg_recv(_pg_return.e.data.data,_pg_return.e.data.size))
	  return;
      }
      /* Add a null terminator */
      ((char *)_pg_return.e.data.data)[_pg_return.e.data.size] = 0;
    }
    break;
    
  default:
      clienterr("Unexpected response type");
  }

#ifdef DEBUG
  if(rsp_id && (rsp_id != _pgrequestid)) {
    /* ID mismatch. This shouldn't happen, but if it does it's probably
       not serious.
    */
    printf("PicoGUI - incorrect packet ID (%i -> %i)\n",_pgrequestid,rsp_id);
  }
#endif

#ifdef DEBUG_EVT
   if (_pg_return.type == PG_RESPONSE_EVENT) 
     printf("Event is %d after case\n",
	    _pg_return.e.event.type);
#endif

   /* If there was an extra packet (left over from a 'ping') 
    * we should suck that up now
    */
   if (extra_packet) {
     struct pgresponse_ret cruft;
     _pg_recv(&cruft,sizeof(cruft));
   }
 
}
示例#7
0
int t1_encrypt(int type, BUFFER *message, char *chainstr, int latency,
	       BUFFER *ek, BUFFER *feedback)
{
  BUFFER *b, *rem, *dest, *line, *field, *content;
  REMAILER remailer[MAXREM];
  int badchains[MAXREM][MAXREM];
  int maxrem, chainlen = 0;
  int chain[20];
  int hop;
  int hashmark = 0;
  int err = 0;

  b = buf_new();
  rem = buf_new();
  dest = buf_new();
  line = buf_new();
  field = buf_new();
  content = buf_new();

  maxrem = t1_rlist(remailer, badchains);
  if (maxrem < 1) {
    clienterr(feedback, "No remailer list!");
    err = -1;
    goto end;
  }
  chainlen = chain_select(chain, chainstr, maxrem, remailer, 1, line);
  if (chainlen < 1) {
    if (line->length)
      clienterr(feedback, line->data);
    else
      clienterr(feedback, "Invalid remailer chain!");
    err = -1;
    goto end;
  }
  if (chain[0] == 0)
    chain[0] = chain_randfinal(type, remailer, badchains, maxrem, 1, chain, chainlen, 0);

  if (chain[0] == -1) {
    clienterr(feedback, "Invalid remailer chain!");
    err = -1;
    goto end;
  }
  if (chain_rand(remailer, badchains, maxrem, chain, chainlen, 1, 0) == -1) {
    clienterr(feedback, "No reliable remailers!");
    err = -1;
    goto end;
  }
  while (buf_getheader(message, field, content) == 0) {
    hdr_encode(content, 0);
    if (type == MSG_POST && bufieq(field, "newsgroups") &&
	remailer[chain[0]].flags.post) {
      buf_appendf(dest, "Anon-Post-To: %b\n", content);
    } else if (type == MSG_MAIL && bufieq(field, "to")) {
      buf_appendf(dest, "Anon-To: %b\n", content);
    } else {
      /* paste header */
      if (type == MSG_POST && bufieq(field, "newsgroups"))
	buf_appendf(dest, "Anon-To: %s\n", MAILtoNEWS);
      if (hashmark == 0) {
	buf_appends(b, "##\n");
	hashmark = 1;
      }
      buf_appendheader(b, field, content);
    }
  }
  buf_nl(b);
  buf_rest(b, message);
  buf_move(message, b);

  if (type != MSG_NULL && dest->length == 0) {
    clienterr(feedback, "No destination address!");
    err = -1;
    goto end;
  }
  if (type == MSG_NULL) {
    buf_sets(dest, "Null:\n");
  }
  for (hop = 0; hop < chainlen; hop++) {
    if (hop == 0) {
      buf_sets(b, "::\n");
      buf_cat(b, dest);
    } else {
      buf_sets(b, "::\nAnon-To: ");
      buf_appends(b, remailer[chain[hop - 1]].addr);
      buf_nl(b);
    }
    if (remailer[chain[hop]].flags.latent && latency > 0)
      buf_appendf(b, "Latent-Time: +%d:00r\n", latency);
    if (ek && remailer[chain[hop]].flags.ek) {
      t1_ek(line, ek, hop);
      buf_appendf(b, "Encrypt-Key: %b\n", line);
    }
    buf_nl(b);
    buf_cat(b, message);
#ifdef USE_PGP
    if (remailer[chain[hop]].flags.pgp) {
      buf_clear(message);
      buf_clear(rem);
      buf_setf(rem, "<%s>", remailer[chain[hop]].addr);
      err = pgp_encrypt(PGP_ENCRYPT | PGP_REMAIL | PGP_TEXT, b, rem,
			NULL, NULL, NULL, NULL);
      if (err < 0) {
	buf_setf(line, "No PGP key for remailer %s!\n",
		 remailer[chain[hop]].name);
	clienterr(feedback, line->data);
	goto end;
      }
      buf_appends(message, "::\nEncrypted: PGP\n\n");
      buf_cat(message, b);
    } else
#endif /* USE_PGP */
    {
      if (remailer[chain[hop]].flags.pgponly) {
	buf_setf(line, "PGP encryption needed for remailer %s!\n",
		 remailer[chain[hop]].name);
	clienterr(feedback, line->data);
	goto end;
      }
      buf_move(message, b);
    }
    if (ek && remailer[chain[hop]].flags.ek)
      buf_appends(message, "\n**\n");
  }
  buf_clear(b);
  if (chainlen == 0) {
    buf_appends(b, "::\n");
    buf_cat(b, dest);
  } else {
    buf_appendf(b, "%s: %s\n", ek ? "::\nAnon-To" : "To",
		remailer[chain[chainlen - 1]].addr);
  }
  buf_nl(b);
  buf_cat(b, message);
  buf_move(message, b);
end:
  buf_free(b);
  buf_free(rem);
  buf_free(dest);
  buf_free(line);
  buf_free(field);
  buf_free(content);
  return (err);
}