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