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