Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %    DDDD    IIIII   SSSSS  TTTTT  RRRR   IIIII  BBBB   U   U  TTTTT  EEEEE   %
      6 %    D   D     I     SS       T    R   R    I    B   B  U   U    T    E       %
      7 %    D   D     I      SSS     T    RRRR     I    BBBB   U   U    T    EEE     %
      8 %    D   D     I        SS    T    R R      I    B   B  U   U    T    E       %
      9 %    DDDDA   IIIII   SSSSS    T    R  R   IIIII  BBBB    UUU     T    EEEEE   %
     10 %                                                                             %
     11 %                      CCCC   AAA    CCCC  H   H  EEEEE                       %
     12 %                     C      A   A  C      H   H  E                           %
     13 %                     C      AAAAA  C      HHHHH  EEE                         %
     14 %                     C      A   A  C      H   H  E                           %
     15 %                      CCCC  A   A   CCCC  H   H  EEEEE                       %
     16 %                                                                             %
     17 %                                                                             %
     18 %                 MagickCore Distributed Pixel Cache Methods                  %
     19 %                                                                             %
     20 %                              Software Design                                %
     21 %                                   Cristy                                    %
     22 %                                January 2013                                 %
     23 %                                                                             %
     24 %                                                                             %
     25 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     26 %  dedicated to making software imaging solutions freely available.           %
     27 %                                                                             %
     28 %  You may not use this file except in compliance with the License.  You may  %
     29 %  obtain a copy of the License at                                            %
     30 %                                                                             %
     31 %    http://www.imagemagick.org/script/license.php                            %
     32 %                                                                             %
     33 %  Unless required by applicable law or agreed to in writing, software        %
     34 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     35 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     36 %  See the License for the specific language governing permissions and        %
     37 %  limitations under the License.                                             %
     38 %                                                                             %
     39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     40 %
     41 % A distributed pixel cache is an extension of the traditional pixel cache
     42 % available on a single host.  The distributed pixel cache may span multiple
     43 % servers so that it can grow in size and transactional capacity to support
     44 % very large images.  Start up the pixel cache server on one or more machines.
     45 % When you read or operate on an image and the local pixel cache resources are
     46 % exhausted, ImageMagick contacts one or more of these remote pixel servers to
     47 % store or retrieve pixels.
     48 %
     49 */
     50 
     51 /*
     53   Include declarations.
     54 */
     55 #include "MagickCore/studio.h"
     56 #include "MagickCore/cache.h"
     57 #include "MagickCore/cache-private.h"
     58 #include "MagickCore/distribute-cache.h"
     59 #include "MagickCore/distribute-cache-private.h"
     60 #include "MagickCore/exception.h"
     61 #include "MagickCore/exception-private.h"
     62 #include "MagickCore/geometry.h"
     63 #include "MagickCore/image.h"
     64 #include "MagickCore/image-private.h"
     65 #include "MagickCore/list.h"
     66 #include "MagickCore/locale_.h"
     67 #include "MagickCore/memory_.h"
     68 #include "MagickCore/nt-base-private.h"
     69 #include "MagickCore/pixel.h"
     70 #include "MagickCore/policy.h"
     71 #include "MagickCore/random_.h"
     72 #include "MagickCore/registry.h"
     73 #include "MagickCore/splay-tree.h"
     74 #include "MagickCore/string_.h"
     75 #include "MagickCore/string-private.h"
     76 #include "MagickCore/version.h"
     77 #include "MagickCore/version-private.h"
     78 #undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
     79 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
     80 #include <netinet/in.h>
     81 #include <netdb.h>
     82 #include <sys/socket.h>
     83 #include <arpa/inet.h>
     84 #define CHAR_TYPE_CAST
     85 #define CLOSE_SOCKET(socket) (void) close(socket)
     86 #define HANDLER_RETURN_TYPE void *
     87 #define HANDLER_RETURN_VALUE (void *) NULL
     88 #define SOCKET_TYPE int
     89 #define LENGTH_TYPE size_t
     90 #define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
     91 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
     92 #define CHAR_TYPE_CAST (char *)
     93 #define CLOSE_SOCKET(socket) (void) closesocket(socket)
     94 #define HANDLER_RETURN_TYPE DWORD WINAPI
     95 #define HANDLER_RETURN_VALUE 0
     96 #define SOCKET_TYPE SOCKET
     97 #define LENGTH_TYPE int
     98 #define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
     99 #else
    100 #ifdef __VMS
    101 #define CLOSE_SOCKET(socket) (void) close(socket)
    102 #else
    103 #define CLOSE_SOCKET(socket)
    104 #endif
    105 #define HANDLER_RETURN_TYPE  void *
    106 #define HANDLER_RETURN_VALUE  (void *) NULL
    107 #define SOCKET_TYPE  int
    108 #undef send
    109 #undef recv
    110 #define send(file,buffer,length,flags)  0
    111 #define recv(file,buffer,length,flags)  0
    112 #endif
    113 
    114 /*
    116   Define declarations.
    117 */
    118 #define DPCHostname  "127.0.0.1"
    119 #define DPCPendingConnections  10
    120 #define DPCPort  6668
    121 #define DPCSessionKeyLength  8
    122 #ifndef MSG_NOSIGNAL
    123 #  define MSG_NOSIGNAL 0
    124 #endif
    125 
    126 /*
    128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    129 %                                                                             %
    130 %                                                                             %
    131 %                                                                             %
    132 +   A c q u i r e D i s t r i b u t e C a c h e I n f o                       %
    133 %                                                                             %
    134 %                                                                             %
    135 %                                                                             %
    136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    137 %
    138 %  AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
    139 %
    140 %  The format of the AcquireDistributeCacheInfo method is:
    141 %
    142 %      DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
    143 %
    144 %  A description of each parameter follows:
    145 %
    146 %    o exception: return any errors or warnings in this structure.
    147 %
    148 */
    149 
    150 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
    151   unsigned char *magick_restrict message)
    152 {
    153   register MagickOffsetType
    154     i;
    155 
    156   ssize_t
    157     count;
    158 
    159 #if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
    160   magick_unreferenced(file);
    161   magick_unreferenced(message);
    162 #endif
    163 
    164   count=0;
    165   for (i=0; i < (MagickOffsetType) length; i+=count)
    166   {
    167     count=recv(file,CHAR_TYPE_CAST message+i,(LENGTH_TYPE) MagickMin(length-i,
    168       (MagickSizeType) SSIZE_MAX),0);
    169     if (count <= 0)
    170       {
    171         count=0;
    172         if (errno != EINTR)
    173           break;
    174       }
    175   }
    176   return(i);
    177 }
    178 
    179 static int ConnectPixelCacheServer(const char *hostname,const int port,
    180   size_t *session_key,ExceptionInfo *exception)
    181 {
    182 #if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
    183   char
    184     service[MagickPathExtent],
    185     *shared_secret;
    186 
    187   int
    188     status;
    189 
    190   SOCKET_TYPE
    191     client_socket;
    192 
    193   ssize_t
    194     count;
    195 
    196   struct addrinfo
    197     hint,
    198     *result;
    199 
    200   unsigned char
    201     secret[MagickPathExtent];
    202 
    203   /*
    204     Connect to distributed pixel cache and get session key.
    205   */
    206   *session_key=0;
    207   shared_secret=GetPolicyValue("shared-secret");
    208   if (shared_secret == (char *) NULL)
    209     {
    210       shared_secret=DestroyString(shared_secret);
    211       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
    212         "DistributedPixelCache","'%s'","shared secret expected");
    213       return(-1);
    214     }
    215   shared_secret=DestroyString(shared_secret);
    216 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
    217   NTInitializeWinsock(MagickTrue);
    218 #endif
    219   (void) ResetMagickMemory(&hint,0,sizeof(hint));
    220   hint.ai_family=AF_INET;
    221   hint.ai_socktype=SOCK_STREAM;
    222   hint.ai_flags=AI_PASSIVE;
    223   (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
    224   status=getaddrinfo(hostname,service,&hint,&result);
    225   if (status != 0)
    226     {
    227       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
    228         "DistributedPixelCache","'%s'",hostname);
    229       return(-1);
    230     }
    231   client_socket=socket(result->ai_family,result->ai_socktype,
    232     result->ai_protocol);
    233   if (client_socket == -1)
    234     {
    235       freeaddrinfo(result);
    236       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
    237         "DistributedPixelCache","'%s'",hostname);
    238       return(-1);
    239     }
    240   status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
    241   if (status == -1)
    242     {
    243       CLOSE_SOCKET(client_socket);
    244       freeaddrinfo(result);
    245       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
    246         "DistributedPixelCache","'%s'",hostname);
    247       return(-1);
    248     }
    249   count=recv(client_socket,CHAR_TYPE_CAST secret,MagickPathExtent,0);
    250   if (count != -1)
    251     {
    252       StringInfo
    253         *nonce;
    254 
    255       nonce=AcquireStringInfo(count);
    256       (void) memcpy(GetStringInfoDatum(nonce),secret,(size_t) count);
    257       *session_key=GetMagickSignature(nonce);
    258       nonce=DestroyStringInfo(nonce);
    259     }
    260   if (*session_key == 0)
    261     {
    262       CLOSE_SOCKET(client_socket);
    263       client_socket=(SOCKET_TYPE) (-1);
    264     }
    265   freeaddrinfo(result);
    266   return(client_socket);
    267 #else
    268   (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
    269     "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
    270   return(MagickFalse);
    271 #endif
    272 }
    273 
    274 static char *GetHostname(int *port,ExceptionInfo *exception)
    275 {
    276   char
    277     *host,
    278     *hosts,
    279     **hostlist;
    280 
    281   int
    282     argc;
    283 
    284   register ssize_t
    285     i;
    286 
    287   static size_t
    288     id = 0;
    289 
    290   /*
    291     Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
    292   */
    293   hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",exception);
    294   if (hosts == (char *) NULL)
    295     {
    296       *port=DPCPort;
    297       return(AcquireString(DPCHostname));
    298     }
    299   (void) SubstituteString(&hosts,","," ");
    300   hostlist=StringToArgv(hosts,&argc);
    301   hosts=DestroyString(hosts);
    302   if (hostlist == (char **) NULL)
    303     {
    304       *port=DPCPort;
    305       return(AcquireString(DPCHostname));
    306     }
    307   hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
    308   for (i=0; i < (ssize_t) argc; i++)
    309     hostlist[i]=DestroyString(hostlist[i]);
    310   hostlist=(char **) RelinquishMagickMemory(hostlist);
    311   (void) SubstituteString(&hosts,":"," ");
    312   hostlist=StringToArgv(hosts,&argc);
    313   if (hostlist == (char **) NULL)
    314     {
    315       *port=DPCPort;
    316       return(AcquireString(DPCHostname));
    317     }
    318   host=AcquireString(hostlist[1]);
    319   if (hostlist[2] == (char *) NULL)
    320     *port=DPCPort;
    321   else
    322     *port=StringToLong(hostlist[2]);
    323   for (i=0; i < (ssize_t) argc; i++)
    324     hostlist[i]=DestroyString(hostlist[i]);
    325   hostlist=(char **) RelinquishMagickMemory(hostlist);
    326   return(host);
    327 }
    328 
    329 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
    330   ExceptionInfo *exception)
    331 {
    332   char
    333     *hostname;
    334 
    335   DistributeCacheInfo
    336     *server_info;
    337 
    338   size_t
    339     session_key;
    340 
    341   /*
    342     Connect to the distributed pixel cache server.
    343   */
    344   server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info));
    345   if (server_info == (DistributeCacheInfo *) NULL)
    346     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    347   (void) ResetMagickMemory(server_info,0,sizeof(*server_info));
    348   server_info->signature=MagickCoreSignature;
    349   server_info->port=0;
    350   hostname=GetHostname(&server_info->port,exception);
    351   session_key=0;
    352   server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
    353     &session_key,exception);
    354   if (server_info->file == -1)
    355     server_info=DestroyDistributeCacheInfo(server_info);
    356   else
    357     {
    358       server_info->session_key=session_key;
    359       (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
    360       server_info->debug=IsEventLogging();
    361     }
    362   hostname=DestroyString(hostname);
    363   return(server_info);
    364 }
    365 
    366 /*
    368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    369 %                                                                             %
    370 %                                                                             %
    371 %                                                                             %
    372 +   D e s t r o y D i s t r i b u t e C a c h e I n f o                       %
    373 %                                                                             %
    374 %                                                                             %
    375 %                                                                             %
    376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    377 %
    378 %  DestroyDistributeCacheInfo() deallocates memory associated with an
    379 %  DistributeCacheInfo structure.
    380 %
    381 %  The format of the DestroyDistributeCacheInfo method is:
    382 %
    383 %      DistributeCacheInfo *DestroyDistributeCacheInfo(
    384 %        DistributeCacheInfo *server_info)
    385 %
    386 %  A description of each parameter follows:
    387 %
    388 %    o server_info: the distributed cache info.
    389 %
    390 */
    391 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
    392   DistributeCacheInfo *server_info)
    393 {
    394   assert(server_info != (DistributeCacheInfo *) NULL);
    395   assert(server_info->signature == MagickCoreSignature);
    396   if (server_info->file > 0)
    397     CLOSE_SOCKET(server_info->file);
    398   server_info->signature=(~MagickCoreSignature);
    399   server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
    400   return(server_info);
    401 }
    402 
    403 /*
    405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    406 %                                                                             %
    407 %                                                                             %
    408 %                                                                             %
    409 +   D i s t r i b u t e P i x e l C a c h e S e r v e r                       %
    410 %                                                                             %
    411 %                                                                             %
    412 %                                                                             %
    413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    414 %
    415 %  DistributePixelCacheServer() waits on the specified port for commands to
    416 %  create, read, update, or destroy a pixel cache.
    417 %
    418 %  The format of the DistributePixelCacheServer() method is:
    419 %
    420 %      void DistributePixelCacheServer(const int port)
    421 %
    422 %  A description of each parameter follows:
    423 %
    424 %    o port: connect the distributed pixel cache at this port.
    425 %
    426 %    o exception: return any errors or warnings in this structure.
    427 %
    428 */
    429 
    430 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
    431   const size_t session_key)
    432 {
    433   /*
    434     Destroy distributed pixel cache.
    435   */
    436   return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
    437 }
    438 
    439 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
    440   const unsigned char *magick_restrict message)
    441 {
    442   MagickOffsetType
    443     count;
    444 
    445   register MagickOffsetType
    446     i;
    447 
    448 #if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
    449   magick_unreferenced(file);
    450   magick_unreferenced(message);
    451 #endif
    452 
    453   /*
    454     Ensure a complete message is sent.
    455   */
    456   count=0;
    457   for (i=0; i < (MagickOffsetType) length; i+=count)
    458   {
    459     count=(MagickOffsetType) send(file,CHAR_TYPE_CAST message+i,(LENGTH_TYPE)
    460       MagickMin(length-i,(MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
    461     if (count <= 0)
    462       {
    463         count=0;
    464         if (errno != EINTR)
    465           break;
    466       }
    467   }
    468   return(i);
    469 }
    470 
    471 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,int file,
    472   const size_t session_key,ExceptionInfo *exception)
    473 {
    474   Image
    475     *image;
    476 
    477   MagickBooleanType
    478     status;
    479 
    480   MagickOffsetType
    481     count;
    482 
    483   MagickSizeType
    484     length;
    485 
    486   register unsigned char
    487     *p;
    488 
    489   unsigned char
    490     message[MagickPathExtent];
    491 
    492   /*
    493     Open distributed pixel cache.
    494   */
    495   image=AcquireImage((ImageInfo *) NULL,exception);
    496   if (image == (Image *) NULL)
    497     return(MagickFalse);
    498   length=sizeof(image->storage_class)+sizeof(image->colorspace)+
    499     sizeof(image->alpha_trait)+sizeof(image->read_mask)+
    500     sizeof(image->write_mask)+sizeof(image->columns)+sizeof(image->rows)+
    501     sizeof(image->number_channels)+MaxPixelChannels*sizeof(*image->channel_map)+
    502     sizeof(image->metacontent_extent);
    503   count=dpc_read(file,length,message);
    504   if (count != (MagickOffsetType) length)
    505     return(MagickFalse);
    506   /*
    507     Deserialize the image attributes.
    508   */
    509   p=message;
    510   (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
    511   p+=sizeof(image->storage_class);
    512   (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
    513   p+=sizeof(image->colorspace);
    514   (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
    515   p+=sizeof(image->alpha_trait);
    516   (void) memcpy(&image->read_mask,p,sizeof(image->read_mask));
    517   p+=sizeof(image->read_mask);
    518   (void) memcpy(&image->write_mask,p,sizeof(image->write_mask));
    519   p+=sizeof(image->write_mask);
    520   (void) memcpy(&image->columns,p,sizeof(image->columns));
    521   p+=sizeof(image->columns);
    522   (void) memcpy(&image->rows,p,sizeof(image->rows));
    523   p+=sizeof(image->rows);
    524   (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
    525   p+=sizeof(image->number_channels);
    526   (void) memcpy(image->channel_map,p,MaxPixelChannels*
    527     sizeof(*image->channel_map));
    528   p+=MaxPixelChannels*sizeof(*image->channel_map);
    529   (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
    530   p+=sizeof(image->metacontent_extent);
    531   if (SyncImagePixelCache(image,exception) == MagickFalse)
    532     return(MagickFalse);
    533   status=AddValueToSplayTree(registry,(const void *) session_key,image);
    534   return(status);
    535 }
    536 
    537 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
    538   int file,const size_t session_key,ExceptionInfo *exception)
    539 {
    540   const unsigned char
    541     *metacontent;
    542 
    543   Image
    544     *image;
    545 
    546   MagickOffsetType
    547     count;
    548 
    549   MagickSizeType
    550     length;
    551 
    552   RectangleInfo
    553     region;
    554 
    555   register const Quantum
    556     *p;
    557 
    558   register unsigned char
    559     *q;
    560 
    561   unsigned char
    562     message[MagickPathExtent];
    563 
    564   /*
    565     Read distributed pixel cache metacontent.
    566   */
    567   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
    568   if (image == (Image *) NULL)
    569     return(MagickFalse);
    570   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
    571     sizeof(region.y)+sizeof(length);
    572   count=dpc_read(file,length,message);
    573   if (count != (MagickOffsetType) length)
    574     return(MagickFalse);
    575   q=message;
    576   (void) memcpy(&region.width,q,sizeof(region.width));
    577   q+=sizeof(region.width);
    578   (void) memcpy(&region.height,q,sizeof(region.height));
    579   q+=sizeof(region.height);
    580   (void) memcpy(&region.x,q,sizeof(region.x));
    581   q+=sizeof(region.x);
    582   (void) memcpy(&region.y,q,sizeof(region.y));
    583   q+=sizeof(region.y);
    584   (void) memcpy(&length,q,sizeof(length));
    585   q+=sizeof(length);
    586   p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
    587     exception);
    588   if (p == (const Quantum *) NULL)
    589     return(MagickFalse);
    590   metacontent=(const unsigned char *) GetVirtualMetacontent(image);
    591   count=dpc_send(file,length,metacontent);
    592   if (count != (MagickOffsetType) length)
    593     return(MagickFalse);
    594   return(MagickTrue);
    595 }
    596 
    597 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
    598   int file,const size_t session_key,ExceptionInfo *exception)
    599 {
    600   Image
    601     *image;
    602 
    603   MagickOffsetType
    604     count;
    605 
    606   MagickSizeType
    607     length;
    608 
    609   RectangleInfo
    610     region;
    611 
    612   register const Quantum
    613     *p;
    614 
    615   register unsigned char
    616     *q;
    617 
    618   unsigned char
    619     message[MagickPathExtent];
    620 
    621   /*
    622     Read distributed pixel cache pixels.
    623   */
    624   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
    625   if (image == (Image *) NULL)
    626     return(MagickFalse);
    627   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
    628     sizeof(region.y)+sizeof(length);
    629   count=dpc_read(file,length,message);
    630   if (count != (MagickOffsetType) length)
    631     return(MagickFalse);
    632   q=message;
    633   (void) memcpy(&region.width,q,sizeof(region.width));
    634   q+=sizeof(region.width);
    635   (void) memcpy(&region.height,q,sizeof(region.height));
    636   q+=sizeof(region.height);
    637   (void) memcpy(&region.x,q,sizeof(region.x));
    638   q+=sizeof(region.x);
    639   (void) memcpy(&region.y,q,sizeof(region.y));
    640   q+=sizeof(region.y);
    641   (void) memcpy(&length,q,sizeof(length));
    642   q+=sizeof(length);
    643   p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
    644     exception);
    645   if (p == (const Quantum *) NULL)
    646     return(MagickFalse);
    647   count=dpc_send(file,length,(unsigned char *) p);
    648   if (count != (MagickOffsetType) length)
    649     return(MagickFalse);
    650   return(MagickTrue);
    651 }
    652 
    653 static void *RelinquishImageRegistry(void *image)
    654 {
    655   return((void *) DestroyImageList((Image *) image));
    656 }
    657 
    658 static MagickBooleanType WriteDistributeCacheMetacontent(
    659   SplayTreeInfo *registry,int file,const size_t session_key,
    660   ExceptionInfo *exception)
    661 {
    662   Image
    663     *image;
    664 
    665   MagickOffsetType
    666     count;
    667 
    668   MagickSizeType
    669     length;
    670 
    671   RectangleInfo
    672     region;
    673 
    674   register Quantum
    675     *q;
    676 
    677   register unsigned char
    678     *p;
    679 
    680   unsigned char
    681     message[MagickPathExtent],
    682     *metacontent;
    683 
    684   /*
    685     Write distributed pixel cache metacontent.
    686   */
    687   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
    688   if (image == (Image *) NULL)
    689     return(MagickFalse);
    690   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
    691     sizeof(region.y)+sizeof(length);
    692   count=dpc_read(file,length,message);
    693   if (count != (MagickOffsetType) length)
    694     return(MagickFalse);
    695   p=message;
    696   (void) memcpy(&region.width,p,sizeof(region.width));
    697   p+=sizeof(region.width);
    698   (void) memcpy(&region.height,p,sizeof(region.height));
    699   p+=sizeof(region.height);
    700   (void) memcpy(&region.x,p,sizeof(region.x));
    701   p+=sizeof(region.x);
    702   (void) memcpy(&region.y,p,sizeof(region.y));
    703   p+=sizeof(region.y);
    704   (void) memcpy(&length,p,sizeof(length));
    705   p+=sizeof(length);
    706   q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
    707     exception);
    708   if (q == (Quantum *) NULL)
    709     return(MagickFalse);
    710   metacontent=(unsigned char *) GetAuthenticMetacontent(image);
    711   count=dpc_read(file,length,metacontent);
    712   if (count != (MagickOffsetType) length)
    713     return(MagickFalse);
    714   return(SyncAuthenticPixels(image,exception));
    715 }
    716 
    717 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
    718   int file,const size_t session_key,ExceptionInfo *exception)
    719 {
    720   Image
    721     *image;
    722 
    723   MagickOffsetType
    724     count;
    725 
    726   MagickSizeType
    727     length;
    728 
    729   RectangleInfo
    730     region;
    731 
    732   register Quantum
    733     *q;
    734 
    735   register unsigned char
    736     *p;
    737 
    738   unsigned char
    739     message[MagickPathExtent];
    740 
    741   /*
    742     Write distributed pixel cache pixels.
    743   */
    744   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
    745   if (image == (Image *) NULL)
    746     return(MagickFalse);
    747   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
    748     sizeof(region.y)+sizeof(length);
    749   count=dpc_read(file,length,message);
    750   if (count != (MagickOffsetType) length)
    751     return(MagickFalse);
    752   p=message;
    753   (void) memcpy(&region.width,p,sizeof(region.width));
    754   p+=sizeof(region.width);
    755   (void) memcpy(&region.height,p,sizeof(region.height));
    756   p+=sizeof(region.height);
    757   (void) memcpy(&region.x,p,sizeof(region.x));
    758   p+=sizeof(region.x);
    759   (void) memcpy(&region.y,p,sizeof(region.y));
    760   p+=sizeof(region.y);
    761   (void) memcpy(&length,p,sizeof(length));
    762   p+=sizeof(length);
    763   q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
    764     exception);
    765   if (q == (Quantum *) NULL)
    766     return(MagickFalse);
    767   count=dpc_read(file,length,(unsigned char *) q);
    768   if (count != (MagickOffsetType) length)
    769     return(MagickFalse);
    770   return(SyncAuthenticPixels(image,exception));
    771 }
    772 
    773 static HANDLER_RETURN_TYPE DistributePixelCacheClient(void *socket)
    774 {
    775   char
    776     *shared_secret;
    777 
    778   ExceptionInfo
    779     *exception;
    780 
    781   MagickBooleanType
    782     status;
    783 
    784   MagickOffsetType
    785     count;
    786 
    787   register unsigned char
    788     *p;
    789 
    790   RandomInfo
    791     *random_info;
    792 
    793   size_t
    794     key,
    795     session_key;
    796 
    797   SOCKET_TYPE
    798     client_socket;
    799 
    800   SplayTreeInfo
    801     *registry;
    802 
    803   StringInfo
    804     *secret;
    805 
    806   unsigned char
    807     command,
    808     session[2*MagickPathExtent];
    809 
    810   /*
    811     Distributed pixel cache client.
    812   */
    813   shared_secret=GetPolicyValue("shared-secret");
    814   if (shared_secret == (char *) NULL)
    815     ThrowFatalException(CacheFatalError,"shared secret expected");
    816   p=session;
    817   (void) CopyMagickString((char *) p,shared_secret,MagickPathExtent);
    818   p+=strlen(shared_secret);
    819   shared_secret=DestroyString(shared_secret);
    820   random_info=AcquireRandomInfo();
    821   secret=GetRandomKey(random_info,DPCSessionKeyLength);
    822   (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
    823   session_key=GetMagickSignature(secret);
    824   random_info=DestroyRandomInfo(random_info);
    825   exception=AcquireExceptionInfo();
    826   registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
    827     (void *(*)(void *)) NULL,RelinquishImageRegistry);
    828   client_socket=(*(SOCKET_TYPE *) socket);
    829   count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
    830   secret=DestroyStringInfo(secret);
    831   for ( ; ; )
    832   {
    833     count=dpc_read(client_socket,1,(unsigned char *) &command);
    834     if (count <= 0)
    835       break;
    836     count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
    837     if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
    838       break;
    839     status=MagickFalse;
    840     switch (command)
    841     {
    842       case 'o':
    843       {
    844         status=OpenDistributeCache(registry,client_socket,session_key,
    845           exception);
    846         count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
    847         break;
    848       }
    849       case 'r':
    850       {
    851         status=ReadDistributeCachePixels(registry,client_socket,session_key,
    852           exception);
    853         break;
    854       }
    855       case 'R':
    856       {
    857         status=ReadDistributeCacheMetacontent(registry,client_socket,
    858           session_key,exception);
    859         break;
    860       }
    861       case 'w':
    862       {
    863         status=WriteDistributeCachePixels(registry,client_socket,session_key,
    864           exception);
    865         break;
    866       }
    867       case 'W':
    868       {
    869         status=WriteDistributeCacheMetacontent(registry,client_socket,
    870           session_key,exception);
    871         break;
    872       }
    873       case 'd':
    874       {
    875         status=DestroyDistributeCache(registry,session_key);
    876         break;
    877       }
    878       default:
    879         break;
    880     }
    881     if (status == MagickFalse)
    882       break;
    883     if (command == 'd')
    884       break;
    885   }
    886   count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
    887   CLOSE_SOCKET(client_socket);
    888   exception=DestroyExceptionInfo(exception);
    889   registry=DestroySplayTree(registry);
    890   return(HANDLER_RETURN_VALUE);
    891 }
    892 
    893 MagickExport void DistributePixelCacheServer(const int port,
    894   ExceptionInfo *exception)
    895 {
    896 #if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
    897   char
    898     service[MagickPathExtent];
    899 
    900   int
    901     status;
    902 
    903 #if defined(MAGICKCORE_THREAD_SUPPORT)
    904   pthread_attr_t
    905     attributes;
    906 
    907   pthread_t
    908     threads;
    909 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    910   DWORD
    911     threadID;
    912 #else
    913   Not implemented!
    914 #endif
    915 
    916   register struct addrinfo
    917     *p;
    918 
    919   SOCKET_TYPE
    920     server_socket;
    921 
    922   struct addrinfo
    923     hint,
    924     *result;
    925 
    926   struct sockaddr_in
    927     address;
    928 
    929   /*
    930     Launch distributed pixel cache server.
    931   */
    932   assert(exception != (ExceptionInfo *) NULL);
    933   assert(exception->signature == MagickCoreSignature);
    934 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
    935   NTInitializeWinsock(MagickFalse);
    936 #endif
    937   (void) ResetMagickMemory(&hint,0,sizeof(hint));
    938   hint.ai_family=AF_INET;
    939   hint.ai_socktype=SOCK_STREAM;
    940   hint.ai_flags=AI_PASSIVE;
    941   (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
    942   status=getaddrinfo((const char *) NULL,service,&hint,&result);
    943   if (status != 0)
    944     ThrowFatalException(CacheFatalError,"UnableToListen");
    945   server_socket=(SOCKET_TYPE) 0;
    946   for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
    947   {
    948     int
    949       one;
    950 
    951     server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
    952     if (server_socket == -1)
    953       continue;
    954     one=1;
    955     status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,
    956       CHAR_TYPE_CAST &one,(socklen_t) sizeof(one));
    957     if (status == -1)
    958       {
    959         CLOSE_SOCKET(server_socket);
    960         continue;
    961       }
    962     status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
    963     if (status == -1)
    964       {
    965         CLOSE_SOCKET(server_socket);
    966         continue;
    967       }
    968     break;
    969   }
    970   if (p == (struct addrinfo *) NULL)
    971     ThrowFatalException(CacheFatalError,"UnableToBind");
    972   freeaddrinfo(result);
    973   status=listen(server_socket,DPCPendingConnections);
    974   if (status != 0)
    975     ThrowFatalException(CacheFatalError,"UnableToListen");
    976 #if defined(MAGICKCORE_THREAD_SUPPORT)
    977   pthread_attr_init(&attributes);
    978 #endif
    979   for ( ; ; )
    980   {
    981     SOCKET_TYPE
    982       client_socket;
    983 
    984     socklen_t
    985       length;
    986 
    987     length=(socklen_t) sizeof(address);
    988     client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
    989     if (client_socket == -1)
    990       ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
    991 #if defined(MAGICKCORE_THREAD_SUPPORT)
    992     status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
    993       (void *) &client_socket);
    994     if (status == -1)
    995       ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
    996 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
    997     if (CreateThread(0,0,DistributePixelCacheClient,(void*) &client_socket,0,
    998         &threadID) == (HANDLE) NULL)
    999       ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
   1000 #else
   1001     Not implemented!
   1002 #endif
   1003   }
   1004 #else
   1005   magick_unreferenced(port);
   1006   magick_unreferenced(exception);
   1007   ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
   1008 #endif
   1009 }
   1010 
   1011 /*
   1013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1014 %                                                                             %
   1015 %                                                                             %
   1016 %                                                                             %
   1017 +   G e t D i s t r i b u t e C a c h e F i l e                               %
   1018 %                                                                             %
   1019 %                                                                             %
   1020 %                                                                             %
   1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1022 %
   1023 %  GetDistributeCacheFile() returns the file associated with this
   1024 %  DistributeCacheInfo structure.
   1025 %
   1026 %  The format of the GetDistributeCacheFile method is:
   1027 %
   1028 %      int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
   1029 %
   1030 %  A description of each parameter follows:
   1031 %
   1032 %    o server_info: the distributed cache info.
   1033 %
   1034 */
   1035 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
   1036 {
   1037   assert(server_info != (DistributeCacheInfo *) NULL);
   1038   assert(server_info->signature == MagickCoreSignature);
   1039   return(server_info->file);
   1040 }
   1041 
   1042 /*
   1044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1045 %                                                                             %
   1046 %                                                                             %
   1047 %                                                                             %
   1048 +   G e t D i s t r i b u t e C a c h e H o s t n a m e                       %
   1049 %                                                                             %
   1050 %                                                                             %
   1051 %                                                                             %
   1052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1053 %
   1054 %  GetDistributeCacheHostname() returns the hostname associated with this
   1055 %  DistributeCacheInfo structure.
   1056 %
   1057 %  The format of the GetDistributeCacheHostname method is:
   1058 %
   1059 %      const char *GetDistributeCacheHostname(
   1060 %        const DistributeCacheInfo *server_info)
   1061 %
   1062 %  A description of each parameter follows:
   1063 %
   1064 %    o server_info: the distributed cache info.
   1065 %
   1066 */
   1067 MagickPrivate const char *GetDistributeCacheHostname(
   1068   const DistributeCacheInfo *server_info)
   1069 {
   1070   assert(server_info != (DistributeCacheInfo *) NULL);
   1071   assert(server_info->signature == MagickCoreSignature);
   1072   return(server_info->hostname);
   1073 }
   1074 
   1075 /*
   1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1078 %                                                                             %
   1079 %                                                                             %
   1080 %                                                                             %
   1081 +   G e t D i s t r i b u t e C a c h e P o r t                               %
   1082 %                                                                             %
   1083 %                                                                             %
   1084 %                                                                             %
   1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1086 %
   1087 %  GetDistributeCachePort() returns the port associated with this
   1088 %  DistributeCacheInfo structure.
   1089 %
   1090 %  The format of the GetDistributeCachePort method is:
   1091 %
   1092 %      int GetDistributeCachePort(const DistributeCacheInfo *server_info)
   1093 %
   1094 %  A description of each parameter follows:
   1095 %
   1096 %    o server_info: the distributed cache info.
   1097 %
   1098 */
   1099 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
   1100 {
   1101   assert(server_info != (DistributeCacheInfo *) NULL);
   1102   assert(server_info->signature == MagickCoreSignature);
   1103   return(server_info->port);
   1104 }
   1105 
   1106 /*
   1108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1109 %                                                                             %
   1110 %                                                                             %
   1111 %                                                                             %
   1112 +   O p e n D i s t r i b u t e P i x e l C a c h e                           %
   1113 %                                                                             %
   1114 %                                                                             %
   1115 %                                                                             %
   1116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1117 %
   1118 %  OpenDistributePixelCache() opens a pixel cache on a remote server.
   1119 %
   1120 %  The format of the OpenDistributePixelCache method is:
   1121 %
   1122 %      MagickBooleanType *OpenDistributePixelCache(
   1123 %        DistributeCacheInfo *server_info,Image *image)
   1124 %
   1125 %  A description of each parameter follows:
   1126 %
   1127 %    o server_info: the distributed cache info.
   1128 %
   1129 %    o image: the image.
   1130 %
   1131 */
   1132 MagickPrivate MagickBooleanType OpenDistributePixelCache(
   1133   DistributeCacheInfo *server_info,Image *image)
   1134 {
   1135   MagickBooleanType
   1136 #ifdef __VMS
   1137      status=MagickTrue;
   1138 #else
   1139     status;
   1140 #endif
   1141 
   1142   MagickOffsetType
   1143     count;
   1144 
   1145   register unsigned char
   1146     *p;
   1147 
   1148   unsigned char
   1149     message[MagickPathExtent];
   1150 
   1151   /*
   1152     Open distributed pixel cache.
   1153   */
   1154   assert(server_info != (DistributeCacheInfo *) NULL);
   1155   assert(server_info->signature == MagickCoreSignature);
   1156   assert(image != (Image *) NULL);
   1157   assert(image->signature == MagickCoreSignature);
   1158   p=message;
   1159   *p++='o';  /* open */
   1160   /*
   1161     Serialize image attributes (see ValidatePixelCacheMorphology()).
   1162   */
   1163   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   1164   p+=sizeof(server_info->session_key);
   1165   (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
   1166   p+=sizeof(image->storage_class);
   1167   (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
   1168   p+=sizeof(image->colorspace);
   1169   (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
   1170   p+=sizeof(image->alpha_trait);
   1171   (void) memcpy(p,&image->read_mask,sizeof(image->read_mask));
   1172   p+=sizeof(image->read_mask);
   1173   (void) memcpy(p,&image->write_mask,sizeof(image->write_mask));
   1174   p+=sizeof(image->write_mask);
   1175   (void) memcpy(p,&image->columns,sizeof(image->columns));
   1176   p+=sizeof(image->columns);
   1177   (void) memcpy(p,&image->rows,sizeof(image->rows));
   1178   p+=sizeof(image->rows);
   1179   (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
   1180   p+=sizeof(image->number_channels);
   1181   (void) memcpy(p,image->channel_map,MaxPixelChannels*
   1182     sizeof(*image->channel_map));
   1183   p+=MaxPixelChannels*sizeof(*image->channel_map);
   1184   (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
   1185   p+=sizeof(image->metacontent_extent);
   1186   count=dpc_send(server_info->file,p-message,message);
   1187   if (count != (MagickOffsetType) (p-message))
   1188     return(MagickFalse);
   1189   status=MagickFalse;
   1190   count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
   1191   if (count != (MagickOffsetType) sizeof(status))
   1192     return(MagickFalse);
   1193   return(status);
   1194 }
   1195 
   1196 /*
   1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1199 %                                                                             %
   1200 %                                                                             %
   1201 %                                                                             %
   1202 +   R e a d D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t     %
   1203 %                                                                             %
   1204 %                                                                             %
   1205 %                                                                             %
   1206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1207 %
   1208 %  ReadDistributePixelCacheMetacontents() reads metacontent from the specified
   1209 %  region of the distributed pixel cache.
   1210 %
   1211 %  The format of the ReadDistributePixelCacheMetacontents method is:
   1212 %
   1213 %      MagickOffsetType ReadDistributePixelCacheMetacontents(
   1214 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
   1215 %        const MagickSizeType length,unsigned char *metacontent)
   1216 %
   1217 %  A description of each parameter follows:
   1218 %
   1219 %    o server_info: the distributed cache info.
   1220 %
   1221 %    o image: the image.
   1222 %
   1223 %    o region: read the metacontent from this region of the image.
   1224 %
   1225 %    o length: the length in bytes of the metacontent.
   1226 %
   1227 %    o metacontent: read these metacontent from the pixel cache.
   1228 %
   1229 */
   1230 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
   1231   DistributeCacheInfo *server_info,const RectangleInfo *region,
   1232   const MagickSizeType length,unsigned char *metacontent)
   1233 {
   1234   MagickOffsetType
   1235     count;
   1236 
   1237   register unsigned char
   1238     *p;
   1239 
   1240   unsigned char
   1241     message[MagickPathExtent];
   1242 
   1243   /*
   1244     Read distributed pixel cache metacontent.
   1245   */
   1246   assert(server_info != (DistributeCacheInfo *) NULL);
   1247   assert(server_info->signature == MagickCoreSignature);
   1248   assert(region != (RectangleInfo *) NULL);
   1249   assert(metacontent != (unsigned char *) NULL);
   1250   if (length > (MagickSizeType) SSIZE_MAX)
   1251     return(-1);
   1252   p=message;
   1253   *p++='R';
   1254   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   1255   p+=sizeof(server_info->session_key);
   1256   (void) memcpy(p,&region->width,sizeof(region->width));
   1257   p+=sizeof(region->width);
   1258   (void) memcpy(p,&region->height,sizeof(region->height));
   1259   p+=sizeof(region->height);
   1260   (void) memcpy(p,&region->x,sizeof(region->x));
   1261   p+=sizeof(region->x);
   1262   (void) memcpy(p,&region->y,sizeof(region->y));
   1263   p+=sizeof(region->y);
   1264   (void) memcpy(p,&length,sizeof(length));
   1265   p+=sizeof(length);
   1266   count=dpc_send(server_info->file,p-message,message);
   1267   if (count != (MagickOffsetType) (p-message))
   1268     return(-1);
   1269   return(dpc_read(server_info->file,length,metacontent));
   1270 }
   1271 
   1272 /*
   1274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1275 %                                                                             %
   1276 %                                                                             %
   1277 %                                                                             %
   1278 +   R e a d D i s t r i b u t e P i x e l C a c h e P i x e l s               %
   1279 %                                                                             %
   1280 %                                                                             %
   1281 %                                                                             %
   1282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1283 %
   1284 %  ReadDistributePixelCachePixels() reads pixels from the specified region of
   1285 %  the distributed pixel cache.
   1286 %
   1287 %  The format of the ReadDistributePixelCachePixels method is:
   1288 %
   1289 %      MagickOffsetType ReadDistributePixelCachePixels(
   1290 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
   1291 %        const MagickSizeType length,unsigned char *magick_restrict pixels)
   1292 %
   1293 %  A description of each parameter follows:
   1294 %
   1295 %    o server_info: the distributed cache info.
   1296 %
   1297 %    o image: the image.
   1298 %
   1299 %    o region: read the pixels from this region of the image.
   1300 %
   1301 %    o length: the length in bytes of the pixels.
   1302 %
   1303 %    o pixels: read these pixels from the pixel cache.
   1304 %
   1305 */
   1306 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
   1307   DistributeCacheInfo *server_info,const RectangleInfo *region,
   1308   const MagickSizeType length,unsigned char *magick_restrict pixels)
   1309 {
   1310   MagickOffsetType
   1311     count;
   1312 
   1313   register unsigned char
   1314     *p;
   1315 
   1316   unsigned char
   1317     message[MagickPathExtent];
   1318 
   1319   /*
   1320     Read distributed pixel cache pixels.
   1321   */
   1322   assert(server_info != (DistributeCacheInfo *) NULL);
   1323   assert(server_info->signature == MagickCoreSignature);
   1324   assert(region != (RectangleInfo *) NULL);
   1325   assert(pixels != (unsigned char *) NULL);
   1326   if (length > (MagickSizeType) SSIZE_MAX)
   1327     return(-1);
   1328   p=message;
   1329   *p++='r';
   1330   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   1331   p+=sizeof(server_info->session_key);
   1332   (void) memcpy(p,&region->width,sizeof(region->width));
   1333   p+=sizeof(region->width);
   1334   (void) memcpy(p,&region->height,sizeof(region->height));
   1335   p+=sizeof(region->height);
   1336   (void) memcpy(p,&region->x,sizeof(region->x));
   1337   p+=sizeof(region->x);
   1338   (void) memcpy(p,&region->y,sizeof(region->y));
   1339   p+=sizeof(region->y);
   1340   (void) memcpy(p,&length,sizeof(length));
   1341   p+=sizeof(length);
   1342   count=dpc_send(server_info->file,p-message,message);
   1343   if (count != (MagickOffsetType) (p-message))
   1344     return(-1);
   1345   return(dpc_read(server_info->file,length,pixels));
   1346 }
   1347 
   1348 /*
   1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1351 %                                                                             %
   1352 %                                                                             %
   1353 %                                                                             %
   1354 +   R e l i n q u i s h D i s t r i b u t e P i x e l C a c h e               %
   1355 %                                                                             %
   1356 %                                                                             %
   1357 %                                                                             %
   1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1359 %
   1360 %  RelinquishDistributePixelCache() frees resources acquired with
   1361 %  OpenDistributePixelCache().
   1362 %
   1363 %  The format of the RelinquishDistributePixelCache method is:
   1364 %
   1365 %      MagickBooleanType RelinquishDistributePixelCache(
   1366 %        DistributeCacheInfo *server_info)
   1367 %
   1368 %  A description of each parameter follows:
   1369 %
   1370 %    o server_info: the distributed cache info.
   1371 %
   1372 */
   1373 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
   1374   DistributeCacheInfo *server_info)
   1375 {
   1376   MagickBooleanType
   1377 #ifdef __VMS
   1378      status = MagickTrue;
   1379 #else
   1380     status;
   1381 #endif
   1382 
   1383   MagickOffsetType
   1384     count;
   1385 
   1386   register unsigned char
   1387     *p;
   1388 
   1389   unsigned char
   1390     message[MagickPathExtent];
   1391 
   1392   /*
   1393     Delete distributed pixel cache.
   1394   */
   1395   assert(server_info != (DistributeCacheInfo *) NULL);
   1396   assert(server_info->signature == MagickCoreSignature);
   1397   p=message;
   1398   *p++='d';
   1399   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   1400   p+=sizeof(server_info->session_key);
   1401   count=dpc_send(server_info->file,p-message,message);
   1402   if (count != (MagickOffsetType) (p-message))
   1403     return(MagickFalse);
   1404   count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
   1405   if (count != (MagickOffsetType) sizeof(status))
   1406     return(MagickFalse);
   1407   return(status);
   1408 }
   1409 
   1410 /*
   1412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1413 %                                                                             %
   1414 %                                                                             %
   1415 %                                                                             %
   1416 +   W r i t e D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t   %
   1417 %                                                                             %
   1418 %                                                                             %
   1419 %                                                                             %
   1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1421 %
   1422 %  WriteDistributePixelCacheMetacontents() writes image metacontent to the
   1423 %  specified region of the distributed pixel cache.
   1424 %
   1425 %  The format of the WriteDistributePixelCacheMetacontents method is:
   1426 %
   1427 %      MagickOffsetType WriteDistributePixelCacheMetacontents(
   1428 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
   1429 %        const MagickSizeType length,const unsigned char *metacontent)
   1430 %
   1431 %  A description of each parameter follows:
   1432 %
   1433 %    o server_info: the distributed cache info.
   1434 %
   1435 %    o image: the image.
   1436 %
   1437 %    o region: write the metacontent to this region of the image.
   1438 %
   1439 %    o length: the length in bytes of the metacontent.
   1440 %
   1441 %    o metacontent: write these metacontent to the pixel cache.
   1442 %
   1443 */
   1444 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
   1445   DistributeCacheInfo *server_info,const RectangleInfo *region,
   1446   const MagickSizeType length,const unsigned char *metacontent)
   1447 {
   1448   MagickOffsetType
   1449     count;
   1450 
   1451   register unsigned char
   1452     *p;
   1453 
   1454   unsigned char
   1455     message[MagickPathExtent];
   1456 
   1457   /*
   1458     Write distributed pixel cache metacontent.
   1459   */
   1460   assert(server_info != (DistributeCacheInfo *) NULL);
   1461   assert(server_info->signature == MagickCoreSignature);
   1462   assert(region != (RectangleInfo *) NULL);
   1463   assert(metacontent != (unsigned char *) NULL);
   1464   if (length > (MagickSizeType) SSIZE_MAX)
   1465     return(-1);
   1466   p=message;
   1467   *p++='W';
   1468   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   1469   p+=sizeof(server_info->session_key);
   1470   (void) memcpy(p,&region->width,sizeof(region->width));
   1471   p+=sizeof(region->width);
   1472   (void) memcpy(p,&region->height,sizeof(region->height));
   1473   p+=sizeof(region->height);
   1474   (void) memcpy(p,&region->x,sizeof(region->x));
   1475   p+=sizeof(region->x);
   1476   (void) memcpy(p,&region->y,sizeof(region->y));
   1477   p+=sizeof(region->y);
   1478   (void) memcpy(p,&length,sizeof(length));
   1479   p+=sizeof(length);
   1480   count=dpc_send(server_info->file,p-message,message);
   1481   if (count != (MagickOffsetType) (p-message))
   1482     return(-1);
   1483   return(dpc_send(server_info->file,length,metacontent));
   1484 }
   1485 
   1486 /*
   1488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1489 %                                                                             %
   1490 %                                                                             %
   1491 %                                                                             %
   1492 +   W r i t e D i s t r i b u t e P i x e l C a c h e P i x e l s             %
   1493 %                                                                             %
   1494 %                                                                             %
   1495 %                                                                             %
   1496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1497 %
   1498 %  WriteDistributePixelCachePixels() writes image pixels to the specified
   1499 %  region of the distributed pixel cache.
   1500 %
   1501 %  The format of the WriteDistributePixelCachePixels method is:
   1502 %
   1503 %      MagickBooleanType WriteDistributePixelCachePixels(
   1504 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
   1505 %        const MagickSizeType length,
   1506 %        const unsigned char *magick_restrict pixels)
   1507 %
   1508 %  A description of each parameter follows:
   1509 %
   1510 %    o server_info: the distributed cache info.
   1511 %
   1512 %    o image: the image.
   1513 %
   1514 %    o region: write the pixels to this region of the image.
   1515 %
   1516 %    o length: the length in bytes of the pixels.
   1517 %
   1518 %    o pixels: write these pixels to the pixel cache.
   1519 %
   1520 */
   1521 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
   1522   DistributeCacheInfo *server_info,const RectangleInfo *region,
   1523   const MagickSizeType length,const unsigned char *magick_restrict pixels)
   1524 {
   1525   MagickOffsetType
   1526     count;
   1527 
   1528   register unsigned char
   1529     *p;
   1530 
   1531   unsigned char
   1532     message[MagickPathExtent];
   1533 
   1534   /*
   1535     Write distributed pixel cache pixels.
   1536   */
   1537   assert(server_info != (DistributeCacheInfo *) NULL);
   1538   assert(server_info->signature == MagickCoreSignature);
   1539   assert(region != (RectangleInfo *) NULL);
   1540   assert(pixels != (const unsigned char *) NULL);
   1541   if (length > (MagickSizeType) SSIZE_MAX)
   1542     return(-1);
   1543   p=message;
   1544   *p++='w';
   1545   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   1546   p+=sizeof(server_info->session_key);
   1547   (void) memcpy(p,&region->width,sizeof(region->width));
   1548   p+=sizeof(region->width);
   1549   (void) memcpy(p,&region->height,sizeof(region->height));
   1550   p+=sizeof(region->height);
   1551   (void) memcpy(p,&region->x,sizeof(region->x));
   1552   p+=sizeof(region->x);
   1553   (void) memcpy(p,&region->y,sizeof(region->y));
   1554   p+=sizeof(region->y);
   1555   (void) memcpy(p,&length,sizeof(length));
   1556   p+=sizeof(length);
   1557   count=dpc_send(server_info->file,p-message,message);
   1558   if (count != (MagickOffsetType) (p-message))
   1559     return(-1);
   1560   return(dpc_send(server_info->file,length,pixels));
   1561 }
   1562