design inquiry

Discussion in 'C Programming' started by Bill Cunningham, Nov 21, 2010.

  1. I have a header that is such and I am not quite sure what the "best way"
    in C to implement it is.

    opcode | filename | 1 byte pad | mode | 1 byte pad

    I have consider malloc() and a struct as such

    struct tftp{
    char padd="0";
    short opcode;
    char * mode;
    char *filename;
    };

    Now I don't like the way "mode" and "filename" is simply a string. Is
    this the best design or does anyone have any better ideas for a hobbyist
    wannabe? Xenophobes need not apply

    Bill
    Bill Cunningham, Nov 21, 2010
    #1
    1. Advertising

  2. Bill Cunningham

    Lew Pitcher Guest

    On November 21, 2010 16:10, in comp.lang.c, lid wrote:

    > I have a header that is such and I am not quite sure what the "best
    > way"
    > in C to implement it is.
    >
    > opcode | filename | 1 byte pad | mode | 1 byte pad
    >
    > I have consider malloc() and a struct as such
    >
    > struct tftp{
    > char padd="0";
    > short opcode;
    > char * mode;
    > char *filename;
    > };
    >
    > Now I don't like the way "mode" and "filename" is simply a string.


    Sorry, Bill, but in the above struct, neither mode nor filename are strings.

    > Is
    > this the best design or does anyone have any better ideas for a hobbyist
    > wannabe?


    "Best design" in what sense?

    Given what you have presented us with (and some assumptions about it), I'd
    have to say "No". Your struct tftp {} is not the "best design" to implement
    a sequence of
    opcode | filename | 1 byte pad | mode | 1 byte pad

    But, then again, I don't know what you intended that sequence to actually
    represent, nor do I know how you intended to use your struct tftp {}

    Perhaps if you explained your goal a bit more, it would be clearer to me.

    > Xenophobes need not apply


    OK.

    FWIW, if your sequence of
    opcode | filename | 1 byte pad | mode | 1 byte pad
    is supposed to represent how you want your structure to store data, then you
    probably should lay the structure out in that manner. Something like
    struct tftp {
    short opcode;
    char filename[]; /* FIXME - Need to specify exact length of array */
    char pad1;
    char mode[]; /* FIXME - Need to specify exact length of array */
    char pad2;
    };

    OTOH, if you simply want to store information derived from or destined for
    that sequence, you could lay out your structure in a different manner:
    struct tftp {
    short opcode;
    char *filename; /* points to space where filename contents are found */
    char *mode; /* points to space where mode contents are found */
    };

    So, what is it you are trying to do?

    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 21, 2010
    #2
    1. Advertising

  3. Lew Pitcher wrote:

    > So, what is it you are trying to do?


    From RFC 1350...

    Sollins [Page 5]

    RFC 1350 TFTP Revision 2 July 1992


    2 bytes string 1 byte string 1 byte
    ------------------------------------------------
    | Opcode | Filename | 0 | Mode | 0 |
    ------------------------------------------------

    ***
    See how the "Filename" and "Mode" areas in this packet are simply
    "string"? I'd be more comfortable with something like char filenam[20]; or
    the like.
    ***

    Figure 5-1: RRQ/WRQ packet


    RRQ and WRQ packets (opcodes 1 and 2 respectively) have the format
    shown in Figure 5-1. The file name is a sequence of bytes in
    netascii terminated by a zero byte. The mode field contains the
    string "netascii", "octet", or "mail" (or any combination of upper
    and lower case, such as "NETASCII", NetAscii", etc.) in netascii
    indicating the three modes defined in the protocol. A host which
    receives netascii mode data must translate the data to its own
    format. Octet mode is used to transfer a file that is in the 8-bit
    format of the machine from which the file is being transferred. It
    is assumed that each type of machine has a single 8-bit format that
    is more common, and that that format is chosen. For example, on a
    DEC-20, a 36 bit machine, this is four 8-bit bytes to a word with
    four bits of breakage. If a host receives a octet file and then
    returns it, the returned file must be identical to the original.
    Mail mode uses the name of a mail recipient in place of a file and
    must begin with a WRQ. Otherwise it is identical to netascii mode.
    The mail recipient string should be of the form "username" or
    "username@hostname". If the second form is used, it allows the
    option of mail forwarding by a relay computer.

    The discussion above assumes that both the sender and recipient are
    operating in the same mode, but there is no reason that this has to
    be the case. For example, one might build a storage server. There
    is no reason that such a machine needs to translate netascii into its
    own form of text. Rather, the sender might send files in netascii,
    but the storage server might simply store them without translation in
    8-bit format. Another such situation is a problem that currently
    exists on DEC-20 systems. Neither netascii nor octet accesses all
    the bits in a word. One might create a special mode for such a
    machine which read all the bits in a word, but in which the receiver
    stored the information in 8-bit format. When such a file is
    retrieved from the storage site, it must be restored to its original
    form to be useful, so the reverse mode must also be implemented. The
    user site will have to remember some information to achieve this. In
    both of these examples, the request packets would specify octet mode
    to the foreign host, but the local host would be in some other mode.
    No such machine or application specific modes have been specified in
    TFTP, but one would be compatible with this specification.

    It is also possible to define other modes for cooperating pairs of
    -----------------
    Code a TFTP header and implement it with *inx's socket API. The socket
    API I understand a little more. This protocol runs on UDP.
    Bill Cunningham, Nov 21, 2010
    #3
  4. Bill Cunningham

    Lew Pitcher Guest

    On November 21, 2010 16:56, in comp.lang.c, lid wrote:

    > Lew Pitcher wrote:
    >
    >> So, what is it you are trying to do?

    >
    > From RFC 1350...
    >
    > Sollins [Page 5]
    >
    > RFC 1350 TFTP Revision 2 July 1992
    >
    >
    > 2 bytes string 1 byte string 1 byte
    > ------------------------------------------------
    > | Opcode | Filename | 0 | Mode | 0 |
    > ------------------------------------------------
    >
    > ***
    > See how the "Filename" and "Mode" areas in this packet are simply
    > "string"? I'd be more comfortable with something like char filenam[20]; or
    > the like.
    > ***


    You may be more comfortable with a fixed-length Filename and Mode, but that
    would violate the protocol.

    [snip]
    > RRQ and WRQ packets (opcodes 1 and 2 respectively) have the format
    > shown in Figure 5-1. The file name is a sequence of bytes in
    > netascii terminated by a zero byte. The mode field contains the
    > string "netascii", "octet", or "mail" (or any combination of upper
    > and lower case, such as "NETASCII", NetAscii", etc.) in netascii
    > indicating the three modes defined in the protocol.


    The above writeup indicates that both Filename and Mode are variable-length
    components. You /might/ be able to do this with C99 VLAs (pedants? your
    opinion?), but otherwise, your structure cannot /exactly/ represent this
    packet.

    If you use a structure to /organize/ this data (rather than as an output or
    input buffer), you could
    struct tftp {
    short mode;
    char *filename; /* points to the filename string */
    char mode[9]; /* can contain any of the valid mode strings */
    };

    However, if you intend to use the structure as an I/O buffer, then you'll
    have to define it fairly generically, and do some work in logic...

    struct tftp {
    unsigned char opcode[2]; /* 2 octets for mode, in network byte order */
    char data[]; /* FIXME - need to specify exact length of array */
    };

    /* your logic....*/
    FILE *connection;
    struct tftp header;
    int src, dst;
    int length;

    /* set header opcode from opcodeValue */
    header.opcode[1] = opcodeValue%256;
    header.opcode[0] = opcodeValue/256;

    /* set header filename from fileName string */
    src = dst = 0;
    do
    header.data[dst++] = fileName[src];
    while (fileName[src++] != 0);

    /* set header Mode from modeName string */
    src = 0;
    do
    header.data[dst++] = modeName[src];
    while (modeName[src++] != 0);

    /* write out the header */
    fwrite(header,sizeof(header.opcode) + dst, 1, connection);


    [snip]
    > -----------------
    > Code a TFTP header and implement it with *inx's socket API. The socket
    > API I understand a little more. This protocol runs on UDP.
    >
    >


    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 21, 2010
    #4
  5. Lew Pitcher wrote:
    > On November 21, 2010 16:56, in comp.lang.c, lid
    > wrote:
    >
    >> Lew Pitcher wrote:
    >>
    >>> So, what is it you are trying to do?

    >>
    >> From RFC 1350...
    >>
    >> Sollins
    >> [Page 5]
    >>
    >> RFC 1350 TFTP Revision 2 July
    >> 1992
    >>
    >>
    >> 2 bytes string 1 byte string 1 byte
    >> ------------------------------------------------
    >> | Opcode | Filename | 0 | Mode | 0 |
    >> ------------------------------------------------
    >>
    >> ***
    >> See how the "Filename" and "Mode" areas in this packet are simply
    >> "string"? I'd be more comfortable with something like char
    >> filenam[20]; or the like.
    >> ***

    >
    > You may be more comfortable with a fixed-length Filename and Mode,
    > but that would violate the protocol.
    >
    > [snip]
    >> RRQ and WRQ packets (opcodes 1 and 2 respectively) have the format
    >> shown in Figure 5-1. The file name is a sequence of bytes in
    >> netascii terminated by a zero byte. The mode field contains the
    >> string "netascii", "octet", or "mail" (or any combination of upper
    >> and lower case, such as "NETASCII", NetAscii", etc.) in netascii
    >> indicating the three modes defined in the protocol.

    >
    > The above writeup indicates that both Filename and Mode are
    > variable-length components. You /might/ be able to do this with C99
    > VLAs (pedants? your opinion?), but otherwise, your structure cannot
    > /exactly/ represent this packet.
    >
    > If you use a structure to /organize/ this data (rather than as an
    > output or input buffer), you could
    > struct tftp {
    > short mode;
    > char *filename; /* points to the filename string */
    > char mode[9]; /* can contain any of the valid mode strings */
    > };


    That's what I intended was for storage.

    >
    > However, if you intend to use the structure as an I/O buffer, then
    > you'll have to define it fairly generically, and do some work in
    > logic...
    >
    > struct tftp {
    > unsigned char opcode[2]; /* 2 octets for mode, in network byte
    > order */


    Why unsigned?

    char data[]; /* FIXME - need to specify exact
    > length of array */ };
    >
    > /* your logic....*/
    > FILE *connection;
    > struct tftp header;
    > int src, dst;
    > int length;
    >
    > /* set header opcode from opcodeValue */
    > header.opcode[1] = opcodeValue%256;
    > header.opcode[0] = opcodeValue/256;


    What's the above? % for modulo? and / for division by 256?

    > /* set header filename from fileName string */
    > src = dst = 0;
    > do
    > header.data[dst++] = fileName[src];
    > while (fileName[src++] != 0);
    >
    > /* set header Mode from modeName string */
    > src = 0;
    > do
    > header.data[dst++] = modeName[src];
    > while (modeName[src++] != 0);


    The two do functions above I don't quite understand. VLAs? Do you mean
    variable length addresses? C99 or 89 whichever's best to implement this.

    > /* write out the header */
    > fwrite(header,sizeof(header.opcode) + dst, 1, connection);


    understood the fwrite.

    Bill
    Bill Cunningham, Nov 21, 2010
    #5
  6. Bill Cunningham

    Lew Pitcher Guest

    On November 21, 2010 17:38, in comp.lang.c, lid wrote:

    > Lew Pitcher wrote:
    >> On November 21, 2010 16:56, in comp.lang.c, lid
    >> wrote:
    >>
    >>> Lew Pitcher wrote:
    >>>
    >>>> So, what is it you are trying to do?
    >>>
    >>> From RFC 1350...
    >>>
    >>> Sollins
    >>> [Page 5]
    >>>
    >>> RFC 1350 TFTP Revision 2 July
    >>> 1992
    >>>
    >>>
    >>> 2 bytes string 1 byte string 1 byte
    >>> ------------------------------------------------
    >>> | Opcode | Filename | 0 | Mode | 0 |
    >>> ------------------------------------------------
    >>>
    >>> ***
    >>> See how the "Filename" and "Mode" areas in this packet are simply
    >>> "string"? I'd be more comfortable with something like char
    >>> filenam[20]; or the like.
    >>> ***

    >>
    >> You may be more comfortable with a fixed-length Filename and Mode,
    >> but that would violate the protocol.
    >>
    >> [snip]
    >>> RRQ and WRQ packets (opcodes 1 and 2 respectively) have the format
    >>> shown in Figure 5-1. The file name is a sequence of bytes in
    >>> netascii terminated by a zero byte. The mode field contains the
    >>> string "netascii", "octet", or "mail" (or any combination of upper
    >>> and lower case, such as "NETASCII", NetAscii", etc.) in netascii
    >>> indicating the three modes defined in the protocol.

    >>
    >> The above writeup indicates that both Filename and Mode are
    >> variable-length components. You /might/ be able to do this with C99
    >> VLAs (pedants? your opinion?), but otherwise, your structure cannot
    >> /exactly/ represent this packet.
    >>
    >> If you use a structure to /organize/ this data (rather than as an
    >> output or input buffer), you could
    >> struct tftp {
    >> short mode;
    >> char *filename; /* points to the filename string */
    >> char mode[9]; /* can contain any of the valid mode strings */
    >> };

    >
    > That's what I intended was for storage.
    >
    >>
    >> However, if you intend to use the structure as an I/O buffer, then
    >> you'll have to define it fairly generically, and do some work in
    >> logic...
    >>
    >> struct tftp {
    >> unsigned char opcode[2]; /* 2 octets for mode, in network byte
    >> order */

    >
    > Why unsigned?


    So that, when you fill in opcode[] with a 16bit value in network byte order,
    you don't get unintentional sign extension.

    >
    > char data[]; /* FIXME - need to specify exact
    >> length of array */ };
    >>
    >> /* your logic....*/
    >> FILE *connection;
    >> struct tftp header;
    >> int src, dst;
    >> int length;
    >>
    >> /* set header opcode from opcodeValue */
    >> header.opcode[1] = opcodeValue%256;
    >> header.opcode[0] = opcodeValue/256;

    >
    > What's the above? % for modulo? and / for division by 256?


    Take an integer value of unknown range, and squeeze it into a 16bit value in
    network byte (aka "big endian") order, as two 8bit quantities.

    I could have done it with logical operations (shifts and logical-ands), and
    probably should have. But, I wanted to emphasize that we are dealing with
    an integer value, shifted in format. So, I used integer arithmetical
    operations, instead.

    The modulo 256 results in a value between 0 and 255, and fits within 8 bits.
    The division by 256 results in a value that is 8bits smaller than the
    original value.

    Thus, I compute the low-order octet of the 2-octet network-byte-order opcode
    using the modulo 256, and I compute the high-order octet of the 2-octet
    network-byte-order opcode using division.

    Perhaps I /should/ have used logical operations....
    header.opcode[1] = opcodeValue & 0xff;
    header.opcode[0] = (opcodeValue>>8) & 0xff;

    >
    >> /* set header filename from fileName string */
    >> src = dst = 0;
    >> do
    >> header.data[dst++] = fileName[src];
    >> while (fileName[src++] != 0);
    >>
    >> /* set header Mode from modeName string */
    >> src = 0;
    >> do
    >> header.data[dst++] = modeName[src];
    >> while (modeName[src++] != 0);

    >
    > The two do functions above I don't quite understand.


    The TFTP protocol header wants two variable-length strings to be packed
    together in one array, with each string terminated by a zero-value sentinal
    byte.

    So, that's what we do.

    We first copy the filename string, including the zero-valued string
    terminator, into the header's array. Following the zero-valued string
    terminator of the filename in that array, we copy the mode string,
    including the zero-valued string terminator.

    The length of the entire TFTP header is variable, and is
    the length of the two octet opcode
    plus the length of the variable-length filename string (including the \0)
    plus the length of the variable-length mode string (including the \0)

    > VLAs? Do you mean variable length addresses?


    No, I mean Variable Length Arrays. Arrays for which the compiler will
    allocate space and compute the length dynamically.

    > C99 or 89 whichever's best to implement this.
    >
    >> /* write out the header */
    >> fwrite(header,sizeof(header.opcode) + dst, 1, connection);

    >
    > understood the fwrite.
    >
    > Bill
    >
    >


    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 21, 2010
    #6
  7. Lew Pitcher wrote:

    [snip]

    > Take an integer value of unknown range, and squeeze it into a 16bit
    > value in network byte (aka "big endian") order, as two 8bit
    > quantities.
    >
    > I could have done it with logical operations (shifts and
    > logical-ands), and probably should have. But, I wanted to emphasize
    > that we are dealing with an integer value, shifted in format. So, I
    > used integer arithmetical operations, instead.
    >
    > The modulo 256 results in a value between 0 and 255, and fits within
    > 8 bits. The division by 256 results in a value that is 8bits smaller
    > than the original value.
    >
    > Thus, I compute the low-order octet of the 2-octet network-byte-order
    > opcode using the modulo 256, and I compute the high-order octet of
    > the 2-octet network-byte-order opcode using division.
    >
    > Perhaps I /should/ have used logical operations....
    > header.opcode[1] = opcodeValue & 0xff;
    > header.opcode[0] = (opcodeValue>>8) & 0xff;
    >


    OK I think you're heading toward posix's ntoh() and hton() when speaking
    about network bytes here right?

    >>> /* set header filename from fileName string */
    >>> src = dst = 0;
    >>> do
    >>> header.data[dst++] = fileName[src];
    >>> while (fileName[src++] != 0);
    >>>
    >>> /* set header Mode from modeName string */
    >>> src = 0;
    >>> do
    >>> header.data[dst++] = modeName[src];
    >>> while (modeName[src++] != 0);

    >>
    >> The two do functions above I don't quite understand.

    >
    > The TFTP protocol header wants two variable-length strings to be
    > packed together in one array, with each string terminated by a
    > zero-value sentinal byte.
    >
    > So, that's what we do.
    >
    > We first copy the filename string, including the zero-valued string
    > terminator, into the header's array. Following the zero-valued string
    > terminator of the filename in that array, we copy the mode string,
    > including the zero-valued string terminator.
    >
    > The length of the entire TFTP header is variable, and is
    > the length of the two octet opcode
    > plus the length of the variable-length filename string (including the
    > \0) plus the length of the variable-length mode string (including the
    > \0)
    >
    >> VLAs? Do you mean variable length addresses?

    >
    > No, I mean Variable Length Arrays. Arrays for which the compiler will
    > allocate space and compute the length dynamically.
    >
    >> C99 or 89 whichever's best to implement this.
    >>
    >>> /* write out the header */
    >>> fwrite(header,sizeof(header.opcode) + dst, 1, connection);

    >>
    >> understood the fwrite.
    >>
    >> Bill


    So is there anything you could recommend I read such as bitwise
    information to make all this sink in?

    Bill
    Bill Cunningham, Nov 21, 2010
    #7
  8. Bill Cunningham

    Lew Pitcher Guest

    On November 21, 2010 18:34, in comp.lang.c, lid wrote:

    > Lew Pitcher wrote:
    >
    > [snip]
    >
    >> Take an integer value of unknown range, and squeeze it into a 16bit
    >> value in network byte (aka "big endian") order, as two 8bit
    >> quantities.

    [snip]
    >
    > OK I think you're heading toward posix's ntoh() and hton() when
    > speaking about network bytes here right?
    >


    If you have those C language extensions at your disposal, then yes. You are
    looking for the htons() function ("host to network short").

    [snip]

    > So is there anything you could recommend I read such as bitwise
    > information to make all this sink in?


    I'm unsure of your meaning when you say "bitwise information".

    If you mean the details of manipulating integers into network-byte-order,
    then if you have C functions available to do some of the work (like
    htons()), use them. Otherwise, think about what you are trying to do in
    simple terms (hint: converting from one "byte order" to another is like
    performing gradeschool math; divisions and remainders).

    If you mean in general, then I suggest that you study the code that others
    have written; particularly in the same area as your intended program. For
    instance, after my last post, I looked (briefly) at the tftp client code
    (written by H. Peter Anvin) in the Slackware distribution library. I find
    that my off-the-top-of-my-head example code is very much like his program
    code, but where I used explicit loops (so you could see what was
    happening), he used standard (C and POSIX) calls.

    Here's an example:

    Here's his tftp header structure (trimmed to the subset that you are looking
    at):
    struct tftphdr {
    short th_opcode; /* packet type */
    char tu_stuff[STUFFSIZE]; /* request packet stuff */
    char th_data[DATASIZE]; /* data or error string */
    };


    And, here's his code for building the header
    static int makerequest(int request, const char *name,
    struct tftphdr *tp, const char *mode)
    {
    char *cp;

    tp->th_opcode = htons((u_short)request);
    cp = (char *) &(tp->th_stuff);
    strcpy(cp, name);
    cp += strlen(name);
    *cp++ = '\0';
    strcpy(cp, mode);
    cp += strlen(mode);
    *cp++ = '\0';
    return (cp - (char *)tp);
    }

    HTH
    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 22, 2010
    #8
  9. Lew Pitcher wrote:

    > I'm unsure of your meaning when you say "bitwise information".


    The bitwise operators. Why did you use in your code two chars? For
    opcode I would've used a short. Would that be wrong?

    > If you mean the details of manipulating integers into
    > network-byte-order, then if you have C functions available to do some
    > of the work (like htons()), use them. Otherwise, think about what you
    > are trying to do in simple terms (hint: converting from one "byte
    > order" to another is like performing gradeschool math; divisions and
    > remainders).
    >
    > If you mean in general, then I suggest that you study the code that
    > others have written; particularly in the same area as your intended
    > program. For instance, after my last post, I looked (briefly) at the
    > tftp client code (written by H. Peter Anvin) in the Slackware
    > distribution library. I find that my off-the-top-of-my-head example
    > code is very much like his program code, but where I used explicit
    > loops (so you could see what was happening), he used standard (C and
    > POSIX) calls.
    >
    > Here's an example:
    >
    > Here's his tftp header structure (trimmed to the subset that you are
    > looking at):
    > struct tftphdr {
    > short th_opcode; /* packet type */
    > char tu_stuff[STUFFSIZE]; /* request packet stuff */
    > char th_data[DATASIZE]; /* data or error string */
    > };
    >
    >
    > And, here's his code for building the header
    > static int makerequest(int request, const char *name,
    > struct tftphdr *tp, const char *mode)
    > {
    > char *cp;
    >
    > tp->th_opcode = htons((u_short)request);
    > cp = (char *) &(tp->th_stuff);

    Not quite sure about the & is it minipulating bits?

    > strcpy(cp, name);
    > cp += strlen(name);
    > *cp++ = '\0';


    Here's the dereference. I have never quite got the hang of that.

    > strcpy(cp, mode);
    > cp += strlen(mode);
    > *cp++ = '\0';
    > return (cp - (char *)tp);
    > }
    >
    > HTH
    Bill Cunningham, Nov 22, 2010
    #9
  10. Bill Cunningham

    Lew Pitcher Guest

    On November 22, 2010 17:07, in comp.lang.c, lid wrote:

    > Lew Pitcher wrote:
    >
    >> I'm unsure of your meaning when you say "bitwise information".

    >
    > The bitwise operators. Why did you use in your code two chars? For
    > opcode I would've used a short. Would that be wrong?


    "Would that be wrong?"

    It depends. How big is a short int on your system? A network short int is
    16bits, stored in big-endian format. Is your short int exactly 16bits long?


    "Why did you use in your code two chars?"
    I used two chars because there's a greater chance for char to be exactly
    8bits long (and thus 2 chars being 16bits long) than there is for a short
    int to be exactly 16bits long.

    Of course, I'm just as "platform dependant" with two chars as you are with
    one short int; both require some external knowledge of how the compiler
    will work.

    Were we working in C99, a better choice might have been uint16.


    [snip]
    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 22, 2010
    #10
  11. Lew Pitcher wrote:
    > On November 21, 2010 18:34, in comp.lang.c, lid
    > wrote:
    >
    >> Lew Pitcher wrote:
    >>
    >> [snip]
    >>
    >>> Take an integer value of unknown range, and squeeze it into a 16bit
    >>> value in network byte (aka "big endian") order, as two 8bit
    >>> quantities.

    > [snip]
    >>
    >> OK I think you're heading toward posix's ntoh() and hton() when
    >> speaking about network bytes here right?
    >>

    >
    > If you have those C language extensions at your disposal, then yes.
    > You are looking for the htons() function ("host to network short").
    >
    > [snip]
    >
    >> So is there anything you could recommend I read such as bitwise
    >> information to make all this sink in?

    >
    > I'm unsure of your meaning when you say "bitwise information".


    The bitwise operators

    > If you mean the details of manipulating integers into
    > network-byte-order, then if you have C functions available to do some
    > of the work (like htons()), use them. Otherwise, think about what you
    > are trying to do in simple terms (hint: converting from one "byte
    > order" to another is like performing gradeschool math; divisions and
    > remainders).
    >
    > If you mean in general, then I suggest that you study the code that
    > others have written; particularly in the same area as your intended
    > program. For instance, after my last post, I looked (briefly) at the
    > tftp client code (written by H. Peter Anvin) in the Slackware
    > distribution library. I find that my off-the-top-of-my-head example
    > code is very much like his program code, but where I used explicit
    > loops (so you could see what was happening), he used standard (C and
    > POSIX) calls.
    >
    > Here's an example:
    >
    > Here's his tftp header structure (trimmed to the subset that you are
    > looking at):
    > struct tftphdr {
    > short th_opcode; /* packet type */
    > char tu_stuff[STUFFSIZE]; /* request packet stuff */
    > char th_data[DATASIZE]; /* data or error string */
    > };
    >


    Can you kind of walk me through that code. It contains a dereference
    which I still haven't quite figured out and the one ampersand. I don't quite
    understand what that line does.

    > And, here's his code for building the header
    > static int makerequest(int request, const char *name,
    > struct tftphdr *tp, const char *mode)
    > {
    > char *cp;
    >
    > tp->th_opcode = htons((u_short)request);
    > cp = (char *) &(tp->th_stuff);
    > strcpy(cp, name);
    > cp += strlen(name);
    > *cp++ = '\0';


    dereference

    > strcpy(cp, mode);
    > cp += strlen(mode);
    > *cp++ = '\0';
    > return (cp - (char *)tp);
    > }
    >
    > HTH
    Bill Cunningham, Nov 22, 2010
    #11
  12. Bill Cunningham

    Lew Pitcher Guest

    On November 22, 2010 17:44, in comp.lang.c, lid wrote:

    > Lew Pitcher wrote:

    [snip]
    >> Here's an example:
    >>
    >> Here's his tftp header structure (trimmed to the subset that you are
    >> looking at):
    >> struct tftphdr {
    >> short th_opcode; /* packet type */
    >> char tu_stuff[STUFFSIZE]; /* request packet stuff */
    >> char th_data[DATASIZE]; /* data or error string */
    >> };
    >>

    >
    > Can you kind of walk me through that code. It contains a dereference
    > which I still haven't quite figured out and the one ampersand. I don't
    > quite understand what that line does.
    >
    >> And, here's his code for building the header


    The function makerequest() will build the tftp header from several supplied
    values.

    Note that the caller will provide both the values that will be populated
    into the header /and/ the space for the header itself.


    >> static int makerequest(int request, const char *name,
    >> struct tftphdr *tp, const char *mode)


    So, the caller will call makerequest(), giving it arguments
    request - which is an int holding the value of the header opcode
    name - which is a pointer to a C character string containing the
    filename to be copied into the header filename
    tp - which is a pointer to a tftphdr structure, where this
    function will build the tftp header, and
    mode - which is a pointer to a C character string containing the
    modename to be copied into the header mode

    The function will return an integer value, indicating the length of the
    entire header built in the space pointed to by tp.

    >> {
    >> char *cp;


    cp is a pointer to characters, currently uninitialized.

    >> tp->th_opcode = htons((u_short)request);


    First, use the htons() function to convert the request integer value into a
    network-byte-order "short", and place that network-short in the tftp header
    opcode (tp->th_opcode).

    >> cp = (char *) &(tp->th_stuff);


    cp now points to the first character in the "stuff" area of the tftp header
    (tp->th_stuff)

    >> strcpy(cp, name);


    We copy the filename into the first characters of the "stuff" area. The
    filename will be terminated with the '\0' as per all C strings.

    >> cp += strlen(name);


    cp used to point at the beginning of "stuff". Now, it points to the
    character after the last significant character of the filename which was
    copied into "stuff". This character /should be/ the '\0' terminating the
    copied string.

    >> *cp++ = '\0';


    We write over that trailing '\0' with our own '\0' (just to be sure), and
    increment cp so that now points to the first character /after/ the '\0'
    which marks the end of the filename in the tftp header "stuff" area.

    >> strcpy(cp, mode);


    We copy the mode string into the next characters of the "stuff" area. The
    mode string will be terminated with the '\0' as per all C strings.

    >> cp += strlen(mode);


    cp used to point at the first character following the filename in
    the "stuff" area. Now, it points to the character after the last
    significant character of the mode string which was copied into "stuff".
    This character /should be/ the '\0' terminating the copied string.

    >> *cp++ = '\0';


    We write over that trailing '\0' with our own '\0' (just to be sure), and
    increment cp so that now points to the first character /after/ the '\0'
    which marks the end of the mode string in the tftp header "stuff" area.

    >> return (cp - (char *)tp);


    We compute the number of characters between the beginning of the tftp header
    and the end, and return that number to the caller. This is, of course, the
    length of the tftp header that we have constructed.

    >> }


    HTH
    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 22, 2010
    #12
  13. Lew Pitcher wrote:

    > And, here's his code for building the header
    > static int makerequest(int request, const char *name,
    > struct tftphdr *tp, const char *mode)
    > {
    > char *cp;
    >
    > tp->th_opcode = htons((u_short)request);
    > cp = (char *) &(tp->th_stuff);
    > strcpy(cp, name);
    > cp += strlen(name);


    Here'es where I get lost with the *cp

    *cp++ = '\0';
    > strcpy(cp, mode);
    > cp += strlen(mode);
    > *cp++ = '\0';
    > return (cp - (char *)tp);
    > }
    >
    > HTH
    Bill Cunningham, Nov 22, 2010
    #13
  14. Lew Pitcher wrote:

    > And, here's his code for building the header
    > static int makerequest(int request, const char *name,
    > struct tftphdr *tp, const char *mode)
    > {
    > char *cp;
    >
    > tp->th_opcode = htons((u_short)request);
    > cp = (char *) &(tp->th_stuff);
    > strcpy(cp, name);
    > cp += strlen(name);
    > *cp++ = '\0';
    > strcpy(cp, mode);
    > cp += strlen(mode);
    > *cp++ = '\0';
    > return (cp - (char *)tp);
    > }


    Don't quite understand the dereference. That's hurting me from being
    able to read this.
    *cp++=='\0'

    cp*tp;
    tp* struct tftphdr;

    cp is set to point to tp which in turn pointers to struct tftphdr is the way
    it looks to me.

    Bill
    Bill Cunningham, Nov 23, 2010
    #14
  15. Bill Cunningham

    Lew Pitcher Guest

    On November 22, 2010 19:15, in comp.lang.c, lid wrote:

    > Lew Pitcher wrote:
    >
    >> And, here's his code for building the header
    >> static int makerequest(int request, const char *name,
    >> struct tftphdr *tp, const char *mode)
    >> {
    >> char *cp;
    >>
    >> tp->th_opcode = htons((u_short)request);
    >> cp = (char *) &(tp->th_stuff);
    >> strcpy(cp, name);
    >> cp += strlen(name);
    >> *cp++ = '\0';
    >> strcpy(cp, mode);
    >> cp += strlen(mode);
    >> *cp++ = '\0';
    >> return (cp - (char *)tp);
    >> }

    >
    > Don't quite understand the dereference. That's hurting me from being
    > able to read this.
    > *cp++=='\0'


    OK, let's split this apart...

    Instead of
    *cp++=='\0'
    try
    *cp = '\0';
    cp = cp + 1;

    Better?

    >
    > cp*tp;
    > tp* struct tftphdr;
    >
    > cp is set to point to tp which in turn pointers to struct tftphdr is the
    > way it looks to me.


    cp points to somewhere in the tp->th_stuff array of char



    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 23, 2010
    #15
  16. Bill Cunningham

    Lew Pitcher Guest

    On November 22, 2010 19:39, in comp.lang.c, wrote:

    > On November 22, 2010 19:15, in comp.lang.c, lid wrote:
    >
    >> Lew Pitcher wrote:
    >>
    >>> And, here's his code for building the header
    >>> static int makerequest(int request, const char *name,
    >>> struct tftphdr *tp, const char *mode)
    >>> {
    >>> char *cp;
    >>>
    >>> tp->th_opcode = htons((u_short)request);
    >>> cp = (char *) &(tp->th_stuff);
    >>> strcpy(cp, name);
    >>> cp += strlen(name);
    >>> *cp++ = '\0';
    >>> strcpy(cp, mode);
    >>> cp += strlen(mode);
    >>> *cp++ = '\0';
    >>> return (cp - (char *)tp);
    >>> }

    >>
    >> Don't quite understand the dereference. That's hurting me from being
    >> able to read this.
    >> *cp++=='\0'

    >
    > OK, let's split this apart...
    >
    > Instead of
    > *cp++=='\0'


    Oops. Let's not propogate Bill's typo.
    The original statement was...

    *cp++ = '\0';

    > try
    > *cp = '\0';
    > cp = cp + 1;
    >
    > Better?
    >
    >>
    >> cp*tp;
    >> tp* struct tftphdr;
    >>
    >> cp is set to point to tp which in turn pointers to struct tftphdr is the
    >> way it looks to me.

    >
    > cp points to somewhere in the tp->th_stuff array of char
    >
    >
    >


    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 23, 2010
    #16
  17. Bill Cunningham

    Lew Pitcher Guest

    On November 21, 2010 17:51, in comp.lang.c, wrote:

    > On November 21, 2010 17:38, in comp.lang.c, lid wrote:
    >
    >> Lew Pitcher wrote:
    >>> On November 21, 2010 16:56, in comp.lang.c, lid
    >>> wrote:
    >>>
    >>>> Lew Pitcher wrote:
    >>>>
    >>>>> So, what is it you are trying to do?
    >>>>
    >>>> From RFC 1350...
    >>>>
    >>>> Sollins
    >>>> [Page 5]
    >>>>
    >>>> RFC 1350 TFTP Revision 2 July
    >>>> 1992
    >>>>
    >>>>
    >>>> 2 bytes string 1 byte string 1 byte
    >>>> ------------------------------------------------
    >>>> | Opcode | Filename | 0 | Mode | 0 |
    >>>> ------------------------------------------------


    Bill, just so you can see a more concrete example, let's consider this:

    I want a TFTP header that
    - specifies opcode 301 (integer 301)
    - specifies a file named "File"
    - specifies a mode named "netascii"

    *As an array of char*, this header would look like....

    0x01 0x2D 'F' 'i' 'l' 'e' 0x00 'n' 'e' 't' 'a' 's' 'c' 'i' 'i' 0x00
    +----+----+---+---+---+---+----+---+---+---+---+---+---+---+---+----+
    hdr +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15
    ========== ==================== ====================================
    opcode filename mode


    HTH
    --
    Lew Pitcher
    Master Codewright & JOAT-in-training | Registered Linux User #112576
    Me: http://pitcher.digitalfreehold.ca/ | Just Linux: http://justlinux.ca/
    ---------- Slackware - Because I know what I'm doing. ------
    Lew Pitcher, Nov 23, 2010
    #17
  18. have you ever finished a program?


    "Bill Cunningham" <> schreef in bericht
    news:4ce98ad3$0$14804$...
    > I have a header that is such and I am not quite sure what the "best
    > way" in C to implement it is.
    >
    > opcode | filename | 1 byte pad | mode | 1 byte pad
    >
    > I have consider malloc() and a struct as such
    >
    > struct tftp{
    > char padd="0";
    > short opcode;
    > char * mode;
    > char *filename;
    > };
    >
    > Now I don't like the way "mode" and "filename" is simply a string. Is
    > this the best design or does anyone have any better ideas for a hobbyist
    > wannabe? Xenophobes need not apply
    >
    > Bill
    >
    >
    Serve Laurijssen, Nov 23, 2010
    #18
  19. Lew Pitcher wrote:
    > On November 22, 2010 17:44, in comp.lang.c, lid
    > wrote:
    >
    >> Lew Pitcher wrote:

    > [snip]
    >>> Here's an example:
    >>>
    >>> Here's his tftp header structure (trimmed to the subset that you are
    >>> looking at):
    >>> struct tftphdr {
    >>> short th_opcode; /* packet type */
    >>> char tu_stuff[STUFFSIZE]; /* request packet stuff */
    >>> char th_data[DATASIZE]; /* data or error string */
    >>> };
    >>>

    >>
    >> Can you kind of walk me through that code. It contains a
    >> dereference which I still haven't quite figured out and the one
    >> ampersand. I don't quite understand what that line does.
    >>
    >>> And, here's his code for building the header

    >
    > The function makerequest() will build the tftp header from several
    > supplied values.
    >
    > Note that the caller will provide both the values that will be
    > populated into the header /and/ the space for the header itself.
    >
    >
    >>> static int makerequest(int request, const char *name,
    >>> struct tftphdr *tp, const char *mode)

    >
    > So, the caller will call makerequest(), giving it arguments
    > request - which is an int holding the value of the header opcode
    > name - which is a pointer to a C character string containing the
    > filename to be copied into the header filename
    > tp - which is a pointer to a tftphdr structure, where this
    > function will build the tftp header, and
    > mode - which is a pointer to a C character string containing the
    > modename to be copied into the header mode
    >
    > The function will return an integer value, indicating the length of
    > the entire header built in the space pointed to by tp.
    >
    >>> {
    >>> char *cp;

    >
    > cp is a pointer to characters, currently uninitialized.
    >
    >>> tp->th_opcode = htons((u_short)request);

    >
    > First, use the htons() function to convert the request integer value
    > into a network-byte-order "short", and place that network-short in
    > the tftp header opcode (tp->th_opcode).
    >
    >>> cp = (char *) &(tp->th_stuff);

    >
    > cp now points to the first character in the "stuff" area of the tftp
    > header (tp->th_stuff)
    >
    >>> strcpy(cp, name);

    >
    > We copy the filename into the first characters of the "stuff" area.
    > The filename will be terminated with the '\0' as per all C strings.
    >
    >>> cp += strlen(name);

    >
    > cp used to point at the beginning of "stuff". Now, it points to the
    > character after the last significant character of the filename which
    > was copied into "stuff". This character /should be/ the '\0'
    > terminating the copied string.
    >
    >>> *cp++ = '\0';

    >
    > We write over that trailing '\0' with our own '\0' (just to be sure),
    > and increment cp so that now points to the first character /after/
    > the '\0' which marks the end of the filename in the tftp header
    > "stuff" area.
    >
    >>> strcpy(cp, mode);

    >
    > We copy the mode string into the next characters of the "stuff" area.
    > The mode string will be terminated with the '\0' as per all C strings.
    >
    >>> cp += strlen(mode);

    >
    > cp used to point at the first character following the filename in
    > the "stuff" area. Now, it points to the character after the last
    > significant character of the mode string which was copied into
    > "stuff". This character /should be/ the '\0' terminating the copied
    > string.
    >
    >>> *cp++ = '\0';

    >
    > We write over that trailing '\0' with our own '\0' (just to be sure),
    > and increment cp so that now points to the first character /after/
    > the '\0' which marks the end of the mode string in the tftp header
    > "stuff" area.
    >
    >>> return (cp - (char *)tp);

    >
    > We compute the number of characters between the beginning of the tftp
    > header and the end, and return that number to the caller. This is, of
    > course, the length of the tftp header that we have constructed.
    >
    >>> }

    >
    > HTH


    Ok I might comes back to this later but I have a lot to digest. Sorry
    for all the repeat posts. I posted and my post didn't show up so I tried a
    couple more times and then they all posted.


    Bill
    Bill Cunningham, Nov 24, 2010
    #19
  20. Lew Pitcher wrote:

    [snip]

    > cp used to point at the beginning of "stuff". Now, it points to the
    > character after the last significant character of the filename which
    > was copied into "stuff". This character /should be/ the '\0'
    > terminating the copied string.
    >
    >>> *cp++ = '\0';


    OK why the * before cp in this examples?

    > We write over that trailing '\0' with our own '\0' (just to be sure),
    > and increment cp so that now points to the first character /after/
    > the '\0' which marks the end of the filename in the tftp header
    > "stuff" area.
    >
    >>> strcpy(cp, mode);

    >
    > We copy the mode string into the next characters of the "stuff" area.
    > The mode string will be terminated with the '\0' as per all C strings.
    >
    >>> cp += strlen(mode);

    >
    > cp used to point at the first character following the filename in
    > the "stuff" area. Now, it points to the character after the last
    > significant character of the mode string which was copied into
    > "stuff". This character /should be/ the '\0' terminating the copied
    > string.
    >
    >>> *cp++ = '\0';

    >
    > We write over that trailing '\0' with our own '\0' (just to be sure),
    > and increment cp so that now points to the first character /after/
    > the '\0' which marks the end of the mode string in the tftp header
    > "stuff" area.
    >
    >>> return (cp - (char *)tp);

    >
    > We compute the number of characters between the beginning of the tftp
    > header and the end, and return that number to the caller. This is, of
    > course, the length of the tftp header that we have constructed.
    >
    >>> }

    >
    > HTH


    Wow I had no idea.

    Bill
    WHere'd you find this from what version of slackware source?
    Bill Cunningham, Nov 24, 2010
    #20
    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. Debashish
    Replies:
    3
    Views:
    1,813
    Mike Treseler
    Aug 8, 2003
  2. Leon Shaw

    Databinding Inquiry

    Leon Shaw, Jul 11, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    378
    Leon Shaw
    Jul 11, 2003
  3. Joe Van Meer

    data relations and datasets inquiry

    Joe Van Meer, May 5, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    432
    Joe Van Meer
    May 5, 2004
  4. Replies:
    1
    Views:
    10,443
    kj12345
    Mar 1, 2005
  5. Shuo Xiang

    [OT]GTKmm toolkit inquiry

    Shuo Xiang, Jul 17, 2003, in forum: C++
    Replies:
    1
    Views:
    347
    Jim Fischer
    Jul 17, 2003
Loading...

Share This Page