1 /*
2  * Copyright (c) 2002-2018 Balabit
3  * Copyright (c) 2018 Laszlo Budai <laszlo.budai@balabit.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * As an additional exemption you are allowed to compile & link against the
20  * OpenSSL libraries as published by the OpenSSL project. See the file
21  * COPYING for details.
22  *
23  */
24 
25 #include "transport/multitransport.h"
26 #include "transport/transport-factory-registry.h"
27 #include "messages.h"
28 
multitransport_add_factory(MultiTransport * self,TransportFactory * transport_factory)29 void multitransport_add_factory(MultiTransport *self, TransportFactory *transport_factory)
30 {
31   transport_factory_registry_add(self->registry, transport_factory);
32 }
33 
34 static void
_do_transport_switch(MultiTransport * self,LogTransport * new_transport,const TransportFactory * new_transport_factory)35 _do_transport_switch(MultiTransport *self, LogTransport *new_transport, const TransportFactory *new_transport_factory)
36 {
37   self->super.fd = log_transport_release_fd(self->active_transport);
38   self->super.cond = new_transport->cond;
39   log_transport_free(self->active_transport);
40   self->active_transport = new_transport;
41   self->active_transport_factory = new_transport_factory;
42 }
43 
44 static const TransportFactory *
_lookup_transport_factory(TransportFactoryRegistry * registry,const TransportFactoryId * factory_id)45 _lookup_transport_factory(TransportFactoryRegistry *registry, const TransportFactoryId *factory_id)
46 {
47   const TransportFactory *factory = transport_factory_registry_lookup(registry, factory_id);
48 
49   if (!factory)
50     {
51       msg_error("Requested transport not found",
52                 evt_tag_str("transport", transport_factory_id_get_transport_name(factory_id)));
53       return NULL;
54     }
55 
56   return factory;
57 }
58 
59 static LogTransport *
_construct_transport(const TransportFactory * factory,gint fd)60 _construct_transport(const TransportFactory *factory, gint fd)
61 {
62   LogTransport *transport = transport_factory_construct_transport(factory, fd);
63   const TransportFactoryId *factory_id = transport_factory_get_id(factory);
64 
65   if (!transport)
66     {
67       msg_error("Failed to construct transport",
68                 evt_tag_str("transport", transport_factory_id_get_transport_name(factory_id)));
69       return NULL;
70     }
71 
72   return transport;
73 }
74 
multitransport_switch(MultiTransport * self,const TransportFactoryId * factory_id)75 gboolean multitransport_switch(MultiTransport *self, const TransportFactoryId *factory_id)
76 {
77   msg_debug("Transport switch requested",
78             evt_tag_str("active-transport", self->active_transport->name),
79             evt_tag_str("requested-transport", transport_factory_id_get_transport_name(factory_id)));
80 
81   const TransportFactory *transport_factory = _lookup_transport_factory(self->registry, factory_id);
82   if (!transport_factory)
83     return FALSE;
84 
85   LogTransport *transport = _construct_transport(transport_factory, self->super.fd);
86   if (!transport)
87     return FALSE;
88 
89   _do_transport_switch(self, transport, transport_factory);
90 
91   msg_debug("Transport switch succeeded",
92             evt_tag_str("new-active-transport", self->active_transport->name));
93 
94   return TRUE;
95 }
96 
97 gboolean
multitransport_contains_factory(MultiTransport * self,const TransportFactoryId * factory_id)98 multitransport_contains_factory(MultiTransport *self, const TransportFactoryId *factory_id)
99 {
100   const TransportFactory *factory = transport_factory_registry_lookup(self->registry, factory_id);
101 
102   return (factory != NULL);
103 }
104 
105 static gssize
_multitransport_write(LogTransport * s,gpointer buf,gsize count)106 _multitransport_write(LogTransport *s, gpointer buf, gsize count)
107 {
108   MultiTransport *self = (MultiTransport *)s;
109   gssize r = log_transport_write(self->active_transport, buf, count);
110   self->super.cond = self->active_transport->cond;
111 
112   return r;
113 }
114 
115 static gssize
_multitransport_read(LogTransport * s,gpointer buf,gsize count,LogTransportAuxData * aux)116 _multitransport_read(LogTransport *s, gpointer buf, gsize count, LogTransportAuxData *aux)
117 {
118   MultiTransport *self = (MultiTransport *)s;
119   gssize r = log_transport_read(self->active_transport, buf, count, aux);
120   self->super.cond = self->active_transport->cond;
121 
122   return r;
123 }
124 
125 static void
_multitransport_free(LogTransport * s)126 _multitransport_free(LogTransport *s)
127 {
128   MultiTransport *self = (MultiTransport *)s;
129   s->fd = log_transport_release_fd(self->active_transport);
130   log_transport_free(self->active_transport);
131   transport_factory_registry_free(self->registry);
132   log_transport_free_method(s);
133 }
134 
135 LogTransport *
multitransport_new(TransportFactory * default_transport_factory,gint fd)136 multitransport_new(TransportFactory *default_transport_factory, gint fd)
137 {
138   MultiTransport *self = g_new0(MultiTransport, 1);
139   self->registry = transport_factory_registry_new();
140   transport_factory_registry_add(self->registry, default_transport_factory);
141 
142   log_transport_init_instance(&self->super, fd);
143   self->super.read = _multitransport_read;
144   self->super.write = _multitransport_write;
145   self->super.free_fn = _multitransport_free;
146   self->active_transport = transport_factory_construct_transport(default_transport_factory, fd);
147   self->active_transport_factory = default_transport_factory;
148 
149   return &self->super;
150 }
151