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