working with bits

Discussion in 'C++' started by iwasinnihon, Apr 11, 2007.

  1. iwasinnihon

    iwasinnihon Guest

    I am working on creating a DNS resolver. According to RPC 1035 a
    number of fields a certain number of bits long need to be sent with
    certain information in it. For example: a 1-bit field followed by a 4-
    bit field followed by 3 1-bit fields, followed by a 16-bit field. How
    do I create these fields and combine them to send to a dns server?
    iwasinnihon, Apr 11, 2007
    #1
    1. Advertising

  2. iwasinnihon wrote:
    > I am working on creating a DNS resolver. According to RPC 1035 a
    > number of fields a certain number of bits long need to be sent with
    > certain information in it. For example: a 1-bit field followed by a 4-
    > bit field followed by 3 1-bit fields, followed by a 16-bit field. How
    > do I create these fields and combine them to send to a dns server?
    >


    You can try to use bitfields but I'm not sure how portable that is.
    Last resort is to create the values by bit manipulation put it directly
    into a buffer.

    Do you have the specs handy ?
    Gianni Mariani, Apr 11, 2007
    #2
    1. Advertising

  3. On Apr 11, 5:33 pm, "iwasinnihon" <> wrote:
    > I am working on creating a DNS resolver. According to RPC 1035 a
    > number of fields a certain number of bits long need to be sent with
    > certain information in it. For example: a 1-bit field followed by a 4-
    > bit field followed by 3 1-bit fields, followed by a 16-bit field. How
    > do I create these fields and combine them to send to a dns server?


    Boost bitset might do the job:
    http://www.boost.org/libs/dynamic_bitset/dynamic_bitset.html

    --
    EventStudio 4.0 - http://www.EventHelix.com/EventStudio
    Model in Plain Text; Generate Sequence Diagrams in PDF/Word
    EventHelix.com, Apr 12, 2007
    #3
  4. iwasinnihon

    James Kanze Guest

    On Apr 11, 11:33 pm, "iwasinnihon" <> wrote:
    > I am working on creating a DNS resolver. According to RPC 1035 a
    > number of fields a certain number of bits long need to be sent with
    > certain information in it. For example: a 1-bit field followed by a 4-
    > bit field followed by 3 1-bit fields, followed by a 16-bit field. How
    > do I create these fields and combine them to send to a dns server?


    Use shifting (<< and >> operators), masking and or'ing (&, | and
    ~ operators).

    For example, for:
    +--+--+--+--+--+--+--+--+
    |QR| Opcode |AA|TC|RD|
    +--+--+--+--+--+--+--+--+

    unsigned char byte = (QR << 7)
    | (Opcode << 3)
    | (AA << 2)
    | (TC << 1)
    | RD ;

    if (and only if) the variables in question can only hold
    legitmate values (and have unsigned type, which they should).
    To extract:

    QR = (byte & 0x80) >> 7 ;
    Opcode = (byte & 0x78) >> 3 ;
    AA = (byte & 0x04) >> 2 ;
    TC = (byte & 0x02) >> 1 ;
    RD = byte & 0x01 ;

    If you just need to compare the value, you can skip the shift:

    if ( (byte & 0x80) != 0 ) ...
    or
    switch( byte & 0x78 ) {
    case 0 << 3 :
    // ...
    break ;
    case 1 << 3 :
    // ...
    }

    To make the code more readable, I'll generally define manifest
    constants along the lines of:
    int const QRmask = 0x80 ;
    int const QRshift = 7 ;
    int const Opcodemask = 0x78 ;
    int const Opcodeshift = 3 ;
    // ...

    Note that you'll have to do the same thing in reverse for
    entities larger than an octet:

    unsigned char buffer[ 4 ] ;
    buffer[ 0 ] = QDCOUNT >> 24 ;
    buffer[ 1 ] = QDCOUNT >> 16 ;
    buffer[ 2 ] = QDCOUNT >> 8 ;
    buffer[ 3 ] = QDCOUNT ;

    And to read:

    QDC0UNT = buffer[ 0 ] << 24
    | buffer[ 1 ] << 16
    | buffer[ 2 ] << 8
    | buffer[ 3 ] ;

    (Formally, even the above is not guaranteed to work in all
    cases, since it supposes 8 bit bytes, etc., and if QDC0UNT is
    signed, 2's complement. In practice, machines which don't fit
    this model are rare enough that I don't usually have to consider
    them. And I generally use the C types int32_t/uint32_t and
    int8_t/uint8_t, so that the code won't compile on a machine
    where this isn't the case.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 12, 2007
    #4
  5. iwasinnihon

    iwasinnihon Guest

    Does anyone know where I can find a simple example of a DNS resolver?
    iwasinnihon, Apr 12, 2007
    #5
  6. iwasinnihon wrote:
    > Does anyone know where I can find a simple example of a DNS resolver?
    >


    glibc ?
    Gianni Mariani, Apr 12, 2007
    #6
  7. iwasinnihon

    red floyd Guest

    red floyd, Apr 12, 2007
    #7
  8. iwasinnihon

    iwasinnihon Guest

    I am still working on this project (Creating a DNS resolver). My
    programming skills have a lot to be desired. I need to combine 4
    buffers together and then use the sendto() socket command to send the
    message to the DNS server. Here are my buffers. The message needs to
    be a char*.

    unsigned int header_buffer = (ID << 80) | (Flags.Flag << 64) |
    (QDCount << 48) | (ANCount << 32) | (NSCount << 16) | ARCount;
    unsigned char QNAME;
    unsigned __int16 QTYPE;
    unsigned __int16 QCLASS;

    I am at a loss as to how to combine these and then get it converted
    into a char* so that I can use sendto().

    Does anyone have any idea?
    iwasinnihon, Apr 18, 2007
    #8
  9. iwasinnihon

    Jerry Coffin Guest

    In article <>,
    says...
    > I am still working on this project (Creating a DNS resolver). My
    > programming skills have a lot to be desired. I need to combine 4
    > buffers together and then use the sendto() socket command to send the
    > message to the DNS server. Here are my buffers. The message needs to
    > be a char*.
    >
    > unsigned int header_buffer = (ID << 80) | (Flags.Flag << 64) |
    > (QDCount << 48) | (ANCount << 32) | (NSCount << 16) | ARCount;
    > unsigned char QNAME;
    > unsigned __int16 QTYPE;
    > unsigned __int16 QCLASS;
    >
    > I am at a loss as to how to combine these and then get it converted
    > into a char* so that I can use sendto().


    Typically you'd do something like:

    struct name_def {
    unsigned int header_buffer = (ID << 80) | // ...
    // (ID << 80)? Really?
    unsigned char QNAME;
    unsigned _int16 QTYPE;
    unsigned _int16 QCLASS;
    };

    name_def some_name;

    sendto(s, reinterpret_cast<char *>(&some_name), ...);

    You can also do the type-pun via a union -- in theory, this has a minor
    advantage, but AFAIK it's _purely_ theoretical. If you really want to
    get into the gory details, there's a thread from a few months back
    starting at:

    http://tinyurl.com/39ayvm

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Apr 18, 2007
    #9
  10. iwasinnihon

    Jerry Coffin Guest

    In article <>,
    says...
    [ ... ]

    > Typically you'd do something like:
    >
    > struct name_def {
    > unsigned int header_buffer = (ID << 80) | // ...
    > // (ID << 80)? Really?
    > unsigned char QNAME;
    > unsigned _int16 QTYPE;
    > unsigned _int16 QCLASS;
    > };


    Oops -- I should have pointed out that you'll have to either make
    header_buffer a const static member, or else do its initialization in a
    ctor intead of inline like this.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
    Jerry Coffin, Apr 18, 2007
    #10
  11. iwasinnihon

    James Kanze Guest

    On Apr 18, 5:16 am, Jerry Coffin <> wrote:
    > In article <>,
    > says...


    > > I am still working on this project (Creating a DNS resolver). My
    > > programming skills have a lot to be desired. I need to combine 4
    > > buffers together and then use the sendto() socket command to send the
    > > message to the DNS server. Here are my buffers. The message needs to
    > > be a char*.


    > > unsigned int header_buffer = (ID << 80) | (Flags.Flag << 64) |
    > > (QDCount << 48) | (ANCount << 32) | (NSCount << 16) | ARCount;


    I'm not sure what hardware you're working on, but it looks
    pretty exotic, if you have over 80 bits in an int.

    > > unsigned char QNAME;
    > > unsigned __int16 QTYPE;
    > > unsigned __int16 QCLASS;


    > > I am at a loss as to how to combine these and then get it converted
    > > into a char* so that I can use sendto().


    > Typically you'd do something like:


    > struct name_def {
    > unsigned int header_buffer = (ID << 80) | // ...
    > // (ID << 80)? Really?
    > unsigned char QNAME;
    > unsigned _int16 QTYPE;
    > unsigned _int16 QCLASS;
    > };


    I rather doubt that this would work either. The compiler will
    probably insert some padding between QNAME and QTYPE. And
    whether the internal format of __int16 corresponds to what is
    required on the line or not is not at all defined. (__int16
    looks like some old Microsoft stuff. In which case, he's
    probably on an Intel based PC, and the internal format does
    *not* correspond to line format.)

    In practice, you have to build up a byte buffer, byte by byte,
    as I explained in my earlier answer. And respect the external
    format in all cases; QNAME is in fact a string, in the format
    one byte length+characters; I suspect that it also has to be
    padded to align to either 2 or 4 bytes (but I've not verified in
    detail)---if not, QTYPE and QCLASS might be mis-aligned. At any
    rate, QNAME is a variable length field, so there's no way you
    can use a struct here, even if all internal fields had the
    correct format.

    The way I usually handle this sort of thing is with push_back,
    into an std::vector<char>; I then consider byte by byte what I
    have to insert. (Alignment can be handled using the % operator
    on v.size().) In some cases, where e.g. I have to insert the
    number of bytes in what follows, I'll simply note the current
    offset (v.size()), insert a placeholder, and then come back
    later and write the actual value. Finally, I'll write &v[0],
    v.size().

    Obviously, this requires a fairly good understanding of the
    lower levels of what is going on. I'd say that that is a
    pre-requisite, however, for implementing any Internet protocol.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 18, 2007
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. GGG
    Replies:
    10
    Views:
    12,510
    Donar
    Jul 6, 2006
  2. sarmin kho
    Replies:
    2
    Views:
    816
    A. Lloyd Flanagan
    Jun 15, 2004
  3. Miki Tebeka
    Replies:
    1
    Views:
    432
    Marcin 'Qrczak' Kowalczyk
    Jun 14, 2004
  4. sergey

    "casting" bits to bits?

    sergey, Nov 8, 2006, in forum: VHDL
    Replies:
    1
    Views:
    689
    sergey
    Nov 8, 2006
  5. Tomás

    Value Bits Vs Object Bits

    Tomás, Jun 2, 2006, in forum: C Programming
    Replies:
    13
    Views:
    533
    Hallvard B Furuseth
    Jul 1, 2006
Loading...

Share This Page