VirtualBox

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

最後變更 在這個檔案從49245是 49063,由 vboxsync 提交於 11 年 前

VboxNetDHCP: Lease: hides fields to internal data-structure and expose accessor functions.

Lease: wasn't intended to be a base class. drop "virtual" from dtor.

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

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