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