VirtualBox

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

Last change on this file since 48420 was 48420, checked in by vboxsync, 11 years ago

DHCP: moves implementation from header to source file.

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