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