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