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