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