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