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