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