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