/*
EIBD eib bus access and management daemon
Copyright (C) 2005-2007 Martin Koegler <mkoegler@auto.tuwien.ac.at>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "layer4.h"
#include "tpdu.h"
T_Broadcast::T_Broadcast (Layer3 * l3, Trace * tr, int write_only)
{
TRACEPRINTF (tr, 4, this, "OpenBroadcast %s", write_only ? "WO" : "RW");
layer3 = l3;
t = tr;
pth_sem_init (&sem);
if (!write_only)
if (!layer3->registerBroadcastCallBack (this))
throw Exception (L4_INIT_FAIL);
}
T_Broadcast::~T_Broadcast ()
{
TRACEPRINTF (t, 4, this, "CloseBroadcast");
layer3->deregisterBroadcastCallBack (this);
}
void
T_Broadcast::Get_L_Data (L_Data_PDU * l)
{
BroadcastComm c;
TPDU *t = TPDU::fromPacket (l->data);
if (t->getType () == T_DATA_XXX_REQ)
{
T_DATA_XXX_REQ_PDU *t1 = (T_DATA_XXX_REQ_PDU *) t;
c.data = t1->data;
c.src = l->source;
outqueue.put (c);
pth_sem_inc (&sem, 0);
}
delete t;
delete l;
}
void
T_Broadcast::Send (const CArray & c)
{
T_DATA_XXX_REQ_PDU t;
t.data = c;
String s = t.Decode ();
TRACEPRINTF (this->t, 4, this, "Send Broadcast %s", s ());
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = 0;
l->AddrType = GroupAddress;
l->data = t.ToPacket ();
layer3->send_L_Data (l);
}
BroadcastComm *
T_Broadcast::Get (pth_event_t stop)
{
pth_event_t s = pth_event (PTH_EVENT_SEM, &sem);
pth_event_concat (s, stop, NULL);
pth_wait (s);
pth_event_isolate (s);
if (pth_event_status (s) == PTH_STATUS_OCCURRED)
{
pth_sem_dec (&sem);
BroadcastComm *c = new BroadcastComm (outqueue.get ());
pth_event_free (s, PTH_FREE_THIS);
t->TracePacket (4, this, "Recv Broadcast", c->data);
return c;
}
pth_event_free (s, PTH_FREE_THIS);
return 0;
}
T_Group::T_Group (Layer3 * l3, Trace * tr, eibaddr_t group, int write_only)
{
TRACEPRINTF (tr, 4, this, "OpenGroup %d/%d/%d %s", (group >> 11) & 0x1f,
(group >> 8) & 0x07, (group) & 0xff, write_only ? "WO" : "RW");
layer3 = l3;
t = tr;
groupaddr = group;
pth_sem_init (&sem);
if (group == 0)
throw Exception (L4_INIT_FAIL);
if (!write_only)
if (!layer3->registerGroupCallBack (this, group))
throw Exception (L4_INIT_FAIL);
}
void
T_Group::Get_L_Data (L_Data_PDU * l)
{
GroupComm c;
TPDU *t = TPDU::fromPacket (l->data);
if (t->getType () == T_DATA_XXX_REQ)
{
T_DATA_XXX_REQ_PDU *t1 = (T_DATA_XXX_REQ_PDU *) t;
c.data = t1->data;
c.src = l->source;
outqueue.put (c);
pth_sem_inc (&sem, 0);
}
delete t;
delete l;
}
void
T_Group::Send (const CArray & c)
{
T_DATA_XXX_REQ_PDU t;
t.data = c;
String s = t.Decode ();
TRACEPRINTF (this->t, 4, this, "Send Group %s", s ());
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = groupaddr;
l->AddrType = GroupAddress;
l->data = t.ToPacket ();
layer3->send_L_Data (l);
}
T_Group::~T_Group ()
{
TRACEPRINTF (t, 4, this, "CloseGroup");
layer3->deregisterGroupCallBack (this, groupaddr);
}
GroupComm *
T_Group::Get (pth_event_t stop)
{
pth_event_t s = pth_event (PTH_EVENT_SEM, &sem);
pth_event_concat (s, stop, NULL);
pth_wait (s);
pth_event_isolate (s);
if (pth_event_status (s) == PTH_STATUS_OCCURRED)
{
pth_sem_dec (&sem);
GroupComm *c = new GroupComm (outqueue.get ());
pth_event_free (s, PTH_FREE_THIS);
t->TracePacket (4, this, "Recv Group", c->data);
return c;
}
pth_event_free (s, PTH_FREE_THIS);
return 0;
}
T_TPDU::T_TPDU (Layer3 * l3, Trace * tr, eibaddr_t d)
{
TRACEPRINTF (tr, 4, this, "OpenTPDU %d.%d.%d", (d >> 12) & 0x0f,
(d >> 8) & 0x0f, (d) & 0xff);
layer3 = l3;
t = tr;
src = d;
pth_sem_init (&sem);
if (!layer3->
registerIndividualCallBack (this, Individual_Lock_None, 0, src))
throw Exception (L4_INIT_FAIL);
}
void
T_TPDU::Get_L_Data (L_Data_PDU * l)
{
TpduComm t;
t.data = l->data;
t.addr = l->source;
outqueue.put (t);
pth_sem_inc (&sem, 0);
delete l;
}
void
T_TPDU::Send (const TpduComm & c)
{
t->TracePacket (4, this, "Send TPDU", c.data);
L_Data_PDU *l = new L_Data_PDU;
l->source = src;
l->dest = c.addr;
l->AddrType = IndividualAddress;
l->data = c.data;
layer3->send_L_Data (l);
}
T_TPDU::~T_TPDU ()
{
TRACEPRINTF (t, 4, this, "CloseTPDU");
layer3->deregisterIndividualCallBack (this, 0, src);
}
TpduComm *
T_TPDU::Get (pth_event_t stop)
{
pth_event_t s = pth_event (PTH_EVENT_SEM, &sem);
pth_event_concat (s, stop, NULL);
pth_wait (s);
pth_event_isolate (s);
if (pth_event_status (s) == PTH_STATUS_OCCURRED)
{
pth_sem_dec (&sem);
TpduComm *c = new TpduComm (outqueue.get ());
pth_event_free (s, PTH_FREE_THIS);
t->TracePacket (4, this, "Recv TPDU", c->data);
return c;
}
pth_event_free (s, PTH_FREE_THIS);
return 0;
}
T_Individual::T_Individual (Layer3 * l3, Trace * tr, eibaddr_t d,
int write_only)
{
TRACEPRINTF (tr, 4, this, "OpenIndividual %d.%d.%d %s", (d >> 12) & 0x0f,
(d >> 8) & 0x0f, (d) & 0xff, write_only ? "WO" : "RW");
layer3 = l3;
t = tr;
dest = d;
pth_sem_init (&sem);
if (!write_only)
if (!layer3->
registerIndividualCallBack (this, Individual_Lock_None, dest))
throw Exception (L4_INIT_FAIL);
}
void
T_Individual::Get_L_Data (L_Data_PDU * l)
{
CArray c;
TPDU *t = TPDU::fromPacket (l->data);
if (t->getType () == T_DATA_XXX_REQ)
{
T_DATA_XXX_REQ_PDU *t1 = (T_DATA_XXX_REQ_PDU *) t;
c = t1->data;
outqueue.put (c);
pth_sem_inc (&sem, 0);
}
delete t;
delete l;
}
void
T_Individual::Send (const CArray & c)
{
T_DATA_XXX_REQ_PDU t;
t.data = c;
String s = t.Decode ();
TRACEPRINTF (this->t, 4, this, "Send Individual %s", s ());
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = dest;
l->AddrType = IndividualAddress;
l->data = t.ToPacket ();
layer3->send_L_Data (l);
}
T_Individual::~T_Individual ()
{
TRACEPRINTF (t, 4, this, "CloseIndividual");
layer3->deregisterIndividualCallBack (this, dest);
}
CArray *
T_Individual::Get (pth_event_t stop)
{
pth_event_t s = pth_event (PTH_EVENT_SEM, &sem);
pth_event_concat (s, stop, NULL);
pth_wait (s);
pth_event_isolate (s);
if (pth_event_status (s) == PTH_STATUS_OCCURRED)
{
pth_sem_dec (&sem);
CArray *c = new CArray (outqueue.get ());
pth_event_free (s, PTH_FREE_THIS);
t->TracePacket (4, this, "Recv Individual", *c);
return c;
}
pth_event_free (s, PTH_FREE_THIS);
return 0;
}
T_Connection::T_Connection (Layer3 * l3, Trace * tr, eibaddr_t d)
{
TRACEPRINTF (tr, 4, this, "OpenConnection %d.%d.%d", (d >> 12) & 0x0f,
(d >> 8) & 0x0f, (d) & 0xff);
layer3 = l3;
t = tr;
dest = d;
pth_sem_init (&insem);
pth_sem_init (&outsem);
pth_sem_init (&bufsem);
recvno = 0;
sendno = 0;
mode = 0;
if (!layer3->
registerIndividualCallBack (this, Individual_Lock_Connection, dest))
throw Exception (L4_INIT_FAIL);
Start ();
}
T_Connection::~T_Connection ()
{
TRACEPRINTF (t, 4, this, "CloseConnection");
Stop ();
while (!buf.isempty ())
delete buf.get ();
layer3->deregisterIndividualCallBack (this, dest);
}
void
T_Connection::Get_L_Data (L_Data_PDU * l)
{
buf.put (l);
pth_sem_inc (&bufsem, 0);
}
void
T_Connection::Send (const CArray & c)
{
t->TracePacket (4, this, "Send", c);
in.put (c);
pth_sem_inc (&insem, 1);
}
CArray *
T_Connection::Get (pth_event_t stop)
{
pth_event_t s = pth_event (PTH_EVENT_SEM, &outsem);
pth_event_concat (s, stop, NULL);
pth_wait (s);
pth_event_isolate (s);
if (pth_event_status (s) == PTH_STATUS_OCCURRED)
{
pth_sem_dec (&outsem);
CArray *c = new CArray (out.get ());
pth_event_free (s, PTH_FREE_THIS);
t->TracePacket (4, this, "RecvConnection", *c);
return c;
}
pth_event_free (s, PTH_FREE_THIS);
return 0;
}
void
T_Connection::SendConnect ()
{
TRACEPRINTF (t, 4, this, "SendConnect");
T_CONNECT_REQ_PDU p;
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = dest;
l->AddrType = IndividualAddress;
l->data = p.ToPacket ();
l->prio = PRIO_SYSTEM;
layer3->send_L_Data (l);
}
void
T_Connection::SendDisconnect ()
{
TRACEPRINTF (t, 4, this, "SendDisconnect");
T_DISCONNECT_REQ_PDU p;
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = dest;
l->AddrType = IndividualAddress;
l->data = p.ToPacket ();
l->prio = PRIO_SYSTEM;
layer3->send_L_Data (l);
}
void
T_Connection::SendAck (int serno)
{
TRACEPRINTF (t, 4, this, "SendACK %d", serno);
T_ACK_PDU p;
p.serno = serno;
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = dest;
l->AddrType = IndividualAddress;
l->data = p.ToPacket ();
layer3->send_L_Data (l);
}
void
T_Connection::SendData (int serno, const CArray & c)
{
T_DATA_CONNECTED_REQ_PDU p;
p.data = c;
p.serno = serno;
TRACEPRINTF (t, 4, this, "SendData %s", p.Decode ()());
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = dest;
l->AddrType = IndividualAddress;
l->data = p.ToPacket ();
layer3->send_L_Data (l);
}
/*
* States:
* 0 CLOSED
* 1 IDLE
* 2 ACK_WAIT
*
*/
void
T_Connection::Run (pth_sem_t * stop1)
{
pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
pth_event_t inev = pth_event (PTH_EVENT_SEM, &insem);
pth_event_t bufev = pth_event (PTH_EVENT_SEM, &bufsem);
while (!buf.isempty ())
delete buf.get ();
pth_sem_set_value (&bufsem, 0);
mode = 0;
SendConnect ();
mode = 1;
sendno = 0;
recvno = 0;
repcount = 0;
pth_event_t timeout = pth_event (PTH_EVENT_TIME, pth_timeout (6, 0));
while (pth_event_status (stop) != PTH_STATUS_OCCURRED && mode != 0)
{
pth_event_concat (bufev, stop, timeout, NULL);
if (mode == 1)
pth_event_concat (bufev, inev, NULL);
pth_wait (bufev);
pth_event_isolate (bufev);
pth_event_isolate (inev);
pth_event_isolate (timeout);
if (pth_event_status (bufev) == PTH_STATUS_OCCURRED)
{
pth_sem_dec (&bufsem);
L_Data_PDU *l = buf.get ();
TPDU *t = TPDU::fromPacket (l->data);
switch (t->getType ())
{
case T_DISCONNECT_REQ:
mode = 0;
break;
case T_CONNECT_REQ:
mode = 0;
break;
case T_DATA_CONNECTED_REQ:
{
T_DATA_CONNECTED_REQ_PDU *t1 = (T_DATA_CONNECTED_REQ_PDU *) t;
if (t1->serno != recvno && t1->serno != ((recvno - 1) & 0x0f))
mode = 0;
else if (t1->serno == recvno)
{
t1->data[0] = t1->data[0] & 0x03;
out.put (t1->data);
pth_sem_inc (&outsem, 0);
SendAck (recvno);
recvno = (recvno + 1) & 0x0f;
}
else if (t1->serno == ((recvno - 1) & 0x0f))
SendAck (t1->serno);
if (mode == 1)
timeout =
pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
pth_timeout (6, 0));
}
break;
case T_NACK:
{
T_NACK_PDU *t1 = (T_NACK_PDU *) t;
if (t1->serno != sendno)
mode = 0;
else if (in.isempty ())
mode = 0;
else if (repcount >= 3 || mode != 2)
mode = 0;
else
{
repcount++;
SendData (sendno, in.top ());
timeout =
pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
pth_timeout (3, 0));
}
}
break;
case T_ACK:
{
T_ACK_PDU *t1 = (T_ACK_PDU *) t;
if (t1->serno != sendno)
mode = 0;
else if (mode != 2)
mode = 0;
else
{
timeout =
pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
pth_timeout (6, 0));
mode = 1;
in.get ();
sendno = (sendno + 1) & 0x0f;
}
}
break;
default:
/* ignore */ ;
}
delete t;
delete l;
}
else if (pth_event_status (inev) == PTH_STATUS_OCCURRED && mode == 1)
{
repcount = 0;
pth_sem_dec (&insem);
SendData (sendno, in.top ());
mode = 2;
timeout =
pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
pth_timeout (3, 0));
}
else if (pth_event_status (timeout) == PTH_STATUS_OCCURRED)
{
if (mode == 2 && repcount < 3)
{
repcount++;
SendData (sendno, in.top ());
timeout =
pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
pth_timeout (3, 0));
}
else
mode = 0;
}
}
pth_event_free (stop, PTH_FREE_THIS);
pth_event_free (inev, PTH_FREE_THIS);
pth_event_free (bufev, PTH_FREE_THIS);
pth_event_free (timeout, PTH_FREE_THIS);
SendDisconnect ();
mode = 0;
layer3->deregisterIndividualCallBack (this, dest);
out.put (CArray ());
pth_sem_inc (&outsem, 0);
}
GroupSocket::GroupSocket (Layer3 * l3, Trace * tr, int write_only)
{
TRACEPRINTF (tr, 4, this, "OpenGroupSocket %s", write_only ? "WO" : "RW");
layer3 = l3;
t = tr;
pth_sem_init (&sem);
if (!write_only)
if (!layer3->registerGroupCallBack (this, 0))
throw Exception (L4_INIT_FAIL);
}
GroupSocket::~GroupSocket ()
{
TRACEPRINTF (t, 4, this, "CloseGroupSocket");
layer3->deregisterGroupCallBack (this, 0);
}
void
GroupSocket::Get_L_Data (L_Data_PDU * l)
{
GroupAPDU c;
TPDU *t = TPDU::fromPacket (l->data);
if (t->getType () == T_DATA_XXX_REQ)
{
T_DATA_XXX_REQ_PDU *t1 = (T_DATA_XXX_REQ_PDU *) t;
c.data = t1->data;
c.src = l->source;
c.dst = l->dest;
outqueue.put (c);
pth_sem_inc (&sem, 0);
}
delete t;
delete l;
}
void
GroupSocket::Send (const GroupAPDU & c)
{
T_DATA_XXX_REQ_PDU t;
t.data = c.data;
String s = t.Decode ();
TRACEPRINTF (this->t, 4, this, "Send GroupSocket %s", s ());
L_Data_PDU *l = new L_Data_PDU;
l->source = 0;
l->dest = c.dst;
l->AddrType = GroupAddress;
l->data = t.ToPacket ();
layer3->send_L_Data (l);
}
GroupAPDU *
GroupSocket::Get (pth_event_t stop)
{
pth_event_t s = pth_event (PTH_EVENT_SEM, &sem);
pth_event_concat (s, stop, NULL);
pth_wait (s);
pth_event_isolate (s);
if (pth_event_status (s) == PTH_STATUS_OCCURRED)
{
pth_sem_dec (&sem);
GroupAPDU *c = new GroupAPDU (outqueue.get ());
pth_event_free (s, PTH_FREE_THIS);
t->TracePacket (4, this, "Recv GroupSocket", c->data);
return c;
}
pth_event_free (s, PTH_FREE_THIS);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1