VirtualBox

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

Last change on this file since 54499 was 54499, checked in by vboxsync, 10 years ago

VBoxNetDHCP: keep a pointer to NetworkManager instead of using a
global. To minimize churn, convert that global into a singleton.
No functional change intended.

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

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