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