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