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