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