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