1 /** @file
2 WCCP (v2) support API.
3
4 @section license License
5
6 Licensed to the Apache Software Foundation (ASF) under one
7 or more contributor license agreements. See the NOTICE file
8 distributed with this work for additional information
9 regarding copyright ownership. The ASF licenses this file
10 to you under the Apache License, Version 2.0 (the
11 "License"); you may not use this file except in compliance
12 with the License. You may obtain a copy of the License at
13
14 http://www.apache.org/licenses/LICENSE-2.0
15
16 Unless required by applicable law or agreed to in writing, software
17 distributed under the License is distributed on an "AS IS" BASIS,
18 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 See the License for the specific language governing permissions and
20 limitations under the License.
21 */
22
23 #pragma once
24
25 #include <memory.h>
26
27 #include "tscore/TsBuffer.h"
28 #include "tscore/Errata.h"
29 #include "tscore/ink_defs.h"
30 #include "tscore/ink_memory.h"
31 // Nasty, defining this with no prefix. The value is still available
32 // in TS_VERSION_STRING.
33 #undef VERSION
34
35 // INADDR_ANY
36 #include <netinet/in.h>
37
38 #include <string_view>
39
40 /// WCCP Support.
41 namespace wccp
42 {
43 /// Forward declare implementation classes.
44 class Impl;
45 class CacheImpl;
46 class RouterImpl;
47
48 /// Namespace for implementation details.
49 namespace detail
50 {
51 /// Cache implementation details.
52 namespace cache
53 {
54 struct GroupData;
55 }
56 namespace router
57 {
58 struct GroupData;
59 }
60 } // namespace detail
61
62 /// Basic time unit for WCCP in seconds
63 /// @note Sec 4.14: HERE_I_AM_T.
64 static time_t const TIME_UNIT = 10;
65 static time_t const ASSIGN_WAIT = (3 * TIME_UNIT) / 2;
66 static time_t const RAPID_TIME = TIME_UNIT / 10;
67
68 /// Service group related constants.
69 /// @internal In a struct so enum values can be imported to more than
70 /// one class.
71 struct ServiceConstants {
72 /// Methods for forwarding intercepted packets to cache.
73 /// @internal Enumerations values match protocol values.
74 enum PacketStyle {
75 NO_PACKET_STYLE = 0, ///< Undefined or invalid.
76 GRE = 1, ///< GRE tunnel only. [default]
77 L2 = 2, ///< L2 rewrite only.
78 GRE_OR_L2 = 3 ///< L2 rewrite or GRE tunnel.
79 };
80
81 /// Cache assignment supported methods.
82 /// @internal Enumerations values match protocol values.
83 enum CacheAssignmentStyle {
84 NO_CACHE_ASSIGN_STYLE = 0, ///< Undefined or invalid.
85 HASH_ONLY = 1, ///< Use only hash assignment. [default]
86 MASK_ONLY = 2, ///< Use only mask assignment.
87 HASH_OR_MASK = 3 ///< Use hash or mask assignment.
88 };
89 };
90
91 /** Service group definition.
92
93 Also used as serialized layout internally by ServiceGroupElt. This is kept
94 in serialized form because it is copied to and from message data far more
95 often then it is accessed directly.
96 */
97 class ServiceGroup : public ServiceConstants
98 {
99 public:
100 typedef ServiceGroup self; ///< Self reference type.
101
102 /// Type of service.
103 enum Type : uint8_t {
104 STANDARD = 0, ///< Well known service.
105 DYNAMIC = 1 ///< Dynamic (locally defined) service.
106 };
107
108 /// Result codes for service definition.
109 enum Result {
110 DEFINED = 0, ///< Service group was created by the call.
111 EXISTS = 1, ///< Service group already existed.
112 CONFLICT = 2 ///< Service group existed but didn't match new definition.
113 };
114
115 /// @name Well known (standard) services.
116 //@{
117 /// HTTP
118 static uint8_t const HTTP = 0;
119 //@}
120 /// Service IDs of this value or less are reserved.
121 static uint8_t const RESERVED = 50;
122
123 /// Number of ports in component (defined by protocol).
124 static size_t const N_PORTS = 8;
125
126 /// @name Flag mask values.
127 //@{
128 /// Source IP address hash
129 static uint32_t const SRC_IP_HASH = 1 << 0;
130 /// Destination IP address hash
131 static uint32_t const DST_IP_HASH = 1 << 1;
132 /// Source port hash.
133 static uint32_t const SRC_PORT_HASH = 1 << 2;
134 /// Destination port hash
135 static uint32_t const DST_PORT_HASH = 1 << 3;
136 /// @a m_ports has port information.
137 static uint32_t const PORTS_DEFINED = 1 << 4;
138 /// @a m_ports has source ports (otherwise destination ports).
139 static uint32_t const PORTS_SOURCE = 1 << 5;
140 /// Alternate source IP address hash
141 static uint32_t const SRC_IP_ALT_HASH = 1 << 8;
142 /// Alternate destination IP address hash
143 static uint32_t const DST_IP_ALT_HASH = 1 << 9;
144 /// Alternate source port hash
145 static uint32_t const SRC_PORT_ALT_HASH = 1 << 10;
146 /// Alternate destination port hash
147 static uint32_t const DST_PORT_ALT_HASH = 1 << 11;
148 /// All hash related flags.
149 static uint32_t const HASH_FLAGS = SRC_IP_HASH | DST_IP_HASH | SRC_PORT_HASH | DST_PORT_HASH | SRC_IP_ALT_HASH | DST_IP_ALT_HASH |
150 SRC_PORT_ALT_HASH | DST_PORT_ALT_HASH;
151 //@}
152
153 /// Default constructor - no member initialization.
154 ServiceGroup();
155 /// Test for equivalent.
156 bool operator==(self const &that) const;
157 /// Test for not equivalent.
158 bool operator!=(self const &that) const;
159
160 /// @name Accessors
161 //@{
162 ServiceGroup::Type getSvcType() const; ///< Get service type field.
163 /** Set the service type.
164 If @a svc is @c SERVICE_STANDARD then all fields except the
165 component header and service id are set to zero as required
166 by the protocol.
167 */
168 self &setSvcType(ServiceGroup::Type svc);
169
170 uint8_t getSvcId() const; ///< Get service ID field.
171 self &setSvcId(uint8_t id); ///< Set service ID field to @a id.
172
173 uint8_t getPriority() const; ///< Get priority field.
174 self &setPriority(uint8_t pri); ///< Set priority field to @a p.
175
176 uint8_t getProtocol() const; ///< Get protocol field.
177 self &setProtocol(uint8_t p); ///< Set protocol field to @a p.
178
179 uint32_t getFlags() const; ///< Get flags field.
180 self &setFlags(uint32_t f); ///< Set the flags flags in field to @a f.
181 /// Set the flags in the flag field that are set in @a f.
182 /// Other flags are unchanged.
183 self &enableFlags(uint32_t f);
184 /// Clear the flags in the flag field that are set in @a f.
185 /// Other flags are unchanged.
186 self &disableFlags(uint32_t f);
187
188 /// Get a port value.
189 uint16_t getPort(int idx ///< Index of target port.
190 ) const;
191 /// Set a port value.
192 self &setPort(int idx, ///< Index of port.
193 uint16_t port ///< Value for port.
194 );
195 /// Zero (clear) all ports.
196 self &clearPorts();
197 //@}
198
199 protected:
200 Type m_svc_type; ///< @ref Type.
201 uint8_t m_svc_id; ///< ID for service type.
202 uint8_t m_priority; ///< Redirection priority ordering.
203 uint8_t m_protocol; ///< IP protocol for service.
204 uint32_t m_flags; ///< Flags.
205 uint16_t m_ports[N_PORTS]; ///< Service ports.
206 };
207
208 /// Security component option (sub-type)
209 enum SecurityOption {
210 SECURITY_NONE = 0, ///< No security @c WCCP2_NO_SECURITY
211 SECURITY_MD5 = 1 ///< MD5 security @c WCCP2_MD5_SECURITY
212 };
213
214 class EndPoint
215 {
216 public:
217 typedef EndPoint self; ///< Self reference type.
218 typedef Impl ImplType; ///< Implementation type.
219
220 /** Set the identifying IP address.
221 This is also used as the address for the socket.
222 */
223 self &setAddr(uint32_t addr ///< IP address.
224 );
225
226 /** Check if this endpoint is ready to use.
227 @return @c true if the address has been set and services
228 have been added.
229 */
230 bool isConfigured() const;
231
232 /** Open a socket for communications.
233
234 If @a addr is @c INADDR_ANY then the identifying address is used.
235 If that is not set this method will attempt to find an arbitrary
236 local address and use that as the identifying address.
237
238 Otherwise @a addr replaces any previously set address.
239
240 @return 0 on success, -ERRNO on failure.
241 @see setAddr
242 */
243 int open(uint32_t addr = INADDR_ANY ///< Local IP address for socket.
244 );
245
246 /// Get the internal socket.
247 /// Useful primarily for socket options and using
248 /// in @c select.
249 int getSocket() const;
250
251 /// Use MD5 based security with @a key.
252 void useMD5Security(std::string_view const key ///< Shared hash key.
253 );
254
255 /// Perform house keeping, including sending outbound messages.
256 int housekeeping();
257
258 /// Receive and process a message on the socket.
259 /// @return 0 for success, -ERRNO on system error.
260 ts::Rv<int> handleMessage();
261
262 protected:
263 /// Default constructor.
264 EndPoint();
265 /// Copy constructor.
266 EndPoint(self const &that);
267 /// Force virtual destructor
268 virtual ~EndPoint();
269
270 ts::IntrusivePtr<ImplType> m_ptr; ///< Implementation instance.
271
272 /** Get a pointer to the implementation instance, creating it if needed.
273 @internal This is paired with @c make so that the implementation check
274 can be done non-virtually inline, while still allowing the actual
275 implementation instantiation to be virtual so the correct type is
276 created.
277 */
278 ImplType *instance();
279
280 virtual ImplType *make() = 0; ///< Create a new implementation instance.
281 };
282
283 class Cache : public EndPoint
284 {
285 public:
286 typedef Cache self; ///< Self reference type.
287 typedef EndPoint super; ///< Parent type.
288 typedef CacheImpl ImplType; ///< Implementation type.
289
290 class Service;
291
292 /// Default constructor.
293 Cache();
294 /// Destructor
295 ~Cache() override;
296
297 /// Define services from a configuration file.
298 ts::Errata loadServicesFromFile(char const *path ///< Path to file.
299 );
300
301 /** Define a service group.
302
303 Return a service reference object which references the group.
304
305 If @a result is not @c NULL then its target is set to
306 - @c ServiceGroup::DEFINED if the service was created.
307 - @c ServiceGroup::EXISTS if the service matches the existing service.
308 - @c ServiceGroup::CONFLICT if the service doesn't match the existing service.
309 */
310 Service defineServiceGroup(ServiceGroup const &svc, ///< Service group description.
311 ServiceGroup::Result *result = nullptr);
312
313 /** Add a seed router to the service group.
314
315 A seed router is one that is defined at start up and is where
316 initial messages will be sent. Other routers will be added as
317 discovered. The protocol cannot start successfully without at
318 least one seed router.
319
320 Seed routers are removed when a reply is received from that router.
321
322 */
323 self &addSeedRouter(uint8_t id, ///< Service group ID.
324 uint32_t addr ///< IP address of router.
325 );
326
327 /// Number of seconds until next housekeeping activity is due.
328 time_t waitTime() const;
329
330 protected:
331 /// Get implementation instance, creating if needed.
332 ImplType *instance();
333 /// Get the current implementation instance cast to correct type.
334 ImplType *impl();
335 /// Get the current implementation instance cast to correct type.
336 ImplType const *impl() const;
337 /// Create a new implementation instance.
338 super::ImplType *make() override;
339 };
340
341 /** Hold a reference to a service group in this end point.
342 This is useful when multiple operations are to be done on the
343 same group, rather than doing a lookup by id every time.
344 */
345 class Cache::Service : public ServiceConstants
346 {
347 public:
348 typedef Service self; ///< Self reference type.
349
350 /// Default constructor (invalid reference).
351 Service();
352
353 /// Add an address for a seed router.
354 self &addSeedRouter(uint32_t addr ///< Router IP address.
355 );
356 /// Set the security key.
357 self &setKey(char const *key /// Shared key.
358 );
359 /// Set the service local security option.
360 self &setSecurity(SecurityOption opt ///< Security style to use.
361 );
362 /// Set intercepted packet forwarding style.
363 self &setForwarding(PacketStyle style ///< Type of forwarding supported.
364 );
365 /// Enable or disable packet return by layer 2 rewrite.
366 self &setReturn(PacketStyle style ///< Type of return supported.
367 );
368
369 /// Set cache assignment style.
370 self &setCacheAssignment(CacheAssignmentStyle style ///< Style to use.
371 );
372
373 private:
374 Service(Cache const &cache, detail::cache::GroupData &group);
375 Cache m_cache; ///< Parent cache.
376 detail::cache::GroupData *m_group = nullptr; ///< Service Group data.
377 friend class Cache;
378 };
379
380 class Router : public EndPoint
381 {
382 public:
383 typedef Router self; ///< Self reference type.
384 typedef EndPoint super; ///< Parent type.
385 typedef RouterImpl ImplType; ///< Implementation type.
386
387 /// Default constructor
388 Router();
389 /// Destructor.
390 ~Router() override;
391
392 /// Transmit pending messages.
393 int sendPendingMessages();
394
395 protected:
396 /// Get implementation instance, creating if needed.
397 ImplType *instance();
398 /// Get the current implementation instance cast to correct type.
399 ImplType *impl();
400 /// Create a new implementation instance.
401 super::ImplType *make() override;
402 };
403
404 // ------------------------------------------------------
405 inline bool
406 ServiceGroup::operator!=(self const &that) const
407 {
408 return !(*this == that);
409 }
410
411 inline ServiceGroup::Type
getSvcType()412 ServiceGroup::getSvcType() const
413 {
414 return static_cast<ServiceGroup::Type>(m_svc_type);
415 }
416 inline uint8_t
getSvcId()417 ServiceGroup::getSvcId() const
418 {
419 return m_svc_id;
420 }
421
422 inline ServiceGroup &
setSvcId(uint8_t id)423 ServiceGroup::setSvcId(uint8_t id)
424 {
425 m_svc_id = id;
426 return *this;
427 }
428
429 inline uint8_t
getPriority()430 ServiceGroup::getPriority() const
431 {
432 return m_priority;
433 }
434
435 inline ServiceGroup &
setPriority(uint8_t pri)436 ServiceGroup::setPriority(uint8_t pri)
437 {
438 m_priority = pri;
439 return *this;
440 }
441
442 inline uint8_t
getProtocol()443 ServiceGroup::getProtocol() const
444 {
445 return m_protocol;
446 }
447
448 inline ServiceGroup &
setProtocol(uint8_t proto)449 ServiceGroup::setProtocol(uint8_t proto)
450 {
451 m_protocol = proto;
452 return *this;
453 }
454
455 inline uint32_t
getFlags()456 ServiceGroup::getFlags() const
457 {
458 return ntohl(m_flags);
459 }
460
461 inline ServiceGroup &
setFlags(uint32_t flags)462 ServiceGroup::setFlags(uint32_t flags)
463 {
464 m_flags = htonl(flags);
465 return *this;
466 }
467
468 inline ServiceGroup &
enableFlags(uint32_t flags)469 ServiceGroup::enableFlags(uint32_t flags)
470 {
471 m_flags |= htonl(flags);
472 return *this;
473 }
474
475 inline ServiceGroup &
disableFlags(uint32_t flags)476 ServiceGroup::disableFlags(uint32_t flags)
477 {
478 m_flags &= ~htonl(flags);
479 return *this;
480 }
481
482 inline uint16_t
getPort(int idx)483 ServiceGroup::getPort(int idx) const
484 {
485 return ntohs(m_ports[idx]);
486 }
487
488 inline ServiceGroup &
setPort(int idx,uint16_t port)489 ServiceGroup::setPort(int idx, uint16_t port)
490 {
491 m_ports[idx] = htons(port);
492 return *this;
493 }
494
495 inline ServiceGroup &
clearPorts()496 ServiceGroup::clearPorts()
497 {
498 memset(m_ports, 0, sizeof(m_ports));
499 return *this;
500 }
501
Service()502 inline Cache::Service::Service() {}
503
Service(Cache const & cache,detail::cache::GroupData & group)504 inline Cache::Service::Service(Cache const &cache, detail::cache::GroupData &group) : m_cache(cache), m_group(&group) {}
505
506 // ------------------------------------------------------
507
508 } // namespace wccp
509