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