diff options
Diffstat (limited to 'docs/tutorials')
-rw-r--r-- | docs/tutorials/015/Compressor.cpp | 38 | ||||
-rw-r--r-- | docs/tutorials/015/Compressor.h | 23 | ||||
-rw-r--r-- | docs/tutorials/015/Crypt.cpp | 18 | ||||
-rw-r--r-- | docs/tutorials/015/Crypt.h | 13 | ||||
-rw-r--r-- | docs/tutorials/015/combine.shar | 333 | ||||
-rw-r--r-- | docs/tutorials/015/page04.html | 1 | ||||
-rw-r--r-- | docs/tutorials/015/page09.html | 2 | ||||
-rw-r--r-- | docs/tutorials/015/page14.html | 22 | ||||
-rw-r--r-- | docs/tutorials/015/page15.html | 25 | ||||
-rw-r--r-- | docs/tutorials/015/page16.html | 16 | ||||
-rw-r--r-- | docs/tutorials/015/page17.html | 8 | ||||
-rw-r--r-- | docs/tutorials/015/page18.html | 68 | ||||
-rw-r--r-- | docs/tutorials/015/page19.html | 119 | ||||
-rw-r--r-- | docs/tutorials/015/page20.html | 61 | ||||
-rw-r--r-- | docs/tutorials/015/page21.html | 99 | ||||
-rw-r--r-- | docs/tutorials/015/page22.html | 82 | ||||
-rw-r--r-- | docs/tutorials/index.html | 13 |
17 files changed, 835 insertions, 106 deletions
diff --git a/docs/tutorials/015/Compressor.cpp b/docs/tutorials/015/Compressor.cpp index 06efab06947..c2f796bd68e 100644 --- a/docs/tutorials/015/Compressor.cpp +++ b/docs/tutorials/015/Compressor.cpp @@ -4,22 +4,38 @@ #include "Compressor.h" #include "ace/SOCK_Stream.h" +/* Construct our baseclass with the proper thread count. I really + should remove this option... + */ Compressor::Compressor( int _thr_count ) : inherited(_thr_count) { + ; } Compressor::~Compressor(void) { + ; } +/* This is where you insert your compression code. Most compressors + want to work on a block of data instead of a byte-stream. + Fortunately the message block has a block that can be compressed. + Take a look at libz for a quick way to add compression to your + apps + */ int Compressor::send(ACE_Message_Block *message, ACE_Time_Value *timeout) { ACE_DEBUG ((LM_INFO, "(%P|%t) Compressor::send() compressing (%s)\n", message->rd_ptr() )); + // Create a block to hold the compressed data. I belive libz + // recommends a buffer about 10-20% larger than the source. + // Other libraries/algorithms may have their own quirks. ACE_Message_Block * compressed = new ACE_Message_Block( message->size() ); - // Perform a bogus compression algorithm + // Perform a bogus compression algorithm. 'CD' just tells me + // that this is compressed data and when we "decompress" we'll + // look for this signature to validate the data received. ACE_OS::sprintf( compressed->wr_ptr(), "CD:%s", message->rd_ptr() ); compressed->wr_ptr( strlen(compressed->wr_ptr())+1 ); @@ -32,12 +48,27 @@ int Compressor::send(ACE_Message_Block *message, ACE_Time_Value *timeout) return( 0 ); } +/* And here's the decompression side. We've written Xmit/Recv so that + we're guaranteed to get an entire block of compressed data. If + we'd used recv() in the Recv object then we might have gotten a + partial block and that may not decompress very nicely. + */ int Compressor::recv(ACE_Message_Block *message, ACE_Time_Value *timeout) { ACE_DEBUG ((LM_INFO, "(%P|%t) Compress::recv() decompressing (%s)\n", message->rd_ptr() )); + // Room for the decompressed data. In the real world you + // would probably want to send the original (uncompressed) + // data size in the message. You can predict the maximum + // possible decompression size but it's cheap and easy just to + // send that along. Look again at how I do exacly that + // between Xmit and Recv. ACE_Message_Block * decompressed = new ACE_Message_Block( message->size() ); + // Check for our signature. Even when you use a real + // compression algorithm you may want to include your own + // signature so that you can verify the block. It pays to be + // paranoid! if( ACE_OS::strncmp( message->rd_ptr(), "CD:", 3 ) ) { ACE_DEBUG ((LM_INFO, "(%P|%t) Improperly encompressed data.\n" )); @@ -45,9 +76,12 @@ int Compressor::recv(ACE_Message_Block *message, ACE_Time_Value *timeout) return(-1); } + // Skip past the signature before going any further. message->rd_ptr( 3 ); - // Perform a bogus decompression algorithm + // Perform a bogus decompression algorithm. This is where you + // would feed to libz or your favorite decompressor. (It's + // costly but you could invoke popen() on gzip!) ACE_OS::sprintf( decompressed->wr_ptr(), "%s", message->rd_ptr() ); decompressed->wr_ptr( strlen(decompressed->wr_ptr())+1 ); diff --git a/docs/tutorials/015/Compressor.h b/docs/tutorials/015/Compressor.h index f1310432841..bc0257b16d1 100644 --- a/docs/tutorials/015/Compressor.h +++ b/docs/tutorials/015/Compressor.h @@ -6,27 +6,38 @@ #include "Protocol_Task.h" -class ACE_SOCK_Stream; - +/* A reallly dumb compression object. (It actually adds 3 bytes to + every message block.) +*/ class Compressor : public Protocol_Task { public: typedef Protocol_Task inherited; - + + // I've given you the option of creating this task derivative + // with a number of threads. In retro-spect that really isn't + // a good idea. Most client/server systems rely on requests + // and responses happening in a predicatable order. Introduce + // a thread pool and message queue and that ordering goes + // right out the window. In other words: Don't ever use the + // constructor parameter! Compressor( int _thr_count = 0 ); + ~Compressor(void); protected: + // This is called when the compressor is on the downstream + // side. We'll take the message, compress it and move it + // along to the next module. int send(ACE_Message_Block *message, ACE_Time_Value *timeout); + // This one is called on the upstream side. No surprise: we + // decompress the data and send it on up the stream. int recv(ACE_Message_Block *message, ACE_Time_Value *timeout); - -private: - mode_t mode_; }; #endif // COMPRESSOR_H diff --git a/docs/tutorials/015/Crypt.cpp b/docs/tutorials/015/Crypt.cpp index 26827ce44b0..1e20b8f5b42 100644 --- a/docs/tutorials/015/Crypt.cpp +++ b/docs/tutorials/015/Crypt.cpp @@ -4,6 +4,8 @@ #include "Crypt.h" #include "ace/SOCK_Stream.h" +/* The expected constructor... + */ Crypt::Crypt( int _thr_count ) : inherited(_thr_count) { @@ -13,13 +15,19 @@ Crypt::~Crypt(void) { } +/* To send the data we'll apply a signature and encryption. + */ int Crypt::send(ACE_Message_Block *message, ACE_Time_Value *timeout) { ACE_DEBUG ((LM_INFO, "(%P|%t) Crypt::send() encrypting (%s)\n", message->rd_ptr() )); + // I suspect that some encryptors might change the data size. + // It probably isn't safe to create a same-size destination buffer. ACE_Message_Block * encrypted = new ACE_Message_Block( message->size() ); - // Perform a bogus encryption algorithm + // Perform a bogus encryption algorithm and add our safety + // signature. Adding the original data size is also probably + // a good idea that I haven't encorporated here. ACE_OS::sprintf( encrypted->wr_ptr(), "ED:%s", message->rd_ptr() ); encrypted->wr_ptr( strlen(encrypted->wr_ptr())+1 ); @@ -32,12 +40,18 @@ int Crypt::send(ACE_Message_Block *message, ACE_Time_Value *timeout) return( 0 ); } +/* The upstream movement requires that we decrypt what the peer has + given us. +*/ int Crypt::recv(ACE_Message_Block *message, ACE_Time_Value *timeout) { ACE_DEBUG ((LM_INFO, "(%P|%t) Crypt::recv() decrypting (%s)\n", message->rd_ptr() )); + // Create a destination for the decrypted data. The same + // block size caveat exists of course. ACE_Message_Block * decrypted = new ACE_Message_Block( message->size() ); + // Check the signature as expected. if( ACE_OS::strncmp( message->rd_ptr(), "ED:", 3 ) ) { ACE_DEBUG ((LM_INFO, "(%P|%t) Improperly encrypted data.\n" )); @@ -45,6 +59,8 @@ int Crypt::recv(ACE_Message_Block *message, ACE_Time_Value *timeout) return(-1); } + // Don't forget to skip past the signature before decrypting + // or things will be quite exciting! message->rd_ptr( 3 ); // Perform a bogus decryption algorithm diff --git a/docs/tutorials/015/Crypt.h b/docs/tutorials/015/Crypt.h index b34dda4c12e..7a38e1bdb52 100644 --- a/docs/tutorials/015/Crypt.h +++ b/docs/tutorials/015/Crypt.h @@ -6,25 +6,30 @@ #include "Protocol_Task.h" -class ACE_SOCK_Stream; - +/* An interface (adaptor) between your favorite encryption method and + an ACE_Stream. +*/ class Crypt : public Protocol_Task { public: typedef Protocol_Task inherited; - + + // Again we have the option of multiple threads and again I + // regret tempting folks to use it. Crypt( int _thr_count = 0 ); + ~Crypt(void); protected: + // Moving downstream will encrypt the data int send(ACE_Message_Block *message, ACE_Time_Value *timeout); + // And moving upstream will decrypt it. int recv(ACE_Message_Block *message, ACE_Time_Value *timeout); -private: }; #endif // CRYPT_H diff --git a/docs/tutorials/015/combine.shar b/docs/tutorials/015/combine.shar index 564843d6251..2faa3e703da 100644 --- a/docs/tutorials/015/combine.shar +++ b/docs/tutorials/015/combine.shar @@ -3,8 +3,8 @@ # To extract the files from this archive, save it to some FILE, remove # everything before the `!/bin/sh' line above, then type `sh FILE'. # -# Made on 1998-10-19 16:39 EDT by <jcej@caldera.lads.com>. -# Source directory was `/scsiA/home/jcej/projects/ACE_wrappers/docs/tutorials/015'. +# Made on 1998-10-19 20:42 EDT by <jcej@chiroptera.tragus.org>. +# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/015'. # # Existing files will *not* be overwritten unless `-c' is specified. # @@ -26,11 +26,16 @@ # 334 -rw-rw-r-- page11.pre # 334 -rw-rw-r-- page12.pre # 326 -rw-rw-r-- page13.pre -# 770 -rw-rw-r-- page14.pre -# 660 -rw-rw-r-- page15.pre -# 213 -rw-rw-r-- page16.pre -# 129 -rw-rw-r-- page17.pre -# 348 -rw-rw-r-- page04.pst +# 540 -rw-rw-r-- page14.pre +# 770 -rw-rw-r-- page15.pre +# 660 -rw-rw-r-- page16.pre +# 213 -rw-rw-r-- page17.pre +# 372 -rw-rw-r-- page18.pre +# 281 -rw-rw-r-- page19.pre +# 356 -rw-rw-r-- page20.pre +# 151 -rw-rw-r-- page21.pre +# 2551 -rw-rw-r-- page22.pre +# 398 -rw-rw-r-- page04.pst # 609 -rw-rw-r-- page09.pst # save_IFS="${IFS}" @@ -78,7 +83,7 @@ else fi rm -f 1231235999 $$.touch # -if mkdir _sh23762; then +if mkdir _sh02329; then $echo 'x -' 'creating lock directory' else $echo 'failed to create lock directory' @@ -594,36 +599,30 @@ if test -f 'page14.pre' && test "$first_param" != -c; then else $echo 'x -' extracting 'page14.pre' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'page14.pre' && -The implementation of Xmit isn't too complicated. If we choose to -combine it with the Recv task we simply lift the recv() method from -that object and drop it into this one. -<P> -Note that close() must decide if it's being called when the stream is -shutdown or when it's svc() method exits. Since we tell the baseclass -not to use any threads it's a safe bet that flags will always be -non-zero. Still, it's good practice to plan for the future by -checking the value. +The Xmit object knows how to send data to the peer. It sits at the +tail of the stream and gets everything that flows down from the head. +In keeping with the spirit of things, this object does only one thing +and doesn't concern itself with anyone else' details. <P> -Note also that when we send the data we prefix it with the data size. -This let's our sibling Recv ensure that an entire block is received -together. This can be very important for compression and encryption -processes which typically work better with blocks of data instead of -streams of data. +The only thing you might want to do is combine it with Recv. Why? +As you'll realize in a page or two, the Xmit and Recv objects must +interact if you're going to ensure a safe transit. By having a single +object it's easier to coordinate and maintain the interaction. <HR> SHAR_EOF - $shar_touch -am 1019163798 'page14.pre' && + $shar_touch -am 1019203498 'page14.pre' && chmod 0664 'page14.pre' || $echo 'restore of' 'page14.pre' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'page14.pre:' 'MD5 check failed' -0d79137eaedd73b820037fcafe6e16b6 page14.pre +bfc300ca2da5b82a5e452713cbf2f544 page14.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page14.pre'`" - test 770 -eq "$shar_count" || - $echo 'page14.pre:' 'original size' '770,' 'current size' "$shar_count!" + test 540 -eq "$shar_count" || + $echo 'page14.pre:' 'original size' '540,' 'current size' "$shar_count!" fi fi # ============= page15.pre ============== @@ -632,18 +631,21 @@ if test -f 'page15.pre' && test "$first_param" != -c; then else $echo 'x -' extracting 'page15.pre' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'page15.pre' && -Recv is the sibling to Xmit. Again, they could be combined into a -single object if you want. +The implementation of Xmit isn't too complicated. If we choose to +combine it with the Recv task we simply lift the recv() method from +that object and drop it into this one. <P> -An ACE_Stream is designed to handle downstream traffic very -well. You put() data into it and it flows along towards the tail. -However, there doesn't seem to be a way to put data in such that it -will travel upstream. To get around that, I've added a get() method -to Recv that will trigger a read on the socket. Recv will then put -the data to the next upstream module and we're on our way. As noted -earlier, that data will eventually show up either in the <i>reader</i> -(if installed on the stream open()) or the stream head reader task's -message queue. +Note that close() must decide if it's being called when the stream is +shutdown or when it's svc() method exits. Since we tell the baseclass +not to use any threads it's a safe bet that flags will always be +non-zero. Still, it's good practice to plan for the future by +checking the value. +<P> +Note also that when we send the data we prefix it with the data size. +This let's our sibling Recv ensure that an entire block is received +together. This can be very important for compression and encryption +processes which typically work better with blocks of data instead of +streams of data. <HR> SHAR_EOF $shar_touch -am 1019163798 'page15.pre' && @@ -653,12 +655,12 @@ SHAR_EOF && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'page15.pre:' 'MD5 check failed' -2d89b3c894cfcfdfef47ae506913cdad page15.pre +0d79137eaedd73b820037fcafe6e16b6 page15.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page15.pre'`" - test 660 -eq "$shar_count" || - $echo 'page15.pre:' 'original size' '660,' 'current size' "$shar_count!" + test 770 -eq "$shar_count" || + $echo 'page15.pre:' 'original size' '770,' 'current size' "$shar_count!" fi fi # ============= page16.pre ============== @@ -667,10 +669,18 @@ if test -f 'page16.pre' && test "$first_param" != -c; then else $echo 'x -' extracting 'page16.pre' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'page16.pre' && -The Recv implementation is nearly as simple as Xmit. There's -opportunity for error when we get the message size and we have to -manage the lifetime of the tickler but other than that it's pretty -basic stuff. +Recv is the sibling to Xmit. Again, they could be combined into a +single object if you want. +<P> +An ACE_Stream is designed to handle downstream traffic very +well. You put() data into it and it flows along towards the tail. +However, there doesn't seem to be a way to put data in such that it +will travel upstream. To get around that, I've added a get() method +to Recv that will trigger a read on the socket. Recv will then put +the data to the next upstream module and we're on our way. As noted +earlier, that data will eventually show up either in the <i>reader</i> +(if installed on the stream open()) or the stream head reader task's +message queue. <HR> SHAR_EOF $shar_touch -am 1019163798 'page16.pre' && @@ -680,12 +690,12 @@ SHAR_EOF && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'page16.pre:' 'MD5 check failed' -7db337f2c6ec74d75560534dec550b0e page16.pre +2d89b3c894cfcfdfef47ae506913cdad page16.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page16.pre'`" - test 213 -eq "$shar_count" || - $echo 'page16.pre:' 'original size' '213,' 'current size' "$shar_count!" + test 660 -eq "$shar_count" || + $echo 'page16.pre:' 'original size' '660,' 'current size' "$shar_count!" fi fi # ============= page17.pre ============== @@ -694,8 +704,10 @@ if test -f 'page17.pre' && test "$first_param" != -c; then else $echo 'x -' extracting 'page17.pre' '(text)' sed 's/^X//' << 'SHAR_EOF' > 'page17.pre' && -This and the next three pages present the protocol objects that -provide compression and encryption. If you were hoping to +The Recv implementation is nearly as simple as Xmit. There's +opportunity for error when we get the message size and we have to +manage the lifetime of the tickler but other than that it's pretty +basic stuff. <HR> SHAR_EOF $shar_touch -am 1019163798 'page17.pre' && @@ -705,12 +717,212 @@ SHAR_EOF && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'page17.pre:' 'MD5 check failed' -d8553fb71b067ee360aca09883a6c775 page17.pre +7db337f2c6ec74d75560534dec550b0e page17.pre SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page17.pre'`" - test 129 -eq "$shar_count" || - $echo 'page17.pre:' 'original size' '129,' 'current size' "$shar_count!" + test 213 -eq "$shar_count" || + $echo 'page17.pre:' 'original size' '213,' 'current size' "$shar_count!" + fi +fi +# ============= page18.pre ============== +if test -f 'page18.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page18.pre' '(file already exists)' +else + $echo 'x -' extracting 'page18.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page18.pre' && +This and the next three pages present the protocol objects that +provide compression and encryption. If you were hoping to learn the +secrets of compression and encryption then I'm going to disappoint +you. There are some really good libraries out there that do this +stuff though and if anyone wants to integrate one of them into the +tutorial I'll be glad to take it! +<HR> +SHAR_EOF + $shar_touch -am 1019203698 'page18.pre' && + chmod 0664 'page18.pre' || + $echo 'restore of' 'page18.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page18.pre:' 'MD5 check failed' +dc5f706bd5a27009aed167c0b137648e page18.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page18.pre'`" + test 372 -eq "$shar_count" || + $echo 'page18.pre:' 'original size' '372,' 'current size' "$shar_count!" + fi +fi +# ============= page19.pre ============== +if test -f 'page19.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page19.pre' '(file already exists)' +else + $echo 'x -' extracting 'page19.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page19.pre' && +Here we implement the details of our compression. By having both +compression and decompression in one object it's easier to keep track +of implementation details. Splitting Xmit/Recv like I did will make +things more difficult if something has to change in their interaction. +<HR> +SHAR_EOF + $shar_touch -am 1019195798 'page19.pre' && + chmod 0664 'page19.pre' || + $echo 'restore of' 'page19.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page19.pre:' 'MD5 check failed' +4eb5dcd181f180d6c460971903efb288 page19.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page19.pre'`" + test 281 -eq "$shar_count" || + $echo 'page19.pre:' 'original size' '281,' 'current size' "$shar_count!" + fi +fi +# ============= page20.pre ============== +if test -f 'page20.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page20.pre' '(file already exists)' +else + $echo 'x -' extracting 'page20.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page20.pre' && +While I might be able to come up with a competitive compressor, I +don't have a snowball's chance to code up encryption. I'd be better +off piping the data through the standard Unix crypt command. +<P> +So, while I was lazy with Compress, I'm realistic with Crypt. I'll +show you the hooks and entry points and let someone else contribute an +encryptor. +<HR> +SHAR_EOF + $shar_touch -am 1019203798 'page20.pre' && + chmod 0664 'page20.pre' || + $echo 'restore of' 'page20.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page20.pre:' 'MD5 check failed' +7f75130d385a34b2c421a8d7cae69cc3 page20.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page20.pre'`" + test 356 -eq "$shar_count" || + $echo 'page20.pre:' 'original size' '356,' 'current size' "$shar_count!" + fi +fi +# ============= page21.pre ============== +if test -f 'page21.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page21.pre' '(file already exists)' +else + $echo 'x -' extracting 'page21.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page21.pre' && +The encryption implementation isn't any smarter than that of the +compressor. Still, the hooks are there for you to insert your +favorite library. +<HR> +SHAR_EOF + $shar_touch -am 1019203898 'page21.pre' && + chmod 0664 'page21.pre' || + $echo 'restore of' 'page21.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page21.pre:' 'MD5 check failed' +7f0f64452098cdef38c5496340a4b6c7 page21.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page21.pre'`" + test 151 -eq "$shar_count" || + $echo 'page21.pre:' 'original size' '151,' 'current size' "$shar_count!" + fi +fi +# ============= page22.pre ============== +if test -f 'page22.pre' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'page22.pre' '(file already exists)' +else + $echo 'x -' extracting 'page22.pre' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'page22.pre' && +Well, this has certainly been one of the more verbose tutorials to +date. I must say "thanks" to everyone who stuck it out this far! +<P> +A quick review of what we've done: +<UL> +X +<LI>Create a simple client application and Client object that uses a +Protocol Stream without really knowing how they work. The app (and +object) rely on the public interface of the Protocol Stream to get the +job done. At this level the protocol details are irrelevant. +<P> +<LI>Next, we create a simple server application and Server object +similar to the client. The Protocol Stream is of course used and we +have to know a little more so that we can insert a <i>reader</i> that +will ultimately process the data from the client. +<P> +<LI>We then go into the details of the Protocol_Stream implementation +and it's Protocol_Task object that forms the basis for the stream +tasks. Each object is kept as small and simple as possible to improve +reusability and future maintenance. +<P> +<LI>Finally, the individual protocol objects are discused. Separate +objects for the peer interface were created as well as the bogus +compressor and encryptor. The protocol can be extended or modified by +creating new such objects and installing them in the Protocol_Stream's +open() method. +X +</UL> +<P> +X +It doesn't sound like much but it certainly took a bunch of files to +get there. It's easy to get lost in the details when there's so much +to cover so you're encouraged to go over things a couple of times. +As always, enhancments of the tutorials is welcome! +<P> +Here's the complete file list: +<UL> +<LI><A HREF="client">Makefile</A> +<P> +<LI><A HREF="Makefile.client">client Makefile</A> +<LI><A HREF="client.cpp">client.cpp</A> +<LI><A HREF="Client.h">Client.h</A> +<LI><A HREF="Client.cpp">Client.cpp</A> +<P> +<LI><A HREF="Makefile.server">Server Makefile</A> +<LI><A HREF="server.cpp">server.cpp</A> +<LI><A HREF="Server.h">Server.h</A> +<LI><A HREF="Server.cpp">Server.cpp</A> +<LI><A HREF="Handler.h">Handler.h</A> +<LI><A HREF="Handler.cpp">Handler.cpp</A> +<P> +<LI><A HREF="Protocol_Stream.cpp">Protocol_Stream.cpp</A> +<LI><A HREF="Protocol_Stream.h">Protocol_Stream.h</A> +<LI><A HREF="Protocol_Task.cpp">Protocol_Task.cpp</A> +<LI><A HREF="Protocol_Task.h">Protocol_Task.h</A> +<P> +<LI><A HREF="Xmit.cpp">Xmit.cpp</A> +<LI><A HREF="Xmit.h">Xmit.h</A> +<LI><A HREF="Recv.cpp">Recv.cpp</A> +<LI><A HREF="Recv.h">Recv.h</A> +<P> +<LI><A HREF="Compressor.cpp">Compressor.cpp</A> +<LI><A HREF="Compressor.h">Compressor.h</A> +<LI><A HREF="Crypt.cpp">Crypt.cpp</A> +<LI><A HREF="Crypt.h">Crypt.h</A> +</UL> +SHAR_EOF + $shar_touch -am 1019204198 'page22.pre' && + chmod 0664 'page22.pre' || + $echo 'restore of' 'page22.pre' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'page22.pre:' 'MD5 check failed' +448ab5a481b51ec392aaac814a0bd005 page22.pre +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page22.pre'`" + test 2551 -eq "$shar_count" || + $echo 'page22.pre:' 'original size' '2551,' 'current size' "$shar_count!" fi fi # ============= page04.pst ============== @@ -726,6 +938,7 @@ X followed by an equally simple Client object. <P> For a quick look back: <UL> +<LI><A HREF="Makefile.client">client Makefile</A> <LI><A HREF="client.cpp">client.cpp</A> <LI><A HREF="Client.h">Client.h</A> <LI><A HREF="Client.cpp">Client.cpp</A> @@ -733,19 +946,19 @@ For a quick look back: <P> Now we'll move on and examine the server counter-part of our client. SHAR_EOF - $shar_touch -am 1019163798 'page04.pst' && + $shar_touch -am 1019202198 'page04.pst' && chmod 0664 'page04.pst' || $echo 'restore of' 'page04.pst' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'page04.pst:' 'MD5 check failed' -67b8e000792dd12883f8c89c09f14f13 page04.pst +8fcb88614fd879307c71cea1d53e276f page04.pst SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pst'`" - test 348 -eq "$shar_count" || - $echo 'page04.pst:' 'original size' '348,' 'current size' "$shar_count!" + test 398 -eq "$shar_count" || + $echo 'page04.pst:' 'original size' '398,' 'current size' "$shar_count!" fi fi # ============= page09.pst ============== @@ -763,23 +976,23 @@ cause confusion. We're going to discuss that mystery now but before we do here's the list of server files if you want to review: X <UL> +<LI><A HREF="Makefile.server">Server Makefile</A> <LI><A HREF="server.cpp">server.cpp</A> <LI><A HREF="Server.h">Server.h</A> <LI><A HREF="Server.cpp">Server.cpp</A> <LI><A HREF="Handler.h">Handler.h</A> <LI><A HREF="Handler.cpp">Handler.cpp</A> -<LI><A HREF="Makefile.server">Server Makefile</A> </UL> <P> SHAR_EOF - $shar_touch -am 1019163798 'page09.pst' && + $shar_touch -am 1019202198 'page09.pst' && chmod 0664 'page09.pst' || $echo 'restore of' 'page09.pst' 'failed' if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then md5sum -c << SHAR_EOF >/dev/null 2>&1 \ || $echo 'page09.pst:' 'MD5 check failed' -a391cfe4b4fcd0002c418310c5b254c9 page09.pst +22cfa1a8dadd48fccc7ed0c82aeba842 page09.pst SHAR_EOF else shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page09.pst'`" @@ -787,5 +1000,5 @@ SHAR_EOF $echo 'page09.pst:' 'original size' '609,' 'current size' "$shar_count!" fi fi -rm -fr _sh23762 +rm -fr _sh02329 exit 0 diff --git a/docs/tutorials/015/page04.html b/docs/tutorials/015/page04.html index 3835dcffb39..5bd479f186e 100644 --- a/docs/tutorials/015/page04.html +++ b/docs/tutorials/015/page04.html @@ -85,6 +85,7 @@ Ok, that's it for the client. We've seen a very simple main() <P> For a quick look back: <UL> +<LI><A HREF="Makefile.client">client Makefile</A> <LI><A HREF="client.cpp">client.cpp</A> <LI><A HREF="Client.h">Client.h</A> <LI><A HREF="Client.cpp">Client.cpp</A> diff --git a/docs/tutorials/015/page09.html b/docs/tutorials/015/page09.html index 6a842298010..e714c7334cf 100644 --- a/docs/tutorials/015/page09.html +++ b/docs/tutorials/015/page09.html @@ -213,12 +213,12 @@ cause confusion. We're going to discuss that mystery now but before we do here's the list of server files if you want to review: <UL> +<LI><A HREF="Makefile.server">Server Makefile</A> <LI><A HREF="server.cpp">server.cpp</A> <LI><A HREF="Server.h">Server.h</A> <LI><A HREF="Server.cpp">Server.cpp</A> <LI><A HREF="Handler.h">Handler.h</A> <LI><A HREF="Handler.cpp">Handler.cpp</A> -<LI><A HREF="Makefile.server">Server Makefile</A> </UL> <P> <P><HR WIDTH="100%"> diff --git a/docs/tutorials/015/page14.html b/docs/tutorials/015/page14.html index 2478f40606e..36e0b02f932 100644 --- a/docs/tutorials/015/page14.html +++ b/docs/tutorials/015/page14.html @@ -12,21 +12,15 @@ <P> <HR WIDTH="100%"> -The implementation of Xmit isn't too complicated. If we choose to -combine it with the Recv task we simply lift the recv() method from -that object and drop it into this one. +The Xmit object knows how to send data to the peer. It sits at the +tail of the stream and gets everything that flows down from the head. +In keeping with the spirit of things, this object does only one thing +and doesn't concern itself with anyone else' details. <P> -Note that close() must decide if it's being called when the stream is -shutdown or when it's svc() method exits. Since we tell the baseclass -not to use any threads it's a safe bet that flags will always be -non-zero. Still, it's good practice to plan for the future by -checking the value. -<P> -Note also that when we send the data we prefix it with the data size. -This let's our sibling Recv ensure that an entire block is received -together. This can be very important for compression and encryption -processes which typically work better with blocks of data instead of -streams of data. +The only thing you might want to do is combine it with Recv. Why? +As you'll realize in a page or two, the Xmit and Recv objects must +interact if you're going to ensure a safe transit. By having a single +object it's easier to coordinate and maintain the interaction. <HR> <PRE> diff --git a/docs/tutorials/015/page15.html b/docs/tutorials/015/page15.html index cae5a12f871..708e19b7183 100644 --- a/docs/tutorials/015/page15.html +++ b/docs/tutorials/015/page15.html @@ -12,18 +12,21 @@ <P> <HR WIDTH="100%"> -Recv is the sibling to Xmit. Again, they could be combined into a -single object if you want. +The implementation of Xmit isn't too complicated. If we choose to +combine it with the Recv task we simply lift the recv() method from +that object and drop it into this one. <P> -An ACE_Stream is designed to handle downstream traffic very -well. You put() data into it and it flows along towards the tail. -However, there doesn't seem to be a way to put data in such that it -will travel upstream. To get around that, I've added a get() method -to Recv that will trigger a read on the socket. Recv will then put -the data to the next upstream module and we're on our way. As noted -earlier, that data will eventually show up either in the <i>reader</i> -(if installed on the stream open()) or the stream head reader task's -message queue. +Note that close() must decide if it's being called when the stream is +shutdown or when it's svc() method exits. Since we tell the baseclass +not to use any threads it's a safe bet that flags will always be +non-zero. Still, it's good practice to plan for the future by +checking the value. +<P> +Note also that when we send the data we prefix it with the data size. +This let's our sibling Recv ensure that an entire block is received +together. This can be very important for compression and encryption +processes which typically work better with blocks of data instead of +streams of data. <HR> <PRE> diff --git a/docs/tutorials/015/page16.html b/docs/tutorials/015/page16.html index 75ca714d7dd..0ff4b76ec8a 100644 --- a/docs/tutorials/015/page16.html +++ b/docs/tutorials/015/page16.html @@ -12,10 +12,18 @@ <P> <HR WIDTH="100%"> -The Recv implementation is nearly as simple as Xmit. There's -opportunity for error when we get the message size and we have to -manage the lifetime of the tickler but other than that it's pretty -basic stuff. +Recv is the sibling to Xmit. Again, they could be combined into a +single object if you want. +<P> +An ACE_Stream is designed to handle downstream traffic very +well. You put() data into it and it flows along towards the tail. +However, there doesn't seem to be a way to put data in such that it +will travel upstream. To get around that, I've added a get() method +to Recv that will trigger a read on the socket. Recv will then put +the data to the next upstream module and we're on our way. As noted +earlier, that data will eventually show up either in the <i>reader</i> +(if installed on the stream open()) or the stream head reader task's +message queue. <HR> <PRE> diff --git a/docs/tutorials/015/page17.html b/docs/tutorials/015/page17.html index f563bfabd9a..d506014a77d 100644 --- a/docs/tutorials/015/page17.html +++ b/docs/tutorials/015/page17.html @@ -12,8 +12,10 @@ <P> <HR WIDTH="100%"> -This and the next three pages present the protocol objects that -provide compression and encryption. If you were hoping to +The Recv implementation is nearly as simple as Xmit. There's +opportunity for error when we get the message size and we have to +manage the lifetime of the tickler but other than that it's pretty +basic stuff. <HR> <PRE> @@ -103,4 +105,4 @@ int <font color=#008888>Recv::recv</font>(ACE_Message_Block * message, ACE_Time_ } </PRE> <P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] </CENTER> +<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page18.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page18.html b/docs/tutorials/015/page18.html new file mode 100644 index 00000000000..7f5603946b8 --- /dev/null +++ b/docs/tutorials/015/page18.html @@ -0,0 +1,68 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 015</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> +This and the next three pages present the protocol objects that +provide compression and encryption. If you were hoping to learn the +secrets of compression and encryption then I'm going to disappoint +you. There are some really good libraries out there that do this +stuff though and if anyone wants to integrate one of them into the +tutorial I'll be glad to take it! +<HR> +<PRE> + +<font color=red>// $Id$</font> + +<font color=blue>#ifndef</font> <font color=purple>COMPRESSOR_H</font> +<font color=blue>#define</font> <font color=purple>COMPRESSOR_h</font> + +<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" + +<font color=red>/* A reallly dumb compression object. (It actually adds 3 bytes to + every message block.) +*/</font> +class Compressor : public Protocol_Task +{ +public: + + typedef Protocol_Task inherited; + + <font color=red>// I've given you the option of creating this task derivative</font> + <font color=red>// with a number of threads. In retro-spect that really isn't </font> + <font color=red>// a good idea. Most client/server systems rely on requests</font> + <font color=red>// and responses happening in a predicatable order. Introduce </font> + <font color=red>// a thread pool and message queue and that ordering goes</font> + <font color=red>// right out the window. In other words: Don't ever use the</font> + <font color=red>// constructor parameter!</font> + Compressor( int _thr_count = 0 ); + + ~Compressor(void); + +protected: + + <font color=red>// This is called when the compressor is on the downstream</font> + <font color=red>// side. We'll take the message, compress it and move it</font> + <font color=red>// along to the next module.</font> + int send(ACE_Message_Block *message, + ACE_Time_Value *timeout); + + <font color=red>// This one is called on the upstream side. No surprise: we</font> + <font color=red>// decompress the data and send it on up the stream.</font> + int recv(ACE_Message_Block *message, + ACE_Time_Value *timeout); +}; + +<font color=blue>#endif</font> <font color=red>// COMPRESSOR_H</font> +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page19.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page19.html b/docs/tutorials/015/page19.html new file mode 100644 index 00000000000..73103ff15bf --- /dev/null +++ b/docs/tutorials/015/page19.html @@ -0,0 +1,119 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 015</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> +Here we implement the details of our compression. By having both +compression and decompression in one object it's easier to keep track +of implementation details. Splitting Xmit/Recv like I did will make +things more difficult if something has to change in their interaction. +<HR> +<PRE> + +<font color=red>// $Id$</font> + +<font color=blue>#include</font> "<font color=green>Compressor.h</font>" +<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" + +<font color=red>/* Construct our baseclass with the proper thread count. I really + should remove this option... + */</font> +<font color=#008888>Compressor::Compressor</font>( int _thr_count ) + : inherited(_thr_count) +{ + ; +} + +<font color=#008888>Compressor::~Compressor</font>(void) +{ + ; +} + +<font color=red>/* This is where you insert your compression code. Most compressors + want to work on a block of data instead of a byte-stream. + Fortunately the message block has a block that can be compressed. + Take a look at libz for a quick way to add compression to your + apps + */</font> +int <font color=#008888>Compressor::send</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) +{ + ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Compressor::send</font>() compressing (%s)\n</font>", message->rd_ptr() )); + + <font color=red>// Create a block to hold the compressed data. I belive libz</font> + <font color=red>// recommends a buffer about 10-20% larger than the source.</font> + <font color=red>// Other libraries/algorithms may have their own quirks.</font> + ACE_Message_Block * compressed = new ACE_Message_Block( message->size() ); + + <font color=red>// Perform a bogus compression algorithm. 'CD' just tells me</font> + <font color=red>// that this is compressed data and when we "<font color=green>decompress</font>" we'll </font> + <font color=red>// look for this signature to validate the data received.</font> + <font color=#008888>ACE_OS::sprintf</font>( compressed->wr_ptr(), "<font color=green>CD:%s</font>", message->rd_ptr() ); + compressed->wr_ptr( strlen(compressed->wr_ptr())+1 ); + + <font color=red>// Send the compressed data down the stream to the next module</font> + this->put_next( compressed ); + + <font color=red>// We're done here.</font> + message->release(); + + return( 0 ); +} + +<font color=red>/* And here's the decompression side. We've written Xmit/Recv so that + we're guaranteed to get an entire block of compressed data. If + we'd used recv() in the Recv object then we might have gotten a + partial block and that may not decompress very nicely. + */</font> +int <font color=#008888>Compressor::recv</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) +{ + ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Compress::recv</font>() decompressing (%s)\n</font>", message->rd_ptr() )); + + <font color=red>// Room for the decompressed data. In the real world you</font> + <font color=red>// would probably want to send the original (uncompressed)</font> + <font color=red>// data size in the message. You can predict the maximum</font> + <font color=red>// possible decompression size but it's cheap and easy just to </font> + <font color=red>// send that along. Look again at how I do exacly that</font> + <font color=red>// between Xmit and Recv.</font> + ACE_Message_Block * decompressed = new ACE_Message_Block( message->size() ); + + <font color=red>// Check for our signature. Even when you use a real</font> + <font color=red>// compression algorithm you may want to include your own</font> + <font color=red>// signature so that you can verify the block. It pays to be</font> + <font color=red>// paranoid!</font> + if( <font color=#008888>ACE_OS::strncmp</font>( message->rd_ptr(), "<font color=green>CD:</font>", 3 ) ) + { + ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) Improperly encompressed data.\n</font>" )); + message->release(); + return(-1); + } + + <font color=red>// Skip past the signature before going any further.</font> + message->rd_ptr( 3 ); + + <font color=red>// Perform a bogus decompression algorithm. This is where you </font> + <font color=red>// would feed to libz or your favorite decompressor. (It's</font> + <font color=red>// costly but you could invoke popen() on gzip!)</font> + <font color=#008888>ACE_OS::sprintf</font>( decompressed->wr_ptr(), "<font color=green>%s</font>", message->rd_ptr() ); + decompressed->wr_ptr( strlen(decompressed->wr_ptr())+1 ); + + <font color=red>// Recv the decompressed data down the stream to the next module</font> + this->put_next( decompressed ); + + <font color=red>// We're done here.</font> + message->release(); + + return( 0 ); +} + +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page20.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page20.html b/docs/tutorials/015/page20.html new file mode 100644 index 00000000000..6f81ebfa5ec --- /dev/null +++ b/docs/tutorials/015/page20.html @@ -0,0 +1,61 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 015</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> +While I might be able to come up with a competitive compressor, I +don't have a snowball's chance to code up encryption. I'd be better +off piping the data through the standard Unix crypt command. +<P> +So, while I was lazy with Compress, I'm realistic with Crypt. I'll +show you the hooks and entry points and let someone else contribute an +encryptor. +<HR> +<PRE> + +<font color=red>// $Id$</font> + +<font color=blue>#ifndef</font> <font color=purple>CRYPT_H</font> +<font color=blue>#define</font> <font color=purple>CRYPT_h</font> + +<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" + +<font color=red>/* An interface (adaptor) between your favorite encryption method and + an ACE_Stream. +*/</font> +class Crypt : public Protocol_Task +{ +public: + + typedef Protocol_Task inherited; + + <font color=red>// Again we have the option of multiple threads and again I</font> + <font color=red>// regret tempting folks to use it.</font> + Crypt( int _thr_count = 0 ); + + ~Crypt(void); + +protected: + + <font color=red>// Moving downstream will encrypt the data</font> + int send(ACE_Message_Block *message, + ACE_Time_Value *timeout); + + <font color=red>// And moving upstream will decrypt it.</font> + int recv(ACE_Message_Block *message, + ACE_Time_Value *timeout); +}; + +<font color=blue>#endif</font> <font color=red>// CRYPT_H</font> +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page21.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page21.html b/docs/tutorials/015/page21.html new file mode 100644 index 00000000000..5b017dcf609 --- /dev/null +++ b/docs/tutorials/015/page21.html @@ -0,0 +1,99 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 015</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> +The encryption implementation isn't any smarter than that of the +compressor. Still, the hooks are there for you to insert your +favorite library. +<HR> +<PRE> + +<font color=red>// $Id$</font> + +<font color=blue>#include</font> "<font color=green>Crypt.h</font>" +<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" + +<font color=red>/* The expected constructor... + */</font> +<font color=#008888>Crypt::Crypt</font>( int _thr_count ) + : inherited(_thr_count) +{ +} + +<font color=#008888>Crypt::~Crypt</font>(void) +{ +} + +<font color=red>/* To send the data we'll apply a signature and encryption. + */</font> +int <font color=#008888>Crypt::send</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) +{ + ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Crypt::send</font>() encrypting (%s)\n</font>", message->rd_ptr() )); + + <font color=red>// I suspect that some encryptors might change the data size.</font> + <font color=red>// It probably isn't safe to create a same-size destination buffer.</font> + ACE_Message_Block * encrypted = new ACE_Message_Block( message->size() ); + + <font color=red>// Perform a bogus encryption algorithm and add our safety</font> + <font color=red>// signature. Adding the original data size is also probably</font> + <font color=red>// a good idea that I haven't encorporated here.</font> + <font color=#008888>ACE_OS::sprintf</font>( encrypted->wr_ptr(), "<font color=green>ED:%s</font>", message->rd_ptr() ); + encrypted->wr_ptr( strlen(encrypted->wr_ptr())+1 ); + + <font color=red>// Send the encrypted data down the stream to the next module</font> + this->put_next( encrypted ); + + <font color=red>// We're done here.</font> + message->release(); + + return( 0 ); +} + +<font color=red>/* The upstream movement requires that we decrypt what the peer has + given us. +*/</font> +int <font color=#008888>Crypt::recv</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) +{ + ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Crypt::recv</font>() decrypting (%s)\n</font>", message->rd_ptr() )); + + <font color=red>// Create a destination for the decrypted data. The same</font> + <font color=red>// block size caveat exists of course.</font> + ACE_Message_Block * decrypted = new ACE_Message_Block( message->size() ); + + <font color=red>// Check the signature as expected.</font> + if( <font color=#008888>ACE_OS::strncmp</font>( message->rd_ptr(), "<font color=green>ED:</font>", 3 ) ) + { + ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) Improperly encrypted data.\n</font>" )); + message->release(); + return(-1); + } + + <font color=red>// Don't forget to skip past the signature before decrypting</font> + <font color=red>// or things will be quite exciting!</font> + message->rd_ptr( 3 ); + + <font color=red>// Perform a bogus decryption algorithm</font> + <font color=#008888>ACE_OS::sprintf</font>( decrypted->wr_ptr(), "<font color=green>%s</font>", message->rd_ptr() ); + decrypted->wr_ptr( strlen(decrypted->wr_ptr())+1 ); + + <font color=red>// Send the decrypted data down the stream to the next module</font> + this->put_next( decrypted ); + + <font color=red>// We're done here.</font> + message->release(); + + return( 0 ); +} +</PRE> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page22.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page22.html b/docs/tutorials/015/page22.html new file mode 100644 index 00000000000..90843ab2d31 --- /dev/null +++ b/docs/tutorials/015/page22.html @@ -0,0 +1,82 @@ +<HTML> +<HEAD> + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> + <META NAME="Author" CONTENT="James CE Johnson"> + <TITLE>ACE Tutorial 015</TITLE> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> + +<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> + +<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> + +<P> +<HR WIDTH="100%"> +Well, this has certainly been one of the more verbose tutorials to +date. I must say "thanks" to everyone who stuck it out this far! +<P> +A quick review of what we've done: +<UL> + +<LI>Create a simple client application and Client object that uses a +Protocol Stream without really knowing how they work. The app (and +object) rely on the public interface of the Protocol Stream to get the +job done. At this level the protocol details are irrelevant. +<P> +<LI>Next, we create a simple server application and Server object +similar to the client. The Protocol Stream is of course used and we +have to know a little more so that we can insert a <i>reader</i> that +will ultimately process the data from the client. +<P> +<LI>We then go into the details of the Protocol_Stream implementation +and it's Protocol_Task object that forms the basis for the stream +tasks. Each object is kept as small and simple as possible to improve +reusability and future maintenance. +<P> +<LI>Finally, the individual protocol objects are discused. Separate +objects for the peer interface were created as well as the bogus +compressor and encryptor. The protocol can be extended or modified by +creating new such objects and installing them in the Protocol_Stream's +open() method. + +</UL> +<P> + +It doesn't sound like much but it certainly took a bunch of files to +get there. It's easy to get lost in the details when there's so much +to cover so you're encouraged to go over things a couple of times. +As always, enhancments of the tutorials is welcome! +<P> +Here's the complete file list: +<UL> +<LI><A HREF="client">Makefile</A> +<P> +<LI><A HREF="Makefile.client">client Makefile</A> +<LI><A HREF="client.cpp">client.cpp</A> +<LI><A HREF="Client.h">Client.h</A> +<LI><A HREF="Client.cpp">Client.cpp</A> +<P> +<LI><A HREF="Makefile.server">Server Makefile</A> +<LI><A HREF="server.cpp">server.cpp</A> +<LI><A HREF="Server.h">Server.h</A> +<LI><A HREF="Server.cpp">Server.cpp</A> +<LI><A HREF="Handler.h">Handler.h</A> +<LI><A HREF="Handler.cpp">Handler.cpp</A> +<P> +<LI><A HREF="Protocol_Stream.cpp">Protocol_Stream.cpp</A> +<LI><A HREF="Protocol_Stream.h">Protocol_Stream.h</A> +<LI><A HREF="Protocol_Task.cpp">Protocol_Task.cpp</A> +<LI><A HREF="Protocol_Task.h">Protocol_Task.h</A> +<P> +<LI><A HREF="Xmit.cpp">Xmit.cpp</A> +<LI><A HREF="Xmit.h">Xmit.h</A> +<LI><A HREF="Recv.cpp">Recv.cpp</A> +<LI><A HREF="Recv.h">Recv.h</A> +<P> +<LI><A HREF="Compressor.cpp">Compressor.cpp</A> +<LI><A HREF="Compressor.h">Compressor.h</A> +<LI><A HREF="Crypt.cpp">Crypt.cpp</A> +<LI><A HREF="Crypt.h">Crypt.h</A> +</UL> +<P><HR WIDTH="100%"> +<CENTER>[<A HREF="..">Tutorial Index</A>] </CENTER> diff --git a/docs/tutorials/index.html b/docs/tutorials/index.html index 1ba3fbcc63a..bbdd6e350e7 100644 --- a/docs/tutorials/index.html +++ b/docs/tutorials/index.html @@ -93,6 +93,19 @@ A word about ACE_Message_Queue</H4> <LI> <A HREF="013/page01.html">Task chains and state machines</A></LI> </OL> + +<P><HR WIDTH="50%" align=left><P> + +<H4> +Paddling down (and up) the ACE_Stream</H4> + +<OL> +<LI> +<A HREF="014/page01.html">ACE_Stream Tutorial, Of Sorts</A></LI> +<LI> +<A HREF="015/page01.html">A certain amount of Protocol is required!</A></LI> +</OL> + <HR> <P>Back to the <A |