VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/DHCP/Config.h@ 69496

Last change on this file since 69496 was 69496, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.0 KB
Line 
1/* $Id: Config.h 69496 2017-10-28 14:55:58Z vboxsync $ */
2/** @file
3 * Config.h
4 */
5
6/*
7 * Copyright (C) 2013-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef _CONFIG_H_
19#define _CONFIG_H_
20
21#include <iprt/asm-math.h>
22#include <iprt/cpp/utils.h>
23
24#include <VBox/com/ptr.h>
25#include <VBox/com/string.h>
26#include <VBox/com/VirtualBox.h>
27
28#include "../NetLib/cpp/utils.h"
29
30
31class RawOption
32{
33public:
34 RawOption()
35 {
36 /** @todo r=bird: this is crazy. */
37 RT_ZERO(*this);
38 }
39 uint8_t u8OptId;
40 uint8_t cbRawOpt;
41 uint8_t au8RawOpt[255];
42};
43
44class ClientData;
45class Client;
46class Lease;
47class BaseConfigEntity;
48
49class NetworkConfigEntity;
50class HostConfigEntity;
51class ClientMatchCriteria;
52class ConfigurationManager;
53
54/*
55 * it's a basic representation of
56 * of out undestanding what client is
57 * XXX: Client might sends Option 61 (RFC2132 9.14 "Client-identifier") signalling
58 * that we may identify it in special way
59 *
60 * XXX: Client might send Option 60 (RFC2132 9.13 "Vendor class undentifier")
61 * in response it's expected server sends Option 43 (RFC2132 8.4. "Vendor Specific Information")
62 */
63class Client
64{
65 friend class Lease;
66 friend class ConfigurationManager;
67
68 public:
69 Client();
70 void initWithMac(const RTMAC& mac);
71 bool operator== (const RTMAC& mac) const;
72 const RTMAC& getMacAddress() const;
73
74 /** Dumps client query */
75 void dump();
76
77 Lease lease();
78 const Lease lease() const;
79
80 public:
81 static const Client NullClient;
82
83 private:
84 Client(ClientData *);
85 SharedPtr<ClientData> m;
86};
87
88
89bool operator== (const Lease&, const Lease&);
90bool operator!= (const Lease&, const Lease&);
91bool operator< (const Lease&, const Lease&);
92
93
94typedef std::map<uint8_t, RawOption> MapOptionId2RawOption;
95typedef MapOptionId2RawOption::iterator MapOptionId2RawOptionIterator;
96typedef MapOptionId2RawOption::const_iterator MapOptionId2RawOptionConstIterator;
97typedef MapOptionId2RawOption::value_type MapOptionId2RawOptionValue;
98
99namespace xml {
100 class ElementNode;
101}
102
103class Lease
104{
105 friend class Client;
106 friend bool operator== (const Lease&, const Lease&);
107 //friend int ConfigurationManager::loadFromFile(const std::string&);
108 friend class ConfigurationManager;
109
110 public:
111 Lease();
112 Lease(const Client&);
113
114 bool isExpired() const;
115 void expire();
116
117 /* Depending on phase *Expiration and phaseStart initialize different values. */
118 void bindingPhase(bool);
119 void phaseStart(uint64_t u64Start);
120 bool isInBindingPhase() const;
121 /* returns 0 if in binding state */
122 uint64_t issued() const;
123
124 void setExpiration(uint32_t);
125 uint32_t getExpiration() const;
126
127 RTNETADDRIPV4 getAddress() const;
128 void setAddress(RTNETADDRIPV4);
129
130 const NetworkConfigEntity *getConfig() const;
131 void setConfig(NetworkConfigEntity *);
132
133 const MapOptionId2RawOption& options() const;
134
135 bool toXML(xml::ElementNode *) const;
136 bool fromXML(const xml::ElementNode *);
137
138 public:
139 static const Lease NullLease;
140
141 private:
142 Lease(ClientData *);
143 SharedPtr<ClientData> m;
144};
145
146
147typedef std::vector<Client> VecClient;
148typedef VecClient::iterator VecClientIterator;
149typedef VecClient::const_iterator VecClientConstIterator;
150
151typedef std::vector<RTMAC> MacAddressContainer;
152typedef MacAddressContainer::iterator MacAddressIterator;
153
154typedef std::vector<RTNETADDRIPV4> Ipv4AddressContainer;
155typedef Ipv4AddressContainer::iterator Ipv4AddressIterator;
156typedef Ipv4AddressContainer::const_iterator Ipv4AddressConstIterator;
157
158typedef std::map<Lease, RTNETADDRIPV4> MapLease2Ip4Address;
159typedef MapLease2Ip4Address::iterator MapLease2Ip4AddressIterator;
160typedef MapLease2Ip4Address::const_iterator MapLease2Ip4AddressConstIterator;
161typedef MapLease2Ip4Address::value_type MapLease2Ip4AddressPair;
162
163/**
164 *
165 */
166class ClientMatchCriteria
167{
168 public:
169 virtual bool check(const Client&) const {return false;};
170};
171
172
173class ORClientMatchCriteria: ClientMatchCriteria
174{
175 ClientMatchCriteria* m_left;
176 ClientMatchCriteria* m_right;
177 ORClientMatchCriteria(ClientMatchCriteria *left, ClientMatchCriteria *right)
178 {
179 m_left = left;
180 m_right = right;
181 }
182
183 virtual bool check(const Client& client) const
184 {
185 return (m_left->check(client) || m_right->check(client));
186 }
187};
188
189
190class ANDClientMatchCriteria: ClientMatchCriteria
191{
192public:
193 ANDClientMatchCriteria(ClientMatchCriteria *left, ClientMatchCriteria *right)
194 {
195 m_left = left;
196 m_right = right;
197 }
198
199 virtual bool check(const Client& client) const
200 {
201 return (m_left->check(client) && m_right->check(client));
202 }
203
204private:
205 ClientMatchCriteria* m_left;
206 ClientMatchCriteria* m_right;
207
208};
209
210
211class AnyClientMatchCriteria: public ClientMatchCriteria
212{
213public:
214 virtual bool check(const Client&) const
215 {
216 return true;
217 }
218};
219
220
221class MACClientMatchCriteria: public ClientMatchCriteria
222{
223public:
224 MACClientMatchCriteria(const RTMAC& mac):m_mac(mac){}
225
226 virtual bool check(const Client& client) const;
227
228private:
229 RTMAC m_mac;
230};
231
232
233#if 0
234/* XXX: Later */
235class VmSlotClientMatchCriteria: public ClientMatchCriteria
236{
237 str::string VmName;
238 uint8_t u8Slot;
239 virtual bool check(const Client& client)
240 {
241 return ( client.VmName == VmName
242 && ( u8Slot == (uint8_t)~0 /* any */
243 || client.u8Slot == u8Slot));
244 }
245};
246#endif
247
248
249/* Option 60 */
250class ClassClientMatchCriteria: ClientMatchCriteria{};
251/* Option 61 */
252class ClientIdentifierMatchCriteria: ClientMatchCriteria{};
253
254
255class BaseConfigEntity
256{
257 public:
258 BaseConfigEntity(const ClientMatchCriteria *criteria = NULL,
259 int matchingLevel = 0)
260 : m_criteria(criteria),
261 m_MatchLevel(matchingLevel){};
262 virtual ~BaseConfigEntity(){};
263 /* XXX */
264 int add(BaseConfigEntity *cfg)
265 {
266 m_children.push_back(cfg);
267 return 0;
268 }
269
270 /* Should return how strong matching */
271 virtual int match(Client& client, BaseConfigEntity **cfg);
272 virtual uint32_t expirationPeriod() const = 0;
273
274 protected:
275 const ClientMatchCriteria *m_criteria;
276 int m_MatchLevel;
277 std::vector<BaseConfigEntity *> m_children;
278};
279
280
281class NullConfigEntity: public BaseConfigEntity
282{
283 public:
284 NullConfigEntity(){}
285 virtual ~NullConfigEntity(){}
286 int add(BaseConfigEntity *) const { return 0;}
287 virtual uint32_t expirationPeriod() const {return 0;}
288};
289
290
291class ConfigEntity: public BaseConfigEntity
292{
293 public:
294 /* range */
295 /* match conditions */
296 ConfigEntity(std::string& name,
297 const BaseConfigEntity *cfg,
298 const ClientMatchCriteria *criteria,
299 int matchingLevel = 0):
300 BaseConfigEntity(criteria, matchingLevel),
301 m_name(name),
302 m_parentCfg(cfg),
303 m_u32ExpirationPeriod(0)
304 {
305 unconst(m_parentCfg)->add(this);
306 }
307
308 virtual uint32_t expirationPeriod() const
309 {
310 if (!m_u32ExpirationPeriod)
311 return m_parentCfg->expirationPeriod();
312 else
313 return m_u32ExpirationPeriod;
314 }
315
316 /* XXX: private:*/
317 std::string m_name;
318 const BaseConfigEntity *m_parentCfg;
319 uint32_t m_u32ExpirationPeriod;
320};
321
322
323/**
324 * Network specific entries
325 */
326class NetworkConfigEntity:public ConfigEntity
327{
328public:
329 /* Address Pool matching with network declaration */
330 NetworkConfigEntity(std::string name,
331 const BaseConfigEntity *cfg,
332 const ClientMatchCriteria *criteria,
333 int matchlvl,
334 const RTNETADDRIPV4& networkID,
335 const RTNETADDRIPV4& networkMask,
336 const RTNETADDRIPV4& lowerIP,
337 const RTNETADDRIPV4& upperIP):
338 ConfigEntity(name, cfg, criteria, matchlvl),
339 m_NetworkID(networkID),
340 m_NetworkMask(networkMask),
341 m_UpperIP(upperIP),
342 m_LowerIP(lowerIP)
343 {
344 };
345
346 NetworkConfigEntity(std::string name,
347 const BaseConfigEntity *cfg,
348 const ClientMatchCriteria *criteria,
349 const RTNETADDRIPV4& networkID,
350 const RTNETADDRIPV4& networkMask):
351 ConfigEntity(name, cfg, criteria, 5),
352 m_NetworkID(networkID),
353 m_NetworkMask(networkMask)
354 {
355 m_UpperIP.u = m_NetworkID.u | (~m_NetworkMask.u);
356 m_LowerIP.u = m_NetworkID.u;
357 };
358
359 const RTNETADDRIPV4& upperIp() const {return m_UpperIP;}
360 const RTNETADDRIPV4& lowerIp() const {return m_LowerIP;}
361 const RTNETADDRIPV4& networkId() const {return m_NetworkID;}
362 const RTNETADDRIPV4& netmask() const {return m_NetworkMask;}
363
364 private:
365 RTNETADDRIPV4 m_NetworkID;
366 RTNETADDRIPV4 m_NetworkMask;
367 RTNETADDRIPV4 m_UpperIP;
368 RTNETADDRIPV4 m_LowerIP;
369};
370
371
372/**
373 * Host specific entry
374 * Address pool is contains one element
375 */
376class HostConfigEntity: public NetworkConfigEntity
377{
378public:
379 HostConfigEntity(const RTNETADDRIPV4& addr,
380 std::string name,
381 const NetworkConfigEntity *cfg,
382 const ClientMatchCriteria *criteria):
383 NetworkConfigEntity(name,
384 static_cast<const ConfigEntity*>(cfg), criteria, 10,
385 cfg->networkId(), cfg->netmask(), addr, addr)
386 {
387 /* upper addr == lower addr */
388 }
389};
390
391class RootConfigEntity: public NetworkConfigEntity
392{
393public:
394 RootConfigEntity(std::string name, uint32_t expirationPeriod);
395 virtual ~RootConfigEntity(){};
396};
397
398
399#if 0
400/**
401 * Shared regions e.g. some of configured networks declarations
402 * are cover each other.
403 * XXX: Shared Network is join on Network config entities with possible
404 * overlaps in address pools. for a moment we won't configure and use them them
405 */
406class SharedNetworkConfigEntity: public NetworkEntity
407{
408public:
409 SharedNetworkConfigEntity(){}
410 int match(const Client& client) const { return m_criteria.match(client)? 3 : 0;}
411
412 SharedNetworkConfigEntity(NetworkEntity& network)
413 {
414 Networks.push_back(network);
415 }
416 virtual ~SharedNetworkConfigEntity(){}
417
418 std::vector<NetworkConfigEntity> Networks;
419};
420#endif
421
422class ConfigurationManager
423{
424public:
425 static ConfigurationManager* getConfigurationManager();
426 static int extractRequestList(PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& rawOpt);
427
428 int loadFromFile(const com::Utf8Str&);
429 int saveToFile();
430 /**
431 *
432 */
433 Client getClientByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg);
434
435 /**
436 * XXX: it's could be done on DHCPOFFER or on DHCPACK (rfc2131 gives freedom here
437 * 3.1.2, what is strict that allocation should do address check before real
438 * allocation)...
439 */
440 Lease allocateLease4Client(const Client& client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg);
441
442 /**
443 * We call this before DHCPACK sent and after DHCPREQUEST received ...
444 * when requested configuration is acceptable.
445 */
446 int commitLease4Client(Client& client);
447
448 /**
449 * Expires client lease.
450 */
451 int expireLease4Client(Client& client);
452
453 static int findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt);
454
455 NetworkConfigEntity *addNetwork(NetworkConfigEntity *pCfg,
456 const RTNETADDRIPV4& networkId,
457 const RTNETADDRIPV4& netmask,
458 RTNETADDRIPV4& UpperAddress,
459 RTNETADDRIPV4& LowerAddress);
460
461 HostConfigEntity *addHost(NetworkConfigEntity*, const RTNETADDRIPV4&, ClientMatchCriteria*);
462 int addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address);
463 int flushAddressList(uint8_t u8OptId);
464 int setString(uint8_t u8OptId, const std::string& str);
465 const std::string& getString(uint8_t u8OptId);
466 const Ipv4AddressContainer& getAddressList(uint8_t u8OptId);
467
468private:
469 ConfigurationManager():m(NULL){}
470 void init();
471
472 ~ConfigurationManager();
473 bool isAddressTaken(const RTNETADDRIPV4& addr, Lease& lease);
474 bool isAddressTaken(const RTNETADDRIPV4& addr);
475
476public:
477 /* nulls */
478 const Ipv4AddressContainer m_empty;
479 const std::string m_noString;
480
481private:
482 struct Data;
483 Data *m;
484};
485
486
487class NetworkManager
488{
489public:
490 static NetworkManager *getNetworkManager(ComPtr<IDHCPServer> aDhcpServer = ComPtr<IDHCPServer>());
491
492 const RTNETADDRIPV4& getOurAddress() const;
493 const RTNETADDRIPV4& getOurNetmask() const;
494 const RTMAC& getOurMac() const;
495
496 void setOurAddress(const RTNETADDRIPV4& aAddress);
497 void setOurNetmask(const RTNETADDRIPV4& aNetmask);
498 void setOurMac(const RTMAC& aMac);
499
500 bool handleDhcpReqDiscover(PCRTNETBOOTP pDhcpMsg, size_t cb);
501 bool handleDhcpReqRequest(PCRTNETBOOTP pDhcpMsg, size_t cb);
502 bool handleDhcpReqDecline(PCRTNETBOOTP pDhcpMsg, size_t cb);
503 bool handleDhcpReqRelease(PCRTNETBOOTP pDhcpMsg, size_t cb);
504
505 void setService(const VBoxNetHlpUDPService *);
506private:
507 NetworkManager();
508 ~NetworkManager();
509
510 int offer4Client(const Client& lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
511 int ack(const Client& lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
512 int nak(const Client& lease, uint32_t u32Xid);
513
514 int prepareReplyPacket4Client(const Client& client, uint32_t u32Xid);
515 int doReply(const Client& client, const std::vector<RawOption>& extra);
516 int processParameterReqList(const Client& client, const uint8_t *pu8ReqList, int cReqList, std::vector<RawOption>& extra);
517
518private:
519 static NetworkManager *g_NetworkManager;
520
521private:
522 struct Data;
523 Data *m;
524
525};
526
527
528extern const ClientMatchCriteria *g_AnyClient;
529extern RootConfigEntity *g_RootConfig;
530extern const NullConfigEntity *g_NullConfig;
531
532/**
533 * Helper class for stuffing DHCP options into a reply packet.
534 */
535class VBoxNetDhcpWriteCursor
536{
537private:
538 uint8_t *m_pbCur; /**< The current cursor position. */
539 uint8_t *m_pbEnd; /**< The end the current option space. */
540 uint8_t *m_pfOverload; /**< Pointer to the flags of the overload option. */
541 uint8_t m_fUsed; /**< Overload fields that have been used. */
542 PRTNETDHCPOPT m_pOpt; /**< The current option. */
543 PRTNETBOOTP m_pDhcp; /**< The DHCP packet. */
544 bool m_fOverflowed; /**< Set if we've overflowed, otherwise false. */
545
546public:
547 /** Instantiate an option cursor for the specified DHCP message. */
548 VBoxNetDhcpWriteCursor(PRTNETBOOTP pDhcp, size_t cbDhcp) :
549 m_pbCur(&pDhcp->bp_vend.Dhcp.dhcp_opts[0]),
550 m_pbEnd((uint8_t *)pDhcp + cbDhcp),
551 m_pfOverload(NULL),
552 m_fUsed(0),
553 m_pOpt(NULL),
554 m_pDhcp(pDhcp),
555 m_fOverflowed(false)
556 {
557 AssertPtr(pDhcp);
558 Assert(cbDhcp > RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts[10]));
559 }
560
561 /** Destructor. */
562 ~VBoxNetDhcpWriteCursor()
563 {
564 m_pbCur = m_pbEnd = m_pfOverload = NULL;
565 m_pOpt = NULL;
566 m_pDhcp = NULL;
567 }
568
569 /**
570 * Try use the bp_file field.
571 * @returns true if not overloaded, false otherwise.
572 */
573 bool useBpFile(void)
574 {
575 if ( m_pfOverload
576 && (*m_pfOverload & 1))
577 return false;
578 m_fUsed |= 1 /* bp_file flag*/;
579 return true;
580 }
581
582
583 /**
584 * Try overload more BOOTP fields
585 */
586 bool overloadMore(void)
587 {
588 /* switch option area. */
589 uint8_t *pbNew;
590 uint8_t *pbNewEnd;
591 uint8_t fField;
592 if (!(m_fUsed & 1))
593 {
594 fField = 1;
595 pbNew = &m_pDhcp->bp_file[0];
596 pbNewEnd = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)];
597 }
598 else if (!(m_fUsed & 2))
599 {
600 fField = 2;
601 pbNew = &m_pDhcp->bp_sname[0];
602 pbNewEnd = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)];
603 }
604 else
605 return false;
606
607 if (!m_pfOverload)
608 {
609 /* Add an overload option. */
610 *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD;
611 *m_pbCur++ = fField;
612 m_pfOverload = m_pbCur;
613 *m_pbCur++ = 1; /* bp_file flag */
614 }
615 else
616 *m_pfOverload |= fField;
617
618 /* pad current option field */
619 while (m_pbCur != m_pbEnd)
620 *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */
621
622 /* switch */
623 m_pbCur = pbNew;
624 m_pbEnd = pbNewEnd;
625 return true;
626 }
627
628 /**
629 * Begin an option.
630 *
631 * @returns true on success, false if we're out of space.
632 *
633 * @param uOption The option number.
634 * @param cb The amount of data.
635 */
636 bool begin(uint8_t uOption, size_t cb)
637 {
638 /* Check that the data of the previous option has all been written. */
639 Assert( !m_pOpt
640 || (m_pbCur - m_pOpt->dhcp_len == (uint8_t *)(m_pOpt + 1)));
641 AssertMsg(cb <= 255, ("%#x\n", cb));
642
643 /* Check if we need to overload more stuff. */
644 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + (m_pfOverload ? 1 : 3))
645 {
646 m_pOpt = NULL;
647 if (!overloadMore())
648 {
649 m_fOverflowed = true;
650 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
651 }
652 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 1)
653 {
654 m_fOverflowed = true;
655 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
656 }
657 }
658
659 /* Emit the option header. */
660 m_pOpt = (PRTNETDHCPOPT)m_pbCur;
661 m_pOpt->dhcp_opt = uOption;
662 m_pOpt->dhcp_len = (uint8_t)cb;
663 m_pbCur += 2;
664 return true;
665 }
666
667 /**
668 * Puts option data.
669 *
670 * @param pvData The data.
671 * @param cb The amount to put.
672 */
673 void put(void const *pvData, size_t cb)
674 {
675 Assert(m_pOpt || m_fOverflowed);
676 if (RT_LIKELY(m_pOpt))
677 {
678 Assert((uintptr_t)m_pbCur - (uintptr_t)(m_pOpt + 1) + cb <= (size_t)m_pOpt->dhcp_len);
679 memcpy(m_pbCur, pvData, cb);
680 m_pbCur += cb;
681 }
682 }
683
684 /**
685 * Puts an IPv4 Address.
686 *
687 * @param IPv4Addr The address.
688 */
689 void putIPv4Addr(RTNETADDRIPV4 IPv4Addr)
690 {
691 put(&IPv4Addr, 4);
692 }
693
694 /**
695 * Adds an IPv4 address option.
696 *
697 * @returns true/false just like begin().
698 *
699 * @param uOption The option number.
700 * @param IPv4Addr The address.
701 */
702 bool optIPv4Addr(uint8_t uOption, RTNETADDRIPV4 IPv4Addr)
703 {
704 if (!begin(uOption, 4))
705 return false;
706 putIPv4Addr(IPv4Addr);
707 return true;
708 }
709
710 /**
711 * Adds an option taking 1 or more IPv4 address.
712 *
713 * If the vector contains no addresses, the option will not be added.
714 *
715 * @returns true/false just like begin().
716 *
717 * @param uOption The option number.
718 * @param rIPv4Addrs Reference to the address vector.
719 */
720 bool optIPv4Addrs(uint8_t uOption, std::vector<RTNETADDRIPV4> const &rIPv4Addrs)
721 {
722 size_t const c = rIPv4Addrs.size();
723 if (!c)
724 return true;
725
726 if (!begin(uOption, 4*c))
727 return false;
728 for (size_t i = 0; i < c; i++)
729 putIPv4Addr(rIPv4Addrs[i]);
730 return true;
731 }
732
733 /**
734 * Puts an 8-bit integer.
735 *
736 * @param u8 The integer.
737 */
738 void putU8(uint8_t u8)
739 {
740 put(&u8, 1);
741 }
742
743 /**
744 * Adds an 8-bit integer option.
745 *
746 * @returns true/false just like begin().
747 *
748 * @param uOption The option number.
749 * @param u8 The integer
750 */
751 bool optU8(uint8_t uOption, uint8_t u8)
752 {
753 if (!begin(uOption, 1))
754 return false;
755 putU8(u8);
756 return true;
757 }
758
759 /**
760 * Puts an 32-bit integer (network endian).
761 *
762 * @param u32 The integer.
763 */
764 void putU32(uint32_t u32)
765 {
766 put(&u32, 4);
767 }
768
769 /**
770 * Adds an 32-bit integer (network endian) option.
771 *
772 * @returns true/false just like begin().
773 *
774 * @param uOption The option number.
775 * @param u32 The integer.
776 */
777 bool optU32(uint8_t uOption, uint32_t u32)
778 {
779 if (!begin(uOption, 4))
780 return false;
781 putU32(u32);
782 return true;
783 }
784
785 /**
786 * Puts a std::string.
787 *
788 * @param rStr Reference to the string.
789 */
790 void putStr(std::string const &rStr)
791 {
792 put(rStr.c_str(), rStr.size());
793 }
794
795 /**
796 * Adds an std::string option if the string isn't empty.
797 *
798 * @returns true/false just like begin().
799 *
800 * @param uOption The option number.
801 * @param rStr Reference to the string.
802 */
803 bool optStr(uint8_t uOption, std::string const &rStr)
804 {
805 const size_t cch = rStr.size();
806 if (!cch)
807 return true;
808
809 if (!begin(uOption, cch))
810 return false;
811 put(rStr.c_str(), cch);
812 return true;
813 }
814
815 /**
816 * Whether we've overflowed.
817 *
818 * @returns true on overflow, false otherwise.
819 */
820 bool hasOverflowed(void) const
821 {
822 return m_fOverflowed;
823 }
824
825 /**
826 * Adds the terminating END option.
827 *
828 * The END will always be added as we're reserving room for it, however, we
829 * might have dropped previous options due to overflows and that is what the
830 * return status indicates.
831 *
832 * @returns true on success, false on a (previous) overflow.
833 */
834 bool optEnd(void)
835 {
836 Assert((uintptr_t)(m_pbEnd - m_pbCur) < 4096);
837 *m_pbCur++ = RTNET_DHCP_OPT_END;
838 return !hasOverflowed();
839 }
840};
841
842#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette