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