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