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