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/pixel.h"
67 #include "MagickCore/policy.h"
68 #include "MagickCore/random_.h"
69 #include "MagickCore/registry.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/version.h"
74 #if defined(MAGICKCORE_HAVE_SOCKET)
75 #include <netinet/in.h>
77 #include <sys/socket.h>
78 #include <arpa/inet.h>
84 #define DPCHostname "127.0.0.1"
85 #define DPCPendingConnections 10
87 #define DPCSessionKeyLength 8
89 # define MSG_NOSIGNAL 0
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 + 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 %
101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 % AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
105 % The format of the AcquireDistributeCacheInfo method is:
107 % DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
109 % A description of each parameter follows:
111 % o exception: return any errors or warnings in this structure.
115 static size_t CRC64(const unsigned char *message,const MagickSizeType length)
117 register MagickOffsetType
123 static MagickBooleanType
124 crc_initial = MagickFalse;
130 Generate a 64-bit cyclic redundancy check for the message.
132 if (crc_initial == MagickFalse)
137 for (i=0; i < 256; i++)
139 register MagickOffsetType
143 for (j=0; j < 8; j++)
145 if ((alpha & 0x01) == 0)
148 alpha=(size_t) ((alpha >> 1) ^
149 MagickULLConstant(0xd800000000000000));
153 crc_initial=MagickTrue;
156 for (i=0; i < (MagickOffsetType) length; i++)
157 crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
161 static inline MagickSizeType MagickMin(const MagickSizeType x,
162 const MagickSizeType y)
169 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
170 unsigned char *restrict message)
172 register MagickOffsetType
179 for (i=0; i < (MagickOffsetType) length; i+=count)
181 count=recv(file,message+i,(size_t) MagickMin(length-i,(MagickSizeType)
193 static int ConnectPixelCacheServer(const char *hostname,const int port,
194 size_t *session_key,ExceptionInfo *exception)
196 #if defined(MAGICKCORE_HAVE_SOCKET)
198 service[MaxTextExtent];
207 register unsigned char
218 secret[MaxTextExtent],
219 session[2*MaxTextExtent];
222 Connect to distributed pixel cache and get session key.
225 shared_secret=GetPolicyValue("shared-secret");
226 if (shared_secret == (const char *) NULL)
228 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
229 "DistributedPixelCache","'%s'","shared secret expected");
233 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
234 p+=strlen(shared_secret);
235 (void) ResetMagickMemory(&hint,0,sizeof(hint));
236 hint.ai_family=AF_INET;
237 hint.ai_socktype=SOCK_STREAM;
238 hint.ai_flags=AI_PASSIVE;
239 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
240 status=getaddrinfo(hostname,service,&hint,&result);
243 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
244 "DistributedPixelCache","'%s'",hostname);
247 client_socket=socket(result->ai_family,result->ai_socktype,
248 result->ai_protocol);
249 if (client_socket == -1)
251 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
252 "DistributedPixelCache","'%s'",hostname);
255 status=connect(client_socket,result->ai_addr,result->ai_addrlen);
258 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
259 "DistributedPixelCache","'%s'",hostname);
262 count=recv(client_socket,secret,MaxTextExtent,0);
268 (void) memcpy(p,secret,(size_t) count);
270 signature=MagickLibVersion;
271 (void) memcpy(p,&signature,sizeof(signature));
272 p+=sizeof(signature);
273 signature=MAGICKCORE_QUANTUM_DEPTH;
274 (void) memcpy(p,&signature,sizeof(signature));
275 p+=sizeof(signature);
276 signature=MAGICKCORE_HDRI_ENABLE;
277 (void) memcpy(p,&signature,sizeof(signature));
278 p+=sizeof(signature);
279 *session_key=CRC64(session,p-session);
281 if (*session_key == 0)
283 close(client_socket);
286 return(client_socket);
288 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
289 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
294 static char *GetHostname(int *port,ExceptionInfo *exception)
311 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
313 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
315 if (hosts == (char *) NULL)
318 return(AcquireString(DPCHostname));
320 (void) SubstituteString(&hosts,","," ");
321 hostlist=StringToArgv(hosts,&argc);
322 hosts=DestroyString(hosts);
323 if (hostlist == (char **) NULL)
326 return(AcquireString(DPCHostname));
328 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
329 for (i=0; i < (ssize_t) argc; i++)
330 hostlist[i]=DestroyString(hostlist[i]);
331 hostlist=(char **) RelinquishMagickMemory(hostlist);
332 (void) SubstituteString(&hosts,":"," ");
333 hostlist=StringToArgv(hosts,&argc);
334 if (hostlist == (char **) NULL)
337 return(AcquireString(DPCHostname));
339 host=AcquireString(hostlist[1]);
340 if (hostlist[2] == (char *) NULL)
343 *port=StringToLong(hostlist[2]);
344 for (i=0; i < (ssize_t) argc; i++)
345 hostlist[i]=DestroyString(hostlist[i]);
346 hostlist=(char **) RelinquishMagickMemory(hostlist);
350 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
351 ExceptionInfo *exception)
363 Connect to the distributed pixel cache server.
365 server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info));
366 if (server_info == (DistributeCacheInfo *) NULL)
367 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
368 (void) ResetMagickMemory(server_info,0,sizeof(*server_info));
369 server_info->signature=MagickSignature;
371 hostname=GetHostname(&server_info->port,exception);
373 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
374 &session_key,exception);
375 server_info->session_key=session_key;
376 (void) CopyMagickString(server_info->hostname,hostname,MaxTextExtent);
377 hostname=DestroyString(hostname);
378 if (server_info->file == -1)
379 server_info=DestroyDistributeCacheInfo(server_info);
384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388 + 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 %
392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394 % DestroyDistributeCacheInfo() deallocates memory associated with an
395 % DistributeCacheInfo structure.
397 % The format of the DestroyDistributeCacheInfo method is:
399 % DistributeCacheInfo *DestroyDistributeCacheInfo(
400 % DistributeCacheInfo *server_info)
402 % A description of each parameter follows:
404 % o server_info: the distributed cache info.
407 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
408 DistributeCacheInfo *server_info)
410 assert(server_info != (DistributeCacheInfo *) NULL);
411 assert(server_info->signature == MagickSignature);
412 if (server_info->file > 0)
413 (void) close(server_info->file);
414 server_info->signature=(~MagickSignature);
415 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424 + 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 %
428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 % DistributePixelCacheServer() waits on the specified port for commands to
431 % create, read, update, or destroy a pixel cache.
433 % The format of the DistributePixelCacheServer() method is:
435 % void DistributePixelCacheServer(const int port)
437 % A description of each parameter follows:
439 % o port: connect the distributed pixel cache at this port.
441 % o exception: return any errors or warnings in this structure.
445 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
446 int file,const size_t session_key)
449 Destroy distributed pixel cache.
451 return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
454 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
455 const unsigned char *restrict message)
460 register MagickOffsetType
464 Ensure a complete message is sent.
467 for (i=0; i < (MagickOffsetType) length; i+=count)
469 count=(MagickOffsetType) send(file,message+i,(size_t) MagickMin(length-i,
470 (MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
481 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
482 int file,const size_t session_key,ExceptionInfo *exception)
496 register unsigned char
500 message[MaxTextExtent];
503 Open distributed pixel cache.
505 image=AcquireImage((ImageInfo *) NULL,exception);
506 if (image == (Image *) NULL)
508 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
509 sizeof(image->alpha_trait)+sizeof(image->mask)+sizeof(image->columns)+
510 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
511 sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
512 count=dpc_read(file,length,message);
513 if (count != (MagickOffsetType) length)
516 Deserialize the image attributes.
519 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
520 p+=sizeof(image->storage_class);
521 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
522 p+=sizeof(image->colorspace);
523 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
524 p+=sizeof(image->alpha_trait);
525 (void) memcpy(&image->mask,p,sizeof(image->mask));
526 p+=sizeof(image->mask);
527 (void) memcpy(&image->columns,p,sizeof(image->columns));
528 p+=sizeof(image->columns);
529 (void) memcpy(&image->rows,p,sizeof(image->rows));
530 p+=sizeof(image->rows);
531 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
532 p+=sizeof(image->number_channels);
533 (void) memcpy(image->channel_map,p,MaxPixelChannels*
534 sizeof(*image->channel_map));
535 p+=MaxPixelChannels*sizeof(*image->channel_map);
536 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
537 p+=sizeof(image->metacontent_extent);
538 if (SyncImagePixelCache(image,exception) == MagickFalse)
540 status=AddValueToSplayTree(registry,(const void *) session_key,image);
544 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
545 int file,const size_t session_key,ExceptionInfo *exception)
562 register const Quantum
565 register unsigned char
569 message[MaxTextExtent];
572 Read distributed pixel cache metacontent.
574 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
575 if (image == (Image *) NULL)
577 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
578 sizeof(region.y)+sizeof(length);
579 count=dpc_read(file,length,message);
580 if (count != (MagickOffsetType) length)
583 (void) memcpy(®ion.width,q,sizeof(region.width));
584 q+=sizeof(region.width);
585 (void) memcpy(®ion.height,q,sizeof(region.height));
586 q+=sizeof(region.height);
587 (void) memcpy(®ion.x,q,sizeof(region.x));
589 (void) memcpy(®ion.y,q,sizeof(region.y));
591 (void) memcpy(&length,q,sizeof(length));
593 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
595 if (p == (const Quantum *) NULL)
597 metacontent=GetVirtualMetacontent(image);
598 count=dpc_send(file,length,metacontent);
599 if (count != (MagickOffsetType) length)
604 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
605 int file,const size_t session_key,ExceptionInfo *exception)
619 register const Quantum
622 register unsigned char
626 message[MaxTextExtent];
629 Read distributed pixel cache pixels.
631 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
632 if (image == (Image *) NULL)
634 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
635 sizeof(region.y)+sizeof(length);
636 count=dpc_read(file,length,message);
637 if (count != (MagickOffsetType) length)
640 (void) memcpy(®ion.width,q,sizeof(region.width));
641 q+=sizeof(region.width);
642 (void) memcpy(®ion.height,q,sizeof(region.height));
643 q+=sizeof(region.height);
644 (void) memcpy(®ion.x,q,sizeof(region.x));
646 (void) memcpy(®ion.y,q,sizeof(region.y));
648 (void) memcpy(&length,q,sizeof(length));
650 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
652 if (p == (const Quantum *) NULL)
654 count=dpc_send(file,length,(unsigned char *) p);
655 if (count != (MagickOffsetType) length)
660 static void *RelinquishImageRegistry(void *image)
662 return((void *) DestroyImageList((Image *) image));
665 static MagickBooleanType WriteDistributeCacheMetacontent(
666 SplayTreeInfo *registry,int file,const size_t session_key,
667 ExceptionInfo *exception)
684 register unsigned char
688 message[MaxTextExtent],
692 Write distributed pixel cache metacontent.
694 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
695 if (image == (Image *) NULL)
697 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
698 sizeof(region.y)+sizeof(length);
699 count=dpc_read(file,length,message);
700 if (count != (MagickOffsetType) length)
703 (void) memcpy(®ion.width,p,sizeof(region.width));
704 p+=sizeof(region.width);
705 (void) memcpy(®ion.height,p,sizeof(region.height));
706 p+=sizeof(region.height);
707 (void) memcpy(®ion.x,p,sizeof(region.x));
709 (void) memcpy(®ion.y,p,sizeof(region.y));
711 (void) memcpy(&length,p,sizeof(length));
713 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
715 if (q == (Quantum *) NULL)
717 metacontent=GetAuthenticMetacontent(image);
718 count=dpc_read(file,length,metacontent);
719 if (count != (MagickOffsetType) length)
721 return(SyncAuthenticPixels(image,exception));
724 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
725 int file,const size_t session_key,ExceptionInfo *exception)
742 register unsigned char
746 message[MaxTextExtent];
749 Write distributed pixel cache pixels.
751 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
752 if (image == (Image *) NULL)
754 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
755 sizeof(region.y)+sizeof(length);
756 count=dpc_read(file,length,message);
757 if (count != (MagickOffsetType) length)
760 (void) memcpy(®ion.width,p,sizeof(region.width));
761 p+=sizeof(region.width);
762 (void) memcpy(®ion.height,p,sizeof(region.height));
763 p+=sizeof(region.height);
764 (void) memcpy(®ion.x,p,sizeof(region.x));
766 (void) memcpy(®ion.y,p,sizeof(region.y));
768 (void) memcpy(&length,p,sizeof(length));
770 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
772 if (q == (Quantum *) NULL)
774 count=dpc_read(file,length,(unsigned char *) q);
775 if (count != (MagickOffsetType) length)
777 return(SyncAuthenticPixels(image,exception));
780 static void *DistributePixelCacheClient(void *socket)
797 register unsigned char
816 session[2*MaxTextExtent];
819 Distributed pixel cache client.
821 shared_secret=GetPolicyValue("shared-secret");
822 if (shared_secret == (const char *) NULL)
823 ThrowFatalException(CacheFatalError,"shared secret expected");
825 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
826 p+=strlen(shared_secret);
827 random_info=AcquireRandomInfo();
828 secret=GetRandomKey(random_info,DPCSessionKeyLength);
829 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
830 p+=DPCSessionKeyLength;
831 signature=MagickLibVersion;
832 (void) memcpy(p,&signature,sizeof(signature));
833 p+=sizeof(signature);
834 signature=MAGICKCORE_QUANTUM_DEPTH;
835 (void) memcpy(p,&signature,sizeof(signature));
836 p+=sizeof(signature);
837 signature=MAGICKCORE_HDRI_ENABLE;
838 (void) memcpy(p,&signature,sizeof(signature));
839 p+=sizeof(signature);
840 session_key=CRC64(session,p-session);
841 random_info=DestroyRandomInfo(random_info);
842 exception=AcquireExceptionInfo();
843 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
844 (void *(*)(void *)) NULL,RelinquishImageRegistry);
845 client_socket=(*(int *) socket);
846 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
847 secret=DestroyStringInfo(secret);
850 count=dpc_read(client_socket,1,(unsigned char *) &command);
853 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
854 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
861 status=OpenDistributeCache(registry,client_socket,session_key,
863 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
868 status=ReadDistributeCachePixels(registry,client_socket,session_key,
874 status=ReadDistributeCacheMetacontent(registry,client_socket,
875 session_key,exception);
880 status=WriteDistributeCachePixels(registry,client_socket,session_key,
886 status=WriteDistributeCacheMetacontent(registry,client_socket,
887 session_key,exception);
892 status=DestroyDistributeCache(registry,client_socket,session_key);
898 if (status == MagickFalse)
903 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
904 (void) close(client_socket);
905 exception=DestroyExceptionInfo(exception);
906 registry=DestroySplayTree(registry);
907 return((void *) NULL);
910 MagickExport void DistributePixelCacheServer(const int port,
911 ExceptionInfo *exception)
913 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
915 service[MaxTextExtent];
927 register struct addrinfo
938 Launch distributed pixel cache server.
940 (void) ResetMagickMemory(&hint,0,sizeof(hint));
941 hint.ai_family=AF_INET;
942 hint.ai_socktype=SOCK_STREAM;
943 hint.ai_flags=AI_PASSIVE;
944 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
945 status=getaddrinfo((const char *) NULL,service,&hint,&result);
947 ThrowFatalException(CacheFatalError,"UnableToListen");
948 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
953 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
954 if (server_socket == -1)
957 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
961 status=bind(server_socket,p->ai_addr,p->ai_addrlen);
964 (void) close(status);
969 if (p == (struct addrinfo *) NULL)
970 ThrowFatalException(CacheFatalError,"UnableToBind");
971 freeaddrinfo(result);
972 status=listen(server_socket,DPCPendingConnections);
974 ThrowFatalException(CacheFatalError,"UnableToListen");
975 pthread_attr_init(&attributes);
984 length=(socklen_t) sizeof(address);
985 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
986 if (client_socket == -1)
987 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
988 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
989 (void *) &client_socket);
991 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
993 (void) close(server_socket);
995 ThrowFatalException(MissingDelegateError,"distributed pixel cache");
1000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1004 + G e t D i s t r i b u t e C a c h e F i l e %
1008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1010 % GetDistributeCacheFile() returns the file associated with this
1011 % DistributeCacheInfo structure.
1013 % The format of the GetDistributeCacheFile method is:
1015 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1017 % A description of each parameter follows:
1019 % o server_info: the distributed cache info.
1022 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1024 assert(server_info != (DistributeCacheInfo *) NULL);
1025 assert(server_info->signature == MagickSignature);
1026 return(server_info->file);
1030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1034 + 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 %
1038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1040 % GetDistributeCacheHostname() returns the hostname associated with this
1041 % DistributeCacheInfo structure.
1043 % The format of the GetDistributeCacheHostname method is:
1045 % const char *GetDistributeCacheHostname(
1046 % const DistributeCacheInfo *server_info)
1048 % A description of each parameter follows:
1050 % o server_info: the distributed cache info.
1053 MagickPrivate const char *GetDistributeCacheHostname(
1054 const DistributeCacheInfo *server_info)
1056 assert(server_info != (DistributeCacheInfo *) NULL);
1057 assert(server_info->signature == MagickSignature);
1058 return(server_info->hostname);
1062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1066 + G e t D i s t r i b u t e C a c h e P o r t %
1070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 % GetDistributeCachePort() returns the port associated with this
1073 % DistributeCacheInfo structure.
1075 % The format of the GetDistributeCachePort method is:
1077 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1079 % A description of each parameter follows:
1081 % o server_info: the distributed cache info.
1084 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1086 assert(server_info != (DistributeCacheInfo *) NULL);
1087 assert(server_info->signature == MagickSignature);
1088 return(server_info->port);
1092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096 + O p e n D i s t r i b u t e P i x e l C a c h e %
1100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1104 % The format of the OpenDistributePixelCache method is:
1106 % MagickBooleanType *OpenDistributePixelCache(
1107 % DistributeCacheInfo *server_info,Image *image)
1109 % A description of each parameter follows:
1111 % o server_info: the distributed cache info.
1113 % o image: the image.
1116 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1117 DistributeCacheInfo *server_info,Image *image)
1125 register unsigned char
1129 message[MaxTextExtent];
1132 Open distributed pixel cache.
1134 assert(server_info != (DistributeCacheInfo *) NULL);
1135 assert(server_info->signature == MagickSignature);
1136 assert(image != (Image *) NULL);
1137 assert(image->signature == MagickSignature);
1139 *p++='o'; /* open */
1141 Serialize image attributes (see ValidatePixelCacheMorphology()).
1143 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1144 p+=sizeof(server_info->session_key);
1145 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1146 p+=sizeof(image->storage_class);
1147 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1148 p+=sizeof(image->colorspace);
1149 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1150 p+=sizeof(image->alpha_trait);
1151 (void) memcpy(p,&image->mask,sizeof(image->mask));
1152 p+=sizeof(image->mask);
1153 (void) memcpy(p,&image->columns,sizeof(image->columns));
1154 p+=sizeof(image->columns);
1155 (void) memcpy(p,&image->rows,sizeof(image->rows));
1156 p+=sizeof(image->rows);
1157 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1158 p+=sizeof(image->number_channels);
1159 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1160 sizeof(*image->channel_map));
1161 p+=MaxPixelChannels*sizeof(*image->channel_map);
1162 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1163 p+=sizeof(image->metacontent_extent);
1164 count=dpc_send(server_info->file,p-message,message);
1165 if (count != (MagickOffsetType) (p-message))
1166 return(MagickFalse);
1168 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1169 if (count != (MagickOffsetType) sizeof(status))
1170 return(MagickFalse);
1175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179 + 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 %
1183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1185 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1186 % region of the distributed pixel cache.
1188 % The format of the ReadDistributePixelCacheMetacontents method is:
1190 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1191 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1192 % const MagickSizeType length,unsigned char *metacontent)
1194 % A description of each parameter follows:
1196 % o server_info: the distributed cache info.
1198 % o image: the image.
1200 % o region: read the metacontent from this region of the image.
1202 % o length: the length in bytes of the metacontent.
1204 % o metacontent: read these metacontent from the pixel cache.
1207 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1208 DistributeCacheInfo *server_info,const RectangleInfo *region,
1209 const MagickSizeType length,unsigned char *metacontent)
1214 register unsigned char
1218 message[MaxTextExtent];
1221 Read distributed pixel cache metacontent.
1223 assert(server_info != (DistributeCacheInfo *) NULL);
1224 assert(server_info->signature == MagickSignature);
1225 assert(region != (RectangleInfo *) NULL);
1226 assert(metacontent != (unsigned char *) NULL);
1227 if (length > (MagickSizeType) SSIZE_MAX)
1231 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1232 p+=sizeof(server_info->session_key);
1233 (void) memcpy(p,®ion->width,sizeof(region->width));
1234 p+=sizeof(region->width);
1235 (void) memcpy(p,®ion->height,sizeof(region->height));
1236 p+=sizeof(region->height);
1237 (void) memcpy(p,®ion->x,sizeof(region->x));
1238 p+=sizeof(region->x);
1239 (void) memcpy(p,®ion->y,sizeof(region->y));
1240 p+=sizeof(region->y);
1241 (void) memcpy(p,&length,sizeof(length));
1243 count=dpc_send(server_info->file,p-message,message);
1244 if (count != (MagickOffsetType) (p-message))
1246 return(dpc_read(server_info->file,length,metacontent));
1250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1254 + 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 %
1258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1260 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1261 % the distributed pixel cache.
1263 % The format of the ReadDistributePixelCachePixels method is:
1265 % MagickOffsetType ReadDistributePixelCachePixels(
1266 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1267 % const MagickSizeType length,unsigned char *pixels)
1269 % A description of each parameter follows:
1271 % o server_info: the distributed cache info.
1273 % o image: the image.
1275 % o region: read the pixels from this region of the image.
1277 % o length: the length in bytes of the pixels.
1279 % o pixels: read these pixels from the pixel cache.
1282 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1283 DistributeCacheInfo *server_info,const RectangleInfo *region,
1284 const MagickSizeType length,unsigned char *pixels)
1289 register unsigned char
1293 message[MaxTextExtent];
1296 Read distributed pixel cache pixels.
1298 assert(server_info != (DistributeCacheInfo *) NULL);
1299 assert(server_info->signature == MagickSignature);
1300 assert(region != (RectangleInfo *) NULL);
1301 assert(pixels != (unsigned char *) NULL);
1302 if (length > (MagickSizeType) SSIZE_MAX)
1306 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1307 p+=sizeof(server_info->session_key);
1308 (void) memcpy(p,®ion->width,sizeof(region->width));
1309 p+=sizeof(region->width);
1310 (void) memcpy(p,®ion->height,sizeof(region->height));
1311 p+=sizeof(region->height);
1312 (void) memcpy(p,®ion->x,sizeof(region->x));
1313 p+=sizeof(region->x);
1314 (void) memcpy(p,®ion->y,sizeof(region->y));
1315 p+=sizeof(region->y);
1316 (void) memcpy(p,&length,sizeof(length));
1318 count=dpc_send(server_info->file,p-message,message);
1319 if (count != (MagickOffsetType) (p-message))
1321 return(dpc_read(server_info->file,length,pixels));
1325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1329 + 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 %
1333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1335 % RelinquishDistributePixelCache() frees resources acquired with
1336 % OpenDistributePixelCache().
1338 % The format of the RelinquishDistributePixelCache method is:
1340 % MagickBooleanType RelinquishDistributePixelCache(
1341 % DistributeCacheInfo *server_info)
1343 % A description of each parameter follows:
1345 % o server_info: the distributed cache info.
1348 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1349 DistributeCacheInfo *server_info)
1357 register unsigned char
1361 message[MaxTextExtent];
1364 Delete distributed pixel cache.
1366 assert(server_info != (DistributeCacheInfo *) NULL);
1367 assert(server_info->signature == MagickSignature);
1370 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1371 p+=sizeof(server_info->session_key);
1372 count=dpc_send(server_info->file,p-message,message);
1373 if (count != (MagickOffsetType) (p-message))
1374 return(MagickFalse);
1375 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1376 if (count != (MagickOffsetType) sizeof(status))
1377 return(MagickFalse);
1382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 + 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 %
1390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1393 % specified region of the distributed pixel cache.
1395 % The format of the WriteDistributePixelCacheMetacontents method is:
1397 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1398 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1399 % const MagickSizeType length,const unsigned char *metacontent)
1401 % A description of each parameter follows:
1403 % o server_info: the distributed cache info.
1405 % o image: the image.
1407 % o region: write the metacontent to this region of the image.
1409 % o length: the length in bytes of the metacontent.
1411 % o metacontent: write these metacontent to the pixel cache.
1414 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1415 DistributeCacheInfo *server_info,const RectangleInfo *region,
1416 const MagickSizeType length,const unsigned char *metacontent)
1421 register unsigned char
1425 message[MaxTextExtent];
1428 Write distributed pixel cache metacontent.
1430 assert(server_info != (DistributeCacheInfo *) NULL);
1431 assert(server_info->signature == MagickSignature);
1432 assert(region != (RectangleInfo *) NULL);
1433 assert(metacontent != (unsigned char *) NULL);
1434 if (length > (MagickSizeType) SSIZE_MAX)
1438 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1439 p+=sizeof(server_info->session_key);
1440 (void) memcpy(p,®ion->width,sizeof(region->width));
1441 p+=sizeof(region->width);
1442 (void) memcpy(p,®ion->height,sizeof(region->height));
1443 p+=sizeof(region->height);
1444 (void) memcpy(p,®ion->x,sizeof(region->x));
1445 p+=sizeof(region->x);
1446 (void) memcpy(p,®ion->y,sizeof(region->y));
1447 p+=sizeof(region->y);
1448 (void) memcpy(p,&length,sizeof(length));
1450 count=dpc_send(server_info->file,p-message,message);
1451 if (count != (MagickOffsetType) (p-message))
1453 return(dpc_send(server_info->file,length,metacontent));
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461 + 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 %
1465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467 % WriteDistributePixelCachePixels() writes image pixels to the specified
1468 % region of the distributed pixel cache.
1470 % The format of the WriteDistributePixelCachePixels method is:
1472 % MagickBooleanType WriteDistributePixelCachePixels(
1473 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1474 % const MagickSizeType length,const unsigned char *pixels)
1476 % A description of each parameter follows:
1478 % o server_info: the distributed cache info.
1480 % o image: the image.
1482 % o region: write the pixels to this region of the image.
1484 % o length: the length in bytes of the pixels.
1486 % o pixels: write these pixels to the pixel cache.
1489 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1490 DistributeCacheInfo *server_info,const RectangleInfo *region,
1491 const MagickSizeType length,const unsigned char *pixels)
1496 register unsigned char
1500 message[MaxTextExtent];
1503 Write distributed pixel cache pixels.
1505 assert(server_info != (DistributeCacheInfo *) NULL);
1506 assert(server_info->signature == MagickSignature);
1507 assert(region != (RectangleInfo *) NULL);
1508 assert(pixels != (const unsigned char *) NULL);
1509 if (length > (MagickSizeType) SSIZE_MAX)
1513 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1514 p+=sizeof(server_info->session_key);
1515 (void) memcpy(p,®ion->width,sizeof(region->width));
1516 p+=sizeof(region->width);
1517 (void) memcpy(p,®ion->height,sizeof(region->height));
1518 p+=sizeof(region->height);
1519 (void) memcpy(p,®ion->x,sizeof(region->x));
1520 p+=sizeof(region->x);
1521 (void) memcpy(p,®ion->y,sizeof(region->y));
1522 p+=sizeof(region->y);
1523 (void) memcpy(p,&length,sizeof(length));
1525 count=dpc_send(server_info->file,p-message,message);
1526 if (count != (MagickOffsetType) (p-message))
1528 return(dpc_send(server_info->file,length,pixels));