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