GNU Radio 3.4.2 C++ API
eth_buffer.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2008 Free Software Foundation, Inc.
00004  * 
00005  * This file is part of GNU Radio
00006  * 
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3, or (at your option)
00010  * any later version.
00011  * 
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License along
00018  * with this program; if not, write to the Free Software Foundation, Inc.,
00019  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  */
00021 #ifndef INCLUDED_USRP2_ETH_BUFFER_H
00022 #define INCLUDED_USRP2_ETH_BUFFER_H
00023 
00024 #include "pktfilter.h"
00025 #include <eth_common.h>
00026 #include <boost/utility.hpp>
00027 #include <vector>
00028 #include <memory>
00029 #include <stdint.h>
00030 
00031 namespace usrp2 {
00032 
00033   class ethernet;
00034   class data_handler;
00035 
00036   /*!
00037    * \brief high-performance interface to send and receive raw
00038    * ethernet frames with out-of-order retirement of received frames.
00039    *
00040    * On many systems it should be possible to implement this on top of libpcap
00041    *
00042    * \internal
00043    */
00044   class eth_buffer : boost::noncopyable 
00045   {
00046     
00047     int           d_fd;                 // socket file descriptor
00048     uint8_t       d_mac[6];             // our mac address
00049     bool          d_using_tpring;       // using kernel mapped packet ring
00050     size_t        d_buflen;             // length of our buffer
00051     uint8_t      *d_buf;                // packet ring
00052     unsigned int  d_frame_nr;           // max frames on ring
00053     size_t        d_frame_size;         // frame storage size
00054     unsigned int  d_head;               // pointer to next frame
00055 
00056     std::vector<uint8_t *>  d_ring;     // pointers into buffer
00057     std::auto_ptr<ethernet> d_ethernet; // our underlying interface
00058   
00059     bool frame_available();
00060 
00061     void inc_head()
00062     {
00063       if (d_head + 1 >= d_frame_nr)
00064         d_head = 0;
00065       else
00066         d_head = d_head + 1;
00067     }
00068 
00069 
00070   public:
00071 
00072     enum result {
00073       EB_OK,            //< everything's fine
00074       EB_ERROR,         //< A non-recoverable error occurred
00075       EB_WOULD_BLOCK,   //< A timeout of 0 was specified and nothing was ready
00076       EB_TIMED_OUT,     //< The timeout expired before anything was ready
00077     };
00078 
00079     static const unsigned int MAX_PKTLEN = 1512;
00080     static const unsigned int MIN_PKTLEN = 64;
00081 
00082     /*!
00083      * \param rx_bufsize is a hint as to the number of bytes of memory
00084      * to allocate for received ethernet frames (0 -> reasonable default)
00085      */
00086     eth_buffer(size_t rx_bufsize = 0);
00087     ~eth_buffer();
00088     
00089     /*!
00090      * \brief open the specified interface
00091      *
00092      * \param ifname ethernet interface name, e.g., "eth0"
00093      * \param protocol is the ethertype protocol number in network order.
00094      *    Use 0 to receive all protocols.
00095      */
00096     bool open(const std::string &ifname, int protocol);
00097 
00098     /*!
00099      * \brief close the interface
00100      */
00101     bool close();
00102 
00103     /*!
00104      * \brief attach packet filter to socket to restrict which packets read sees.
00105      * \param pf        the packet filter
00106      */
00107     bool attach_pktfilter(pktfilter *pf);
00108 
00109     /*!
00110      * \brief return 6 byte string containing our MAC address
00111      */
00112     const uint8_t *mac() const { return d_mac; }
00113 
00114     /*!
00115      * \brief Call \p f for each frame in the receive buffer.
00116      * \param f is the frame data handler
00117      * \param timeout (in ms) controls behavior when there are no frames to read
00118      *
00119      * If \p timeout is 0, rx_frames will not wait for frames if none are 
00120      * available, and f will not be invoked.  If \p timeout is -1 (the 
00121      * default), rx_frames will block indefinitely until frames are 
00122      * available.  If \p timeout is positive, it indicates the number of
00123      * milliseconds to wait for a frame to become available.  Once the
00124      * timeout has expired, rx_frames will return, f never having been 
00125      * invoked.
00126      *
00127      * \p f will be called on each ethernet frame that is available.
00128      * \p f returns a bit mask with one of the following set or cleared:
00129      * 
00130      * data_handler::KEEP  - hold onto the frame and present it again during 
00131      *                       the next call to rx_frames, otherwise discard it
00132      *
00133      * data_handler::DONE -  return from rx_frames now even though more frames
00134      *                       might be available; otherwise continue if more 
00135      *                       frames are ready.
00136      *
00137      * The idea of holding onto a frame for the next iteration allows
00138      * the caller to scan the received packet stream for particular
00139      * classes of frames (such as command replies) leaving the rest
00140      * intact.  On the next call all kept frames, followed by any new
00141      * frames received, will be presented in order to \p f.  
00142      * See usrp2.cc for an example of the pattern.
00143      *
00144      * \returns EB_OK if at least one frame was received
00145      * \returns EB_WOULD_BLOCK if \p timeout is 0 and the call would have blocked
00146      * \returns EB_TIMED_OUT if timeout occurred
00147      * \returns EB_ERROR if there was an unrecoverable error.
00148      */
00149     result rx_frames(data_handler *f, int timeout=-1);
00150 
00151     /*
00152      * \brief Release frame from buffer
00153      *
00154      * Call to release a frame previously held by a data_handler::KEEP.
00155      * The pointer may be offset from the base of the frame up to its length.
00156      */
00157     void release_frame(void *p);
00158 
00159     /*
00160      * \brief Write an ethernet frame to the interface.
00161      *
00162      * \param base points to the beginning of the frame (the 14-byte ethernet header).
00163      * \param len is the length of the frame in bytes.
00164      * \param flags is 0 or the bitwise-or of values from eth_flags
00165      *
00166      * The frame must begin with a 14-byte ethernet header.
00167      *
00168      * \returns EB_OK if the frame was successfully enqueued.
00169      * \returns EB_WOULD_BLOCK if flags contains EF_DONT_WAIT and the call would have blocked.
00170      * \returns EB_ERROR if there was an unrecoverable error.
00171      */
00172     result tx_frame(const void *base, size_t len, int flags=0);
00173 
00174     /*
00175      * \brief Write an ethernet frame to the interface using scatter/gather.
00176      *
00177      * \param iov points to an array of iovec structs
00178      * \param iovcnt is the number of entries
00179      * \param flags is 0 or the bitwise-or of values from eth_flags
00180      *
00181      * The frame must begin with a 14-byte ethernet header.
00182      *
00183      * \returns EB_OK if the frame was successfully enqueued.
00184      * \returns EB_WOULD_BLOCK if flags contains EF_DONT_WAIT and the call would have blocked.
00185      * \returns EB_ERROR if there was an unrecoverable error.
00186      */
00187     result tx_framev(const eth_iovec *iov, int iovcnt, int flags=0);
00188 
00189     /*
00190      * \brief Returns maximum possible number of frames in buffer
00191      */
00192     unsigned int max_frames() const { return d_frame_nr; }
00193 
00194   };
00195 
00196 };  // namespace usrp2
00197 
00198 #endif /* INCLUDED_USRP2_ETH_BUFFER_H */