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