Example #1
0
void
EIBNetIPTunnel::Run (pth_sem_t * stop1)
{
  int channel = -1;
  int mod = 0;
  int rno = 0;
  int sno = 0;
  int retry = 0;
  int heartbeat = 0;
  int drop = 0;
  eibaddr_t myaddr;
  pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
  pth_event_t input = pth_event (PTH_EVENT_SEM, &insignal);
  pth_event_t timeout = pth_event (PTH_EVENT_RTIME, pth_time (0, 0));
  pth_event_t timeout1 = pth_event (PTH_EVENT_RTIME, pth_time (10, 0));
  L_Data_PDU *c;

  EIBNetIPPacket p;
  EIBNetIPPacket *p1;
  EIBnet_ConnectRequest creq;
  creq.nat = saddr.sin_addr.s_addr == 0;
  EIBnet_ConnectResponse cresp;
  EIBnet_ConnectionStateRequest csreq;
  csreq.nat = saddr.sin_addr.s_addr == 0;
  EIBnet_ConnectionStateResponse csresp;
  EIBnet_TunnelRequest treq;
  EIBnet_TunnelACK tresp;
  EIBnet_DisconnectRequest dreq;
  dreq.nat = saddr.sin_addr.s_addr == 0;
  EIBnet_DisconnectResponse dresp;
  creq.caddr = saddr;
  creq.daddr = saddr;
  creq.CRI.resize (3);
  creq.CRI[0] = 0x04;
  creq.CRI[1] = 0x02;
  creq.CRI[2] = 0x00;
  p = creq.ToPacket ();
  sock->sendaddr = caddr;
  sock->Send (p);

  while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
    {
      if (mod == 1)
	pth_event_concat (stop, input, NULL);
      if (mod == 2 || mod == 3)
	pth_event_concat (stop, timeout, NULL);

      pth_event_concat (stop, timeout1, NULL);

      p1 = sock->Get (stop);
      pth_event_isolate (stop);
      pth_event_isolate (timeout);
      pth_event_isolate (timeout1);
      if (p1)
	{
	  switch (p1->service)
	    {
	    case CONNECTION_RESPONSE:
	      if (mod)
		goto err;
	      if (parseEIBnet_ConnectResponse (*p1, cresp))
		{
		  TRACEPRINTF (t, 1, this, "Recv wrong connection response");
		  break;
		}
	      if (cresp.status != 0)
		{
		  TRACEPRINTF (t, 1, this, "Connect failed with error %02X",
			       cresp.status);
		  if (cresp.status == 0x23 && support_busmonitor == 1
		      && connect_busmonitor == 1)
		    {
		      TRACEPRINTF (t, 1, this, "Disable busmonitor support");
		      support_busmonitor = 0;
		      connect_busmonitor = 0;
		      creq.CRI[1] = 0x02;
		      pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout1,
				 pth_time (10, 0));
		      p = creq.ToPacket ();
		      TRACEPRINTF (t, 1, this, "Connectretry");
		      sock->sendaddr = caddr;
		      sock->Send (p);
		    }
		  break;
		}
	      if (cresp.CRD () != 3)
		{
		  TRACEPRINTF (t, 1, this, "Recv wrong connection response");
		  break;
		}
	      myaddr = (cresp.CRD[1] << 8) | cresp.CRD[2];
	      daddr = cresp.daddr;
	      if (!cresp.nat)
		{
		  if (NAT)
		    daddr.sin_addr = caddr.sin_addr;
		  if (dataport != -1)
		    daddr.sin_port = htons (dataport);
		}
	      channel = cresp.channel;
	      mod = 1;
	      sno = 0;
	      rno = 0;
	      sock->recvaddr2 = daddr;
	      sock->recvall = 3;
	      pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout1,
			 pth_time (30, 0));
	      heartbeat = 0;
	      break;

	    case TUNNEL_REQUEST:
	      if (mod == 0)
		{
		  TRACEPRINTF (t, 1, this, "Not connected");
		  goto err;
		}
	      if (parseEIBnet_TunnelRequest (*p1, treq))
		{
		  TRACEPRINTF (t, 1, this, "Invalid request");
		  break;
		}
	      if (treq.channel != channel)
		{
		  TRACEPRINTF (t, 1, this, "Not for us");
		  break;
		}
	      if (((treq.seqno + 1) & 0xff) == rno)
		{
		  tresp.status = 0;
		  tresp.channel = channel;
		  tresp.seqno = treq.seqno;
		  p = tresp.ToPacket ();
		  sock->sendaddr = daddr;
		  sock->Send (p);
		  sock->recvall = 0;
		  break;
		}
	      if (treq.seqno != rno)
		{
		  TRACEPRINTF (t, 1, this, "Wrong sequence %d<->%d",
			       treq.seqno, rno);
		  if (treq.seqno < rno)
		    treq.seqno += 0x100;
		  if (treq.seqno >= rno + 5)
		    {
		      dreq.caddr = saddr;
		      dreq.channel = channel;
		      p = dreq.ToPacket ();
		      sock->sendaddr = caddr;
		      sock->Send (p);
		      sock->recvall = 0;
		      mod = 0;
		    }
		  break;
		}
	      rno++;
	      if (rno > 0xff)
		rno = 0;
	      tresp.status = 0;
	      tresp.channel = channel;
	      tresp.seqno = treq.seqno;
	      p = tresp.ToPacket ();
	      sock->sendaddr = daddr;
	      sock->Send (p);
	      //Confirmation
	      if (treq.CEMI[0] == 0x2E)
		{
		  if (mod == 3)
		    mod = 1;
		  break;
		}
	      if (treq.CEMI[0] == 0x2B)
		{
		  L_Busmonitor_PDU *l2 = CEMI_to_Busmonitor (treq.CEMI);
		  outqueue.put (l2);
		  pth_sem_inc (&outsignal, 1);
		  break;
		}
	      if (treq.CEMI[0] != 0x29)
		{
		  TRACEPRINTF (t, 1, this, "Unexpected CEMI Type %02X",
			       treq.CEMI[0]);
		  break;
		}
	      c = CEMI_to_L_Data (treq.CEMI);
	      if (c)
		{

		  TRACEPRINTF (t, 1, this, "Recv %s", c->Decode ()());
		  if (mode == 0)
		    {
		      if (vmode)
			{
			  L_Busmonitor_PDU *l2 = new L_Busmonitor_PDU;
			  l2->pdu.set (c->ToPacket ());
			  outqueue.put (l2);
			  pth_sem_inc (&outsignal, 1);
			}
		      if (c->AddrType == IndividualAddress
			  && c->dest == myaddr)
			c->dest = 0;
		      outqueue.put (c);
		      pth_sem_inc (&outsignal, 1);
		      break;
		    }
		  L_Busmonitor_PDU *p1 = new L_Busmonitor_PDU;
		  p1->pdu = c->ToPacket ();
		  delete c;
		  outqueue.put (p1);
		  pth_sem_inc (&outsignal, 1);
		  break;
		}
	      TRACEPRINTF (t, 1, this, "Unknown CEMI");
	      break;
	    case TUNNEL_RESPONSE:
	      if (mod == 0)
		{
		  TRACEPRINTF (t, 1, this, "Not connected");
		  goto err;
		}
	      if (parseEIBnet_TunnelACK (*p1, tresp))
		{
		  TRACEPRINTF (t, 1, this, "Invalid response");
		  break;
		}
	      if (tresp.channel != channel)
		{
		  TRACEPRINTF (t, 1, this, "Not for us");
		  break;
		}
	      if (tresp.seqno != sno)
		{
		  TRACEPRINTF (t, 1, this, "Wrong sequence %d<->%d",
			       tresp.seqno, sno);
		  break;
		}
	      if (tresp.status)
		{
		  TRACEPRINTF (t, 1, this, "Error in ACK %d", tresp.status);
		  break;
		}
	      if (mod == 2)
		{
		  sno++;
		  if (sno > 0xff)
		    sno = 0;
		  pth_sem_dec (&insignal);
		  inqueue.get ();
		  if (noqueue)
		    {
		      mod = 3;
		      pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout,
				 pth_time (1, 0));
		    }
		  else
		    mod = 1;
		  retry = 0;
		  drop = 0;
		}
	      else
		TRACEPRINTF (t, 1, this, "Unexpected ACK");
	      break;
	    case CONNECTIONSTATE_RESPONSE:
	      if (parseEIBnet_ConnectionStateResponse (*p1, csresp))
		{
		  TRACEPRINTF (t, 1, this, "Invalid response");
		  break;
		}
	      if (csresp.channel != channel)
		{
		  TRACEPRINTF (t, 1, this, "Not for us");
		  break;
		}
	      if (csresp.status == 0)
		{
		  if (heartbeat > 0)
		    heartbeat--;
		  else
		    TRACEPRINTF (t, 1, this,
				 "Duplicate Connection State Response");
		}
	      else if (csresp.status == 0x21)
		{
		  TRACEPRINTF (t, 1, this,
			       "Connection State Response not connected");
		  dreq.caddr = saddr;
		  dreq.channel = channel;
		  p = dreq.ToPacket ();
		  sock->sendaddr = caddr;
		  sock->Send (p);
		  sock->recvall = 0;
		  mod = 0;
		}
	      else
		TRACEPRINTF (t, 1, this,
			     "Connection State Response Error %02x",
			     csresp.status);
	      break;
	    case DISCONNECT_REQUEST:
	      if (mod == 0)
		{
		  TRACEPRINTF (t, 1, this, "Not connected");
		  goto err;
		}
	      if (parseEIBnet_DisconnectRequest (*p1, dreq))
		{
		  TRACEPRINTF (t, 1, this, "Invalid request");
		  break;
		}
	      if (dreq.channel != channel)
		{
		  TRACEPRINTF (t, 1, this, "Not for us");
		  break;
		}
	      dresp.channel = channel;
	      dresp.status = 0;
	      p = dresp.ToPacket ();
	      t->TracePacket (1, this, "SendDis", p.data);
	      sock->sendaddr = caddr;
	      sock->Send (p);
	      sock->recvall = 0;
	      mod = 0;
	      break;
	    case DISCONNECT_RESPONSE:
	      if (mod == 0)
		{
		  TRACEPRINTF (t, 1, this, "Not connected");
		  break;
		}
	      if (parseEIBnet_DisconnectResponse (*p1, dresp))
		{
		  TRACEPRINTF (t, 1, this, "Invalid request");
		  break;
		}
	      if (dresp.channel != channel)
		{
		  TRACEPRINTF (t, 1, this, "Not for us");
		  break;
		}
	      mod = 0;
	      sock->recvall = 0;
	      TRACEPRINTF (t, 1, this, "Disconnected");
	      pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout1,
			 pth_time (0, 100));
	      break;
	    default:
	    err:
	      TRACEPRINTF (t, 1, this, "Recv unexpected service %04X",
			   p1->service);
	    }
	  delete p1;
	}
      if (mod == 2 && pth_event_status (timeout) == PTH_STATUS_OCCURRED)
	{
	  mod = 1;
	  retry++;
	  if (retry > 3)
	    {
	      TRACEPRINTF (t, 1, this, "Drop");
	      pth_sem_dec (&insignal);
	      inqueue.get ();
	      retry = 0;
	      drop++;
	      if (drop >= 3)
		{
		  dreq.caddr = saddr;
		  dreq.channel = channel;
		  p = dreq.ToPacket ();
		  sock->sendaddr = caddr;
		  sock->Send (p);
		  sock->recvall = 0;
		  mod = 0;
		}
	    }
	}
      if (mod == 3 && pth_event_status (timeout) == PTH_STATUS_OCCURRED)
	mod = 1;
      if (mod != 0 && pth_event_status (timeout1) == PTH_STATUS_OCCURRED)
	{
	  pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout1,
		     pth_time (30, 0));
	  if (heartbeat < 5)
	    {
	      csreq.caddr = saddr;
	      csreq.channel = channel;
	      p = csreq.ToPacket ();
	      TRACEPRINTF (t, 1, this, "Heartbeat");
	      sock->sendaddr = caddr;
	      sock->Send (p);
	      heartbeat++;
	    }
	  else
	    {
	      TRACEPRINTF (t, 1, this, "Disconnection because of errors");
	      dreq.caddr = saddr;
	      dreq.channel = channel;
	      p = dreq.ToPacket ();
	      sock->sendaddr = caddr;
	      if (channel != -1)
		sock->Send (p);
	      sock->recvall = 0;
	      mod = 0;
	    }
	}
      if (mod == 0 && pth_event_status (timeout1) == PTH_STATUS_OCCURRED)
	{
	  pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout1,
		     pth_time (10, 0));
	  creq.CRI[1] =
	    ((connect_busmonitor && support_busmonitor) ? 0x80 : 0x02);
	  p = creq.ToPacket ();
	  TRACEPRINTF (t, 1, this, "Connectretry");
	  sock->sendaddr = caddr;
	  sock->Send (p);
	}

      if (!inqueue.isempty () && inqueue.top ()() == 0)
	{
	  pth_sem_dec (&insignal);
	  inqueue.get ();
	  if (support_busmonitor)
	    {
	      dreq.caddr = saddr;
	      dreq.channel = channel;
	      p = dreq.ToPacket ();
	      sock->sendaddr = caddr;
	      sock->Send (p);
	    }
	}

      if (!inqueue.isempty () && mod == 1)
	{
	  treq.channel = channel;
	  treq.seqno = sno;
	  treq.CEMI = inqueue.top ();
	  p = treq.ToPacket ();
	  t->TracePacket (1, this, "SendTunnel", p.data);
	  sock->sendaddr = daddr;
	  sock->Send (p);
	  mod = 2;
	  pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout,
		     pth_time (1, 0));
	}
    }
out:
  dreq.caddr = saddr;
  dreq.channel = channel;
  p = dreq.ToPacket ();
  sock->sendaddr = caddr;
  if (channel != -1)
    sock->Send (p);

  pth_event_free (stop, PTH_FREE_THIS);
  pth_event_free (input, PTH_FREE_THIS);
  pth_event_free (timeout, PTH_FREE_THIS);
  pth_event_free (timeout1, PTH_FREE_THIS);
}
Example #2
0
/* Fork off the pin entry if this has not already been done.  Note,
   that this function must always be used to aquire the lock for the
   pinentry - we will serialize _all_ pinentry calls.
 */
static int
start_pinentry (ctrl_t ctrl)
{
  int rc;
  const char *pgmname;
  assuan_context_t ctx;
  const char *argv[5];
  int no_close_list[3];
  int i;
  pth_event_t evt;
  const char *tmpstr;
  unsigned long pinentry_pid;
  const char *value;

  evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
  if (!pth_mutex_acquire (&entry_lock, 0, evt))
    {
      if (pth_event_occurred (evt))
        rc = gpg_error (GPG_ERR_TIMEOUT);
      else
        rc = gpg_error (GPG_ERR_INTERNAL);
      pth_event_free (evt, PTH_FREE_THIS);
      log_error (_("failed to acquire the pinentry lock: %s\n"),
                 gpg_strerror (rc));
      return rc;
    }
  pth_event_free (evt, PTH_FREE_THIS);

  entry_owner = ctrl;

  if (entry_ctx)
    return 0; 

  if (opt.verbose)
    log_info ("starting a new PIN Entry\n");

#ifdef HAVE_W32_SYSTEM      
  fflush (stdout);
  fflush (stderr);
#endif
  if (fflush (NULL))
    {
#ifndef HAVE_W32_SYSTEM
      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
#endif
      log_error ("error flushing pending output: %s\n", strerror (errno));
      /* At least Windows XP fails here with EBADF.  According to docs
         and Wine an fflush(NULL) is the same as _flushall.  However
         the Wime implementaion does not flush stdin,stdout and stderr
         - see above.  Lets try to ignore the error. */
#ifndef HAVE_W32_SYSTEM
      return unlock_pinentry (tmperr);
#endif
    }

  if (!opt.pinentry_program || !*opt.pinentry_program)
    opt.pinentry_program = gnupg_module_name (GNUPG_MODULE_NAME_PINENTRY);
    pgmname = opt.pinentry_program;
  if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
    pgmname = opt.pinentry_program;
  else
    pgmname++;

  /* OS X needs the entire file name in argv[0], so that it can locate
     the resource bundle.  For other systems we stick to the usual
     convention of supplying only the name of the program.  */
#ifdef __APPLE__
  argv[0] = opt.pinentry_program;
#else /*!__APPLE__*/
  argv[0] = pgmname;
#endif /*__APPLE__*/

  if (!opt.keep_display
      && (value = session_env_getenv (ctrl->session_env, "DISPLAY")))
    {
      argv[1] = "--display";
      argv[2] = value;
      argv[3] = NULL;
    }
  else
    argv[1] = NULL;
  
  i=0;
  if (!opt.running_detached)
    {
      if (log_get_fd () != -1)
        no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
      no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
    }
  no_close_list[i] = -1;

  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
      return rc;
    }

  /* Connect to the pinentry and perform initial handshaking.  Note
     that atfork is used to change the environment for pinentry.  We
     start the server in detached mode to suppress the console window
     under Windows.  */
  rc = assuan_pipe_connect (ctx, opt.pinentry_program, argv,
			    no_close_list, atfork_cb, ctrl,
			    ASSUAN_PIPE_CONNECT_DETACHED);
  if (rc)
    {
      log_error ("can't connect to the PIN entry module: %s\n",
                 gpg_strerror (rc));
      assuan_release (ctx);
      return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
    }
  entry_ctx = ctx;

  if (DBG_ASSUAN)
    log_debug ("connection to PIN entry established\n");

  rc = assuan_transact (entry_ctx, 
                        opt.no_grab? "OPTION no-grab":"OPTION grab",
                        NULL, NULL, NULL, NULL, NULL, NULL);
  if (rc)
    return unlock_pinentry (rc);

  value = session_env_getenv (ctrl->session_env, "GPG_TTY");
  if (value)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION ttyname=%s", value) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }
  value = session_env_getenv (ctrl->session_env, "TERM");
  if (value)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }
  if (ctrl->lc_ctype)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }
  if (ctrl->lc_messages)
    {
      char *optstr;
      if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
	return unlock_pinentry (out_of_core ());
      rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
			    NULL);
      xfree (optstr);
      if (rc)
	return unlock_pinentry (rc);
    }

  {
    /* Provide a few default strings for use by the pinentries.  This
       may help a pinentry to avoid implementing localization code.  */
    static struct { const char *key, *value; } tbl[] = {
      /* TRANSLATORS: These are labels for buttons etc used in
         Pinentries.  An underscore indicates that the next letter
         should be used as an accelerator.  Double the underscore for
         a literal one.  The actual to be translated text starts after
         the second vertical bar.  */
      { "ok",     N_("|pinentry-label|_OK") },
      { "cancel", N_("|pinentry-label|_Cancel") },
      { "prompt", N_("|pinentry-label|PIN:") },
      { NULL, NULL}
    };
    char *optstr;
    int idx;
    const char *s, *s2;

    for (idx=0; tbl[idx].key; idx++)
      {
        s = _(tbl[idx].value);
        if (*s == '|' && (s2=strchr (s+1,'|')))
          s = s2+1;
        if (asprintf (&optstr, "OPTION default-%s=%s", tbl[idx].key, s) < 0 )
          return unlock_pinentry (out_of_core ());
        assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                         NULL);
        xfree (optstr);
      }
  }

  
  /* Tell the pinentry the name of a file it shall touch after having
     messed with the tty.  This is optional and only supported by
     newer pinentries and thus we do no error checking. */
  tmpstr = opt.pinentry_touch_file;
  if (tmpstr && !strcmp (tmpstr, "/dev/null"))
    tmpstr = NULL;
  else if (!tmpstr)
    tmpstr = get_agent_socket_name ();
  if (tmpstr)
    {
      char *optstr;
      
      if (asprintf (&optstr, "OPTION touch-file=%s", tmpstr ) < 0 )
        ;
      else
        {
          assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
                           NULL);
          xfree (optstr);
        }
    }


  /* Now ask the Pinentry for its PID.  If the Pinentry is new enough
     it will send the pid back and we will use an inquire to notify
     our client.  The client may answer the inquiry either with END or
     with CAN to cancel the pinentry. */
  rc = assuan_transact (entry_ctx, "GETINFO pid", 
                        getinfo_pid_cb, &pinentry_pid,
                        NULL, NULL, NULL, NULL);
  if (rc)
    {
      log_info ("You may want to update to a newer pinentry\n");
      rc = 0;
    }
  else if (!rc && (pid_t)pinentry_pid == (pid_t)(-1))
    log_error ("pinentry did not return a PID\n");
  else
    {
      rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
      if (gpg_err_code (rc) == GPG_ERR_CANCELED)
        return unlock_pinentry (gpg_error (GPG_ERR_CANCELED));
      rc = 0;
    }

  return 0;
}
Example #3
0
FrSimThreadEvent::FrSimThreadEvent()
{
  msgPrt = pth_msgport_create(NULL);
  ev = pth_event(PTH_EVENT_MSG, msgPrt);
}
Example #4
0
int main(int argc, char *argv[])
{
    int i;
    sigset_t ss;
    int sig;
    pth_event_t ev;

    /* initialize Pth library */
    pth_init();

    /* display test program header */
    printf("This is TEST_PHILO, a Pth test showing the Five Dining Philosophers\n");
    printf("\n");
    printf("This is a demonstration showing the famous concurrency problem of the\n");
    printf("Five Dining Philosophers as analysed 1965 by E.W.Dijkstra:\n");
    printf("\n");
    printf("Five philosophers are sitting around a round table, each with a bowl of\n");
    printf("Chinese food in front of him. Between periods of talking they may start\n");
    printf("eating whenever they want to, with their bowls being filled frequently.\n");
    printf("But there are only five chopsticks available, one each to the left of\n");
    printf("each bowl - and for eating Chinese food one needs two chopsticks. When\n");
    printf("a philosopher wants to start eating, he must pick up the chopstick to\n");
    printf("the left of his bowl and the chopstick to the right of his bowl. He\n");
    printf("may find, however, that either one (or even both) of the chopsticks is\n");
    printf("unavailable as it is being used by another philosopher sitting on his\n");
    printf("right or left, so he has to wait.\n");
    printf("\n");
    printf("This situation shows classical contention under concurrency (the\n");
    printf("philosophers want to grab the chopsticks) and the possibility of a\n");
    printf("deadlock (all philosophers wait that the chopstick to their left becomes\n");
    printf("available).\n");
    printf("\n");
    printf("The demonstration runs max. 60 seconds. To stop before, press CTRL-C.\n");
    printf("\n");
    printf("+----P1----+----P2----+----P3----+----P4----+----P5----+\n");

    /* initialize the control table */
    tab = (table *)malloc(sizeof(table));
    if (!pth_mutex_init(&(tab->mutex))) {
        perror("pth_mutex_init");
        exit(1);
    }
    for (i = 0; i < PHILNUM; i++) {
        (tab->self)[i] = i;
        (tab->status)[i] = thinking;
        if (!pth_cond_init(&((tab->condition)[i]))) {
            perror("pth_cond_init");
            exit(1);
        }
    }

    /* spawn the philosopher threads */
    for (i = 0; i < PHILNUM; i++) {
        if (((tab->tid)[i] =
              pth_spawn(PTH_ATTR_DEFAULT, philosopher,
                        &((tab->self)[i]))) == NULL) {
            perror("pth_spawn");
            exit(1);
        }
    }

    /* wait until 60 seconds have elapsed or CTRL-C was pressed */
    sigemptyset(&ss);
    sigaddset(&ss, SIGINT);
    ev = pth_event(PTH_EVENT_TIME, pth_timeout(60,0));
    pth_sigwait_ev(&ss, &sig, ev);
    pth_event_free(ev, PTH_FREE_ALL);

    /* cancel and join the philosopher threads */
    for (i = 0; i < PHILNUM; i++)
        pth_cancel((tab->tid)[i]);
    while (pth_join(NULL, NULL));

    /* finish display */
    printf("+----------+----------+----------+----------+----------+\n");

    /* free the control table */
    free(tab);

    /* shutdown Pth library */
    pth_kill();

    return 0;
}
Example #5
0
void
Layer3::Run (pth_sem_t * stop1)
{
  pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
  unsigned i;

  running = true;
  for (i = 0; i < layer2 (); i++)
    layer2[i].Start ();

  TRACEPRINTF (t, 3, this, "L3 started");
  while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
    {
      pth_event_t bufev = pth_event (PTH_EVENT_SEM, &bufsem);
      pth_event_concat (bufev, stop, NULL);
      pth_wait (bufev);
      pth_event_isolate (bufev);

      if (pth_event_status (bufev) != PTH_STATUS_OCCURRED)
        {
          pth_event_free (bufev, PTH_FREE_THIS);
          continue;
        }
      pth_event_free (bufev, PTH_FREE_THIS);

      pth_sem_dec (&bufsem);
      LPDU *l = buf.get ();
      if (!l)
	continue;
      if (l->getType () == L_Busmonitor)
	{
	  L_Busmonitor_PDU *l1, *l2;
	  l1 = (L_Busmonitor_PDU *) l;

	  TRACEPRINTF (t, 3, this, "Recv %s", l1->Decode ()());
	  for (i = 0; i < busmonitor (); i++)
	    {
	      l2 = new L_Busmonitor_PDU (*l1);
	      busmonitor[i].cb->Send_L_Busmonitor (l2);
	    }
	  for (i = 0; i < vbusmonitor (); i++)
	    {
	      l2 = new L_Busmonitor_PDU (*l1);
	      vbusmonitor[i].cb->Send_L_Busmonitor (l2);
	    }
	}
      if (l->getType () == L_Data)
	{
	  L_Data_PDU *l1;
	  l1 = (L_Data_PDU *) l;
	  if (l1->repeated)
	    {
	      CArray d1 = l1->ToPacket ();
	      for (i = 0; i < ignore (); i++)
		if (d1 == ignore[i].data)
		  {
		    TRACEPRINTF (t, 3, this, "Repeated discareded");
		    goto wt;
		  }
	    }
	  l1->repeated = 1;
	  ignore.resize (ignore () + 1);
	  ignore[ignore () - 1].data = l1->ToPacket ();
	  ignore[ignore () - 1].end = getTime () + 1000000;
	  l1->repeated = 0;

	  if (l1->AddrType == IndividualAddress
	      && l1->dest == defaultAddr)
	    l1->dest = 0;
	  TRACEPRINTF (t, 3, this, "Recv %s", l1->Decode ()());

	  if (l1->AddrType == GroupAddress && l1->dest == 0)
	    {
	      for (i = 0; i < broadcast (); i++)
		broadcast[i].cb->Send_L_Data (new L_Data_PDU (*l1));
	    }
	  if (l1->AddrType == GroupAddress && l1->dest != 0)
	    {
	      for (i = 0; i < group (); i++)
                {
                  Group_Info &grp = group[i];
		  if (grp.dest == l1->dest || grp.dest == 0)
		    grp.cb->Send_L_Data (new L_Data_PDU (*l1));
                }
	    }
	  if (l1->AddrType == IndividualAddress)
	    {
	      for (i = 0; i < individual (); i++)
                {
                  Individual_Info &indiv = individual[i];
		  if (indiv.dest == l1->dest || indiv.dest == 0)
		    if (indiv.src == l1->source || indiv.src == 0)
		      indiv.cb->Send_L_Data (new L_Data_PDU (*l1));
	        }
	    }

          // finally, send to all (other(?)) L2 interfaces
          // TODO: filter by addresses
          send_L_Data(l1);
	}
      // ignore[] is ordered, any timed-out items are at the front
      for (i = 0; i < ignore (); i++)
	if (ignore[i].end >= getTime ())
          break;
      if (i)
        ignore.deletepart (0, i);
    wt:
      delete l;

    }
  TRACEPRINTF (t, 3, this, "L3 stopping");

  running = false;
  for (i = 0; i < layer2 (); i++)
    layer2[i].Stop ();

  pth_event_free (stop, PTH_FREE_THIS);
}
Example #6
0
int main(int argc, char *argv[])
{
    char caLine[MAXLINELEN];
    pth_event_t ev = NULL;
    pth_event_t evt = NULL;
    pth_t t_worker = NULL;
    pth_t t_ticker = NULL;
    pth_attr_t t_attr;
    pth_msgport_t mp = NULL;
    pth_msgport_t mp_worker = NULL;
    struct query *q = NULL;
    int n;

    if (!pth_init()) {
        perror("pth_init");
        exit(1);
    }

    /* murray added for tmp debug */
/* 
    pth_time_t intval, former;

    printf("-------------------------\n");
    pth_time_set(&former, PTH_TIME_NOW);
    pth_usleep(300);
    pth_time_set(&intval, PTH_TIME_NOW);
    pth_time_sub(&intval, &former);
    double val = pth_time_t2d(&intval);
    printf("the intval is [%f]\n", val);
    pth_debug2("the intval is [%f]\n", val);
    return 0;
*/


    fprintf(stderr, "This is TEST_MP, a Pth test using message ports.\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "Lines on stdin are send to a worker thread via message\n");
    fprintf(stderr, "ports, translated to upper case by the worker thread and\n");
    fprintf(stderr, "send back to the main thread via message ports.\n");
    fprintf(stderr, "Additionally a useless ticker thread awakens every 5s.\n");
    fprintf(stderr, "Enter \"quit\" on stdin for stopping this test.\n");
    fprintf(stderr, "\n");

    t_attr = pth_attr_new();
    pth_attr_set(t_attr, PTH_ATTR_NAME, "worker");
    pth_attr_set(t_attr, PTH_ATTR_JOINABLE, TRUE);
    pth_attr_set(t_attr, PTH_ATTR_STACK_SIZE, 16*1024);
    t_worker = pth_spawn(t_attr, worker, NULL);
    pth_attr_set(t_attr, PTH_ATTR_NAME, "ticker");
    t_ticker = pth_spawn(t_attr, ticker, NULL);
    pth_attr_destroy(t_attr);
    pth_yield(NULL);

    mp_worker = pth_msgport_find("worker");
    mp = pth_msgport_create("main");
    q = (struct query *)malloc(sizeof(struct query));
    ev = pth_event(PTH_EVENT_MSG, mp);

    evt = NULL;
    for (;;) {
        if (evt == NULL)
            evt = pth_event(PTH_EVENT_TIME, pth_timeout(20,0));
        else
            evt = pth_event(PTH_EVENT_TIME|PTH_MODE_REUSE, evt, pth_timeout(20,0));
        n = pth_readline_ev(STDIN_FILENO, caLine, MAXLINELEN, evt);
        if (n == -1 && pth_event_status(evt) == PTH_STATUS_OCCURRED) {
            fprintf(stderr, "main: Hey, what are you waiting for? Type in something!\n");
            continue;
        }
        if (n < 0) {
            fprintf(stderr, "main: I/O read error on stdin\n");
            break;
        }
        if (n == 0) {
            fprintf(stderr, "main: EOF on stdin\n");
            break;
        }
        caLine[n-1] = NUL;
        if (strcmp(caLine, "quit") == 0) {
            fprintf(stderr, "main: quit\n");
            break;
        }
        fprintf(stderr, "main: out --> <%s>\n", caLine);
        q->string = caLine;
        q->head.m_replyport = mp;
        pth_msgport_put(mp_worker, (pth_message_t *)q);
        pth_wait(ev);
        q = (struct query *)pth_msgport_get(mp);
        fprintf(stderr, "main: in <-- <%s>\n", q->string);
    }

    free(q);
    pth_event_free(ev, PTH_FREE_THIS);
    pth_event_free(evt, PTH_FREE_THIS);
    pth_msgport_destroy(mp);
    pth_cancel(t_worker);
    pth_join(t_worker, NULL);
    pth_cancel(t_ticker);
    pth_join(t_ticker, NULL);
    pth_kill();
    return 0;
}
Example #7
0
void
FT12LowLevelDriver::Run (pth_sem_t * stop1)
{
  CArray last;
  int i;
  uchar buf[255];

  pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
  pth_event_t input = pth_event (PTH_EVENT_SEM, &in_signal);
  pth_event_t timeout = pth_event (PTH_EVENT_RTIME, pth_time (0, 100000));
  while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
    {
      pth_event_isolate (input);
      pth_event_isolate (timeout);
      if (mode == 0)
	pth_event_concat (stop, input, NULL);
      if (mode == 1)
	pth_event_concat (stop, timeout, NULL);

      i = pth_read_ev (fd, buf, sizeof (buf), stop);
      if (i > 0)
	{
	  t->TracePacket (0, this, "Recv", i, buf);
	  akt.setpart (buf, akt (), i);
	}

      while (akt.len () > 0)
	{
	  if (akt[0] == 0xE5 && mode == 1)
	    {
	      pth_sem_dec (&in_signal);
	      inqueue.get ();
	      if (inqueue.isempty ())
		pth_sem_set_value (&send_empty, 1);
	      akt.deletepart (0, 1);
	      mode = 0;
	      repeatcount = 0;
	    }
	  else if (akt[0] == 0x10)
	    {
	      if (akt () < 4)
		break;
	      if (akt[1] == akt[2] && akt[3] == 0x16)
		{
		  uchar c1 = 0xE5;
		  t->TracePacket (0, this, "Send Ack", 1, &c1);
		  if(write (fd, &c1, 1) != 1)
		    {
		      ERRORPRINTF (t, E_ERROR | 10, this, "write error (%s)", strerror(errno));
		      break;
		    }
		  if ((akt[1] == 0xF3 && !recvflag) ||
		      (akt[1] == 0xD3 && recvflag))
		    {
		      //right sequence number
		      recvflag = !recvflag;
		    }
		  if ((akt[1] & 0x0f) == 0)
		    {
		      const uchar reset[1] = { 0xA0 };
		      CArray *c = new CArray (reset, sizeof (reset));
		      t->TracePacket (0, this, "RecvReset", *c);
		      outqueue.put (c);
		      pth_sem_inc (&out_signal, TRUE);
		    }
		}
	      akt.deletepart (0, 4);
	    }
	  else if (akt[0] == 0x68)
	    {
	      int len;
	      uchar c1;
	      if (akt () < 7)
		break;
	      if (akt[1] != akt[2] || akt[3] != 0x68)
		{
		  //receive error, try to resume
		  akt.deletepart (0, 1);
		  continue;
		}
	      if (akt () < akt[1] + 6U)
		break;

	      c1 = 0;
	      for (i = 4; i < akt[1] + 4U; i++)
		c1 += akt[i];
	      if (akt[akt[1] + 4] != c1 || akt[akt[1] + 5] != 0x16)
		{
		  len = akt[1] + 6;
		  //Forget wrong short frame
		  akt.deletepart (0, len);
		  continue;
		}

	      c1 = 0xE5;
	      t->TracePacket (0, this, "Send Ack", 1, &c1);
	      i = write (fd, &c1, 1);

	      if ((akt[4] == 0xF3 && recvflag) ||
		  (akt[4] == 0xD3 && !recvflag))
		{
		  if (CArray (akt.array () + 5, akt[1] - 1) != last)
		    {
		      TRACEPRINTF (t, 0, this, "Sequence jump");
		      recvflag = !recvflag;
		    }
		  else
		    TRACEPRINTF (t, 0, this, "Wrong Sequence");
		}

	      if ((akt[4] == 0xF3 && !recvflag) ||
		  (akt[4] == 0xD3 && recvflag))
		{
		  recvflag = !recvflag;
		  CArray *c = new CArray;
		  len = akt[1] + 6;
		  c->setpart (akt.array () + 5, 0, len - 7);
		  last = *c;
		  outqueue.put (c);
		  pth_sem_inc (&out_signal, TRUE);
		}
              // XXX TODO otherwise set 'len' to what? Or continue?
	      akt.deletepart (0, len);
	    }
	  else
	    //Forget unknown byte
	    akt.deletepart (0, 1);
	}

      if (mode == 1 && pth_event_status (timeout) == PTH_STATUS_OCCURRED)
	mode = 0;

      if (mode == 0 && !inqueue.isempty ())
	{
	  const CArray & c = inqueue.top ();
	  t->TracePacket (0, this, "Send", c);
	  repeatcount++;
	  i = pth_write_ev (fd, c.array (), c (), stop);
	  if (i == c ())
	    {
	      mode = 1;
	      timeout =
		pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout,
			   pth_time (0, 100000));
	    }
	}
    }
  pth_event_free (stop, PTH_FREE_THIS);
  pth_event_free (timeout, PTH_FREE_THIS);
  pth_event_free (input, PTH_FREE_THIS);
}