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