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); }
/* 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; }
FrSimThreadEvent::FrSimThreadEvent() { msgPrt = pth_msgport_create(NULL); ev = pth_event(PTH_EVENT_MSG, msgPrt); }
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; }
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); }
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; }
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); }