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