2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2009 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
,
54 const char *srcip
, int Dataport
, Trace
* tr
)
57 TRACEPRINTF (t
, 2, this, "Open");
58 pth_sem_init (&insignal
);
59 pth_sem_init (&outsignal
);
60 getwait
= pth_event (PTH_EVENT_SEM
, &outsignal
);
62 if (!GetHostIP (&caddr
, dest
))
64 caddr
.sin_port
= htons (port
);
65 if (!GetSourceAddress (&caddr
, &raddr
))
67 raddr
.sin_port
= htons (sport
);
70 sock
= new EIBNetIPSocket (raddr
, 0, t
);
79 if (!GetHostIP (&saddr
, srcip
))
85 saddr
.sin_port
= htons (sport
);
90 sock
->sendaddr
= caddr
;
91 sock
->recvaddr
= caddr
;
95 TRACEPRINTF (t
, 2, this, "Opened");
98 EIBNetIPTunnel::~EIBNetIPTunnel ()
100 TRACEPRINTF (t
, 2, this, "Close");
102 while (!outqueue
.isempty ())
103 delete outqueue
.get ();
104 pth_event_free (getwait
, PTH_FREE_THIS
);
109 bool EIBNetIPTunnel::init ()
115 EIBNetIPTunnel::Send_L_Data (LPDU
* l
)
117 TRACEPRINTF (t
, 2, this, "Send %s", l
->Decode ()());
118 if (l
->getType () != L_Data
)
123 L_Data_PDU
*l1
= (L_Data_PDU
*) l
;
124 inqueue
.put (L_Data_ToCEMI (0x11, *l1
));
125 pth_sem_inc (&insignal
, 1);
128 L_Busmonitor_PDU
*l2
= new L_Busmonitor_PDU
;
129 l2
->pdu
.set (l
->ToPacket ());
131 pth_sem_inc (&outsignal
, 1);
134 pth_sem_inc (&outsignal
, 1);
138 EIBNetIPTunnel::Get_L_Data (pth_event_t stop
)
141 pth_event_concat (getwait
, stop
, NULL
);
146 pth_event_isolate (getwait
);
148 if (pth_event_status (getwait
) == PTH_STATUS_OCCURRED
)
150 pth_sem_dec (&outsignal
);
151 LPDU
*c
= outqueue
.get ();
153 TRACEPRINTF (t
, 2, this, "Recv %s", c
->Decode ()());
161 EIBNetIPTunnel::Send_Queue_Empty ()
163 return inqueue
.isempty ();
167 EIBNetIPTunnel::openVBusmonitor ()
174 EIBNetIPTunnel::closeVBusmonitor ()
181 EIBNetIPTunnel::enterBusmonitor ()
188 EIBNetIPTunnel::leaveBusmonitor ()
195 EIBNetIPTunnel::Open ()
201 EIBNetIPTunnel::Close ()
207 EIBNetIPTunnel::Connection_Lost ()
213 EIBNetIPTunnel::Run (pth_sem_t
* stop1
)
223 pth_event_t stop
= pth_event (PTH_EVENT_SEM
, stop1
);
224 pth_event_t input
= pth_event (PTH_EVENT_SEM
, &insignal
);
225 pth_event_t timeout
= pth_event (PTH_EVENT_TIME
, pth_timeout (0, 0));
226 pth_event_t timeout1
= pth_event (PTH_EVENT_TIME
, pth_timeout (10, 0));
231 EIBnet_ConnectRequest creq
;
232 EIBnet_ConnectResponse cresp
;
233 EIBnet_ConnectionStateRequest csreq
;
234 EIBnet_ConnectionStateResponse csresp
;
235 EIBnet_TunnelRequest treq
;
236 EIBnet_TunnelACK tresp
;
237 EIBnet_DisconnectRequest dreq
;
238 EIBnet_DisconnectResponse dresp
;
245 p
= creq
.ToPacket ();
246 sock
->sendaddr
= caddr
;
249 while (pth_event_status (stop
) != PTH_STATUS_OCCURRED
)
252 pth_event_concat (stop
, input
, NULL
);
254 pth_event_concat (stop
, timeout
, NULL
);
256 pth_event_concat (stop
, timeout1
, NULL
);
258 p1
= sock
->Get (stop
);
259 pth_event_isolate (stop
);
260 pth_event_isolate (timeout
);
261 pth_event_isolate (timeout1
);
266 case CONNECTION_RESPONSE
:
269 if (parseEIBnet_ConnectResponse (*p1
, cresp
))
271 TRACEPRINTF (t
, 1, this, "Recv wrong connection response");
274 if (cresp
.status
!= 0)
276 TRACEPRINTF (t
, 1, this, "Connect failed with error %02X",
280 if (cresp
.CRD () != 3)
282 TRACEPRINTF (t
, 1, this, "Recv wrong connection response");
285 myaddr
= (cresp
.CRD
[1] << 8) | cresp
.CRD
[2];
288 daddr
.sin_addr
= caddr
.sin_addr
;
290 daddr
.sin_port
= htons (dataport
);
291 channel
= cresp
.channel
;
295 sock
->recvaddr
= daddr
;
296 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout1
,
297 pth_timeout (30, 0));
304 TRACEPRINTF (t
, 1, this, "Not connected");
307 if (parseEIBnet_TunnelRequest (*p1
, treq
))
309 TRACEPRINTF (t
, 1, this, "Invalid request");
312 if (treq
.channel
!= channel
)
314 TRACEPRINTF (t
, 1, this, "Not for us");
317 if (((treq
.seqno
+ 1) & 0xff) == rno
)
320 tresp
.channel
= channel
;
321 tresp
.seqno
= treq
.seqno
;
322 p
= tresp
.ToPacket ();
323 sock
->sendaddr
= daddr
;
327 if (treq
.seqno
!= rno
)
329 TRACEPRINTF (t
, 1, this, "Wrong sequence %d<->%d",
331 if (treq
.seqno
< rno
)
333 if (treq
.seqno
>= rno
+ 5)
336 dreq
.channel
= channel
;
337 p
= dreq
.ToPacket ();
338 sock
->sendaddr
= caddr
;
348 tresp
.channel
= channel
;
349 tresp
.seqno
= treq
.seqno
;
350 p
= tresp
.ToPacket ();
351 sock
->sendaddr
= daddr
;
354 if (treq
.CEMI
[0] == 0x2E)
356 if (treq
.CEMI
[0] != 0x29)
358 TRACEPRINTF (t
, 1, this, "Unexpected CEMI Type %02X",
362 c
= CEMI_to_L_Data (treq
.CEMI
);
366 TRACEPRINTF (t
, 1, this, "Recv %s", c
->Decode ()());
371 L_Busmonitor_PDU
*l2
= new L_Busmonitor_PDU
;
372 l2
->pdu
.set (c
->ToPacket ());
374 pth_sem_inc (&outsignal
, 1);
376 if (c
->AddrType
== IndividualAddress
377 && c
->dest
== myaddr
)
380 pth_sem_inc (&outsignal
, 1);
383 L_Busmonitor_PDU
*p1
= new L_Busmonitor_PDU
;
384 p1
->pdu
= c
->ToPacket ();
387 pth_sem_inc (&outsignal
, 1);
390 TRACEPRINTF (t
, 1, this, "Unknown CEMI");
392 case TUNNEL_RESPONSE
:
395 TRACEPRINTF (t
, 1, this, "Not connected");
398 if (parseEIBnet_TunnelACK (*p1
, tresp
))
400 TRACEPRINTF (t
, 1, this, "Invalid response");
403 if (tresp
.channel
!= channel
)
405 TRACEPRINTF (t
, 1, this, "Not for us");
408 if (tresp
.seqno
!= sno
)
410 TRACEPRINTF (t
, 1, this, "Wrong sequence %d<->%d",
416 TRACEPRINTF (t
, 1, this, "Error in ACK %d", tresp
.status
);
424 pth_sem_dec (&insignal
);
431 TRACEPRINTF (t
, 1, this, "Unexpected ACK");
433 case CONNECTIONSTATE_RESPONSE
:
434 if (parseEIBnet_ConnectionStateResponse (*p1
, csresp
))
436 TRACEPRINTF (t
, 1, this, "Invalid response");
439 if (csresp
.channel
!= channel
)
441 TRACEPRINTF (t
, 1, this, "Not for us");
444 if (csresp
.status
== 0)
449 TRACEPRINTF (t
, 1, this,
450 "Duplicate Connection State Response");
452 else if (csresp
.status
== 0x21)
454 TRACEPRINTF (t
, 1, this,
455 "Connection State Response not connected");
457 dreq
.channel
= channel
;
458 p
= dreq
.ToPacket ();
459 sock
->sendaddr
= caddr
;
464 TRACEPRINTF (t
, 1, this,
465 "Connection State Response Error %02x",
468 case DISCONNECT_REQUEST
:
471 TRACEPRINTF (t
, 1, this, "Not connected");
474 if (parseEIBnet_DisconnectRequest (*p1
, dreq
))
476 TRACEPRINTF (t
, 1, this, "Invalid request");
479 if (dreq
.channel
!= channel
)
481 TRACEPRINTF (t
, 1, this, "Not for us");
484 dresp
.channel
= channel
;
486 p
= treq
.ToPacket ();
487 t
->TracePacket (1, this, "SendDis", p
.data
);
488 sock
->sendaddr
= caddr
;
492 case DISCONNECT_RESPONSE
:
495 TRACEPRINTF (t
, 1, this, "Not connected");
498 if (parseEIBnet_DisconnectResponse (*p1
, dresp
))
500 TRACEPRINTF (t
, 1, this, "Invalid request");
503 if (dresp
.channel
!= channel
)
505 TRACEPRINTF (t
, 1, this, "Not for us");
509 TRACEPRINTF (t
, 1, this, "Disconnected");
513 TRACEPRINTF (t
, 1, this, "Recv unexpected service %04X",
518 if (mod
== 2 && pth_event_status (timeout
) == PTH_STATUS_OCCURRED
)
524 TRACEPRINTF (t
, 1, this, "Drop");
525 pth_sem_dec (&insignal
);
532 dreq
.channel
= channel
;
533 p
= dreq
.ToPacket ();
534 sock
->sendaddr
= caddr
;
540 if (mod
!= 0 && pth_event_status (timeout1
) == PTH_STATUS_OCCURRED
)
542 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout1
,
543 pth_timeout (30, 0));
547 csreq
.channel
= channel
;
548 p
= csreq
.ToPacket ();
549 TRACEPRINTF (t
, 1, this, "Heartbeat");
550 sock
->sendaddr
= caddr
;
556 TRACEPRINTF (t
, 1, this, "Disconnection because of errors");
558 dreq
.channel
= channel
;
559 p
= dreq
.ToPacket ();
560 sock
->sendaddr
= caddr
;
566 if (mod
== 0 && pth_event_status (timeout1
) == PTH_STATUS_OCCURRED
)
568 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout1
,
569 pth_timeout (10, 0));
570 p
= creq
.ToPacket ();
571 TRACEPRINTF (t
, 1, this, "Connectretry");
572 sock
->sendaddr
= caddr
;
576 if (!inqueue
.isempty () && mod
== 1)
578 treq
.channel
= channel
;
580 treq
.CEMI
= inqueue
.top ();
581 p
= treq
.ToPacket ();
582 t
->TracePacket (1, this, "SendTunnel", p
.data
);
583 sock
->sendaddr
= daddr
;
586 pth_event (PTH_EVENT_TIME
| PTH_MODE_REUSE
, timeout
,
592 dreq
.channel
= channel
;
593 p
= dreq
.ToPacket ();
594 sock
->sendaddr
= caddr
;
598 pth_event_free (stop
, PTH_FREE_THIS
);
599 pth_event_free (input
, PTH_FREE_THIS
);
600 pth_event_free (timeout
, PTH_FREE_THIS
);
601 pth_event_free (timeout1
, PTH_FREE_THIS
);