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