iface_mgr.h 36.8 KB
Newer Older
Marcin Siodelski's avatar
Marcin Siodelski committed
1
// Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

#ifndef IFACE_MGR_H
#define IFACE_MGR_H

18
#include <asiolink/io_address.h>
19
#include <dhcp/dhcp4.h>
20
#include <dhcp/dhcp6.h>
21
22
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
23
#include <dhcp/pkt_filter.h>
24

25
#include <boost/function.hpp>
26
27
28
29
30
31
#include <boost/noncopyable.hpp>
#include <boost/scoped_array.hpp>
#include <boost/shared_ptr.hpp>

#include <list>

32
33
namespace isc {

34
namespace dhcp {
35
36
37
38
39
40
41
42

/// @brief IfaceMgr exception thrown thrown when interface detection fails.
class IfaceDetectError : public Exception {
public:
    IfaceDetectError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

43
44
45
46
47
48
49
/// @brief Exception thrown when it is not allowed to set new Packet Filter.
class PacketFilterChangeDenied : public Exception {
public:
    PacketFilterChangeDenied(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/// @brief IfaceMgr exception thrown thrown when socket opening
/// or configuration failed.
class SocketConfigError : public Exception {
public:
    SocketConfigError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief IfaceMgr exception thrown thrown when error occured during
/// reading data from socket.
class SocketReadError : public Exception {
public:
    SocketReadError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief IfaceMgr exception thrown thrown when error occured during
/// sedning data through socket.
class SocketWriteError : public Exception {
public:
    SocketWriteError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

74
75
/// Holds information about socket.
struct SocketInfo {
76

77
78
79
80
    isc::asiolink::IOAddress addr_; /// bound address
    uint16_t port_;   /// socket port
    uint16_t family_; /// IPv4 or IPv6

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    /// @brief Socket descriptor (a.k.a. primary socket).
    int sockfd_;

    /// @brief Fallback socket descriptor.
    ///
    /// This socket descriptor holds the handle to the fallback socket.
    /// The fallback socket is created when there is a need for the regular
    /// datagram socket to be bound to an IP address and port, besides
    /// primary socket (sockfd_) which is actually used to receive and process
    /// the DHCP messages. The fallback socket (if exists) is always associated
    /// with the primary socket. In particular, the need for the fallback socket
    /// arises when raw socket is a primary one. When primary socket is open,
    /// it is bound to an interface not the address and port. The implications
    /// include the possibility that the other process (e.g. the other instance
    /// of DHCP server) will bind to the same address and port through which the
    /// raw socket receives the DHCP messages.Another implication is that the
    /// kernel, being unaware of the DHCP server operating through the raw
    /// socket, will respond with the ICMP "Destination port unreachable"
    /// messages when DHCP messages are only received through the raw socket.
    /// In order to workaround the issues mentioned here, the fallback socket
    /// should be opened so as/ the kernel is aware that the certain address
    /// and port is in use.
    ///
    /// The fallback description is supposed to be set to a negative value if
    /// the fallback socket is closed (not open).
    int fallbackfd_;

108
109
    /// @brief SocketInfo constructor.
    ///
110
111
112
113
114
115
116
117
118
    /// @param addr An address the socket is bound to.
    /// @param port A port the socket is bound to.
    /// @param sockfd Socket descriptor.
    /// @param fallbackfd A descriptor of the fallback socket.
    SocketInfo(const isc::asiolink::IOAddress& addr, const uint16_t port,
               const int sockfd, const int fallbackfd = -1)
        : addr_(addr), port_(port), family_(addr.getFamily()),
          sockfd_(sockfd), fallbackfd_(fallbackfd) { }

119
120
121
};


122
/// @brief Represents a single network interface
123
///
124
125
126
127
/// Iface structure represents network interface with all useful
/// information, like name, interface index, MAC address and
/// list of assigned addresses
class Iface {
128
public:
129

130
    /// Maximum MAC address length (Infiniband uses 20 bytes)
131
132
    static const unsigned int MAX_MAC_LEN = 20;

133
    /// Type that defines list of addresses
134
    typedef std::vector<isc::asiolink::IOAddress> AddressCollection;
135

136
137
138
139
140
141
142
143
    /// @brief Type that holds a list of socket information.
    ///
    /// @warning The type of the container used here must guarantee
    /// that the iterators do not invalidate when erase() is called.
    /// This is because, the \ref closeSockets function removes
    /// elements selectively by calling erase on the element to be
    /// removed and further iterates through remaining elements.
    ///
144
    /// @todo: Add SocketCollectionConstIter type
145
146
    typedef std::list<SocketInfo> SocketCollection;

147
148
149
150
151
152
153
154
155
156
    /// @brief Iface constructor.
    ///
    /// Creates Iface object that represents network interface.
    ///
    /// @param name name of the interface
    /// @param ifindex interface index (unique integer identifier)
    Iface(const std::string& name, int ifindex);

    /// @brief Closes all open sockets on interface.
    void closeSockets();
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    /// @brief Closes all IPv4 or IPv6 sockets.
    ///
    /// This function closes sockets of the specific 'type' and closes them.
    /// The 'type' of the socket indicates whether it is used to send IPv4
    /// or IPv6 packets. The allowed values of the parameter are AF_INET and
    /// AF_INET6 for IPv4 and IPv6 packets respectively. It is important
    /// to realize that the actual types of sockets may be different than
    /// AF_INET for IPv4 packets. This is because, historically the IfaceMgr
    /// always used AF_INET sockets for IPv4 traffic. This is no longer the
    /// case when the Direct IPv4 traffic must be supported. In order to support
    /// direct traffic, the IfaceMgr operates on raw sockets, e.g. AF_PACKET
    /// family sockets on Linux.
    ///
    /// @todo Replace the AF_INET and AF_INET6 values with an enum
    /// which will not be confused with the actual socket type.
    ///
    /// @param family type of the sockets to be closed (AF_INET or AF_INET6)
    ///
    /// @throw BadValue if family value is different than AF_INET or AF_INET6.
    void closeSockets(const uint16_t family);

179
    /// @brief Returns full interface name as "ifname/ifindex" string.
180
    ///
181
182
    /// @return string with interface name
    std::string getFullName() const;
183

184
185
186
187
    /// @brief Returns link-layer address a plain text.
    ///
    /// @return MAC address as a plain text (string)
    std::string getPlainMac() const;
188

189
190
191
192
193
    /// @brief Sets MAC address of the interface.
    ///
    /// @param mac pointer to MAC address buffer
    /// @param macLen length of mac address
    void setMac(const uint8_t* mac, size_t macLen);
194

195
196
197
198
    /// @brief Returns MAC length.
    ///
    /// @return length of MAC address
    size_t getMacLen() const { return mac_len_; }
199

200
201
202
203
204
    /// @brief Returns pointer to MAC address.
    ///
    /// Note: Returned pointer is only valid as long as the interface object
    /// that returned it.
    const uint8_t* getMac() const { return mac_; }
205

206
207
    /// @brief Sets flag_*_ fields based on bitmask value returned by OS
    ///
208
    /// @note Implementation of this method is OS-dependent as bits have
209
210
211
212
    /// different meaning on each OS.
    ///
    /// @param flags bitmask value returned by OS in interface detection
    void setFlags(uint32_t flags);
213

214
215
216
217
    /// @brief Returns interface index.
    ///
    /// @return interface index
    uint16_t getIndex() const { return ifindex_; }
218

219
220
221
222
    /// @brief Returns interface name.
    ///
    /// @return interface name
    std::string getName() const { return name_; };
223

224
225
226
227
    /// @brief Sets up hardware type of the interface.
    ///
    /// @param type hardware type
    void setHWType(uint16_t type ) { hardware_type_ = type; }
228

229
230
231
232
    /// @brief Returns hardware type of the interface.
    ///
    /// @return hardware type
    uint16_t getHWType() const { return hardware_type_; }
233

234
235
236
237
238
239
240
241
242
243
244
    /// @brief Returns all interfaces available on an interface.
    ///
    /// Care should be taken to not use this collection after Iface object
    /// ceases to exist. That is easy in most cases as Iface objects are
    /// created by IfaceMgr that is a singleton an is expected to be
    /// available at all time. We may revisit this if we ever decide to
    /// implement dynamic interface detection, but such fancy feature would
    /// mostly be useful for clients with wifi/vpn/virtual interfaces.
    ///
    /// @return collection of addresses
    const AddressCollection& getAddresses() const { return addrs_; }
245

246
247
248
249
250
251
252
253
254
    /// @brief Adds an address to an interface.
    ///
    /// This only adds an address to collection, it does not physically
    /// configure address on actual network interface.
    ///
    /// @param addr address to be added
    void addAddress(const isc::asiolink::IOAddress& addr) {
        addrs_.push_back(addr);
    }
255

256
257
258
259
260
261
262
263
264
265
    /// @brief Deletes an address from an interface.
    ///
    /// This only deletes address from collection, it does not physically
    /// remove address configuration from actual network interface.
    ///
    /// @param addr address to be removed.
    ///
    /// @return true if removal was successful (address was in collection),
    ///         false otherwise
    bool delAddress(const isc::asiolink::IOAddress& addr);
266

267
268
269
270
271
272
    /// @brief Adds socket descriptor to an interface.
    ///
    /// @param sock SocketInfo structure that describes socket.
    void addSocket(const SocketInfo& sock) {
        sockets_.push_back(sock);
    }
273

274
275
276
277
278
279
280
281
    /// @brief Closes socket.
    ///
    /// Closes socket and removes corresponding SocketInfo structure
    /// from an interface.
    ///
    /// @param sockfd socket descriptor to be closed/removed.
    /// @return true if there was such socket, false otherwise
    bool delSocket(uint16_t sockfd);
282

283
284
285
286
287
288
289
290
291
292
293
294
295
296
    /// @brief Returns collection of all sockets added to interface.
    ///
    /// When new socket is created with @ref IfaceMgr::openSocket
    /// it is added to sockets collection on particular interface.
    /// If socket is opened by other means (e.g. function that does
    /// not use @ref IfaceMgr::openSocket) it will not be available
    /// in this collection. Note that functions like
    /// @ref IfaceMgr::openSocketFromIface use
    /// @ref IfaceMgr::openSocket internally.
    /// The returned reference is only valid during the lifetime of
    /// the IfaceMgr object that returned it.
    ///
    /// @return collection of sockets added to interface
    const SocketCollection& getSockets() const { return sockets_; }
297

Tomek Mrugalski's avatar
Tomek Mrugalski committed
298
299
300
301
    /// @brief Removes any unicast addresses
    ///
    /// Removes any unicast addresses that the server was configured to
    /// listen on
302
303
304
305
    void clearUnicasts() {
        unicasts_.clear();
    }

Tomek Mrugalski's avatar
Tomek Mrugalski committed
306
307
308
309
310
    /// @brief Adds unicast the server should listen on
    ///
    /// @throw BadValue if specified address is already defined on interface
    /// @param addr unicast address to listen on
    void addUnicast(const isc::asiolink::IOAddress& addr);
311

Tomek Mrugalski's avatar
Tomek Mrugalski committed
312
313
314
    /// @brief Returns a container of addresses the server should listen on
    ///
    /// @return address collection (may be empty)
315
316
317
318
    const AddressCollection& getUnicasts() const {
        return unicasts_;
    }

319
protected:
320
    /// Socket used to send data.
321
    SocketCollection sockets_;
322

323
    /// Network interface name.
324
    std::string name_;
325

326
    /// Interface index (a value that uniquely indentifies an interface).
327
    int ifindex_;
328

329
    /// List of assigned addresses.
330
    AddressCollection addrs_;
331

332
333
334
    /// List of unicast addresses the server should listen on
    AddressCollection unicasts_;

335
    /// Link-layer address.
336
    uint8_t mac_[MAX_MAC_LEN];
337

338
    /// Length of link-layer address (usually 6).
339
    size_t mac_len_;
340

341
    /// Hardware type.
342
    uint16_t hardware_type_;
343

344
345
346
public:
    /// @todo: Make those fields protected once we start supporting more
    /// than just Linux
347

348
    /// Specifies if selected interface is loopback.
349
    bool flag_loopback_;
350

351
    /// Specifies if selected interface is up.
352
    bool flag_up_;
353

354
355
    /// Flag specifies if selected interface is running
    /// (e.g. cable plugged in, wifi associated).
356
    bool flag_running_;
357

358
    /// Flag specifies if selected interface is multicast capable.
359
    bool flag_multicast_;
360

361
    /// Flag specifies if selected interface is broadcast capable.
362
    bool flag_broadcast_;
363

364
365
    /// Interface flags (this value is as is returned by OS,
    /// it may mean different things on different OSes).
366
    uint32_t flags_;
367

368
369
370
371
372
373
374
    /// Indicates that IPv4 sockets should (true) or should not (false)
    /// be opened on this interface.
    bool inactive4_;

    /// Indicates that IPv6 sockets should (true) or should not (false)
    /// be opened on this interface.
    bool inactive6_;
375
};
376

377
378
379
380
381
382
383
/// @brief This type describes the callback function invoked when error occurs
/// in the IfaceMgr.
///
/// @param errmsg An error message.
typedef
boost::function<void(const std::string& errmsg)> IfaceMgrErrorMsgCallback;

384
/// @brief Handles network interfaces, transmission and reception.
385
386
387
388
389
390
391
///
/// IfaceMgr is an interface manager class that detects available network
/// interfaces, configured addresses, link-local addresses, and provides
/// API for using sockets.
///
class IfaceMgr : public boost::noncopyable {
public:
392
    /// Defines callback used when commands are received over control session.
393
394
    typedef void (*SessionCallback) (void);

395
396
397
398
399
400
401
402
403
    /// @brief Packet reception buffer size
    ///
    /// RFC3315 states that server responses may be
    /// fragmented if they are over MTU. There is no
    /// text whether client's packets may be larger
    /// than 1500. For now, we can assume that
    /// we don't support packets larger than 1500.
    static const uint32_t RCVBUFSIZE = 1500;

404
405
406
407
    // TODO performance improvement: we may change this into
    //      2 maps (ifindex-indexed and name-indexed) and
    //      also hide it (make it public make tests easier for now)

408
    /// Type that holds a list of interfaces.
409
    typedef std::list<Iface> IfaceCollection;
410
411
412
413
414
415
416

    /// IfaceMgr is a singleton class. This method returns reference
    /// to its sole instance.
    ///
    /// @return the only existing instance of interface manager
    static IfaceMgr& instance();

Marcin Siodelski's avatar
Marcin Siodelski committed
417
    /// @brief Check if packet be sent directly to the client having no address.
418
419
420
421
422
423
424
    ///
    /// Checks if IfaceMgr can send DHCPv4 packet to the client
    /// who hasn't got address assigned. If this is not supported
    /// broadcast address should be used to send response to
    /// the client.
    ///
    /// @return true if direct response is supported.
425
    bool isDirectResponseSupported() const;
426

427
428
429
430
431
432
433
    /// @brief Returns interface with specified interface index
    ///
    /// @param ifindex index of searched interface
    ///
    /// @return interface with requested index (or NULL if no such
    ///         interface is present)
    ///
434
    Iface* getIface(int ifindex);
435
436
437
438
439
440
441
442
443
444
445

    /// @brief Returns interface with specified interface name
    ///
    /// @param ifname name of searched interface
    ///
    /// @return interface with requested name (or NULL if no such
    ///         interface is present)
    ///
    Iface*
    getIface(const std::string& ifname);

Tomek Mrugalski's avatar
Tomek Mrugalski committed
446
447
    /// @brief Returns container with all interfaces.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
448
449
450
451
    /// This reference is only valid as long as IfaceMgr is valid. However,
    /// since IfaceMgr is a singleton and is expected to be destroyed after
    /// main() function completes, you should not worry much about this.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
452
453
454
    /// @return container with all interfaces.
    const IfaceCollection& getIfaces() { return ifaces_; }

455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
    ///
    /// This method takes Pkt6 (see overloaded implementation that takes
    /// Pkt4) and chooses appropriate socket to send it. This method
    /// may throw BadValue if specified packet does not have outbound
    /// interface specified, no such interface exists, or specified
    /// interface does not have any appropriate sockets open.
    ///
    /// @param pkt a packet to be transmitted
    ///
    /// @return a socket descriptor
    uint16_t getSocket(const isc::dhcp::Pkt6& pkt);

    /// @brief Return most suitable socket for transmitting specified IPv6 packet.
    ///
    /// This method takes Pkt4 (see overloaded implementation that takes
    /// Pkt6) and chooses appropriate socket to send it. This method
    /// may throw BadValue if specified packet does not have outbound
    /// interface specified, no such interface exists, or specified
    /// interface does not have any appropriate sockets open.
    ///
    /// @param pkt a packet to be transmitted
    ///
    /// @return a socket descriptor
    uint16_t getSocket(const isc::dhcp::Pkt4& pkt);

481
    /// Debugging method that prints out all available interfaces.
482
483
    ///
    /// @param out specifies stream to print list of interfaces to
484
    void printIfaces(std::ostream& out = std::cout);
485

Tomek Mrugalski's avatar
Tomek Mrugalski committed
486
    /// @brief Sends an IPv6 packet.
487
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
488
    /// Sends an IPv6 packet. All parameters for actual transmission are specified in
489
490
    /// Pkt6 structure itself. That includes destination address, src/dst port
    /// and interface over which data will be sent.
491
492
493
    ///
    /// @param pkt packet to be sent
    ///
494
495
    /// @throw isc::BadValue if invalid interface specified in the packet.
    /// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
496
    /// @return true if sending was successful
Tomek Mrugalski's avatar
Tomek Mrugalski committed
497
    bool send(const Pkt6Ptr& pkt);
498

Tomek Mrugalski's avatar
Tomek Mrugalski committed
499
500
501
502
503
504
505
506
    /// @brief Sends an IPv4 packet.
    ///
    /// Sends an IPv4 packet. All parameters for actual transmission are specified
    /// in Pkt4 structure itself. That includes destination address, src/dst
    /// port and interface over which data will be sent.
    ///
    /// @param pkt a packet to be sent
    ///
507
508
    /// @throw isc::BadValue if invalid interface specified in the packet.
    /// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
509
    /// @return true if sending was successful
Tomek Mrugalski's avatar
Tomek Mrugalski committed
510
    bool send(const Pkt4Ptr& pkt);
511

Tomek Mrugalski's avatar
Tomek Mrugalski committed
512
    /// @brief Tries to receive IPv6 packet over open IPv6 sockets.
513
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
514
    /// Attempts to receive a single IPv6 packet of any of the open IPv6 sockets.
515
516
517
    /// If reception is successful and all information about its sender
    /// are obtained, Pkt6 object is created and returned.
    ///
518
519
520
    /// TODO Start using select() and add timeout to be able
    /// to not wait infinitely, but rather do something useful
    /// (e.g. remove expired leases)
521
    ///
522
523
524
    /// @param timeout_sec specifies integral part of the timeout (in seconds)
    /// @param timeout_usec specifies fractional part of the timeout
    /// (in microseconds)
525
    ///
526
    /// @throw isc::BadValue if timeout_usec is greater than one million
527
    /// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
528
    /// @return Pkt6 object representing received packet (or NULL)
529
    Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
530

Tomek Mrugalski's avatar
Tomek Mrugalski committed
531
532
533
534
535
536
    /// @brief Tries to receive IPv4 packet over open IPv4 sockets.
    ///
    /// Attempts to receive a single IPv4 packet of any of the open IPv4 sockets.
    /// If reception is successful and all information about its sender
    /// are obtained, Pkt4 object is created and returned.
    ///
537
538
539
    /// @param timeout_sec specifies integral part of the timeout (in seconds)
    /// @param timeout_usec specifies fractional part of the timeout
    /// (in microseconds)
Tomek Mrugalski's avatar
Tomek Mrugalski committed
540
    ///
541
    /// @throw isc::BadValue if timeout_usec is greater than one million
542
    /// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
543
    /// @return Pkt4 object representing received packet (or NULL)
544
    Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
545

546
547
548
549
550
551
552
553
    /// Opens UDP/IP socket and binds it to address, interface and port.
    ///
    /// Specific type of socket (UDP/IPv4 or UDP/IPv6) depends on passed addr
    /// family.
    ///
    /// @param ifname name of the interface
    /// @param addr address to be bound.
    /// @param port UDP port.
Marcin Siodelski's avatar
Marcin Siodelski committed
554
555
556
557
    /// @param receive_bcast configure IPv4 socket to receive broadcast messages.
    /// This parameter is ignored for IPv6 sockets.
    /// @param send_bcast configure IPv4 socket to send broadcast messages.
    /// This parameter is ignored for IPv6 sockets.
558
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
559
560
561
    /// Method will throw if socket creation, socket binding or multicast
    /// join fails.
    ///
562
    /// @return socket descriptor, if socket creation, binding and multicast
Tomek Mrugalski's avatar
Tomek Mrugalski committed
563
    /// group join were all successful.
564
    int openSocket(const std::string& ifname,
565
                   const isc::asiolink::IOAddress& addr,
Marcin Siodelski's avatar
Marcin Siodelski committed
566
567
568
                   const uint16_t port,
                   const bool receive_bcast = false,
                   const bool send_bcast = false);
569

570
571
    /// @brief Opens UDP/IP socket and binds it to interface specified.
    ///
572
573
574
575
    /// This method differs from \ref openSocket in that it does not require
    /// the specification of a local address to which socket will be bound.
    /// Instead, the method searches through the addresses on the specified
    /// interface and selects one that matches the address family.
576
577
578
    ///
    /// @param ifname name of the interface
    /// @param port UDP port
579
    /// @param family address family (AF_INET or AF_INET6)
580
581
    /// @return socket descriptor, if socket creation, binding and multicast
    /// group join were all successful.
582
    /// @throw isc::Unexpected if failed to create and bind socket.
583
584
    /// @throw isc::BadValue if there is no address on specified interface
    /// that belongs to given family.
585
586
    int openSocketFromIface(const std::string& ifname,
                            const uint16_t port,
587
588
                            const uint8_t family);

589
590
    /// @brief Opens UDP/IP socket and binds to address specified
    ///
591
592
    /// This methods differs from \ref openSocket in that it does not require
    /// the specification of the interface to which the socket will be bound.
593
594
595
596
597
    ///
    /// @param addr address to be bound
    /// @param port UDP port
    /// @return socket descriptor, if socket creation, binding and multicast
    /// group join were all successful.
598
    /// @throw isc::Unexpected if failed to create and bind socket
599
600
    /// @throw isc::BadValue if specified address is not available on
    /// any interface
601
602
603
604
605
    int openSocketFromAddress(const isc::asiolink::IOAddress& addr,
                              const uint16_t port);

    /// @brief Opens UDP/IP socket to be used to connect to remote address
    ///
606
607
608
609
    /// This method identifies the local address to be used to connect to the
    /// remote address specified as argument.  Once the local address is
    /// identified, \ref openSocket is called to open a socket and bind it to
    /// the interface, address and port.
610
611
612
613
614
    ///
    /// @param remote_addr remote address to connect to
    /// @param port UDP port
    /// @return socket descriptor, if socket creation, binding and multicast
    /// group join were all successful.
615
    /// @throw isc::Unexpected if failed to create and bind socket
616
617
    int openSocketFromRemoteAddress(const isc::asiolink::IOAddress& remote_addr,
                                    const uint16_t port);
618

619

Tomek Mrugalski's avatar
Tomek Mrugalski committed
620
621
    /// Opens IPv6 sockets on detected interfaces.
    ///
622
623
624
625
626
627
628
629
630
631
632
633
    /// @todo This function will throw an exception immediately when a socket
    /// fails to open. This is undersired behavior because it will preclude
    /// other sockets from opening. We should strive to provide similar mechanism
    /// that has been introduced for V4 sockets. If socket creation fails the
    /// appropriate error handler is called and once the handler returns the
    /// function contnues to open other sockets. The change in the IfaceMgr
    /// is quite straight forward and it is proven to work for V4. However,
    /// unit testing it is a bit involved, because for unit testing we need
    /// a replacement of the openSocket6 function which will mimic the
    /// behavior of the real socket opening. For the V4 we have the means to
    /// to achieve that with the replaceable PktFilter class. For V6, the
    /// implementation is hardcoded in the openSocket6.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
634
635
    ///
    /// @param port specifies port number (usually DHCP6_SERVER_PORT)
636
    ///
637
    /// @throw SocketOpenFailure if tried and failed to open socket.
638
    /// @return true if any sockets were open
Tomek Mrugalski's avatar
Tomek Mrugalski committed
639
    bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
640

641
642
    /// Opens IPv4 sockets on detected interfaces.
    ///
643
    /// @param port specifies port number (usually DHCP4_SERVER_PORT)
644
    /// @param use_bcast configure sockets to support broadcast messages.
645
646
647
648
649
650
    /// @param error_handler A pointer to a callback function which is called
    /// by the openSockets4 when it fails to open a socket. This parameter
    /// can be NULL to indicate that the callback should not be used. In such
    /// case the @c isc::dhcp::SocketConfigError exception is thrown instead.
    /// When a callback is installed the function will continue when callback
    /// returns control.
651
652
653
    ///
    /// @throw SocketOpenFailure if tried and failed to open socket and callback
    /// function hasn't been specified.
654
    /// @return true if any sockets were open
655
    bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT,
656
                      const bool use_bcast = true,
657
                      IfaceMgrErrorMsgCallback error_handler = NULL);
658

Marcin Siodelski's avatar
Marcin Siodelski committed
659
    /// @brief Closes all open sockets.
660
    /// Is used in destructor, but also from Dhcpv4Srv and Dhcpv6Srv classes.
Marcin Siodelski's avatar
Marcin Siodelski committed
661
    void closeSockets();
662

663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
    /// @brief Closes all IPv4 or IPv6 sockets.
    ///
    /// This function closes sockets of the specific 'type' and closes them.
    /// The 'type' of the socket indicates whether it is used to send IPv4
    /// or IPv6 packets. The allowed values of the parameter are AF_INET and
    /// AF_INET6 for IPv4 and IPv6 packets respectively. It is important
    /// to realize that the actual types of sockets may be different than
    /// AF_INET for IPv4 packets. This is because, historically the IfaceMgr
    /// always used AF_INET sockets for IPv4 traffic. This is no longer the
    /// case when the Direct IPv4 traffic must be supported. In order to support
    /// direct traffic, the IfaceMgr operates on raw sockets, e.g. AF_PACKET
    /// family sockets on Linux.
    ///
    /// @todo Replace the AF_INET and AF_INET6 values with an enum
    /// which will not be confused with the actual socket type.
    ///
    /// @param family type of the sockets to be closed (AF_INET or AF_INET6)
    ///
    /// @throw BadValue if family value is different than AF_INET or AF_INET6.
    void closeSockets(const uint16_t family);

684
    /// @brief Returns number of detected interfaces.
685
686
687
688
    ///
    /// @return number of detected interfaces
    uint16_t countIfaces() { return ifaces_.size(); }

689
690
691
692
693
694
695
696
697
698
699
700
    /// @brief Sets session socket and a callback
    ///
    /// Specifies session socket and a callback that will be called
    /// when data will be received over that socket.
    ///
    /// @param socketfd socket descriptor
    /// @param callback callback function
    void set_session_socket(int socketfd, SessionCallback callback) {
        session_socket_ = socketfd;
        session_callback_ = callback;
    }

Marcin Siodelski's avatar
Marcin Siodelski committed
701
702
703
704
705
    /// @brief Set Packet Filter object to handle send/receive packets.
    ///
    /// Packet Filters expose low-level functions handling sockets opening
    /// and sending/receiving packets through those sockets. This function
    /// sets custom Packet Filter (represented by a class derived from PktFilter)
Marcin Siodelski's avatar
Marcin Siodelski committed
706
    /// to be used by IfaceMgr. Note that there must be no IPv4 sockets open
707
708
    /// when this function is called. Call closeSockets(AF_INET) to close
    /// all hanging IPv4 sockets opened by the current packet filter object.
Marcin Siodelski's avatar
Marcin Siodelski committed
709
710
711
712
713
    ///
    /// @param packet_filter new packet filter to be used by IfaceMgr to send/receive
    /// packets and open sockets.
    ///
    /// @throw InvalidPacketFilter if provided packet filter object is NULL.
714
    /// @throw PacketFilterChangeDenied if there are open IPv4 sockets
715
    void setPacketFilter(const PktFilterPtr& packet_filter);
716

717
718
719
    /// @brief Set Packet Filter object to handle send/receive packets.
    ///
    /// This function sets Packet Filter object to be used by IfaceMgr,
Marcin Siodelski's avatar
Marcin Siodelski committed
720
721
722
723
724
725
726
727
728
    /// appropriate for the current OS. Setting the argument to 'true'
    /// indicates that function should set a packet filter class
    /// which supports direct responses to clients having no address
    /// assigned yet. Filters picked by this function will vary, depending
    /// on the OS being used. There is no guarantee that there is an
    /// implementation that supports this feature on a particular OS.
    /// If there isn't, the PktFilterInet object will be set. If the
    /// argument is set to 'false', PktFilterInet object instance will
    /// be set as the Packet Filter regrdaless of the OS type.
729
730
    ///
    /// @param direct_response_desired specifies whether the Packet Filter
Marcin Siodelski's avatar
Marcin Siodelski committed
731
    /// object being set should support direct traffic to the host
732
733
734
    /// not having address assigned.
    void setMatchingPacketFilter(const bool direct_response_desired = false);

735
    /// A value of socket descriptor representing "not specified" state.
736
    static const int INVALID_SOCKET = -1;
737

738
739
740
741
742
743
    // don't use private, we need derived classes in tests
protected:

    /// @brief Protected constructor.
    ///
    /// Protected constructor. This is a singleton class. We don't want
Tomek Mrugalski's avatar
Tomek Mrugalski committed
744
    /// anyone to create instances of IfaceMgr. Use instance() method instead.
745
746
    IfaceMgr();

747
    virtual ~IfaceMgr();
748

Tomek Mrugalski's avatar
Tomek Mrugalski committed
749
750
751
752
753
754
755
756
757
    /// @brief Opens IPv4 socket.
    ///
    /// Please do not use this method directly. Use openSocket instead.
    ///
    /// This method may throw exception if socket creation fails.
    ///
    /// @param iface reference to interface structure.
    /// @param addr an address the created socket should be bound to
    /// @param port a port that created socket should be bound to
758
759
    /// @param receive_bcast configure socket to receive broadcast messages
    /// @param send_bcast configure socket to send broadcast messages.
Tomek Mrugalski's avatar
Tomek Mrugalski committed
760
761
    ///
    /// @return socket descriptor
Marcin Siodelski's avatar
Marcin Siodelski committed
762
763
764
    int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr,
                    const uint16_t port, const bool receive_bcast = false,
                    const bool send_bcast = false);
765

Tomek Mrugalski's avatar
Tomek Mrugalski committed
766
767
768
769
770
771
772
773
774
775
776
    /// @brief Opens IPv6 socket.
    ///
    /// Please do not use this method directly. Use openSocket instead.
    ///
    /// This method may throw exception if socket creation fails.
    ///
    /// @param iface reference to interface structure.
    /// @param addr an address the created socket should be bound to
    /// @param port a port that created socket should be bound to
    ///
    /// @return socket descriptor
Tomek Mrugalski's avatar
Tomek Mrugalski committed
777
    int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, uint16_t port);
778

Tomek Mrugalski's avatar
Tomek Mrugalski committed
779
780
781
    /// @brief Adds an interface to list of known interfaces.
    ///
    /// @param iface reference to Iface object.
782
783
784
785
    void addInterface(const Iface& iface) {
        ifaces_.push_back(iface);
    }

786
787
788
789
    /// @brief Detects network interfaces.
    ///
    /// This method will eventually detect available interfaces. For now
    /// it offers stub implementation. First interface name and link-local
790
    /// IPv6 address is read from interfaces.txt file.
791
792
793
    void
    detectIfaces();

794
795
796
797
798
    /// @brief Stub implementation of network interface detection.
    ///
    /// This implementations reads a single line from interfaces.txt file
    /// and pretends to detect such interface. First interface name and
    /// link-local IPv6 address or IPv4 address is read from the
799
    /// interfaces.txt file.
800
801
802
    void
    stubDetectIfaces();

803
804
805
806
    // TODO: having 2 maps (ifindex->iface and ifname->iface would)
    //      probably be better for performance reasons

    /// List of available interfaces
807
    IfaceCollection ifaces_;
808
809
810
811

    // TODO: Also keep this interface on Iface once interface detection
    // is implemented. We may need it e.g. to close all sockets on
    // specific interface
812
813
814
    //int recvsock_; // TODO: should be fd_set eventually, but we have only
    //int sendsock_; // 2 sockets for now. Will do for until next release

815
    // We can't use the same socket, as receiving socket
816
817
818
    // is bound to multicast address. And we all know what happens
    // to people who try to use multicast as source address.

819
    /// Length of the control_buf_ array
820
    size_t control_buf_len_;
821

822
    /// Control-buffer, used in transmission and reception.
823
824
    boost::scoped_array<char> control_buf_;

825
826
827
828
829
830
831
    /// @brief A wrapper for OS-specific operations before sending IPv4 packet
    ///
    /// @param m message header (will be later used for sendmsg() call)
    /// @param control_buf buffer to be used during transmission
    /// @param control_buf_len buffer length
    /// @param pkt packet to be sent
    void os_send4(struct msghdr& m, boost::scoped_array<char>& control_buf,
832
                  size_t control_buf_len, const Pkt4Ptr& pkt);
833
834
835
836
837
838
839
840
841

    /// @brief OS-specific operations during IPv4 packet reception
    ///
    /// @param m message header (was used during recvmsg() call)
    /// @param pkt packet received (some fields will be set here)
    ///
    /// @return true if successful, false otherwise
    bool os_receive4(struct msghdr& m, Pkt4Ptr& pkt);

842
    /// Socket descriptor of the session socket.
843
844
    int session_socket_;

845
    /// A callback that will be called when data arrives over session_socket_.
846
    SessionCallback session_callback_;
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
private:

    /// @brief Joins IPv6 multicast group on a socket.
    ///
    /// Socket must be created and bound to an address. Note that this
    /// address is different than the multicast address. For example DHCPv6
    /// server should bind its socket to link-local address (fe80::1234...)
    /// and later join ff02::1:2 multicast group.
    ///
    /// @param sock socket fd (socket must be bound)
    /// @param ifname interface name (for link-scoped multicast groups)
    /// @param mcast multicast address to join (e.g. "ff02::1:2")
    ///
    /// @return true if multicast join was successful
    ///
    bool
863
864
    joinMulticast(int sock, const std::string& ifname,
                  const std::string& mcast);
865

866
867
868
869
870
    /// @brief Identifies local network address to be used to
    /// connect to remote address.
    ///
    /// This method identifies local network address that can be used
    /// to connect to remote address specified.
871
    /// It first creates socket and makes attempt to connect
872
873
874
875
876
877
878
    /// to remote location via this socket. If connection
    /// is established successfully, the local address to which
    /// socket is bound is returned.
    ///
    /// @param remote_addr remote address to connect to
    /// @param port port to be used
    /// @return local address to be used to connect to remote address
879
    /// @throw isc::Unexpected if unable to identify local address
880
881
882
    isc::asiolink::IOAddress
    getLocalAddress(const isc::asiolink::IOAddress& remote_addr,
                    const uint16_t port);
883

884
885
886
887
888
889
890
891
892
893
894
895
896
    /// @brief Handles an error which occurs during operation on the socket.
    ///
    /// If the handler callback is specified (non-NULL), this handler is
    /// called and the specified error message is passed to it. If the
    /// handler is not specified, the @c isc::dhcpSocketConfigError exception
    /// is thrown with the specified message.
    ///
    /// @param errmsg An error message to be passed to a handlder function or
    /// to the @c isc::dhcp::SocketConfigError exception.
    /// @param handler An error handler function or NULL.
    void handleSocketConfigError(const std::string& errmsg,
                                 IfaceMgrErrorMsgCallback handler);

Marcin Siodelski's avatar
Marcin Siodelski committed
897
898
899
900
901
902
903
904
    /// Holds instance of a class derived from PktFilter, used by the
    /// IfaceMgr to open sockets and send/receive packets through these
    /// sockets. It is possible to supply custom object using
    /// setPacketFilter class. Various Packet Filters differ mainly by using
    /// different types of sockets, e.g. SOCK_DGRAM,  SOCK_RAW and different
    /// families, e.g. AF_INET, AF_PACKET etc. Another possible type of
    /// Packet Filter is the one used for unit testing, which doesn't
    /// open sockets but rather mimics their behavior (mock object).
905
    PktFilterPtr packet_filter_;
906
907
908
};

}; // namespace isc::dhcp
909
}; // namespace isc
910

911
#endif // IFACE_MGR_H