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