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