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