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