2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2008 Martin Koegler <mkoegler@auto.tuwien.ac.at>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "eibnettunnel.h"
24 EIBNetIPTunnel::addAddress (eibaddr_t addr
)
30 EIBNetIPTunnel::removeAddress (eibaddr_t addr
)
36 EIBNetIPTunnel::addGroupAddress (eibaddr_t addr
)
42 EIBNetIPTunnel::removeGroupAddress (eibaddr_t addr
)
48 EIBNetIPTunnel::getDefaultAddr ()
53 EIBNetIPTunnel::EIBNetIPTunnel (const char *dest
, int port
, int sport
,
57 TRACEPRINTF (t
, 2, this, "Open");
58 pth_sem_init (&insignal
);
59 pth_sem_init (&outsignal
);
60 getwait
= pth_event (PTH_EVENT_SEM
, &outsignal
);
61 if (!GetHostIP (&caddr
, dest
))
62 throw Exception (DEV_OPEN_FAIL
);
63 caddr
.sin_port
= htons (port
);
64 if (!GetSourceAddress (&caddr
, &saddr
))
65 throw Exception (DEV_OPEN_FAIL
);
66 saddr
.sin_port
= htons (sport
);
67 sock
= new EIBNetIPSocket (saddr
, 0, t
);
72 throw Exception (DEV_OPEN_FAIL
);
74 sock
->sendaddr
= caddr
;
75 sock
->recvaddr
= caddr
;
79 TRACEPRINTF (t
, 2, this, "Opened");
82 EIBNetIPTunnel::~EIBNetIPTunnel ()
84 TRACEPRINTF (t
, 2, this, "Close");
86 while (!outqueue
.isempty ())
87 delete outqueue
.get ();
88 pth_event_free (getwait
, PTH_FREE_THIS
);
94 EIBNetIPTunnel::Send_L_Data (LPDU
* l
)
96 TRACEPRINTF (t
, 2, this, "Send %s", l
->Decode ()());
97 if (l
->getType () != L_Data
)
102 L_Data_PDU
*l1
= (L_Data_PDU
*) l
;
103 inqueue
.put (L_Data_ToCEMI (0x11, *l1
));
104 pth_sem_inc (&insignal
, 1);
107 L_Busmonitor_PDU
*l2
= new L_Busmonitor_PDU
;
108 l2
->pdu
.set (l
->ToPacket ());
110 pth_sem_inc (&outsignal
, 1);
113 pth_sem_inc (&outsignal
, 1);
117 EIBNetIPTunnel::Get_L_Data (pth_event_t stop
)
120 pth_event_concat (getwait
, stop
, NULL
);
125 pth_event_isolate (getwait
);
127 if (pth_event_status (getwait
) == PTH_STATUS_OCCURRED
)
129 pth_sem_dec (&outsignal
);
130 LPDU
*c
= outqueue
.get ();
132 TRACEPRINTF (t
, 2, this, "Recv %s", c
->Decode ()());
140 EIBNetIPTunnel::Send_Queue_Empty ()
142 return inqueue
.isempty ();
146 EIBNetIPTunnel::openVBusmonitor ()
153 EIBNetIPTunnel::closeVBusmonitor ()
160 EIBNetIPTunnel::enterBusmonitor ()
167 EIBNetIPTunnel::leaveBusmonitor ()
174 EIBNetIPTunnel::Open ()
180 EIBNetIPTunnel::Close ()
186 EIBNetIPTunnel::Connection_Lost ()
192 EIBNetIPTunnel::Run (pth_sem_t
* stop1
)
202 pth_event_t stop
= pth_event (PTH_EVENT_SEM
, stop1
);
203 pth_event_t input
= pth_event (PTH_EVENT_SEM
, &insignal
);
204 pth_event_t timeout
= pth_event (PTH_EVENT_TIME
, pth_timeout (0, 0));
205 pth_event_t timeout1
= pth_event (PTH_EVENT_TIME
, pth_timeout (10, 0));
210 EIBnet_ConnectRequest creq
;
211 EIBnet_ConnectResponse cresp
;
212 EIBnet_ConnectionStateRequest csreq
;
213 EIBnet_ConnectionStateResponse csresp
;
214 EIBnet_TunnelRequest treq
;
215 EIBnet_TunnelACK tresp
;
216 EIBnet_DisconnectRequest dreq
;
217 EIBnet_DisconnectResponse dresp
;
224 p
= creq
.ToPacket ();
225 sock
->sendaddr
= caddr
;
228 while (pth_event_status (stop
) != PTH_STATUS_OCCURRED
)
231 pth_event_concat (stop
, input
, NULL
);
233 pth_event_concat (stop
, timeout
, NULL
);
235 pth_event_concat (stop
, timeout1
, NULL
);
237 p1
= sock
->Get (stop
);
238 pth_event_isolate (stop
);
239 pth_event_isolate (timeout
);
240 pth_event_isolate (timeout1
);
245 case CONNECTION_RESPONSE
:
248 if (parseEIBnet_ConnectResponse (*p1
, cresp
))
250 TRACEPRINTF (t
, 1, this, "Recv wrong connection response");
253 if (cresp
.status
!= 0)
255 TRACEPRINTF (t
, 1, this, "Connect failed with error %02X",
259 if (cresp
.CRD () != 3)
261 TRACEPRINTF (t
, 1, this, "Recv wrong connection response");
264 myaddr
= (cresp
.CRD
[1] << 8) | cresp
.CRD
[2];
266 channel
= cresp
.channel
;
270 sock
->recvaddr
= daddr
;
271 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout1
,
272 pth_timeout (30, 0));
279 TRACEPRINTF (t
, 1, this, "Not connected");
282 if (parseEIBnet_TunnelRequest (*p1
, treq
))
284 TRACEPRINTF (t
, 1, this, "Invalid request");
287 if (treq
.channel
!= channel
)
289 TRACEPRINTF (t
, 1, this, "Not for us");
292 if (((treq
.seqno
+ 1) & 0xff) == rno
)
295 tresp
.channel
= channel
;
296 tresp
.seqno
= treq
.seqno
;
297 p
= tresp
.ToPacket ();
298 sock
->sendaddr
= daddr
;
302 if (treq
.seqno
!= rno
)
304 TRACEPRINTF (t
, 1, this, "Wrong sequence %d<->%d",
306 if (treq
.seqno
< rno
)
308 if (treq
.seqno
>= rno
+ 5)
311 dreq
.channel
= channel
;
312 p
= dreq
.ToPacket ();
313 sock
->sendaddr
= caddr
;
323 tresp
.channel
= channel
;
324 tresp
.seqno
= treq
.seqno
;
325 p
= tresp
.ToPacket ();
326 sock
->sendaddr
= daddr
;
329 if (treq
.CEMI
[0] == 0x2E)
331 if (treq
.CEMI
[0] != 0x29)
333 TRACEPRINTF (t
, 1, this, "Unexpected CEMI Type %02X",
337 c
= CEMI_to_L_Data (treq
.CEMI
);
341 TRACEPRINTF (t
, 1, this, "Recv %s", c
->Decode ()());
346 L_Busmonitor_PDU
*l2
= new L_Busmonitor_PDU
;
347 l2
->pdu
.set (c
->ToPacket ());
349 pth_sem_inc (&outsignal
, 1);
351 if (c
->AddrType
== IndividualAddress
352 && c
->dest
== myaddr
)
355 pth_sem_inc (&outsignal
, 1);
358 L_Busmonitor_PDU
*p1
= new L_Busmonitor_PDU
;
359 p1
->pdu
= c
->ToPacket ();
362 pth_sem_inc (&outsignal
, 1);
365 TRACEPRINTF (t
, 1, this, "Unknown CEMI");
367 case TUNNEL_RESPONSE
:
370 TRACEPRINTF (t
, 1, this, "Not connected");
373 if (parseEIBnet_TunnelACK (*p1
, tresp
))
375 TRACEPRINTF (t
, 1, this, "Invalid response");
378 if (tresp
.channel
!= channel
)
380 TRACEPRINTF (t
, 1, this, "Not for us");
383 if (tresp
.seqno
!= sno
)
385 TRACEPRINTF (t
, 1, this, "Wrong sequence %d<->%d",
391 TRACEPRINTF (t
, 1, this, "Error in ACK %d", tresp
.status
);
399 pth_sem_dec (&insignal
);
406 TRACEPRINTF (t
, 1, this, "Unexpected ACK");
408 case CONNECTIONSTATE_RESPONSE
:
409 if (parseEIBnet_ConnectionStateResponse (*p1
, csresp
))
411 TRACEPRINTF (t
, 1, this, "Invalid response");
414 if (csresp
.channel
!= channel
)
416 TRACEPRINTF (t
, 1, this, "Not for us");
419 if (csresp
.status
== 0)
424 TRACEPRINTF (t
, 1, this,
425 "Duplicate Connection State Response");
427 else if (csresp
.status
== 0x21)
429 TRACEPRINTF (t
, 1, this,
430 "Connection State Response not connected");
432 dreq
.channel
= channel
;
433 p
= dreq
.ToPacket ();
434 sock
->sendaddr
= caddr
;
439 TRACEPRINTF (t
, 1, this,
440 "Connection State Response Error %02x",
443 case DISCONNECT_REQUEST
:
446 TRACEPRINTF (t
, 1, this, "Not connected");
449 if (parseEIBnet_DisconnectRequest (*p1
, dreq
))
451 TRACEPRINTF (t
, 1, this, "Invalid request");
454 if (dreq
.channel
!= channel
)
456 TRACEPRINTF (t
, 1, this, "Not for us");
459 dresp
.channel
= channel
;
461 p
= treq
.ToPacket ();
462 t
->TracePacket (1, this, "SendDis", p
.data
);
463 sock
->sendaddr
= caddr
;
467 case DISCONNECT_RESPONSE
:
470 TRACEPRINTF (t
, 1, this, "Not connected");
473 if (parseEIBnet_DisconnectResponse (*p1
, dresp
))
475 TRACEPRINTF (t
, 1, this, "Invalid request");
478 if (dresp
.channel
!= channel
)
480 TRACEPRINTF (t
, 1, this, "Not for us");
484 TRACEPRINTF (t
, 1, this, "Disconnected");
488 TRACEPRINTF (t
, 1, this, "Recv unexpected service %04X",
493 if (mod
== 2 && pth_event_status (timeout
) == PTH_STATUS_OCCURRED
)
499 TRACEPRINTF (t
, 1, this, "Drop");
500 pth_sem_dec (&insignal
);
507 dreq
.channel
= channel
;
508 p
= dreq
.ToPacket ();
509 sock
->sendaddr
= caddr
;
515 if (mod
!= 0 && pth_event_status (timeout1
) == PTH_STATUS_OCCURRED
)
517 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout1
,
518 pth_timeout (30, 0));
522 csreq
.channel
= channel
;
523 p
= csreq
.ToPacket ();
524 TRACEPRINTF (t
, 1, this, "Heartbeat");
525 sock
->sendaddr
= caddr
;
531 TRACEPRINTF (t
, 1, this, "Disconnection because of errors");
533 dreq
.channel
= channel
;
534 p
= dreq
.ToPacket ();
535 sock
->sendaddr
= caddr
;
541 if (mod
== 0 && pth_event_status (timeout1
) == PTH_STATUS_OCCURRED
)
543 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout1
,
544 pth_timeout (10, 0));
545 p
= creq
.ToPacket ();
546 TRACEPRINTF (t
, 1, this, "Connectretry");
547 sock
->sendaddr
= caddr
;
551 if (!inqueue
.isempty () && mod
== 1)
553 treq
.channel
= channel
;
555 treq
.CEMI
= inqueue
.top ();
556 p
= treq
.ToPacket ();
557 t
->TracePacket (1, this, "SendTunnel", p
.data
);
558 sock
->sendaddr
= daddr
;
561 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout
,
567 dreq
.channel
= channel
;
568 p
= dreq
.ToPacket ();
569 sock
->sendaddr
= caddr
;
573 pth_event_free (stop
, PTH_FREE_THIS
);
574 pth_event_free (input
, PTH_FREE_THIS
);
575 pth_event_free (timeout
, PTH_FREE_THIS
);
576 pth_event_free (timeout1
, PTH_FREE_THIS
);