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/list.h"
64 #include "MagickCore/locale_.h"
65 #include "MagickCore/memory_.h"
66 #include "MagickCore/nt-base-private.h"
67 #include "MagickCore/pixel.h"
68 #include "MagickCore/policy.h"
69 #include "MagickCore/random_.h"
70 #include "MagickCore/registry.h"
71 #include "MagickCore/splay-tree.h"
72 #include "MagickCore/string_.h"
73 #include "MagickCore/string-private.h"
74 #include "MagickCore/version.h"
75 #include "MagickCore/version-private.h"
76 #if defined(MAGICKCORE_HAVE_SOCKET) && !defined(__MINGW32__) && !defined(__MINGW64__)
77 #include <netinet/in.h>
79 #include <sys/socket.h>
80 #include <arpa/inet.h>
86 #define DPCHostname "127.0.0.1"
87 #define DPCPendingConnections 10
89 #define DPCSessionKeyLength 8
91 # define MSG_NOSIGNAL 0
95 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 + 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 %
103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 % AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
107 % The format of the AcquireDistributeCacheInfo method is:
109 % DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
111 % A description of each parameter follows:
113 % o exception: return any errors or warnings in this structure.
117 static inline MagickSizeType MagickMin(const MagickSizeType x,
118 const MagickSizeType y)
125 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
126 unsigned char *restrict message)
128 register MagickOffsetType
135 for (i=0; i < (MagickOffsetType) length; i+=count)
137 count=recv(file,message+i,(size_t) MagickMin(length-i,(MagickSizeType)
149 static int ConnectPixelCacheServer(const char *hostname,const int port,
150 size_t *session_key,ExceptionInfo *exception)
152 #if defined(MAGICKCORE_HAVE_SOCKET) && !defined(__MINGW32__) && !defined(__MINGW64__)
154 service[MaxTextExtent];
171 secret[MaxTextExtent];
174 Connect to distributed pixel cache and get session key.
177 shared_secret=GetPolicyValue("shared-secret");
178 if (shared_secret == (const char *) NULL)
180 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
181 "DistributedPixelCache","'%s'","shared secret expected");
184 (void) ResetMagickMemory(&hint,0,sizeof(hint));
185 hint.ai_family=AF_INET;
186 hint.ai_socktype=SOCK_STREAM;
187 hint.ai_flags=AI_PASSIVE;
188 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
189 status=getaddrinfo(hostname,service,&hint,&result);
192 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
193 "DistributedPixelCache","'%s'",hostname);
196 client_socket=socket(result->ai_family,result->ai_socktype,
197 result->ai_protocol);
198 if (client_socket == -1)
200 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
201 "DistributedPixelCache","'%s'",hostname);
204 status=connect(client_socket,result->ai_addr,result->ai_addrlen);
207 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
208 "DistributedPixelCache","'%s'",hostname);
211 count=recv(client_socket,secret,MaxTextExtent,0);
217 nonce=AcquireStringInfo(count);
218 (void) memcpy(GetStringInfoDatum(nonce),secret,(size_t) count);
219 *session_key=GetMagickSignature(nonce);
220 nonce=DestroyStringInfo(nonce);
222 if (*session_key == 0)
224 close(client_socket);
227 return(client_socket);
229 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
230 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
235 static char *GetHostname(int *port,ExceptionInfo *exception)
252 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
254 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
256 if (hosts == (char *) NULL)
259 return(AcquireString(DPCHostname));
261 (void) SubstituteString(&hosts,","," ");
262 hostlist=StringToArgv(hosts,&argc);
263 hosts=DestroyString(hosts);
264 if (hostlist == (char **) NULL)
267 return(AcquireString(DPCHostname));
269 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
270 for (i=0; i < (ssize_t) argc; i++)
271 hostlist[i]=DestroyString(hostlist[i]);
272 hostlist=(char **) RelinquishMagickMemory(hostlist);
273 (void) SubstituteString(&hosts,":"," ");
274 hostlist=StringToArgv(hosts,&argc);
275 if (hostlist == (char **) NULL)
278 return(AcquireString(DPCHostname));
280 host=AcquireString(hostlist[1]);
281 if (hostlist[2] == (char *) NULL)
284 *port=StringToLong(hostlist[2]);
285 for (i=0; i < (ssize_t) argc; i++)
286 hostlist[i]=DestroyString(hostlist[i]);
287 hostlist=(char **) RelinquishMagickMemory(hostlist);
291 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
292 ExceptionInfo *exception)
304 Connect to the distributed pixel cache server.
306 server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info));
307 if (server_info == (DistributeCacheInfo *) NULL)
308 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
309 (void) ResetMagickMemory(server_info,0,sizeof(*server_info));
310 server_info->signature=MagickSignature;
312 hostname=GetHostname(&server_info->port,exception);
314 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
315 &session_key,exception);
316 server_info->session_key=session_key;
317 (void) CopyMagickString(server_info->hostname,hostname,MaxTextExtent);
318 hostname=DestroyString(hostname);
319 if (server_info->file == -1)
320 server_info=DestroyDistributeCacheInfo(server_info);
325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 + 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 %
333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 % DestroyDistributeCacheInfo() deallocates memory associated with an
336 % DistributeCacheInfo structure.
338 % The format of the DestroyDistributeCacheInfo method is:
340 % DistributeCacheInfo *DestroyDistributeCacheInfo(
341 % DistributeCacheInfo *server_info)
343 % A description of each parameter follows:
345 % o server_info: the distributed cache info.
348 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
349 DistributeCacheInfo *server_info)
351 assert(server_info != (DistributeCacheInfo *) NULL);
352 assert(server_info->signature == MagickSignature);
353 if (server_info->file > 0)
354 (void) close(server_info->file);
355 server_info->signature=(~MagickSignature);
356 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 + 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 %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371 % DistributePixelCacheServer() waits on the specified port for commands to
372 % create, read, update, or destroy a pixel cache.
374 % The format of the DistributePixelCacheServer() method is:
376 % void DistributePixelCacheServer(const int port)
378 % A description of each parameter follows:
380 % o port: connect the distributed pixel cache at this port.
382 % o exception: return any errors or warnings in this structure.
386 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
387 int file,const size_t session_key)
390 Destroy distributed pixel cache.
392 return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
395 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
396 const unsigned char *restrict message)
401 register MagickOffsetType
405 Ensure a complete message is sent.
408 for (i=0; i < (MagickOffsetType) length; i+=count)
410 count=(MagickOffsetType) send(file,message+i,(size_t) MagickMin(length-i,
411 (MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
422 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
423 int file,const size_t session_key,ExceptionInfo *exception)
437 register unsigned char
441 message[MaxTextExtent];
444 Open distributed pixel cache.
446 image=AcquireImage((ImageInfo *) NULL,exception);
447 if (image == (Image *) NULL)
449 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
450 sizeof(image->alpha_trait)+sizeof(image->mask)+sizeof(image->columns)+
451 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
452 sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
453 count=dpc_read(file,length,message);
454 if (count != (MagickOffsetType) length)
457 Deserialize the image attributes.
460 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
461 p+=sizeof(image->storage_class);
462 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
463 p+=sizeof(image->colorspace);
464 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
465 p+=sizeof(image->alpha_trait);
466 (void) memcpy(&image->mask,p,sizeof(image->mask));
467 p+=sizeof(image->mask);
468 (void) memcpy(&image->columns,p,sizeof(image->columns));
469 p+=sizeof(image->columns);
470 (void) memcpy(&image->rows,p,sizeof(image->rows));
471 p+=sizeof(image->rows);
472 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
473 p+=sizeof(image->number_channels);
474 (void) memcpy(image->channel_map,p,MaxPixelChannels*
475 sizeof(*image->channel_map));
476 p+=MaxPixelChannels*sizeof(*image->channel_map);
477 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
478 p+=sizeof(image->metacontent_extent);
479 if (SyncImagePixelCache(image,exception) == MagickFalse)
481 status=AddValueToSplayTree(registry,(const void *) session_key,image);
485 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
486 int file,const size_t session_key,ExceptionInfo *exception)
503 register const Quantum
506 register unsigned char
510 message[MaxTextExtent];
513 Read distributed pixel cache metacontent.
515 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
516 if (image == (Image *) NULL)
518 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
519 sizeof(region.y)+sizeof(length);
520 count=dpc_read(file,length,message);
521 if (count != (MagickOffsetType) length)
524 (void) memcpy(®ion.width,q,sizeof(region.width));
525 q+=sizeof(region.width);
526 (void) memcpy(®ion.height,q,sizeof(region.height));
527 q+=sizeof(region.height);
528 (void) memcpy(®ion.x,q,sizeof(region.x));
530 (void) memcpy(®ion.y,q,sizeof(region.y));
532 (void) memcpy(&length,q,sizeof(length));
534 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
536 if (p == (const Quantum *) NULL)
538 metacontent=(const unsigned char *) GetVirtualMetacontent(image);
539 count=dpc_send(file,length,metacontent);
540 if (count != (MagickOffsetType) length)
545 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
546 int file,const size_t session_key,ExceptionInfo *exception)
560 register const Quantum
563 register unsigned char
567 message[MaxTextExtent];
570 Read distributed pixel cache pixels.
572 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
573 if (image == (Image *) NULL)
575 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
576 sizeof(region.y)+sizeof(length);
577 count=dpc_read(file,length,message);
578 if (count != (MagickOffsetType) length)
581 (void) memcpy(®ion.width,q,sizeof(region.width));
582 q+=sizeof(region.width);
583 (void) memcpy(®ion.height,q,sizeof(region.height));
584 q+=sizeof(region.height);
585 (void) memcpy(®ion.x,q,sizeof(region.x));
587 (void) memcpy(®ion.y,q,sizeof(region.y));
589 (void) memcpy(&length,q,sizeof(length));
591 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
593 if (p == (const Quantum *) NULL)
595 count=dpc_send(file,length,(unsigned char *) p);
596 if (count != (MagickOffsetType) length)
601 static void *RelinquishImageRegistry(void *image)
603 return((void *) DestroyImageList((Image *) image));
606 static MagickBooleanType WriteDistributeCacheMetacontent(
607 SplayTreeInfo *registry,int file,const size_t session_key,
608 ExceptionInfo *exception)
625 register unsigned char
629 message[MaxTextExtent],
633 Write distributed pixel cache metacontent.
635 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
636 if (image == (Image *) NULL)
638 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
639 sizeof(region.y)+sizeof(length);
640 count=dpc_read(file,length,message);
641 if (count != (MagickOffsetType) length)
644 (void) memcpy(®ion.width,p,sizeof(region.width));
645 p+=sizeof(region.width);
646 (void) memcpy(®ion.height,p,sizeof(region.height));
647 p+=sizeof(region.height);
648 (void) memcpy(®ion.x,p,sizeof(region.x));
650 (void) memcpy(®ion.y,p,sizeof(region.y));
652 (void) memcpy(&length,p,sizeof(length));
654 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
656 if (q == (Quantum *) NULL)
658 metacontent=(unsigned char *) GetAuthenticMetacontent(image);
659 count=dpc_read(file,length,metacontent);
660 if (count != (MagickOffsetType) length)
662 return(SyncAuthenticPixels(image,exception));
665 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
666 int file,const size_t session_key,ExceptionInfo *exception)
683 register unsigned char
687 message[MaxTextExtent];
690 Write distributed pixel cache pixels.
692 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
693 if (image == (Image *) NULL)
695 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
696 sizeof(region.y)+sizeof(length);
697 count=dpc_read(file,length,message);
698 if (count != (MagickOffsetType) length)
701 (void) memcpy(®ion.width,p,sizeof(region.width));
702 p+=sizeof(region.width);
703 (void) memcpy(®ion.height,p,sizeof(region.height));
704 p+=sizeof(region.height);
705 (void) memcpy(®ion.x,p,sizeof(region.x));
707 (void) memcpy(®ion.y,p,sizeof(region.y));
709 (void) memcpy(&length,p,sizeof(length));
711 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
713 if (q == (Quantum *) NULL)
715 count=dpc_read(file,length,(unsigned char *) q);
716 if (count != (MagickOffsetType) length)
718 return(SyncAuthenticPixels(image,exception));
721 static void *DistributePixelCacheClient(void *socket)
738 register unsigned char
756 session[2*MaxTextExtent];
759 Distributed pixel cache client.
761 shared_secret=GetPolicyValue("shared-secret");
762 if (shared_secret == (const char *) NULL)
763 ThrowFatalException(CacheFatalError,"shared secret expected");
765 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
766 p+=strlen(shared_secret);
767 random_info=AcquireRandomInfo();
768 secret=GetRandomKey(random_info,DPCSessionKeyLength);
769 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
770 session_key=GetMagickSignature(secret);
771 random_info=DestroyRandomInfo(random_info);
772 exception=AcquireExceptionInfo();
773 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
774 (void *(*)(void *)) NULL,RelinquishImageRegistry);
775 client_socket=(*(int *) socket);
776 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
777 secret=DestroyStringInfo(secret);
780 count=dpc_read(client_socket,1,(unsigned char *) &command);
783 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
784 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
791 status=OpenDistributeCache(registry,client_socket,session_key,
793 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
798 status=ReadDistributeCachePixels(registry,client_socket,session_key,
804 status=ReadDistributeCacheMetacontent(registry,client_socket,
805 session_key,exception);
810 status=WriteDistributeCachePixels(registry,client_socket,session_key,
816 status=WriteDistributeCacheMetacontent(registry,client_socket,
817 session_key,exception);
822 status=DestroyDistributeCache(registry,client_socket,session_key);
828 if (status == MagickFalse)
833 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
834 (void) close(client_socket);
835 exception=DestroyExceptionInfo(exception);
836 registry=DestroySplayTree(registry);
837 return((void *) NULL);
840 MagickExport void DistributePixelCacheServer(const int port,
841 ExceptionInfo *exception)
843 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT) && !defined(__MINGW32__) && !defined(__MINGW64__)
845 service[MaxTextExtent];
857 register struct addrinfo
868 Launch distributed pixel cache server.
870 (void) ResetMagickMemory(&hint,0,sizeof(hint));
871 hint.ai_family=AF_INET;
872 hint.ai_socktype=SOCK_STREAM;
873 hint.ai_flags=AI_PASSIVE;
874 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
875 status=getaddrinfo((const char *) NULL,service,&hint,&result);
877 ThrowFatalException(CacheFatalError,"UnableToListen");
879 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
884 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
885 if (server_socket == -1)
888 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
892 status=bind(server_socket,p->ai_addr,p->ai_addrlen);
895 (void) close(status);
900 if (p == (struct addrinfo *) NULL)
901 ThrowFatalException(CacheFatalError,"UnableToBind");
902 freeaddrinfo(result);
903 status=listen(server_socket,DPCPendingConnections);
905 ThrowFatalException(CacheFatalError,"UnableToListen");
906 pthread_attr_init(&attributes);
915 length=(socklen_t) sizeof(address);
916 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
917 if (client_socket == -1)
918 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
919 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
920 (void *) &client_socket);
922 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
924 (void) close(server_socket);
926 ThrowFatalException(MissingDelegateError,"distributed pixel cache");
931 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935 + G e t D i s t r i b u t e C a c h e F i l e %
939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941 % GetDistributeCacheFile() returns the file associated with this
942 % DistributeCacheInfo structure.
944 % The format of the GetDistributeCacheFile method is:
946 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
948 % A description of each parameter follows:
950 % o server_info: the distributed cache info.
953 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
955 assert(server_info != (DistributeCacheInfo *) NULL);
956 assert(server_info->signature == MagickSignature);
957 return(server_info->file);
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
965 + 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 %
969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
971 % GetDistributeCacheHostname() returns the hostname associated with this
972 % DistributeCacheInfo structure.
974 % The format of the GetDistributeCacheHostname method is:
976 % const char *GetDistributeCacheHostname(
977 % const DistributeCacheInfo *server_info)
979 % A description of each parameter follows:
981 % o server_info: the distributed cache info.
984 MagickPrivate const char *GetDistributeCacheHostname(
985 const DistributeCacheInfo *server_info)
987 assert(server_info != (DistributeCacheInfo *) NULL);
988 assert(server_info->signature == MagickSignature);
989 return(server_info->hostname);
993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
997 + G e t D i s t r i b u t e C a c h e P o r t %
1001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1003 % GetDistributeCachePort() returns the port associated with this
1004 % DistributeCacheInfo structure.
1006 % The format of the GetDistributeCachePort method is:
1008 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1010 % A description of each parameter follows:
1012 % o server_info: the distributed cache info.
1015 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1017 assert(server_info != (DistributeCacheInfo *) NULL);
1018 assert(server_info->signature == MagickSignature);
1019 return(server_info->port);
1023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1027 + O p e n D i s t r i b u t e P i x e l C a c h e %
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1035 % The format of the OpenDistributePixelCache method is:
1037 % MagickBooleanType *OpenDistributePixelCache(
1038 % DistributeCacheInfo *server_info,Image *image)
1040 % A description of each parameter follows:
1042 % o server_info: the distributed cache info.
1044 % o image: the image.
1047 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1048 DistributeCacheInfo *server_info,Image *image)
1056 register unsigned char
1060 message[MaxTextExtent];
1063 Open distributed pixel cache.
1065 assert(server_info != (DistributeCacheInfo *) NULL);
1066 assert(server_info->signature == MagickSignature);
1067 assert(image != (Image *) NULL);
1068 assert(image->signature == MagickSignature);
1070 *p++='o'; /* open */
1072 Serialize image attributes (see ValidatePixelCacheMorphology()).
1074 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1075 p+=sizeof(server_info->session_key);
1076 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1077 p+=sizeof(image->storage_class);
1078 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1079 p+=sizeof(image->colorspace);
1080 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1081 p+=sizeof(image->alpha_trait);
1082 (void) memcpy(p,&image->mask,sizeof(image->mask));
1083 p+=sizeof(image->mask);
1084 (void) memcpy(p,&image->columns,sizeof(image->columns));
1085 p+=sizeof(image->columns);
1086 (void) memcpy(p,&image->rows,sizeof(image->rows));
1087 p+=sizeof(image->rows);
1088 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1089 p+=sizeof(image->number_channels);
1090 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1091 sizeof(*image->channel_map));
1092 p+=MaxPixelChannels*sizeof(*image->channel_map);
1093 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1094 p+=sizeof(image->metacontent_extent);
1095 count=dpc_send(server_info->file,p-message,message);
1096 if (count != (MagickOffsetType) (p-message))
1097 return(MagickFalse);
1099 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1100 if (count != (MagickOffsetType) sizeof(status))
1101 return(MagickFalse);
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1110 + 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 %
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1117 % region of the distributed pixel cache.
1119 % The format of the ReadDistributePixelCacheMetacontents method is:
1121 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1122 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1123 % const MagickSizeType length,unsigned char *metacontent)
1125 % A description of each parameter follows:
1127 % o server_info: the distributed cache info.
1129 % o image: the image.
1131 % o region: read the metacontent from this region of the image.
1133 % o length: the length in bytes of the metacontent.
1135 % o metacontent: read these metacontent from the pixel cache.
1138 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1139 DistributeCacheInfo *server_info,const RectangleInfo *region,
1140 const MagickSizeType length,unsigned char *metacontent)
1145 register unsigned char
1149 message[MaxTextExtent];
1152 Read distributed pixel cache metacontent.
1154 assert(server_info != (DistributeCacheInfo *) NULL);
1155 assert(server_info->signature == MagickSignature);
1156 assert(region != (RectangleInfo *) NULL);
1157 assert(metacontent != (unsigned char *) NULL);
1158 if (length > (MagickSizeType) SSIZE_MAX)
1162 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1163 p+=sizeof(server_info->session_key);
1164 (void) memcpy(p,®ion->width,sizeof(region->width));
1165 p+=sizeof(region->width);
1166 (void) memcpy(p,®ion->height,sizeof(region->height));
1167 p+=sizeof(region->height);
1168 (void) memcpy(p,®ion->x,sizeof(region->x));
1169 p+=sizeof(region->x);
1170 (void) memcpy(p,®ion->y,sizeof(region->y));
1171 p+=sizeof(region->y);
1172 (void) memcpy(p,&length,sizeof(length));
1174 count=dpc_send(server_info->file,p-message,message);
1175 if (count != (MagickOffsetType) (p-message))
1177 return(dpc_read(server_info->file,length,metacontent));
1181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1185 + 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 %
1189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1192 % the distributed pixel cache.
1194 % The format of the ReadDistributePixelCachePixels method is:
1196 % MagickOffsetType ReadDistributePixelCachePixels(
1197 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1198 % const MagickSizeType length,unsigned char *pixels)
1200 % A description of each parameter follows:
1202 % o server_info: the distributed cache info.
1204 % o image: the image.
1206 % o region: read the pixels from this region of the image.
1208 % o length: the length in bytes of the pixels.
1210 % o pixels: read these pixels from the pixel cache.
1213 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1214 DistributeCacheInfo *server_info,const RectangleInfo *region,
1215 const MagickSizeType length,unsigned char *pixels)
1220 register unsigned char
1224 message[MaxTextExtent];
1227 Read distributed pixel cache pixels.
1229 assert(server_info != (DistributeCacheInfo *) NULL);
1230 assert(server_info->signature == MagickSignature);
1231 assert(region != (RectangleInfo *) NULL);
1232 assert(pixels != (unsigned char *) NULL);
1233 if (length > (MagickSizeType) SSIZE_MAX)
1237 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1238 p+=sizeof(server_info->session_key);
1239 (void) memcpy(p,®ion->width,sizeof(region->width));
1240 p+=sizeof(region->width);
1241 (void) memcpy(p,®ion->height,sizeof(region->height));
1242 p+=sizeof(region->height);
1243 (void) memcpy(p,®ion->x,sizeof(region->x));
1244 p+=sizeof(region->x);
1245 (void) memcpy(p,®ion->y,sizeof(region->y));
1246 p+=sizeof(region->y);
1247 (void) memcpy(p,&length,sizeof(length));
1249 count=dpc_send(server_info->file,p-message,message);
1250 if (count != (MagickOffsetType) (p-message))
1252 return(dpc_read(server_info->file,length,pixels));
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1260 + 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 %
1264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1266 % RelinquishDistributePixelCache() frees resources acquired with
1267 % OpenDistributePixelCache().
1269 % The format of the RelinquishDistributePixelCache method is:
1271 % MagickBooleanType RelinquishDistributePixelCache(
1272 % DistributeCacheInfo *server_info)
1274 % A description of each parameter follows:
1276 % o server_info: the distributed cache info.
1279 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1280 DistributeCacheInfo *server_info)
1288 register unsigned char
1292 message[MaxTextExtent];
1295 Delete distributed pixel cache.
1297 assert(server_info != (DistributeCacheInfo *) NULL);
1298 assert(server_info->signature == MagickSignature);
1301 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1302 p+=sizeof(server_info->session_key);
1303 count=dpc_send(server_info->file,p-message,message);
1304 if (count != (MagickOffsetType) (p-message))
1305 return(MagickFalse);
1306 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1307 if (count != (MagickOffsetType) sizeof(status))
1308 return(MagickFalse);
1313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317 + 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 %
1321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1324 % specified region of the distributed pixel cache.
1326 % The format of the WriteDistributePixelCacheMetacontents method is:
1328 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1329 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1330 % const MagickSizeType length,const unsigned char *metacontent)
1332 % A description of each parameter follows:
1334 % o server_info: the distributed cache info.
1336 % o image: the image.
1338 % o region: write the metacontent to this region of the image.
1340 % o length: the length in bytes of the metacontent.
1342 % o metacontent: write these metacontent to the pixel cache.
1345 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1346 DistributeCacheInfo *server_info,const RectangleInfo *region,
1347 const MagickSizeType length,const unsigned char *metacontent)
1352 register unsigned char
1356 message[MaxTextExtent];
1359 Write distributed pixel cache metacontent.
1361 assert(server_info != (DistributeCacheInfo *) NULL);
1362 assert(server_info->signature == MagickSignature);
1363 assert(region != (RectangleInfo *) NULL);
1364 assert(metacontent != (unsigned char *) NULL);
1365 if (length > (MagickSizeType) SSIZE_MAX)
1369 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1370 p+=sizeof(server_info->session_key);
1371 (void) memcpy(p,®ion->width,sizeof(region->width));
1372 p+=sizeof(region->width);
1373 (void) memcpy(p,®ion->height,sizeof(region->height));
1374 p+=sizeof(region->height);
1375 (void) memcpy(p,®ion->x,sizeof(region->x));
1376 p+=sizeof(region->x);
1377 (void) memcpy(p,®ion->y,sizeof(region->y));
1378 p+=sizeof(region->y);
1379 (void) memcpy(p,&length,sizeof(length));
1381 count=dpc_send(server_info->file,p-message,message);
1382 if (count != (MagickOffsetType) (p-message))
1384 return(dpc_send(server_info->file,length,metacontent));
1388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 + 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 %
1396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398 % WriteDistributePixelCachePixels() writes image pixels to the specified
1399 % region of the distributed pixel cache.
1401 % The format of the WriteDistributePixelCachePixels method is:
1403 % MagickBooleanType WriteDistributePixelCachePixels(
1404 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1405 % const MagickSizeType length,const unsigned char *pixels)
1407 % A description of each parameter follows:
1409 % o server_info: the distributed cache info.
1411 % o image: the image.
1413 % o region: write the pixels to this region of the image.
1415 % o length: the length in bytes of the pixels.
1417 % o pixels: write these pixels to the pixel cache.
1420 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1421 DistributeCacheInfo *server_info,const RectangleInfo *region,
1422 const MagickSizeType length,const unsigned char *pixels)
1427 register unsigned char
1431 message[MaxTextExtent];
1434 Write distributed pixel cache pixels.
1436 assert(server_info != (DistributeCacheInfo *) NULL);
1437 assert(server_info->signature == MagickSignature);
1438 assert(region != (RectangleInfo *) NULL);
1439 assert(pixels != (const unsigned char *) NULL);
1440 if (length > (MagickSizeType) SSIZE_MAX)
1444 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1445 p+=sizeof(server_info->session_key);
1446 (void) memcpy(p,®ion->width,sizeof(region->width));
1447 p+=sizeof(region->width);
1448 (void) memcpy(p,®ion->height,sizeof(region->height));
1449 p+=sizeof(region->height);
1450 (void) memcpy(p,®ion->x,sizeof(region->x));
1451 p+=sizeof(region->x);
1452 (void) memcpy(p,®ion->y,sizeof(region->y));
1453 p+=sizeof(region->y);
1454 (void) memcpy(p,&length,sizeof(length));
1456 count=dpc_send(server_info->file,p-message,message);
1457 if (count != (MagickOffsetType) (p-message))
1459 return(dpc_send(server_info->file,length,pixels));