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