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