2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
11 % CCCC AAA CCCC H H EEEEE %
13 % C AAAAA C HHHHH EEE %
15 % CCCC A A CCCC H H EEEEE %
18 % MagickCore Distributed Pixel Cache Methods %
25 % Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
26 % dedicated to making software imaging solutions freely available. %
28 % You may not use this file except in compliance with the License. You may %
29 % obtain a copy of the License at %
31 % http://www.imagemagick.org/script/license.php %
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. %
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
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/locale_.h"
64 #include "MagickCore/memory_.h"
65 #include "MagickCore/policy.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/splay-tree.h"
69 #include "MagickCore/string_.h"
70 #include "MagickCore/string-private.h"
71 #if defined(MAGICKCORE_HAVE_SOCKET)
72 #include <netinet/in.h>
74 #include <sys/socket.h>
75 #include <arpa/inet.h>
81 #define DPCHostname "127.0.0.1"
83 #define DPCSessionKeyLength 8
86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90 + 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 %
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 % AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
98 % The format of the AcquireDistributeCacheInfo method is:
100 % DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
102 % A description of each parameter follows:
104 % o exception: return any errors or warnings in this structure.
108 static MagickSizeType CRC64(const unsigned char *message,const size_t length)
116 static MagickBooleanType
117 crc_initial = MagickFalse;
119 static MagickSizeType
122 if (crc_initial == MagickFalse)
127 for (i=0; i < 256; i++)
132 alpha=(MagickSizeType) i;
133 for (j=0; j < 8; j++)
135 if ((alpha & 0x01) == 0)
138 alpha=(MagickSizeType) ((alpha >> 1) ^
139 MagickULLConstant(0xd800000000000000));
143 crc_initial=MagickTrue;
146 for (i=0; i < (ssize_t) length; i++)
147 crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
151 static int ConnectPixelCacheServer(const char *hostname,const int port,
152 MagickSizeType *session_key,ExceptionInfo *exception)
154 #if defined(MAGICKCORE_HAVE_SOCKET)
156 secret[MaxTextExtent];
175 session[MaxTextExtent];
178 Connect to distributed pixel cache and get session key.
181 shared_secret=GetPolicyValue("shared-secret");
182 if (shared_secret == (const char *) NULL)
184 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
185 "DistributedPixelCache","'%s'","shared secret expected");
188 (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
189 DPCSessionKeyLength);
190 host=gethostbyname(hostname);
191 client_socket=socket(AF_INET,SOCK_STREAM,0);
192 if (client_socket == -1)
194 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
195 "DistributedPixelCache","'%s'",hostname);
198 (void) ResetMagickMemory(&address,0,sizeof(address));
199 address.sin_family=AF_INET;
200 address.sin_port=htons((uint16_t) port);
201 address.sin_addr=(*((struct in_addr *) host->h_addr));
202 status=connect(client_socket,(struct sockaddr *) &address,(socklen_t)
203 sizeof(struct sockaddr));
206 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
207 "DistributedPixelCache","'%s'",hostname);
210 count=recv(client_socket,secret,MaxTextExtent,0);
213 (void) memcpy(session+strlen(shared_secret),secret,(size_t) count);
214 *session_key=CRC64(session,strlen(shared_secret)+count);
216 if (*session_key == 0)
218 close(client_socket);
221 return(client_socket);
223 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
224 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
229 static char *GetHostname(int *port,ExceptionInfo *exception)
246 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
248 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
250 if (hosts == (char *) NULL)
253 return(AcquireString(DPCHostname));
255 (void) SubstituteString(&hosts,","," ");
256 hostlist=StringToArgv(hosts,&argc);
257 hosts=DestroyString(hosts);
258 if (hostlist == (char **) NULL)
261 return(AcquireString(DPCHostname));
263 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
264 for (i=0; i < (ssize_t) argc; i++)
265 hostlist[i]=DestroyString(hostlist[i]);
266 hostlist=(char **) RelinquishMagickMemory(hostlist);
267 (void) SubstituteString(&hosts,":"," ");
268 hostlist=StringToArgv(hosts,&argc);
269 if (hostlist == (char **) NULL)
272 return(AcquireString(DPCHostname));
274 host=AcquireString(hostlist[1]);
275 if (hostlist[2] == (char *) NULL)
278 *port=StringToLong(hostlist[2]);
279 for (i=0; i < (ssize_t) argc; i++)
280 hostlist[i]=DestroyString(hostlist[i]);
281 hostlist=(char **) RelinquishMagickMemory(hostlist);
285 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
286 ExceptionInfo *exception)
292 *distribute_cache_info;
297 distribute_cache_info=(DistributeCacheInfo *) AcquireMagickMemory(
298 sizeof(*distribute_cache_info));
299 if (distribute_cache_info == (DistributeCacheInfo *) NULL)
300 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
301 (void) ResetMagickMemory(distribute_cache_info,0,
302 sizeof(*distribute_cache_info));
303 distribute_cache_info->signature=MagickSignature;
305 Contact pixel cache server.
307 distribute_cache_info->port=0;
308 hostname=GetHostname(&distribute_cache_info->port,exception);
310 distribute_cache_info->file=ConnectPixelCacheServer(hostname,
311 distribute_cache_info->port,&session_key,exception);
312 distribute_cache_info->session_key=session_key;
313 (void) CopyMagickString(distribute_cache_info->hostname,hostname,
315 hostname=DestroyString(hostname);
316 if (distribute_cache_info->file == -1)
317 distribute_cache_info=DestroyDistributeCacheInfo(distribute_cache_info);
318 return(distribute_cache_info);
322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326 + 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 %
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 % DestroyDistributeCacheInfo() deallocates memory associated with an
333 % DistributeCacheInfo structure.
335 % The format of the DestroyDistributeCacheInfo method is:
337 % DistributeCacheInfo *DestroyDistributeCacheInfo(
338 % DistributeCacheInfo *distribute_cache_info)
340 % A description of each parameter follows:
342 % o distribute_cache_info: the distributed cache info.
345 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
346 DistributeCacheInfo *distribute_cache_info)
348 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
349 assert(distribute_cache_info->signature == MagickSignature);
350 distribute_cache_info->signature=(~MagickSignature);
351 distribute_cache_info=(DistributeCacheInfo *) RelinquishMagickMemory(
352 distribute_cache_info);
353 return(distribute_cache_info);
357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
361 + 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 %
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367 % DistributePixelCacheServer() waits on the specified port for commands to
368 % create, read, update, or destroy a pixel cache.
370 % The format of the DistributePixelCacheServer() method is:
372 % void DistributePixelCacheServer(const size_t port)
374 % A description of each parameter follows:
376 % o port: connect the distributed pixel cache at this port.
378 % o exception: return any errors or warnings in this structure.
382 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *image_registry,
383 int file,const MagickSizeType session_key)
385 return(DeleteNodeFromSplayTree(image_registry,(const void *) session_key));
388 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *image_registry,
389 int file,const MagickSizeType session_key)
400 register unsigned char
410 buffer[MaxTextExtent];
412 exception=AcquireExceptionInfo();
413 image=AcquireImage((ImageInfo *) NULL,exception);
414 exception=DestroyExceptionInfo(exception);
415 if (image == (Image *) NULL)
417 length=sizeof(image->columns)+sizeof(image->rows)+
418 sizeof(image->number_channels);
419 count=recv(file,buffer,length,0);
420 if (count != (ssize_t) length)
423 (void) memcpy(&image->columns,p,sizeof(image->columns));
424 p+=sizeof(image->columns);
425 (void) memcpy(&image->rows,p,sizeof(image->rows));
426 p+=sizeof(image->rows);
427 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
428 p+=sizeof(image->number_channels);
429 status=AddValueToSplayTree(image_registry,(const void *) session_key,image);
433 static MagickBooleanType ReadDistributeCacheMetacontent(
434 SplayTreeInfo *image_registry,int file,const MagickSizeType session_key)
448 register const Quantum
451 register unsigned char
461 buffer[MaxTextExtent];
463 image=(Image *) GetValueFromSplayTree(image_registry,(const void *)
465 if (image == (Image *) NULL)
467 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
468 sizeof(region.y)+sizeof(length);
469 count=recv(file,buffer,length,0);
470 if (count != (ssize_t) length)
473 (void) memcpy(®ion.width,q,sizeof(region.width));
474 q+=sizeof(region.width);
475 (void) memcpy(®ion.height,q,sizeof(region.height));
476 q+=sizeof(region.width);
477 (void) memcpy(®ion.x,q,sizeof(region.x));
478 q+=sizeof(region.width);
479 (void) memcpy(®ion.y,q,sizeof(region.y));
480 q+=sizeof(region.width);
481 (void) memcpy(&length,q,sizeof(length));
483 exception=AcquireExceptionInfo();
484 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
486 exception=DestroyExceptionInfo(exception);
487 if (p == (const Quantum *) NULL)
489 metacontent=GetVirtualMetacontent(image);
490 count=send(file,metacontent,length,0);
491 if (count != (ssize_t) length)
496 static MagickBooleanType ReadDistributeCachePixels(
497 SplayTreeInfo *image_registry,int file,const MagickSizeType session_key)
508 register const Quantum
511 register unsigned char
521 buffer[MaxTextExtent];
523 image=(Image *) GetValueFromSplayTree(image_registry,(const void *)
525 if (image == (Image *) NULL)
527 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
528 sizeof(region.y)+sizeof(length);
529 count=recv(file,buffer,length,0);
530 if (count != (ssize_t) length)
533 (void) memcpy(®ion.width,q,sizeof(region.width));
534 q+=sizeof(region.width);
535 (void) memcpy(®ion.height,q,sizeof(region.height));
536 q+=sizeof(region.width);
537 (void) memcpy(®ion.x,q,sizeof(region.x));
538 q+=sizeof(region.width);
539 (void) memcpy(®ion.y,q,sizeof(region.y));
540 q+=sizeof(region.width);
541 (void) memcpy(&length,q,sizeof(length));
543 exception=AcquireExceptionInfo();
544 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
546 exception=DestroyExceptionInfo(exception);
547 if (p == (const Quantum *) NULL)
549 count=send(file,p,length,0);
550 if (count != (ssize_t) length)
555 static MagickBooleanType WriteDistributeCacheMetacontent(
556 SplayTreeInfo *image_registry,int file,const MagickSizeType session_key)
573 register unsigned char
583 buffer[MaxTextExtent],
586 image=(Image *) GetValueFromSplayTree(image_registry,(const void *)
588 if (image == (Image *) NULL)
590 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
591 sizeof(region.y)+sizeof(length);
592 count=recv(file,buffer,length,0);
593 if (count != (ssize_t) length)
596 (void) memcpy(®ion.width,p,sizeof(region.width));
597 p+=sizeof(region.width);
598 (void) memcpy(®ion.height,p,sizeof(region.height));
599 p+=sizeof(region.width);
600 (void) memcpy(®ion.x,p,sizeof(region.x));
601 p+=sizeof(region.width);
602 (void) memcpy(®ion.y,p,sizeof(region.y));
603 p+=sizeof(region.width);
604 (void) memcpy(&length,p,sizeof(length));
606 exception=AcquireExceptionInfo();
607 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
609 exception=DestroyExceptionInfo(exception);
610 if (q == (Quantum *) NULL)
612 metacontent=GetAuthenticMetacontent(image);
613 count=recv(file,metacontent,length,0);
614 if (count != (ssize_t) length)
616 status=SyncAuthenticPixels(image,exception);
620 static MagickBooleanType WriteDistributeCachePixels(
621 SplayTreeInfo *image_registry,int file,const MagickSizeType session_key)
638 register unsigned char
648 buffer[MaxTextExtent];
650 image=(Image *) GetValueFromSplayTree(image_registry,(const void *)
652 if (image == (Image *) NULL)
654 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
655 sizeof(region.y)+sizeof(length);
656 count=recv(file,buffer,length,0);
657 if (count != (ssize_t) length)
660 (void) memcpy(®ion.width,p,sizeof(region.width));
661 p+=sizeof(region.width);
662 (void) memcpy(®ion.height,p,sizeof(region.height));
663 p+=sizeof(region.width);
664 (void) memcpy(®ion.x,p,sizeof(region.x));
665 p+=sizeof(region.width);
666 (void) memcpy(®ion.y,p,sizeof(region.y));
667 p+=sizeof(region.width);
668 (void) memcpy(&length,p,sizeof(length));
670 exception=AcquireExceptionInfo();
671 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
673 exception=DestroyExceptionInfo(exception);
674 if (q == (Quantum *) NULL)
676 count=recv(file,q,length,0);
677 if (count != (ssize_t) length)
679 status=SyncAuthenticPixels(image,exception);
683 static void *DistributePixelCacheClient(void *socket)
712 session[MaxTextExtent];
715 Generate session key.
717 shared_secret=GetPolicyValue("shared-secret");
718 if (shared_secret == (const char *) NULL)
719 ThrowFatalException(CacheFatalError,"shared secret expected");
720 (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
721 DPCSessionKeyLength);
722 random_info=AcquireRandomInfo();
723 secret=GetRandomKey(random_info,DPCSessionKeyLength);
724 (void) memcpy(session+strlen(shared_secret),GetStringInfoDatum(secret),
725 DPCSessionKeyLength);
726 session_key=CRC64(session,strlen(shared_secret)+DPCSessionKeyLength);
727 random_info=DestroyRandomInfo(random_info);
728 image_registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
729 (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
730 client_socket=(*(int *) socket);
731 count=send(client_socket,GetStringInfoDatum(secret),DPCSessionKeyLength,0);
732 secret=DestroyStringInfo(secret);
735 count=recv(client_socket,&command,1,0);
738 count=recv(client_socket,&key,sizeof(key),0);
739 if ((count != (ssize_t) sizeof(key)) && (key != session_key))
746 status=OpenDistributeCache(image_registry,client_socket,session_key);
751 status=ReadDistributeCachePixels(image_registry,client_socket,
757 status=ReadDistributeCacheMetacontent(image_registry,client_socket,
763 status=WriteDistributeCachePixels(image_registry,client_socket,
769 status=WriteDistributeCacheMetacontent(image_registry,client_socket,
775 status=DestroyDistributeCache(image_registry,client_socket,session_key);
781 count=send(client_socket,&status,sizeof(status),0);
782 if (count != (ssize_t) sizeof(status))
785 (void) close(client_socket);
786 image_registry=DestroySplayTree(image_registry);
787 return((void *) NULL);
790 MagickExport void DistributePixelCacheServer(const size_t port,
791 ExceptionInfo *exception)
793 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
808 Launch distributed pixel cache server.
810 server_socket=socket(AF_INET,SOCK_STREAM,0);
811 address.sin_family=AF_INET;
812 address.sin_port=htons(port);
813 address.sin_addr.s_addr=htonl(INADDR_ANY);
814 status=bind(server_socket,(struct sockaddr *) &address,(socklen_t)
817 ThrowFatalException(CacheFatalError,"UnableToBind");
818 status=listen(server_socket,5);
820 ThrowFatalException(CacheFatalError,"UnableToListen");
821 pthread_attr_init(&attributes);
830 length=(socklen_t) sizeof(address);
831 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
832 if (client_socket == -1)
833 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
834 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
835 (void *) &client_socket);
837 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
839 (void) close(server_socket);
841 ThrowFatalException(MissingDelegateError,"distributed pixel cache");
846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850 + G e t D i s t r i b u t e C a c h e F i l e %
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 % GetDistributeCacheFile() returns the file associated with this
857 % DistributeCacheInfo structure.
859 % The format of the GetDistributeCacheFile method is:
861 % int GetDistributeCacheFile(
862 % const DistributeCacheInfo *distribute_cache_info)
864 % A description of each parameter follows:
866 % o distribute_cache_info: the distributed cache info.
869 MagickPrivate int GetDistributeCacheFile(
870 const DistributeCacheInfo *distribute_cache_info)
872 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
873 assert(distribute_cache_info->signature == MagickSignature);
874 return(distribute_cache_info->file);
878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
882 + 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 %
886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
888 % GetDistributeCacheHostname() returns the hostname associated with this
889 % DistributeCacheInfo structure.
891 % The format of the GetDistributeCacheHostname method is:
893 % const char *GetDistributeCacheHostname(
894 % const DistributeCacheInfo *distribute_cache_info)
896 % A description of each parameter follows:
898 % o distribute_cache_info: the distributed cache info.
901 MagickPrivate const char *GetDistributeCacheHostname(
902 const DistributeCacheInfo *distribute_cache_info)
904 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
905 assert(distribute_cache_info->signature == MagickSignature);
906 return(distribute_cache_info->hostname);
910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914 + G e t D i s t r i b u t e C a c h e P o r t %
918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920 % GetDistributeCachePort() returns the port associated with this
921 % DistributeCacheInfo structure.
923 % The format of the GetDistributeCachePort method is:
925 % int GetDistributeCachePort(
926 % const DistributeCacheInfo *distribute_cache_info)
928 % A description of each parameter follows:
930 % o distribute_cache_info: the distributed cache info.
933 MagickPrivate int GetDistributeCachePort(
934 const DistributeCacheInfo *distribute_cache_info)
936 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
937 assert(distribute_cache_info->signature == MagickSignature);
938 return(distribute_cache_info->port);
942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
946 + O p e n D i s t r i b u t e P i x e l C a c h e %
950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
952 % OpenDistributePixelCache() opens a pixel cache on a remote server.
954 % The format of the OpenDistributePixelCache method is:
956 % MagickBooleanType *OpenDistributePixelCache(
957 % DistributeCacheInfo *distribute_cache_info,Image *image)
959 % A description of each parameter follows:
961 % o distribute_cache_info: the distributed cache info.
963 % o image: the image.
966 MagickPrivate MagickBooleanType OpenDistributePixelCache(
967 DistributeCacheInfo *distribute_cache_info,Image *image)
972 register unsigned char
979 buffer[MaxTextExtent];
981 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
982 assert(distribute_cache_info->signature == MagickSignature);
983 assert(image != (Image *) NULL);
984 assert(image->signature == MagickSignature);
987 (void) memcpy(p,&distribute_cache_info->session_key,
988 sizeof(distribute_cache_info->session_key));
989 p+=sizeof(distribute_cache_info->session_key);
990 (void) memcpy(p,&image->columns,sizeof(image->columns));
991 p+=sizeof(image->columns);
992 (void) memcpy(p,&image->rows,sizeof(image->rows));
993 p+=sizeof(image->rows);
994 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
995 p+=sizeof(image->number_channels);
996 count=send(distribute_cache_info->file,buffer,p-buffer,0);
997 if (count != (ssize_t) (p-buffer))
999 count=recv(distribute_cache_info->file,&status,sizeof(status),0);
1000 if (count != (ssize_t) sizeof(status))
1001 return(MagickFalse);
1006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1010 + 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 %
1014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1017 % region of the distributed pixel cache.
1019 % The format of the ReadDistributePixelCacheMetacontents method is:
1021 % MagickBooleanType *ReadDistributePixelCacheMetacontents(
1022 % DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1023 % const MagickSizeType length,unsigned char *metacontent)
1025 % A description of each parameter follows:
1027 % o distribute_cache_info: the distributed cache info.
1029 % o image: the image.
1031 % o region: read the metacontent from this region of the image.
1033 % o length: the length in bytes of the metacontent.
1035 % o metacontent: read these metacontent from the pixel cache.
1038 MagickPrivate MagickBooleanType ReadDistributePixelCacheMetacontent(
1039 DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1040 const MagickSizeType length,unsigned char *metacontent)
1045 register unsigned char
1052 buffer[MaxTextExtent];
1054 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
1055 assert(distribute_cache_info->signature == MagickSignature);
1056 assert(region != (RectangleInfo *) NULL);
1057 assert(metacontent != (unsigned char *) NULL);
1058 assert(length == ((size_t) length));
1060 *p++='R'; /* read */
1061 (void) memcpy(p,&distribute_cache_info->session_key,
1062 sizeof(distribute_cache_info->session_key));
1063 p+=sizeof(distribute_cache_info->session_key);
1064 (void) memcpy(p,®ion->width,sizeof(region->width));
1065 p+=sizeof(region->width);
1066 (void) memcpy(p,®ion->height,sizeof(region->height));
1067 p+=sizeof(region->height);
1068 (void) memcpy(p,®ion->x,sizeof(region->x));
1069 p+=sizeof(region->x);
1070 (void) memcpy(p,®ion->y,sizeof(region->y));
1071 p+=sizeof(region->y);
1072 (void) memcpy(p,&length,sizeof(length));
1074 count=send(distribute_cache_info->file,buffer,p-buffer,0);
1075 if (count != (ssize_t) (p-buffer))
1076 return(MagickFalse);
1077 count=recv(distribute_cache_info->file,(unsigned char *) metacontent,(size_t)
1079 if (count != (ssize_t) length)
1080 return(MagickFalse);
1081 count=recv(distribute_cache_info->file,&status,sizeof(status),0);
1082 if (count != (ssize_t) sizeof(status))
1083 return(MagickFalse);
1084 return(status != 0 ? MagickTrue : MagickFalse);
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1092 + 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 %
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1098 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1099 % the distributed pixel cache.
1101 % The format of the ReadDistributePixelCachePixels method is:
1103 % MagickBooleanType *ReadDistributePixelCachePixels(
1104 % DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1105 % const MagickSizeType length,unsigned char *pixels)
1107 % A description of each parameter follows:
1109 % o distribute_cache_info: the distributed cache info.
1111 % o image: the image.
1113 % o region: read the pixels from this region of the image.
1115 % o length: the length in bytes of the pixels.
1117 % o pixels: read these pixels from the pixel cache.
1120 MagickPrivate MagickBooleanType ReadDistributePixelCachePixels(
1121 DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1122 const MagickSizeType length,unsigned char *pixels)
1127 register unsigned char
1134 buffer[MaxTextExtent];
1136 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
1137 assert(distribute_cache_info->signature == MagickSignature);
1138 assert(region != (RectangleInfo *) NULL);
1139 assert(pixels != (unsigned char *) NULL);
1140 assert(length == ((size_t) length));
1142 *p++='r'; /* read */
1143 (void) memcpy(p,&distribute_cache_info->session_key,
1144 sizeof(distribute_cache_info->session_key));
1145 p+=sizeof(distribute_cache_info->session_key);
1146 (void) memcpy(p,®ion->width,sizeof(region->width));
1147 p+=sizeof(region->width);
1148 (void) memcpy(p,®ion->height,sizeof(region->height));
1149 p+=sizeof(region->height);
1150 (void) memcpy(p,®ion->x,sizeof(region->x));
1151 p+=sizeof(region->x);
1152 (void) memcpy(p,®ion->y,sizeof(region->y));
1153 p+=sizeof(region->y);
1154 (void) memcpy(p,&length,sizeof(length));
1156 count=send(distribute_cache_info->file,buffer,p-buffer,0);
1157 if (count != (ssize_t) (p-buffer))
1158 return(MagickFalse);
1159 count=recv(distribute_cache_info->file,(unsigned char *) pixels,(size_t)
1161 if (count != (ssize_t) length)
1162 return(MagickFalse);
1163 count=recv(distribute_cache_info->file,&status,sizeof(status),0);
1164 if (count != (ssize_t) sizeof(status))
1165 return(MagickFalse);
1166 return(status != 0 ? MagickTrue : MagickFalse);
1170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1174 + 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 %
1178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180 % RelinquishDistributePixelCache() frees resources acquired with
1181 % OpenDistributePixelCache().
1183 % The format of the RelinquishDistributePixelCache method is:
1185 % MagickBooleanType RelinquishDistributePixelCache(
1186 % DistributeCacheInfo *distribute_cache_info)
1188 % A description of each parameter follows:
1190 % o distribute_cache_info: the distributed cache info.
1193 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1194 DistributeCacheInfo *distribute_cache_info)
1196 register unsigned char
1203 buffer[MaxTextExtent];
1205 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
1206 assert(distribute_cache_info->signature == MagickSignature);
1208 *p++='d'; /* delete */
1209 (void) memcpy(p,&distribute_cache_info->session_key,
1210 sizeof(distribute_cache_info->session_key));
1211 p+=sizeof(distribute_cache_info->session_key);
1212 count=send(distribute_cache_info->file,buffer,p-buffer,0);
1213 if (count != (ssize_t) (p-buffer))
1214 return(MagickFalse);
1219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1223 + 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 %
1227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1229 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1230 % specified region of the distributed pixel cache.
1233 % The format of the WriteDistributePixelCacheMetacontents method is:
1235 % MagickBooleanType *WriteDistributePixelCacheMetacontents(
1236 % DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1237 % const MagickSizeType length,const unsigned char *metacontent)
1239 % A description of each parameter follows:
1241 % o distribute_cache_info: the distributed cache info.
1243 % o image: the image.
1245 % o region: write the metacontent to this region of the image.
1247 % o length: the length in bytes of the metacontent.
1249 % o metacontent: write these metacontent to the pixel cache.
1252 MagickPrivate MagickBooleanType WriteDistributePixelCacheMetacontent(
1253 DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1254 const MagickSizeType length,const unsigned char *metacontent)
1259 register unsigned char
1266 buffer[MaxTextExtent];
1268 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
1269 assert(distribute_cache_info->signature == MagickSignature);
1270 assert(region != (RectangleInfo *) NULL);
1271 assert(metacontent != (unsigned char *) NULL);
1272 assert(length == ((size_t) length));
1274 *p++='W'; /* write */
1275 (void) memcpy(p,&distribute_cache_info->session_key,
1276 sizeof(distribute_cache_info->session_key));
1277 p+=sizeof(distribute_cache_info->session_key);
1278 (void) memcpy(p,®ion->width,sizeof(region->width));
1279 p+=sizeof(region->width);
1280 (void) memcpy(p,®ion->height,sizeof(region->height));
1281 p+=sizeof(region->height);
1282 (void) memcpy(p,®ion->x,sizeof(region->x));
1283 p+=sizeof(region->x);
1284 (void) memcpy(p,®ion->y,sizeof(region->y));
1285 p+=sizeof(region->y);
1286 (void) memcpy(p,&length,sizeof(length));
1288 count=send(distribute_cache_info->file,buffer,p-buffer,0);
1289 if (count != (ssize_t) (p-buffer))
1290 return(MagickFalse);
1291 count=send(distribute_cache_info->file,(unsigned char *) metacontent,(size_t)
1293 if (count != (ssize_t) length)
1294 return(MagickFalse);
1295 count=recv(distribute_cache_info->file,&status,sizeof(status),0);
1296 if (count != (ssize_t) sizeof(status))
1297 return(MagickFalse);
1298 return(status != 0 ? MagickTrue : MagickFalse);
1302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306 + 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 %
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312 % WriteDistributePixelCachePixels() writes image pixels to the specified
1313 % region of the distributed pixel cache.
1316 % The format of the WriteDistributePixelCachePixels method is:
1318 % MagickBooleanType *WriteDistributePixelCachePixels(
1319 % DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1320 % const MagickSizeType length,const unsigned char *pixels)
1322 % A description of each parameter follows:
1324 % o distribute_cache_info: the distributed cache info.
1326 % o image: the image.
1328 % o region: write the pixels to this region of the image.
1330 % o length: the length in bytes of the pixels.
1332 % o pixels: write these pixels to the pixel cache.
1335 MagickPrivate MagickBooleanType WriteDistributePixelCachePixels(
1336 DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
1337 const MagickSizeType length,const unsigned char *pixels)
1342 register unsigned char
1349 buffer[MaxTextExtent];
1351 assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
1352 assert(distribute_cache_info->signature == MagickSignature);
1353 assert(region != (RectangleInfo *) NULL);
1354 assert(pixels != (const unsigned char *) NULL);
1355 assert(length == ((size_t) length));
1357 *p++='w'; /* write */
1358 (void) memcpy(p,&distribute_cache_info->session_key,
1359 sizeof(distribute_cache_info->session_key));
1360 p+=sizeof(distribute_cache_info->session_key);
1361 (void) memcpy(p,®ion->width,sizeof(region->width));
1362 p+=sizeof(region->width);
1363 (void) memcpy(p,®ion->height,sizeof(region->height));
1364 p+=sizeof(region->height);
1365 (void) memcpy(p,®ion->x,sizeof(region->x));
1366 p+=sizeof(region->x);
1367 (void) memcpy(p,®ion->y,sizeof(region->y));
1368 p+=sizeof(region->y);
1369 (void) memcpy(p,&length,sizeof(length));
1371 count=send(distribute_cache_info->file,buffer,p-buffer,0);
1372 if (count != (ssize_t) (p-buffer))
1373 return(MagickFalse);
1374 count=send(distribute_cache_info->file,(unsigned char *) pixels,(size_t)
1376 if (count != (ssize_t) length)
1377 return(MagickFalse);
1378 count=recv(distribute_cache_info->file,&status,sizeof(status),0);
1379 if (count != (ssize_t) sizeof(status))
1380 return(MagickFalse);
1381 return(status != 0 ? MagickTrue : MagickFalse);