design inquiry

B

Bill Cunningham

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
 
L

Lew Pitcher

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?
 
B

Bill Cunningham

Lew said:
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
 
L

Lew Pitcher

Lew said:
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]
 
B

Bill Cunningham

Lew said:
Lew said:
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
 
L

Lew Pitcher

Lew said:
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.
 
B

Bill Cunningham

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.


understood the fwrite.

Bill

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

Bill
 
L

Lew Pitcher

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
 
B

Bill Cunningham

Lew said:
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.
 
L

Lew Pitcher

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]
 
B

Bill Cunningham

Lew said:
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
 
L

Lew Pitcher

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.


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.

cp is a pointer to characters, currently uninitialized.

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 now points to the first character in the "stuff" area of the tftp header
(tp->th_stuff)

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 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.

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.

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 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.

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.

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
 
B

Bill Cunningham

Lew said:
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';
 
B

Bill Cunningham

Lew said:
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
 
L

Lew Pitcher

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
 
L

Lew Pitcher

Lew said:
On November 21, 2010 16:56, in comp.lang.c, (e-mail address removed)
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

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
 
B

Bill Cunningham

Lew said:
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.


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.

cp is a pointer to characters, currently uninitialized.

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 now points to the first character in the "stuff" area of the tftp
header (tp->th_stuff)

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 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.

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.

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 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.

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.

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
 
B

Bill Cunningham

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.

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.


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 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.


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.


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?
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top