From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,bc1361a952ec75ca X-Google-Attributes: gid103376,public X-Google-Thread: 109fba,582dff0b3f065a52 X-Google-Attributes: gid109fba,public X-Google-ArrivalTime: 2001-08-08 22:12:31 PST Path: archiver1.google.com!newsfeed.google.com!newsfeed.stanford.edu!nntp.cs.ubc.ca!news-spur1.maxwell.syr.edu!news.maxwell.syr.edu!newshub2.home.com!news.home.com!news1.rdc2.on.home.com.POSTED!not-for-mail Message-ID: <3B721BC3.76A2161C@home.com> From: "Warren W. Gay VE3WWG" X-Mailer: Mozilla 4.75 [en] (Windows NT 5.0; U) X-Accept-Language: en MIME-Version: 1.0 Newsgroups: comp.lang.ada,comp.lang.c++ Subject: Re: How Ada could have prevented the Red Code distributed denial of service attack. References: <3b690498.1111845720@news.worldonline.nl> <9kbu15$9bj@augusta.math.psu.edu> <9kbvsr$a02@augusta.math.psu.edu> <3B69DB35.4412459E@home.com> <3B6F312F.DA4E178E@home.com> <23lok9.ioi.ln@10.0.0.2> <3B70AB15.35845A98@home.com> <3B70C665.BBC5F000@home.com> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Date: Thu, 09 Aug 2001 05:12:29 GMT NNTP-Posting-Host: 24.141.193.224 X-Complaints-To: abuse@home.net X-Trace: news1.rdc2.on.home.com 997333949 24.141.193.224 (Wed, 08 Aug 2001 22:12:29 PDT) NNTP-Posting-Date: Wed, 08 Aug 2001 22:12:29 PDT Organization: Excite@Home - The Leader in Broadband http://home.com/faster Xref: archiver1.google.com comp.lang.ada:11661 comp.lang.c++:81149 Date: 2001-08-09T05:12:29+00:00 List-Id: I cross posted this to comp.lang.c++ because it compares the Ada and C++ streams approaches, that others might find useful reading, whether they like the Ada approach or not. David Bolen wrote: > "Warren W. Gay VE3WWG" writes: ...snip... > To answer your question, yes, that's how I do it. Virtually all of my > development for the past decade+ has been networking and I'm rarely > involved in a homogenous environment (systems, tools, etc...), so as > it happens portability is ingrained in everything I do. As it should be. However, in my experience, there is always local I/O issues that do not require that "extra engineering". Another simple example, might be I/O to/from a temporary file. > But that's really an aside unrelated to the question I was asking. I > wasn't looking to justify why you would take one approach over the > other, but just looking for information about how Ada handles > structure I/O. The entire reason for the prior discussion was to illustrate why sizes of things were needed (hence the I/O of structs for example). Ada let's you precisely get at the physical or logical sizes upon demand. My point was that in C/C++, you must exercise discretion to compute what you need with the sizeof operator. (eg. sizeof "ab" may not be 3 on your platform, as a simple example). > > For example, if you were to write cpio, excluding the portable format > > (-c), are you not going to write the binary header out directly? > > Sure you are. You don't have to of course, but this is different > > from general experience. > > I'm not sure if you mean writing the full binary header as a structure > in one shot, or just writing binary data in the header. I'd have less > of a problem with the latter than the former - although doing the > former does get to my question about Ada's structures, e.g., > consistency of packing, compatibility across platforms and compilers. Well, for a number of years, non -c headers could not be used on other platforms. Try taking HPUX cpio non -c archive to SCO UNIX, and you would be disappointed. I would still be surprised if many non -c cpio formats will interoperate. I would never depend upon it, without testing it in advance. However, that's perhaps the one aspect of portability that you were not concerned with. > > EVEN IF YOU IGNORE FILEs, you don't have portability concerns when > > you write to pipes, UNIX sockets (ie. local to the same host), > > call msgsnd() and msgrcv() for message queues. These do not require > > any endian issues because you're talking to processes within the > > same host. It would simply be a _waste_ to write to your > > process on the same host, in an endian neutral way (depending > > upon the endian orientation). > > This shifts to an endian focus when that was really only part of my > original question. I may not have endian concerns with local I/O but > I could certainly have larger structure alignment concerns between two > communicating applications. You misunderstood my intention. I was charged with showing where the I/O sizes were necessary -- that was the only point I was making. Ie., where you _don't_ have endian issues, like local unix sockets and pipes, you'll just do I/O on the structs in question. You won't data marshal all of the individual structure members. > In the Ada case, would writing a structure to one of those constructs > then be readable (as a complete structure) from the other end with > code written with another Ada compiler from a different vendor? (Without doing research on this, shamelessly:) I expect not because I don't believe the LRM (Language Reference Manual [for Ada]) spells out what the implementation has to use for the various data types in question. I believe they tend to be similar: For example a string (which is a character array) is usually written out with the first subscript value, and last subscript value, followed by the characters in the array. However, the sizes of the lower and upper bounds might be 32 bits in one implementation, and say 16 bits on another. Yet another, may make the octets vary in length according the the value. But for more radical platforms that use 1's complement integers or something, even the integer representation could be different. So really, the answer is _no_, there is no portability guaranteed AFAIK for stream IO, for communication on different platforms. For portability.. You _can_ override the default 'Read and 'Write attributes for a type, as well as the 'Input and 'Output attributes. If you do this, you can spell out how they are represented to/from a stream. In fact, you _will_ do this if you care about portable file formats (although there are other ways this can be accomplished in Ada). In C++ you'd simply do the same thing by writing stream methods for the classes involved. But unfortunately, you cannot do this easily for base types. For example : #include ostream &operator<<(ostream &stream, int iobj) { char buf[32]; snprintf(buf,sizeof buf,"[%d]",iobj); // my personal format return stream << buf; } won't work if I want to output ints in my "own way" (here I simply wanted to emit the string form of the int to the stream for int types). The reason it doesn't work, is because it's already defined for you : streams.cc:15: ambiguous overload for `_IO_ostream_withassign & << int &' /usr/include/g++/iostream.h:77: candidates are: class ostream & ostream::operator <<(char) /usr/include/g++/iostream.h:78: class ostream & ostream::operator <<(unsigned char) /usr/include/g++/iostream.h:79: class ostream & ostream::operator <<(signed char) /usr/include/g++/iostream.h:86: class ostream & ostream::operator <<(int) etc.. This is unfortunate, because if you wanted to automatically do endian conversions for example, this choice has been eliminated. To write out an int using your own custom format in C++, requires deriving a new stream class, something along the lines of : #include class My_Stream : public ofstream { }; My_Stream &operator<<(My_Stream &stream, int iobj) { char buf[32]; snprintf(buf,sizeof buf,"%d",iobj); stream << "'" << buf << "'"; // Output int 'my way' return stream; } Ada's approach is different (for streams). Rather than create a whole new stream class, you simply customize the data type formats for the data types themselves. When they are put to the stream, your routines are called for the I/O for those data types, instead of the default ones. The beauty of this is that you specify once the I/O formats that your "building blocks" will use, and all records (objects) that use them can then be input/output to the stream with no further code (in C++ you would additionally be forced to declare a My_Stream &operator <<() method to output the class/struct's to the stream, if need be. In Ada, records (struct) have each of the members output to the stream automatically (unless you override). However, there are times when you need to override the record's default I/O format in order to omit of certain members from I/O etc. But the default does what you want in many cases. Ada and C++ also part company in another way WRT streams: Ada's typing mechanism permits you to refine types further. For example, in C++ if you declare two integer types: typedef int feet; typedef int meters; then both of these are treated the same in the stream I/O. :< In Ada however, you can: type Feet is new Integer; type Meters is new Integer; and then define how Feet and Meters are I/O'd to/from a stream. These I/O formats can be different, even though these are just specialized distinctions of an Integer. This can be an advantage, depending upon the range of an integer etc. (because a more efficient stream format can be chosen for it). My biggest beef with C++'s typing system is that it is distinguished at the underlying implementation type alone. If I went to the trouble of : typedef int feet; typedef int meters; This gets in the way of specialized method calls that might be different: object::extend_length(feet measure); object::extend_length(meters measure); // these both cannot coexist This fails because according to C++ rules, these map to a duplication of methods, because feet and meters are considered "the same" (ie. int). Ada, makes the distinction here, which again, makes it possible to better map the concept to programming. C++ is too close to the implementation of the compiled code. Anyway, I am digressing. ;-) > > There is however, another "distributed systems annex?", to Confirmed, as "Distributed Systems Annex E". > > which I must confess ignorance of > > at the moment (I have not yet tried it), that does the equivalence > > of RPC (or at least I think GNAT does it this way). > > > > Now I am not certain of this point, but it is _likely_, though > > probably not guaranteed, that XDR formats will be used for this > > (big endian format, portable etc.) But please don't quote me on > > this, since this particular answer is entirely _wild_ _speculation_ > > on my part. Someone with more Ada experience can help us out on > > this point, if they are willing. > > Thanks - that's really what my question was aimed at. While having > such an XDR (or XDR-like) definition in an Annex would bring that into > the Ada specification, it sounds like handling this with Ada is pretty > close to how its handled in other situations. Well, XDR _might_ only be true for GNAT's implementation. I wouldn't necessarily "expect" it to be so everywhere else. However, where representation is important on a simple socket, you can use the streams attribute overrides (see above) to specify how the data elements are written. As shown, if you do this carefully, you can input and output entire records (struct/class) as required. I find this much more convenient than the C++ approach to streams. Additionally, Ada typechecks each stream I/O call as well: -- error if My_Int_32 is not Integer_32 type Integer_32'Write(Stream,My_Int_32); whereas C++ can automatically promote, or call an unintended method instead: short My_Int_32; // whoopsey, not a 32 bit integer. cout << My_Int_32; // This is actually sending out a short -- not detected This of course, is easy to do with include files, #ifs and macros at work. It's not usually this blatant, but this sort of error does happen. Anyway, I hope you found that useful. ;-) -- Warren W. Gay VE3WWG http://members.home.net/ve3wwg