Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > design inquiry

Reply
Thread Tools

design inquiry

 
 
Bill Cunningham
Guest
Posts: n/a
 
      11-21-2010
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


 
Reply With Quote
 
 
 
 
Lew Pitcher
Guest
Posts: n/a
 
      11-21-2010
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. ------


 
Reply With Quote
 
 
 
 
Bill Cunningham
Guest
Posts: n/a
 
      11-21-2010
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.


 
Reply With Quote
 
Lew Pitcher
Guest
Posts: n/a
 
      11-21-2010
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. ------


 
Reply With Quote
 
Bill Cunningham
Guest
Posts: n/a
 
      11-21-2010
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


 
Reply With Quote
 
Lew Pitcher
Guest
Posts: n/a
 
      11-21-2010
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>> & 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. ------


 
Reply With Quote
 
Bill Cunningham
Guest
Posts: n/a
 
      11-21-2010
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>> & 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


 
Reply With Quote
 
Lew Pitcher
Guest
Posts: n/a
 
      11-22-2010
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. ------


 
Reply With Quote
 
Bill Cunningham
Guest
Posts: n/a
 
      11-22-2010
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



 
Reply With Quote
 
Lew Pitcher
Guest
Posts: n/a
 
      11-22-2010
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. ------


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Inquiry Death from Above MCSE 4 03-19-2006 08:47 AM
data relations and datasets inquiry Joe Van Meer ASP .Net 0 05-05-2004 01:30 PM
Response to Bilal's inquiry about the $2.25 M Bilal's cousin MCSE 3 02-13-2004 01:16 AM
Inquiry about a VHDL signal tracer tool... Debashish VHDL 3 08-08-2003 06:04 PM
Databinding Inquiry Leon Shaw ASP .Net 1 07-11-2003 07:11 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57