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