]> 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 %                                   Cristy                                    %
22 %                                January 2013                                 %
23 %                                                                             %
24 %                                                                             %
25 %  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
26 %  dedicated to making software imaging solutions freely available.           %
27 %                                                                             %
28 %  You may not use this file except in compliance with the License.  You may  %
29 %  obtain a copy of the License at                                            %
30 %                                                                             %
31 %    http://www.imagemagick.org/script/license.php                            %
32 %                                                                             %
33 %  Unless required by applicable law or agreed to in writing, software        %
34 %  distributed under the License is distributed on an "AS IS" BASIS,          %
35 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
36 %  See the License for the specific language governing permissions and        %
37 %  limitations under the License.                                             %
38 %                                                                             %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40 %
41 % A distributed pixel cache is an extension of the traditional pixel cache
42 % available on a single host.  The distributed pixel cache may span multiple
43 % servers so that it can grow in size and transactional capacity to support
44 % very large images.  Start up the pixel cache server on one or more machines.
45 % When you read or operate on an image and the local pixel cache resources are
46 % exhausted, ImageMagick contacts one or more of these remote pixel servers to
47 % store or retrieve pixels.
48 %
49 */
50 \f
51 /*
52   Include declarations.
53 */
54 #include "MagickCore/studio.h"
55 #include "MagickCore/cache.h"
56 #include "MagickCore/cache-private.h"
57 #include "MagickCore/distribute-cache.h"
58 #include "MagickCore/distribute-cache-private.h"
59 #include "MagickCore/exception.h"
60 #include "MagickCore/exception-private.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/locale_.h"
65 #include "MagickCore/memory_.h"
66 #include "MagickCore/nt-base-private.h"
67 #include "MagickCore/pixel.h"
68 #include "MagickCore/policy.h"
69 #include "MagickCore/random_.h"
70 #include "MagickCore/registry.h"
71 #include "MagickCore/splay-tree.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/string-private.h"
74 #include "MagickCore/version.h"
75 #include "MagickCore/version-private.h"
76 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
77 #include <netinet/in.h>
78 #include <netdb.h>
79 #include <sys/socket.h>
80 #include <arpa/inet.h>
81 #else
82 #undef send
83 #undef recv
84 #define send(file,buffer,length,flags)  0
85 #define recv(file,buffer,length,flags)  0
86 #endif
87 \f
88 /*
89   Define declarations.
90 */
91 #define DPCHostname  "127.0.0.1"
92 #define DPCPendingConnections  10
93 #define DPCPort  6668
94 #define DPCSessionKeyLength  8
95 #ifndef MSG_NOSIGNAL
96 #  define MSG_NOSIGNAL 0
97 #endif
98 \f
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 +   A c q u i r e D i s t r i b u t e C a c h e I n f o                       %
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 %
110 %  AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
111 %
112 %  The format of the AcquireDistributeCacheInfo method is:
113 %
114 %      DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
115 %
116 %  A description of each parameter follows:
117 %
118 %    o exception: return any errors or warnings in this structure.
119 %
120 */
121
122 static inline MagickSizeType MagickMin(const MagickSizeType x,
123   const MagickSizeType y)
124 {
125   if (x < y)
126     return(x);
127   return(y);
128 }
129
130 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
131   unsigned char *restrict message)
132 {
133   register MagickOffsetType
134     i;
135
136   ssize_t
137     count;
138
139   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) && defined(MAGICKCORE_THREAD_SUPPORT)
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 magick_unused(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->read_mask)+
456     sizeof(image->write_mask)+sizeof(image->columns)+sizeof(image->rows)+
457     sizeof(image->number_channels)+MaxPixelChannels*sizeof(*image->channel_map)+
458     sizeof(image->metacontent_extent);
459   count=dpc_read(file,length,message);
460   if (count != (MagickOffsetType) length)
461     return(MagickFalse);
462   /*
463     Deserialize the image attributes.
464   */
465   p=message;
466   (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
467   p+=sizeof(image->storage_class);
468   (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
469   p+=sizeof(image->colorspace);
470   (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
471   p+=sizeof(image->alpha_trait);
472   (void) memcpy(&image->read_mask,p,sizeof(image->read_mask));
473   p+=sizeof(image->read_mask);
474   (void) memcpy(&image->write_mask,p,sizeof(image->write_mask));
475   p+=sizeof(image->write_mask);
476   (void) memcpy(&image->columns,p,sizeof(image->columns));
477   p+=sizeof(image->columns);
478   (void) memcpy(&image->rows,p,sizeof(image->rows));
479   p+=sizeof(image->rows);
480   (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
481   p+=sizeof(image->number_channels);
482   (void) memcpy(image->channel_map,p,MaxPixelChannels*
483     sizeof(*image->channel_map));
484   p+=MaxPixelChannels*sizeof(*image->channel_map);
485   (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
486   p+=sizeof(image->metacontent_extent);
487   if (SyncImagePixelCache(image,exception) == MagickFalse)
488     return(MagickFalse);
489   status=AddValueToSplayTree(registry,(const void *) session_key,image);
490   return(status);
491 }
492
493 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
494   int file,const size_t session_key,ExceptionInfo *exception)
495 {
496   const unsigned char
497     *metacontent;
498
499   Image
500     *image;
501
502   MagickOffsetType
503     count;
504
505   MagickSizeType
506     length;
507
508   RectangleInfo
509     region;
510
511   register const Quantum
512     *p;
513
514   register unsigned char
515     *q;
516
517   unsigned char
518     message[MaxTextExtent];
519
520   /*
521     Read distributed pixel cache metacontent.
522   */
523   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
524   if (image == (Image *) NULL)
525     return(MagickFalse);
526   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
527     sizeof(region.y)+sizeof(length);
528   count=dpc_read(file,length,message);
529   if (count != (MagickOffsetType) length)
530     return(MagickFalse);
531   q=message;
532   (void) memcpy(&region.width,q,sizeof(region.width));
533   q+=sizeof(region.width);
534   (void) memcpy(&region.height,q,sizeof(region.height));
535   q+=sizeof(region.height);
536   (void) memcpy(&region.x,q,sizeof(region.x));
537   q+=sizeof(region.x);
538   (void) memcpy(&region.y,q,sizeof(region.y));
539   q+=sizeof(region.y);
540   (void) memcpy(&length,q,sizeof(length));
541   q+=sizeof(length);
542   p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
543     exception);
544   if (p == (const Quantum *) NULL)
545     return(MagickFalse);
546   metacontent=(const unsigned char *) GetVirtualMetacontent(image);
547   count=dpc_send(file,length,metacontent);
548   if (count != (MagickOffsetType) length)
549     return(MagickFalse);
550   return(MagickTrue);
551 }
552
553 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
554   int file,const size_t session_key,ExceptionInfo *exception)
555 {
556   Image
557     *image;
558
559   MagickOffsetType
560     count;
561
562   MagickSizeType
563     length;
564
565   RectangleInfo
566     region;
567
568   register const Quantum
569     *p;
570
571   register unsigned char
572     *q;
573
574   unsigned char
575     message[MaxTextExtent];
576
577   /*
578     Read distributed pixel cache pixels.
579   */
580   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
581   if (image == (Image *) NULL)
582     return(MagickFalse);
583   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
584     sizeof(region.y)+sizeof(length);
585   count=dpc_read(file,length,message);
586   if (count != (MagickOffsetType) length)
587     return(MagickFalse);
588   q=message;
589   (void) memcpy(&region.width,q,sizeof(region.width));
590   q+=sizeof(region.width);
591   (void) memcpy(&region.height,q,sizeof(region.height));
592   q+=sizeof(region.height);
593   (void) memcpy(&region.x,q,sizeof(region.x));
594   q+=sizeof(region.x);
595   (void) memcpy(&region.y,q,sizeof(region.y));
596   q+=sizeof(region.y);
597   (void) memcpy(&length,q,sizeof(length));
598   q+=sizeof(length);
599   p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
600     exception);
601   if (p == (const Quantum *) NULL)
602     return(MagickFalse);
603   count=dpc_send(file,length,(unsigned char *) p);
604   if (count != (MagickOffsetType) length)
605     return(MagickFalse);
606   return(MagickTrue);
607 }
608
609 static void *RelinquishImageRegistry(void *image)
610 {
611   return((void *) DestroyImageList((Image *) image));
612 }
613
614 static MagickBooleanType WriteDistributeCacheMetacontent(
615   SplayTreeInfo *registry,int file,const size_t session_key,
616   ExceptionInfo *exception)
617 {
618   Image
619     *image;
620
621   MagickOffsetType
622     count;
623
624   MagickSizeType
625     length;
626
627   RectangleInfo
628     region;
629
630   register Quantum
631     *q;
632
633   register unsigned char
634     *p;
635
636   unsigned char
637     message[MaxTextExtent],
638     *metacontent;
639
640   /*
641     Write distributed pixel cache metacontent.
642   */
643   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
644   if (image == (Image *) NULL)
645     return(MagickFalse);
646   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
647     sizeof(region.y)+sizeof(length);
648   count=dpc_read(file,length,message);
649   if (count != (MagickOffsetType) length)
650     return(MagickFalse);
651   p=message;
652   (void) memcpy(&region.width,p,sizeof(region.width));
653   p+=sizeof(region.width);
654   (void) memcpy(&region.height,p,sizeof(region.height));
655   p+=sizeof(region.height);
656   (void) memcpy(&region.x,p,sizeof(region.x));
657   p+=sizeof(region.x);
658   (void) memcpy(&region.y,p,sizeof(region.y));
659   p+=sizeof(region.y);
660   (void) memcpy(&length,p,sizeof(length));
661   p+=sizeof(length);
662   q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
663     exception);
664   if (q == (Quantum *) NULL)
665     return(MagickFalse);
666   metacontent=(unsigned char *) GetAuthenticMetacontent(image);
667   count=dpc_read(file,length,metacontent);
668   if (count != (MagickOffsetType) length)
669     return(MagickFalse);
670   return(SyncAuthenticPixels(image,exception));
671 }
672
673 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
674   int file,const size_t session_key,ExceptionInfo *exception)
675 {
676   Image
677     *image;
678
679   MagickOffsetType
680     count;
681
682   MagickSizeType
683     length;
684
685   RectangleInfo
686     region;
687
688   register Quantum
689     *q;
690
691   register unsigned char
692     *p;
693
694   unsigned char
695     message[MaxTextExtent];
696
697   /*
698     Write distributed pixel cache pixels.
699   */
700   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
701   if (image == (Image *) NULL)
702     return(MagickFalse);
703   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
704     sizeof(region.y)+sizeof(length);
705   count=dpc_read(file,length,message);
706   if (count != (MagickOffsetType) length)
707     return(MagickFalse);
708   p=message;
709   (void) memcpy(&region.width,p,sizeof(region.width));
710   p+=sizeof(region.width);
711   (void) memcpy(&region.height,p,sizeof(region.height));
712   p+=sizeof(region.height);
713   (void) memcpy(&region.x,p,sizeof(region.x));
714   p+=sizeof(region.x);
715   (void) memcpy(&region.y,p,sizeof(region.y));
716   p+=sizeof(region.y);
717   (void) memcpy(&length,p,sizeof(length));
718   p+=sizeof(length);
719   q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
720     exception);
721   if (q == (Quantum *) NULL)
722     return(MagickFalse);
723   count=dpc_read(file,length,(unsigned char *) q);
724   if (count != (MagickOffsetType) length)
725     return(MagickFalse);
726   return(SyncAuthenticPixels(image,exception));
727 }
728
729 static void *DistributePixelCacheClient(void *socket)
730 {
731   const char
732     *shared_secret;
733
734   ExceptionInfo
735     *exception;
736
737   int
738     client_socket;
739
740   MagickBooleanType
741     status;
742
743   MagickOffsetType
744     count;
745
746   register unsigned char
747     *p;
748
749   RandomInfo
750     *random_info;
751
752   size_t
753     key,
754     session_key;
755
756   SplayTreeInfo
757     *registry;
758
759   StringInfo
760     *secret;
761
762   unsigned char
763     command,
764     session[2*MaxTextExtent];
765
766   /*
767     Distributed pixel cache client.
768   */
769   shared_secret=GetPolicyValue("shared-secret");
770   if (shared_secret == (const char *) NULL)
771     ThrowFatalException(CacheFatalError,"shared secret expected");
772   p=session;
773   (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
774   p+=strlen(shared_secret);
775   random_info=AcquireRandomInfo();
776   secret=GetRandomKey(random_info,DPCSessionKeyLength);
777   (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
778   session_key=GetMagickSignature(secret);
779   random_info=DestroyRandomInfo(random_info);
780   exception=AcquireExceptionInfo();
781   registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
782     (void *(*)(void *)) NULL,RelinquishImageRegistry);
783   client_socket=(*(int *) socket);
784   count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
785   secret=DestroyStringInfo(secret);
786   for ( ; ; )
787   {
788     count=dpc_read(client_socket,1,(unsigned char *) &command);
789     if (count <= 0)
790       break;
791     count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
792     if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
793       break;
794     status=MagickFalse;
795     switch (command)
796     {
797       case 'o':
798       {
799         status=OpenDistributeCache(registry,client_socket,session_key,
800           exception);
801         count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
802         break;
803       }
804       case 'r':
805       {
806         status=ReadDistributeCachePixels(registry,client_socket,session_key,
807           exception);
808         break;
809       }
810       case 'R':
811       {
812         status=ReadDistributeCacheMetacontent(registry,client_socket,
813           session_key,exception);
814         break;
815       }
816       case 'w':
817       {
818         status=WriteDistributeCachePixels(registry,client_socket,session_key,
819           exception);
820         break;
821       }
822       case 'W':
823       {
824         status=WriteDistributeCacheMetacontent(registry,client_socket,
825           session_key,exception);
826         break;
827       }
828       case 'd':
829       {
830         status=DestroyDistributeCache(registry,client_socket,session_key);
831         break;
832       }
833       default:
834         break;
835     }
836     if (status == MagickFalse)
837       break;
838     if (command == 'd')
839       break;
840   }
841   count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
842   (void) close(client_socket);
843   exception=DestroyExceptionInfo(exception);
844   registry=DestroySplayTree(registry);
845   return((void *) NULL);
846 }
847
848 MagickExport void DistributePixelCacheServer(const int port,
849   ExceptionInfo *exception)
850 {
851 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
852   char
853     service[MaxTextExtent];
854
855   int
856     server_socket,
857     status;
858
859   pthread_attr_t
860     attributes;
861
862   pthread_t
863     threads;
864
865   register struct addrinfo
866     *p;
867
868   struct addrinfo
869     hint,
870     *result;
871
872   struct sockaddr_in
873     address;
874
875   /*
876     Launch distributed pixel cache server.
877   */
878   assert(exception != (ExceptionInfo *) NULL);
879   assert(exception->signature == MagickSignature);
880   (void) ResetMagickMemory(&hint,0,sizeof(hint));
881   hint.ai_family=AF_INET;
882   hint.ai_socktype=SOCK_STREAM;
883   hint.ai_flags=AI_PASSIVE;
884   (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
885   status=getaddrinfo((const char *) NULL,service,&hint,&result);
886   if (status != 0)
887     ThrowFatalException(CacheFatalError,"UnableToListen");
888   server_socket=0;
889   for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
890   {
891     int
892       one;
893
894     server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
895     if (server_socket == -1)
896       continue;
897     one=1;
898     status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
899       sizeof(one));
900     if (status == -1)
901       continue;
902     status=bind(server_socket,p->ai_addr,p->ai_addrlen);
903     if (status == -1)
904       {
905         (void) close(status);
906         continue;
907       }
908     break;
909   }
910   if (p == (struct addrinfo *) NULL)
911     ThrowFatalException(CacheFatalError,"UnableToBind");
912   freeaddrinfo(result);
913   status=listen(server_socket,DPCPendingConnections);
914   if (status != 0)
915     ThrowFatalException(CacheFatalError,"UnableToListen");
916   pthread_attr_init(&attributes);
917   for ( ; ; )
918   {
919     int
920       client_socket;
921
922     socklen_t
923       length;
924
925     length=(socklen_t) sizeof(address);
926     client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
927     if (client_socket == -1)
928       ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
929     status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
930       (void *) &client_socket);
931     if (status == -1)
932       ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
933   }
934   (void) close(server_socket);
935 #else
936   ThrowFatalException(MissingDelegateError,"distributed pixel cache");
937 #endif
938 }
939 \f
940 /*
941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
942 %                                                                             %
943 %                                                                             %
944 %                                                                             %
945 +   G e t D i s t r i b u t e C a c h e F i l e                               %
946 %                                                                             %
947 %                                                                             %
948 %                                                                             %
949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
950 %
951 %  GetDistributeCacheFile() returns the file associated with this
952 %  DistributeCacheInfo structure.
953 %
954 %  The format of the GetDistributeCacheFile method is:
955 %
956 %      int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
957 %
958 %  A description of each parameter follows:
959 %
960 %    o server_info: the distributed cache info.
961 %
962 */
963 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
964 {
965   assert(server_info != (DistributeCacheInfo *) NULL);
966   assert(server_info->signature == MagickSignature);
967   return(server_info->file);
968 }
969 \f
970 /*
971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
972 %                                                                             %
973 %                                                                             %
974 %                                                                             %
975 +   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                       %
976 %                                                                             %
977 %                                                                             %
978 %                                                                             %
979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 %
981 %  GetDistributeCacheHostname() returns the hostname associated with this
982 %  DistributeCacheInfo structure.
983 %
984 %  The format of the GetDistributeCacheHostname method is:
985 %
986 %      const char *GetDistributeCacheHostname(
987 %        const DistributeCacheInfo *server_info)
988 %
989 %  A description of each parameter follows:
990 %
991 %    o server_info: the distributed cache info.
992 %
993 */
994 MagickPrivate const char *GetDistributeCacheHostname(
995   const DistributeCacheInfo *server_info)
996 {
997   assert(server_info != (DistributeCacheInfo *) NULL);
998   assert(server_info->signature == MagickSignature);
999   return(server_info->hostname);
1000 }
1001 \f
1002 /*
1003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1004 %                                                                             %
1005 %                                                                             %
1006 %                                                                             %
1007 +   G e t D i s t r i b u t e C a c h e P o r t                               %
1008 %                                                                             %
1009 %                                                                             %
1010 %                                                                             %
1011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1012 %
1013 %  GetDistributeCachePort() returns the port associated with this
1014 %  DistributeCacheInfo structure.
1015 %
1016 %  The format of the GetDistributeCachePort method is:
1017 %
1018 %      int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1019 %
1020 %  A description of each parameter follows:
1021 %
1022 %    o server_info: the distributed cache info.
1023 %
1024 */
1025 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1026 {
1027   assert(server_info != (DistributeCacheInfo *) NULL);
1028   assert(server_info->signature == MagickSignature);
1029   return(server_info->port);
1030 }
1031 \f
1032 /*
1033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1034 %                                                                             %
1035 %                                                                             %
1036 %                                                                             %
1037 +   O p e n D i s t r i b u t e P i x e l C a c h e                           %
1038 %                                                                             %
1039 %                                                                             %
1040 %                                                                             %
1041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042 %
1043 %  OpenDistributePixelCache() opens a pixel cache on a remote server.
1044 %
1045 %  The format of the OpenDistributePixelCache method is:
1046 %
1047 %      MagickBooleanType *OpenDistributePixelCache(
1048 %        DistributeCacheInfo *server_info,Image *image)
1049 %
1050 %  A description of each parameter follows:
1051 %
1052 %    o server_info: the distributed cache info.
1053 %
1054 %    o image: the image.
1055 %
1056 */
1057 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1058   DistributeCacheInfo *server_info,Image *image)
1059 {
1060   MagickBooleanType
1061     status;
1062
1063   MagickOffsetType
1064     count;
1065
1066   register unsigned char
1067     *p;
1068
1069   unsigned char
1070     message[MaxTextExtent];
1071
1072   /*
1073     Open distributed pixel cache.
1074   */
1075   assert(server_info != (DistributeCacheInfo *) NULL);
1076   assert(server_info->signature == MagickSignature);
1077   assert(image != (Image *) NULL);
1078   assert(image->signature == MagickSignature);
1079   p=message;
1080   *p++='o';  /* open */
1081   /*
1082     Serialize image attributes (see ValidatePixelCacheMorphology()).
1083   */
1084   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1085   p+=sizeof(server_info->session_key);
1086   (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1087   p+=sizeof(image->storage_class);
1088   (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1089   p+=sizeof(image->colorspace);
1090   (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1091   p+=sizeof(image->alpha_trait);
1092   (void) memcpy(p,&image->read_mask,sizeof(image->read_mask));
1093   p+=sizeof(image->read_mask);
1094   (void) memcpy(p,&image->write_mask,sizeof(image->write_mask));
1095   p+=sizeof(image->write_mask);
1096   (void) memcpy(p,&image->columns,sizeof(image->columns));
1097   p+=sizeof(image->columns);
1098   (void) memcpy(p,&image->rows,sizeof(image->rows));
1099   p+=sizeof(image->rows);
1100   (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1101   p+=sizeof(image->number_channels);
1102   (void) memcpy(p,image->channel_map,MaxPixelChannels*
1103     sizeof(*image->channel_map));
1104   p+=MaxPixelChannels*sizeof(*image->channel_map);
1105   (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1106   p+=sizeof(image->metacontent_extent);
1107   count=dpc_send(server_info->file,p-message,message);
1108   if (count != (MagickOffsetType) (p-message))
1109     return(MagickFalse);
1110   status=MagickFalse;
1111   count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1112   if (count != (MagickOffsetType) sizeof(status))
1113     return(MagickFalse);
1114   return(status);
1115 }
1116 \f
1117 /*
1118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 %                                                                             %
1120 %                                                                             %
1121 %                                                                             %
1122 +   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     %
1123 %                                                                             %
1124 %                                                                             %
1125 %                                                                             %
1126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 %
1128 %  ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1129 %  region of the distributed pixel cache.
1130 %
1131 %  The format of the ReadDistributePixelCacheMetacontents method is:
1132 %
1133 %      MagickOffsetType ReadDistributePixelCacheMetacontents(
1134 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
1135 %        const MagickSizeType length,unsigned char *metacontent)
1136 %
1137 %  A description of each parameter follows:
1138 %
1139 %    o server_info: the distributed cache info.
1140 %
1141 %    o image: the image.
1142 %
1143 %    o region: read the metacontent from this region of the image.
1144 %
1145 %    o length: the length in bytes of the metacontent.
1146 %
1147 %    o metacontent: read these metacontent from the pixel cache.
1148 %
1149 */
1150 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1151   DistributeCacheInfo *server_info,const RectangleInfo *region,
1152   const MagickSizeType length,unsigned char *metacontent)
1153 {
1154   MagickOffsetType
1155     count;
1156
1157   register unsigned char
1158     *p;
1159
1160   unsigned char
1161     message[MaxTextExtent];
1162
1163   /*
1164     Read distributed pixel cache metacontent.
1165   */
1166   assert(server_info != (DistributeCacheInfo *) NULL);
1167   assert(server_info->signature == MagickSignature);
1168   assert(region != (RectangleInfo *) NULL);
1169   assert(metacontent != (unsigned char *) NULL);
1170   if (length > (MagickSizeType) SSIZE_MAX)
1171     return(-1);
1172   p=message;
1173   *p++='R';
1174   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1175   p+=sizeof(server_info->session_key);
1176   (void) memcpy(p,&region->width,sizeof(region->width));
1177   p+=sizeof(region->width);
1178   (void) memcpy(p,&region->height,sizeof(region->height));
1179   p+=sizeof(region->height);
1180   (void) memcpy(p,&region->x,sizeof(region->x));
1181   p+=sizeof(region->x);
1182   (void) memcpy(p,&region->y,sizeof(region->y));
1183   p+=sizeof(region->y);
1184   (void) memcpy(p,&length,sizeof(length));
1185   p+=sizeof(length);
1186   count=dpc_send(server_info->file,p-message,message);
1187   if (count != (MagickOffsetType) (p-message))
1188     return(-1);
1189   return(dpc_read(server_info->file,length,metacontent));
1190 }
1191 \f
1192 /*
1193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1194 %                                                                             %
1195 %                                                                             %
1196 %                                                                             %
1197 +   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               %
1198 %                                                                             %
1199 %                                                                             %
1200 %                                                                             %
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202 %
1203 %  ReadDistributePixelCachePixels() reads pixels from the specified region of
1204 %  the distributed pixel cache.
1205 %
1206 %  The format of the ReadDistributePixelCachePixels method is:
1207 %
1208 %      MagickOffsetType ReadDistributePixelCachePixels(
1209 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
1210 %        const MagickSizeType length,unsigned char *restrict pixels)
1211 %
1212 %  A description of each parameter follows:
1213 %
1214 %    o server_info: the distributed cache info.
1215 %
1216 %    o image: the image.
1217 %
1218 %    o region: read the pixels from this region of the image.
1219 %
1220 %    o length: the length in bytes of the pixels.
1221 %
1222 %    o pixels: read these pixels from the pixel cache.
1223 %
1224 */
1225 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1226   DistributeCacheInfo *server_info,const RectangleInfo *region,
1227   const MagickSizeType length,unsigned char *restrict pixels)
1228 {
1229   MagickOffsetType
1230     count;
1231
1232   register unsigned char
1233     *p;
1234
1235   unsigned char
1236     message[MaxTextExtent];
1237
1238   /*
1239     Read distributed pixel cache pixels.
1240   */
1241   assert(server_info != (DistributeCacheInfo *) NULL);
1242   assert(server_info->signature == MagickSignature);
1243   assert(region != (RectangleInfo *) NULL);
1244   assert(pixels != (unsigned char *) NULL);
1245   if (length > (MagickSizeType) SSIZE_MAX)
1246     return(-1);
1247   p=message;
1248   *p++='r';
1249   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1250   p+=sizeof(server_info->session_key);
1251   (void) memcpy(p,&region->width,sizeof(region->width));
1252   p+=sizeof(region->width);
1253   (void) memcpy(p,&region->height,sizeof(region->height));
1254   p+=sizeof(region->height);
1255   (void) memcpy(p,&region->x,sizeof(region->x));
1256   p+=sizeof(region->x);
1257   (void) memcpy(p,&region->y,sizeof(region->y));
1258   p+=sizeof(region->y);
1259   (void) memcpy(p,&length,sizeof(length));
1260   p+=sizeof(length);
1261   count=dpc_send(server_info->file,p-message,message);
1262   if (count != (MagickOffsetType) (p-message))
1263     return(-1);
1264   return(dpc_read(server_info->file,length,pixels));
1265 }
1266 \f
1267 /*
1268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1269 %                                                                             %
1270 %                                                                             %
1271 %                                                                             %
1272 +   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               %
1273 %                                                                             %
1274 %                                                                             %
1275 %                                                                             %
1276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1277 %
1278 %  RelinquishDistributePixelCache() frees resources acquired with
1279 %  OpenDistributePixelCache().
1280 %
1281 %  The format of the RelinquishDistributePixelCache method is:
1282 %
1283 %      MagickBooleanType RelinquishDistributePixelCache(
1284 %        DistributeCacheInfo *server_info)
1285 %
1286 %  A description of each parameter follows:
1287 %
1288 %    o server_info: the distributed cache info.
1289 %
1290 */
1291 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1292   DistributeCacheInfo *server_info)
1293 {
1294   MagickBooleanType
1295     status;
1296
1297   MagickOffsetType
1298     count;
1299
1300   register unsigned char
1301     *p;
1302
1303   unsigned char
1304     message[MaxTextExtent];
1305
1306   /*
1307     Delete distributed pixel cache.
1308   */
1309   assert(server_info != (DistributeCacheInfo *) NULL);
1310   assert(server_info->signature == MagickSignature);
1311   p=message;
1312   *p++='d';
1313   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1314   p+=sizeof(server_info->session_key);
1315   count=dpc_send(server_info->file,p-message,message);
1316   if (count != (MagickOffsetType) (p-message))
1317     return(MagickFalse);
1318   count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1319   if (count != (MagickOffsetType) sizeof(status))
1320     return(MagickFalse);
1321   return(status);
1322 }
1323 \f
1324 /*
1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1326 %                                                                             %
1327 %                                                                             %
1328 %                                                                             %
1329 +   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   %
1330 %                                                                             %
1331 %                                                                             %
1332 %                                                                             %
1333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334 %
1335 %  WriteDistributePixelCacheMetacontents() writes image metacontent to the
1336 %  specified region of the distributed pixel cache.
1337 %
1338 %  The format of the WriteDistributePixelCacheMetacontents method is:
1339 %
1340 %      MagickOffsetType WriteDistributePixelCacheMetacontents(
1341 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
1342 %        const MagickSizeType length,const unsigned char *metacontent)
1343 %
1344 %  A description of each parameter follows:
1345 %
1346 %    o server_info: the distributed cache info.
1347 %
1348 %    o image: the image.
1349 %
1350 %    o region: write the metacontent to this region of the image.
1351 %
1352 %    o length: the length in bytes of the metacontent.
1353 %
1354 %    o metacontent: write these metacontent to the pixel cache.
1355 %
1356 */
1357 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1358   DistributeCacheInfo *server_info,const RectangleInfo *region,
1359   const MagickSizeType length,const unsigned char *metacontent)
1360 {
1361   MagickOffsetType
1362     count;
1363
1364   register unsigned char
1365     *p;
1366
1367   unsigned char
1368     message[MaxTextExtent];
1369
1370   /*
1371     Write distributed pixel cache metacontent.
1372   */
1373   assert(server_info != (DistributeCacheInfo *) NULL);
1374   assert(server_info->signature == MagickSignature);
1375   assert(region != (RectangleInfo *) NULL);
1376   assert(metacontent != (unsigned char *) NULL);
1377   if (length > (MagickSizeType) SSIZE_MAX)
1378     return(-1);
1379   p=message;
1380   *p++='W';
1381   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1382   p+=sizeof(server_info->session_key);
1383   (void) memcpy(p,&region->width,sizeof(region->width));
1384   p+=sizeof(region->width);
1385   (void) memcpy(p,&region->height,sizeof(region->height));
1386   p+=sizeof(region->height);
1387   (void) memcpy(p,&region->x,sizeof(region->x));
1388   p+=sizeof(region->x);
1389   (void) memcpy(p,&region->y,sizeof(region->y));
1390   p+=sizeof(region->y);
1391   (void) memcpy(p,&length,sizeof(length));
1392   p+=sizeof(length);
1393   count=dpc_send(server_info->file,p-message,message);
1394   if (count != (MagickOffsetType) (p-message))
1395     return(-1);
1396   return(dpc_send(server_info->file,length,metacontent));
1397 }
1398 \f
1399 /*
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401 %                                                                             %
1402 %                                                                             %
1403 %                                                                             %
1404 +   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             %
1405 %                                                                             %
1406 %                                                                             %
1407 %                                                                             %
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409 %
1410 %  WriteDistributePixelCachePixels() writes image pixels to the specified
1411 %  region of the distributed pixel cache.
1412 %
1413 %  The format of the WriteDistributePixelCachePixels method is:
1414 %
1415 %      MagickBooleanType WriteDistributePixelCachePixels(
1416 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
1417 %        const MagickSizeType length,const unsigned char *restrict pixels)
1418 %
1419 %  A description of each parameter follows:
1420 %
1421 %    o server_info: the distributed cache info.
1422 %
1423 %    o image: the image.
1424 %
1425 %    o region: write the pixels to this region of the image.
1426 %
1427 %    o length: the length in bytes of the pixels.
1428 %
1429 %    o pixels: write these pixels to the pixel cache.
1430 %
1431 */
1432 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1433   DistributeCacheInfo *server_info,const RectangleInfo *region,
1434   const MagickSizeType length,const unsigned char *restrict pixels)
1435 {
1436   MagickOffsetType
1437     count;
1438
1439   register unsigned char
1440     *p;
1441
1442   unsigned char
1443     message[MaxTextExtent];
1444
1445   /*
1446     Write distributed pixel cache pixels.
1447   */
1448   assert(server_info != (DistributeCacheInfo *) NULL);
1449   assert(server_info->signature == MagickSignature);
1450   assert(region != (RectangleInfo *) NULL);
1451   assert(pixels != (const unsigned char *) NULL);
1452   if (length > (MagickSizeType) SSIZE_MAX)
1453     return(-1);
1454   p=message;
1455   *p++='w';
1456   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1457   p+=sizeof(server_info->session_key);
1458   (void) memcpy(p,&region->width,sizeof(region->width));
1459   p+=sizeof(region->width);
1460   (void) memcpy(p,&region->height,sizeof(region->height));
1461   p+=sizeof(region->height);
1462   (void) memcpy(p,&region->x,sizeof(region->x));
1463   p+=sizeof(region->x);
1464   (void) memcpy(p,&region->y,sizeof(region->y));
1465   p+=sizeof(region->y);
1466   (void) memcpy(p,&length,sizeof(length));
1467   p+=sizeof(length);
1468   count=dpc_send(server_info->file,p-message,message);
1469   if (count != (MagickOffsetType) (p-message))
1470     return(-1);
1471   return(dpc_send(server_info->file,length,pixels));
1472 }