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