MagickCore 6.9.13-48
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
distribute-cache.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% DDDD IIIII SSSSS TTTTT RRRR IIIII BBBB U U TTTTT EEEEE %
6% D D I SS T R R I B B U U T E %
7% D D I SSS T RRRR I BBBB U U T EEE %
8% D D I SS T R R I B B U U T E %
9% DDDDA IIIII SSSSS T R R IIIII BBBB UUU T EEEEE %
10% %
11% CCCC AAA CCCC H H EEEEE %
12% C A A C H H E %
13% C AAAAA C HHHHH EEE %
14% C A A C H H E %
15% CCCC A A CCCC H H EEEEE %
16% %
17% %
18% MagickCore Distributed Pixel Cache Methods %
19% %
20% Software Design %
21% Cristy %
22% January 2013 %
23% %
24% %
25% Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
26% dedicated to making software imaging solutions freely available. %
27% %
28% You may not use this file except in compliance with the License. You may %
29% obtain a copy of the License at %
30% %
31% https://imagemagick.org/license/ %
32% %
33% Unless required by applicable law or agreed to in writing, software %
34% distributed under the License is distributed on an "AS IS" BASIS, %
35% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36% See the License for the specific language governing permissions and %
37% limitations under the License. %
38% %
39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40%
41% A distributed pixel cache is an extension of the traditional pixel cache
42% available on a single host. The distributed pixel cache may span multiple
43% servers so that it can grow in size and transactional capacity to support
44% very large images. Start up the pixel cache server on one or more machines.
45% When you read or operate on an image and the local pixel cache resources are
46% exhausted, ImageMagick contacts one or more of these remote pixel servers to
47% store or retrieve pixels.
48%
49*/
50
51/*
52 Include declarations.
53*/
54#include "magick/studio.h"
55#include "magick/cache.h"
56#include "magick/cache-private.h"
57#include "magick/distribute-cache.h"
58#include "magick/distribute-cache-private.h"
59#include "magick/exception.h"
60#include "magick/exception-private.h"
61#include "magick/geometry.h"
62#include "magick/image.h"
63#include "magick/image-private.h"
64#include "magick/list.h"
65#include "magick/locale_.h"
66#include "magick/memory_.h"
67#include "magick/nt-base-private.h"
68#include "magick/policy.h"
69#include "magick/random_.h"
70#include "magick/registry.h"
71#include "magick/splay-tree.h"
72#include "magick/string_.h"
73#include "magick/string-private.h"
74#include "magick/version.h"
75#include "magick/version-private.h"
76#undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
77#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
78#include <netinet/in.h>
79#include <netdb.h>
80#include <sys/socket.h>
81#include <arpa/inet.h>
82#define CLOSE_SOCKET(socket) (void) close(socket)
83#define HANDLER_RETURN_TYPE void *
84#define HANDLER_RETURN_VALUE (void *) NULL
85#define SOCKET_TYPE int
86#define LENGTH_TYPE size_t
87#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
88#elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__) && !defined(__MINGW64__)
89#define CLOSE_SOCKET(socket) (void) closesocket(socket)
90#define HANDLER_RETURN_TYPE DWORD WINAPI
91#define HANDLER_RETURN_VALUE 0
92#define SOCKET_TYPE SOCKET
93#define LENGTH_TYPE int
94#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
95#else
96#ifdef __VMS
97#define CLOSE_SOCKET(socket) (void) close(socket)
98#else
99#define CLOSE_SOCKET(socket)
100#endif
101#define HANDLER_RETURN_TYPE void *
102#define HANDLER_RETURN_VALUE (void *) NULL
103#define SOCKET_TYPE int
104#define LENGTH_TYPE size_t
105#undef send
106#undef recv
107#define send(file,buffer,length,flags) 0
108#define recv(file,buffer,length,flags) 0
109#endif
110
111/*
112 Define declarations.
113*/
114#define DPCHostname "127.0.0.1"
115#define DPCPendingConnections 10
116#define DPCPort 6668
117#define DPCSessionKeyLength 8
118#ifndef MSG_NOSIGNAL
119# define MSG_NOSIGNAL 0
120#endif
121
122#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#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__) && !defined(__MINGW64__)
1174 DWORD timeout = 5000; // ms
1175 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,(const char *)
1176 &timeout,sizeof(timeout));
1177#else
1178 struct timeval tv;
1179 tv.tv_sec=5;
1180 tv.tv_usec=0;
1181 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));
1182#endif
1183 }
1184 if (status == -1)
1185 {
1186 CLOSE_SOCKET(server_socket);
1187 continue;
1188 }
1189 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1190 if (status == -1)
1191 {
1192 CLOSE_SOCKET(server_socket);
1193 continue;
1194 }
1195 break;
1196 }
1197 if (p == (struct addrinfo *) NULL)
1198 ThrowFatalException(CacheFatalError,"UnableToBind");
1199 freeaddrinfo(result);
1200 status=listen(server_socket,DPCPendingConnections);
1201 if (status != 0)
1202 ThrowFatalException(CacheFatalError,"UnableToListen");
1203#if defined(MAGICKCORE_THREAD_SUPPORT)
1204 pthread_attr_init(&attributes);
1205 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1206#endif
1207 for ( ; ; )
1208 {
1209 SOCKET_TYPE
1210 *client_socket_ptr;
1211
1212 socklen_t
1213 length = (socklen_t) sizeof(address);
1214
1215 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(sizeof(SOCKET_TYPE));
1216 if (client_socket_ptr == NULL)
1217 continue; /* skip connection */
1218 *client_socket_ptr=accept(server_socket,(struct sockaddr *) &address,
1219 &length);
1220 if (*client_socket_ptr == -1)
1221 {
1222 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1223 client_socket_ptr);
1224 continue;
1225 }
1226#if defined(MAGICKCORE_THREAD_SUPPORT)
1227 status=pthread_create(&thread_id, &attributes,DistributePixelCacheClient,
1228 (void *) client_socket_ptr);
1229 if (status != 0)
1230 {
1231 CLOSE_SOCKET(*client_socket_ptr);
1232 RelinquishMagickMemory(client_socket_ptr);
1233 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
1234 }
1235#elif defined(_MSC_VER)
1236 if (CreateThread(0,0,DistributePixelCacheClient,(void*) client_socket_ptr,0,&threadID) == (HANDLE) NULL)
1237 {
1238 CLOSE_SOCKET(*client_socket_ptr);
1239 RelinquishMagickMemory(client_socket_ptr);
1240 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
1241 }
1242#else
1243 Not implemented!
1244#endif
1245 }
1246}
1247
1248/*
1249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250% %
1251% %
1252% %
1253+ G e t D i s t r i b u t e C a c h e F i l e %
1254% %
1255% %
1256% %
1257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258%
1259% GetDistributeCacheFile() returns the file associated with this
1260% DistributeCacheInfo structure.
1261%
1262% The format of the GetDistributeCacheFile method is:
1263%
1264% int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1265%
1266% A description of each parameter follows:
1267%
1268% o server_info: the distributed cache info.
1269%
1270*/
1271MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1272{
1273 assert(server_info != (DistributeCacheInfo *) NULL);
1274 assert(server_info->signature == MagickCoreSignature);
1275 return(server_info->file);
1276}
1277
1278/*
1279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1280% %
1281% %
1282% %
1283+ 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 %
1284% %
1285% %
1286% %
1287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288%
1289% GetDistributeCacheHostname() returns the hostname associated with this
1290% DistributeCacheInfo structure.
1291%
1292% The format of the GetDistributeCacheHostname method is:
1293%
1294% const char *GetDistributeCacheHostname(
1295% const DistributeCacheInfo *server_info)
1296%
1297% A description of each parameter follows:
1298%
1299% o server_info: the distributed cache info.
1300%
1301*/
1302MagickPrivate const char *GetDistributeCacheHostname(
1303 const DistributeCacheInfo *server_info)
1304{
1305 assert(server_info != (DistributeCacheInfo *) NULL);
1306 assert(server_info->signature == MagickCoreSignature);
1307 return(server_info->hostname);
1308}
1309
1310/*
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312% %
1313% %
1314% %
1315+ G e t D i s t r i b u t e C a c h e P o r t %
1316% %
1317% %
1318% %
1319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1320%
1321% GetDistributeCachePort() returns the port associated with this
1322% DistributeCacheInfo structure.
1323%
1324% The format of the GetDistributeCachePort method is:
1325%
1326% int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1327%
1328% A description of each parameter follows:
1329%
1330% o server_info: the distributed cache info.
1331%
1332*/
1333MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1334{
1335 assert(server_info != (DistributeCacheInfo *) NULL);
1336 assert(server_info->signature == MagickCoreSignature);
1337 return(server_info->port);
1338}
1339
1340/*
1341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342% %
1343% %
1344% %
1345+ O p e n D i s t r i b u t e P i x e l C a c h e %
1346% %
1347% %
1348% %
1349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1350%
1351% OpenDistributePixelCache() opens a pixel cache on a remote server.
1352%
1353% The format of the OpenDistributePixelCache method is:
1354%
1355% MagickBooleanType *OpenDistributePixelCache(
1356% DistributeCacheInfo *server_info,Image *image)
1357%
1358% A description of each parameter follows:
1359%
1360% o server_info: the distributed cache info.
1361%
1362% o image: the image.
1363%
1364*/
1365MagickPrivate MagickBooleanType OpenDistributePixelCache(
1366 DistributeCacheInfo *server_info,Image *image)
1367{
1368 MagickBooleanType
1369 status;
1370
1371 MagickOffsetType
1372 count;
1373
1374 unsigned char
1375 message[MagickPathExtent],
1376 *p;
1377
1378 /*
1379 Open distributed pixel cache.
1380 */
1381 assert(server_info != (DistributeCacheInfo *) NULL);
1382 assert(server_info->signature == MagickCoreSignature);
1383 assert(image != (Image *) NULL);
1384 assert(image->signature == MagickCoreSignature);
1385 p=message;
1386 *p++='o'; /* open */
1387 /*
1388 Serialize image attributes (see ValidatePixelCacheMorphology()).
1389 */
1390 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1391 p+=(ptrdiff_t) sizeof(server_info->session_key);
1392 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1393 p+=(ptrdiff_t) sizeof(image->storage_class);
1394 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1395 p+=(ptrdiff_t) sizeof(image->colorspace);
1396 (void) memcpy(p,&image->channels,sizeof(image->channels));
1397 p+=(ptrdiff_t) sizeof(image->channels);
1398 (void) memcpy(p,&image->columns,sizeof(image->columns));
1399 p+=(ptrdiff_t) sizeof(image->columns);
1400 (void) memcpy(p,&image->rows,sizeof(image->rows));
1401 p+=(ptrdiff_t) sizeof(image->rows);
1402 count=dpc_send(server_info->file,p-message,message);
1403 if (count != (MagickOffsetType) (p-message))
1404 return(MagickFalse);
1405 status=MagickFalse;
1406 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1407 if (count != (MagickOffsetType) sizeof(status))
1408 return(MagickFalse);
1409 return(status);
1410}
1411
1412/*
1413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414% %
1415% %
1416% %
1417+ 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 %
1418% %
1419% %
1420% %
1421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422%
1423% ReadDistributePixelCacheIndexes() reads indexes from the specified region
1424% of the distributed pixel cache.
1425%
1426% The format of the ReadDistributePixelCacheIndexes method is:
1427%
1428% MagickOffsetType ReadDistributePixelCacheIndexes(
1429% DistributeCacheInfo *server_info,const RectangleInfo *region,
1430% const MagickSizeType length,unsigned char *indexes)
1431%
1432% A description of each parameter follows:
1433%
1434% o server_info: the distributed cache info.
1435%
1436% o image: the image.
1437%
1438% o region: read the indexes from this region of the image.
1439%
1440% o length: the length in bytes of the indexes.
1441%
1442% o indexes: read these indexes from the pixel cache.
1443%
1444*/
1445MagickPrivate MagickOffsetType ReadDistributePixelCacheIndexes(
1446 DistributeCacheInfo *server_info,const RectangleInfo *region,
1447 const MagickSizeType length,unsigned char *indexes)
1448{
1449 MagickOffsetType
1450 count;
1451
1452 unsigned char
1453 message[MagickPathExtent],
1454 *p;
1455
1456 /*
1457 Read distributed pixel cache indexes.
1458 */
1459 assert(server_info != (DistributeCacheInfo *) NULL);
1460 assert(server_info->signature == MagickCoreSignature);
1461 assert(region != (RectangleInfo *) NULL);
1462 assert(indexes != (unsigned char *) NULL);
1463 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1464 return(-1);
1465 p=message;
1466 *p++='R';
1467 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1468 p+=(ptrdiff_t) sizeof(server_info->session_key);
1469 (void) memcpy(p,&region->width,sizeof(region->width));
1470 p+=(ptrdiff_t) sizeof(region->width);
1471 (void) memcpy(p,&region->height,sizeof(region->height));
1472 p+=(ptrdiff_t) sizeof(region->height);
1473 (void) memcpy(p,&region->x,sizeof(region->x));
1474 p+=(ptrdiff_t) sizeof(region->x);
1475 (void) memcpy(p,&region->y,sizeof(region->y));
1476 p+=(ptrdiff_t) sizeof(region->y);
1477 (void) memcpy(p,&length,sizeof(length));
1478 p+=(ptrdiff_t) sizeof(length);
1479 count=dpc_send(server_info->file,p-message,message);
1480 if (count != (MagickOffsetType) (p-message))
1481 return(-1);
1482 return(dpc_read(server_info->file,length,indexes));
1483}
1484
1485/*
1486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1487% %
1488% %
1489% %
1490+ 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 %
1491% %
1492% %
1493% %
1494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495%
1496% ReadDistributePixelCachePixels() reads pixels from the specified region of
1497% the distributed pixel cache.
1498%
1499% The format of the ReadDistributePixelCachePixels method is:
1500%
1501% MagickOffsetType ReadDistributePixelCachePixels(
1502% DistributeCacheInfo *server_info,const RectangleInfo *region,
1503% const MagickSizeType length,unsigned char *magick_restrict pixels)
1504%
1505% A description of each parameter follows:
1506%
1507% o server_info: the distributed cache info.
1508%
1509% o image: the image.
1510%
1511% o region: read the pixels from this region of the image.
1512%
1513% o length: the length in bytes of the pixels.
1514%
1515% o pixels: read these pixels from the pixel cache.
1516%
1517*/
1518MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1519 DistributeCacheInfo *server_info,const RectangleInfo *region,
1520 const MagickSizeType length,unsigned char *magick_restrict pixels)
1521{
1522 MagickOffsetType
1523 count;
1524
1525 unsigned char
1526 message[MagickPathExtent],
1527 *p;
1528
1529 /*
1530 Read distributed pixel cache pixels.
1531 */
1532 assert(server_info != (DistributeCacheInfo *) NULL);
1533 assert(server_info->signature == MagickCoreSignature);
1534 assert(region != (RectangleInfo *) NULL);
1535 assert(pixels != (unsigned char *) NULL);
1536 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1537 return(-1);
1538 p=message;
1539 *p++='r';
1540 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1541 p+=(ptrdiff_t) sizeof(server_info->session_key);
1542 (void) memcpy(p,&region->width,sizeof(region->width));
1543 p+=(ptrdiff_t) sizeof(region->width);
1544 (void) memcpy(p,&region->height,sizeof(region->height));
1545 p+=(ptrdiff_t) sizeof(region->height);
1546 (void) memcpy(p,&region->x,sizeof(region->x));
1547 p+=(ptrdiff_t) sizeof(region->x);
1548 (void) memcpy(p,&region->y,sizeof(region->y));
1549 p+=(ptrdiff_t) sizeof(region->y);
1550 (void) memcpy(p,&length,sizeof(length));
1551 p+=(ptrdiff_t) sizeof(length);
1552 count=dpc_send(server_info->file,p-message,message);
1553 if (count != (MagickOffsetType) (p-message))
1554 return(-1);
1555 return(dpc_read(server_info->file,length,pixels));
1556}
1557
1558/*
1559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560% %
1561% %
1562% %
1563+ 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 %
1564% %
1565% %
1566% %
1567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568%
1569% RelinquishDistributePixelCache() frees resources acquired with
1570% OpenDistributePixelCache().
1571%
1572% The format of the RelinquishDistributePixelCache method is:
1573%
1574% MagickBooleanType RelinquishDistributePixelCache(
1575% DistributeCacheInfo *server_info)
1576%
1577% A description of each parameter follows:
1578%
1579% o server_info: the distributed cache info.
1580%
1581*/
1582MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1583 DistributeCacheInfo *server_info)
1584{
1585 MagickBooleanType
1586 status;
1587
1588 MagickOffsetType
1589 count;
1590
1591 unsigned char
1592 message[MagickPathExtent],
1593 *p;
1594
1595 /*
1596 Delete distributed pixel cache.
1597 */
1598 assert(server_info != (DistributeCacheInfo *) NULL);
1599 assert(server_info->signature == MagickCoreSignature);
1600 p=message;
1601 *p++='d';
1602 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1603 p+=(ptrdiff_t) sizeof(server_info->session_key);
1604 count=dpc_send(server_info->file,p-message,message);
1605 if (count != (MagickOffsetType) (p-message))
1606 return(MagickFalse);
1607 status=MagickFalse;
1608 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1609 if (count != (MagickOffsetType) sizeof(status))
1610 return(MagickFalse);
1611 return(status);
1612}
1613
1614/*
1615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616% %
1617% %
1618% %
1619+ 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 %
1620% %
1621% %
1622% %
1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624%
1625% WriteDistributePixelCacheIndexes() writes image indexes to the specified
1626% region of the distributed pixel cache.
1627%
1628% The format of the WriteDistributePixelCacheIndexes method is:
1629%
1630% MagickOffsetType WriteDistributePixelCacheIndexes(
1631% DistributeCacheInfo *server_info,const RectangleInfo *region,
1632% const MagickSizeType length,const unsigned char *indexes)
1633%
1634% A description of each parameter follows:
1635%
1636% o server_info: the distributed cache info.
1637%
1638% o image: the image.
1639%
1640% o region: write the indexes to this region of the image.
1641%
1642% o length: the length in bytes of the indexes.
1643%
1644% o indexes: write these indexes to the pixel cache.
1645%
1646*/
1647MagickPrivate MagickOffsetType WriteDistributePixelCacheIndexes(
1648 DistributeCacheInfo *server_info,const RectangleInfo *region,
1649 const MagickSizeType length,const unsigned char *indexes)
1650{
1651 MagickOffsetType
1652 count;
1653
1654 unsigned char
1655 message[MagickPathExtent],
1656 *p;
1657
1658 /*
1659 Write distributed pixel cache indexes.
1660 */
1661 assert(server_info != (DistributeCacheInfo *) NULL);
1662 assert(server_info->signature == MagickCoreSignature);
1663 assert(region != (RectangleInfo *) NULL);
1664 assert(indexes != (unsigned char *) NULL);
1665 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1666 return(-1);
1667 p=message;
1668 *p++='W';
1669 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1670 p+=(ptrdiff_t) sizeof(server_info->session_key);
1671 (void) memcpy(p,&region->width,sizeof(region->width));
1672 p+=(ptrdiff_t) sizeof(region->width);
1673 (void) memcpy(p,&region->height,sizeof(region->height));
1674 p+=(ptrdiff_t) sizeof(region->height);
1675 (void) memcpy(p,&region->x,sizeof(region->x));
1676 p+=(ptrdiff_t) sizeof(region->x);
1677 (void) memcpy(p,&region->y,sizeof(region->y));
1678 p+=(ptrdiff_t) sizeof(region->y);
1679 (void) memcpy(p,&length,sizeof(length));
1680 p+=(ptrdiff_t) sizeof(length);
1681 count=dpc_send(server_info->file,p-message,message);
1682 if (count != (MagickOffsetType) (p-message))
1683 return(-1);
1684 return(dpc_send(server_info->file,length,indexes));
1685}
1686
1687/*
1688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1689% %
1690% %
1691% %
1692+ 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 %
1693% %
1694% %
1695% %
1696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697%
1698% WriteDistributePixelCachePixels() writes image pixels to the specified
1699% region of the distributed pixel cache.
1700%
1701% The format of the WriteDistributePixelCachePixels method is:
1702%
1703% MagickBooleanType WriteDistributePixelCachePixels(
1704% DistributeCacheInfo *server_info,const RectangleInfo *region,
1705% const MagickSizeType length,
1706% const unsigned char *magick_restrict pixels)
1707%
1708% A description of each parameter follows:
1709%
1710% o server_info: the distributed cache info.
1711%
1712% o image: the image.
1713%
1714% o region: write the pixels to this region of the image.
1715%
1716% o length: the length in bytes of the pixels.
1717%
1718% o pixels: write these pixels to the pixel cache.
1719%
1720*/
1721MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1722 DistributeCacheInfo *server_info,const RectangleInfo *region,
1723 const MagickSizeType length,const unsigned char *magick_restrict pixels)
1724{
1725 MagickOffsetType
1726 count;
1727
1728 unsigned char
1729 message[MagickPathExtent],
1730 *p;
1731
1732 /*
1733 Write distributed pixel cache pixels.
1734 */
1735 assert(server_info != (DistributeCacheInfo *) NULL);
1736 assert(server_info->signature == MagickCoreSignature);
1737 assert(region != (RectangleInfo *) NULL);
1738 assert(pixels != (const unsigned char *) NULL);
1739 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1740 return(-1);
1741 p=message;
1742 *p++='w';
1743 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1744 p+=(ptrdiff_t) sizeof(server_info->session_key);
1745 (void) memcpy(p,&region->width,sizeof(region->width));
1746 p+=(ptrdiff_t) sizeof(region->width);
1747 (void) memcpy(p,&region->height,sizeof(region->height));
1748 p+=(ptrdiff_t) sizeof(region->height);
1749 (void) memcpy(p,&region->x,sizeof(region->x));
1750 p+=(ptrdiff_t) sizeof(region->x);
1751 (void) memcpy(p,&region->y,sizeof(region->y));
1752 p+=(ptrdiff_t) sizeof(region->y);
1753 (void) memcpy(p,&length,sizeof(length));
1754 p+=(ptrdiff_t) sizeof(length);
1755 count=dpc_send(server_info->file,p-message,message);
1756 if (count != (MagickOffsetType) (p-message))
1757 return(-1);
1758 return(dpc_send(server_info->file,length,pixels));
1759}