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 MagickSizeType CRC64(const unsigned char *message,
116 const MagickSizeType length)
121 register MagickOffsetType
124 static MagickBooleanType
125 crc_initial = MagickFalse;
127 static MagickSizeType
131 Generate a 64-bit cyclic redundancy check for the message.
133 if (crc_initial == MagickFalse)
138 for (i=0; i < 256; i++)
140 register MagickOffsetType
143 alpha=(MagickSizeType) i;
144 for (j=0; j < 8; j++)
146 if ((alpha & 0x01) == 0)
149 alpha=(MagickSizeType) ((alpha >> 1) ^
150 MagickULLConstant(0xd800000000000000));
154 crc_initial=MagickTrue;
157 for (i=0; i < (MagickOffsetType) length; i++)
158 crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
162 static inline MagickSizeType MagickMin(const MagickSizeType x,
163 const MagickSizeType y)
170 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
171 unsigned char *restrict message)
173 register MagickOffsetType
180 for (i=0; i < (MagickOffsetType) length; i+=count)
182 count=recv(file,message+i,(size_t) MagickMin(length-i,(MagickSizeType)
194 static int ConnectPixelCacheServer(const char *hostname,const int port,
195 MagickSizeType *session_key,ExceptionInfo *exception)
197 #if defined(MAGICKCORE_HAVE_SOCKET)
199 service[MaxTextExtent];
211 register unsigned char
219 secret[MaxTextExtent],
220 session[2*MaxTextExtent];
223 Connect to distributed pixel cache and get session key.
226 shared_secret=GetPolicyValue("shared-secret");
227 if (shared_secret == (const char *) NULL)
229 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
230 "DistributedPixelCache","'%s'","shared secret expected");
234 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
235 p+=strlen(shared_secret);
236 (void) ResetMagickMemory(&hint,0,sizeof(hint));
237 hint.ai_family=AF_INET;
238 hint.ai_socktype=SOCK_STREAM;
239 hint.ai_flags=AI_PASSIVE;
240 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
241 status=getaddrinfo(hostname,service,&hint,&result);
244 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
245 "DistributedPixelCache","'%s'",hostname);
248 client_socket=socket(result->ai_family,result->ai_socktype,
249 result->ai_protocol);
250 if (client_socket == -1)
252 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
253 "DistributedPixelCache","'%s'",hostname);
256 status=connect(client_socket,result->ai_addr,result->ai_addrlen);
259 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
260 "DistributedPixelCache","'%s'",hostname);
263 count=recv(client_socket,secret,MaxTextExtent,0);
269 (void) memcpy(p,secret,(size_t) count);
271 signature=MagickLibVersion;
272 (void) memcpy(p,&signature,sizeof(signature));
273 p+=sizeof(signature);
274 signature=MAGICKCORE_QUANTUM_DEPTH;
275 (void) memcpy(p,&signature,sizeof(signature));
276 p+=sizeof(signature);
277 signature=MAGICKCORE_HDRI_ENABLE;
278 (void) memcpy(p,&signature,sizeof(signature));
279 p+=sizeof(signature);
280 *session_key=CRC64(session,p-session);
282 if (*session_key == 0)
284 close(client_socket);
287 return(client_socket);
289 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
290 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
295 static char *GetHostname(int *port,ExceptionInfo *exception)
312 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
314 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
316 if (hosts == (char *) NULL)
319 return(AcquireString(DPCHostname));
321 (void) SubstituteString(&hosts,","," ");
322 hostlist=StringToArgv(hosts,&argc);
323 hosts=DestroyString(hosts);
324 if (hostlist == (char **) NULL)
327 return(AcquireString(DPCHostname));
329 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
330 for (i=0; i < (ssize_t) argc; i++)
331 hostlist[i]=DestroyString(hostlist[i]);
332 hostlist=(char **) RelinquishMagickMemory(hostlist);
333 (void) SubstituteString(&hosts,":"," ");
334 hostlist=StringToArgv(hosts,&argc);
335 if (hostlist == (char **) NULL)
338 return(AcquireString(DPCHostname));
340 host=AcquireString(hostlist[1]);
341 if (hostlist[2] == (char *) NULL)
344 *port=StringToLong(hostlist[2]);
345 for (i=0; i < (ssize_t) argc; i++)
346 hostlist[i]=DestroyString(hostlist[i]);
347 hostlist=(char **) RelinquishMagickMemory(hostlist);
351 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
352 ExceptionInfo *exception)
364 Connect to the distributed pixel cache server.
366 server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info));
367 if (server_info == (DistributeCacheInfo *) NULL)
368 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
369 (void) ResetMagickMemory(server_info,0,sizeof(*server_info));
370 server_info->signature=MagickSignature;
372 hostname=GetHostname(&server_info->port,exception);
374 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
375 &session_key,exception);
376 server_info->session_key=session_key;
377 (void) CopyMagickString(server_info->hostname,hostname,MaxTextExtent);
378 hostname=DestroyString(hostname);
379 if (server_info->file == -1)
380 server_info=DestroyDistributeCacheInfo(server_info);
385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389 + 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 %
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 % DestroyDistributeCacheInfo() deallocates memory associated with an
396 % DistributeCacheInfo structure.
398 % The format of the DestroyDistributeCacheInfo method is:
400 % DistributeCacheInfo *DestroyDistributeCacheInfo(
401 % DistributeCacheInfo *server_info)
403 % A description of each parameter follows:
405 % o server_info: the distributed cache info.
408 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
409 DistributeCacheInfo *server_info)
411 assert(server_info != (DistributeCacheInfo *) NULL);
412 assert(server_info->signature == MagickSignature);
413 if (server_info->file > 0)
414 (void) close(server_info->file);
415 server_info->signature=(~MagickSignature);
416 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425 + 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 %
429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431 % DistributePixelCacheServer() waits on the specified port for commands to
432 % create, read, update, or destroy a pixel cache.
434 % The format of the DistributePixelCacheServer() method is:
436 % void DistributePixelCacheServer(const int port)
438 % A description of each parameter follows:
440 % o port: connect the distributed pixel cache at this port.
442 % o exception: return any errors or warnings in this structure.
446 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
447 int file,const MagickSizeType session_key)
450 Destroy distributed pixel cache.
452 return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
455 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
456 const unsigned char *restrict message)
461 register MagickOffsetType
465 Ensure a complete message is sent.
468 for (i=0; i < (MagickOffsetType) length; i+=count)
470 count=(MagickOffsetType) send(file,message+i,(size_t) MagickMin(length-i,
471 (MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
482 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
483 int file,const MagickSizeType session_key,ExceptionInfo *exception)
497 register unsigned char
501 message[MaxTextExtent];
504 Open distributed pixel cache.
506 image=AcquireImage((ImageInfo *) NULL,exception);
507 if (image == (Image *) NULL)
509 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
510 sizeof(image->alpha_trait)+sizeof(image->mask)+sizeof(image->columns)+
511 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
512 sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
513 count=dpc_read(file,length,message);
514 if (count != (MagickOffsetType) length)
517 Deserialize image attributes.
520 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
521 p+=sizeof(image->storage_class);
522 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
523 p+=sizeof(image->colorspace);
524 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
525 p+=sizeof(image->alpha_trait);
526 (void) memcpy(&image->mask,p,sizeof(image->mask));
527 p+=sizeof(image->mask);
528 (void) memcpy(&image->columns,p,sizeof(image->columns));
529 p+=sizeof(image->columns);
530 (void) memcpy(&image->rows,p,sizeof(image->rows));
531 p+=sizeof(image->rows);
532 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
533 p+=sizeof(image->number_channels);
534 (void) memcpy(image->channel_map,p,MaxPixelChannels*
535 sizeof(*image->channel_map));
536 p+=MaxPixelChannels*sizeof(*image->channel_map);
537 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
538 p+=sizeof(image->metacontent_extent);
539 if (SyncImagePixelCache(image,exception) == MagickFalse)
541 status=AddValueToSplayTree(registry,(const void *) session_key,image);
545 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
546 int file,const MagickSizeType session_key,ExceptionInfo *exception)
563 register const Quantum
566 register unsigned char
570 message[MaxTextExtent];
573 Read distributed pixel cache metacontent.
575 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
576 if (image == (Image *) NULL)
578 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
579 sizeof(region.y)+sizeof(length);
580 count=dpc_read(file,length,message);
581 if (count != (MagickOffsetType) length)
584 (void) memcpy(®ion.width,q,sizeof(region.width));
585 q+=sizeof(region.width);
586 (void) memcpy(®ion.height,q,sizeof(region.height));
587 q+=sizeof(region.height);
588 (void) memcpy(®ion.x,q,sizeof(region.x));
590 (void) memcpy(®ion.y,q,sizeof(region.y));
592 (void) memcpy(&length,q,sizeof(length));
594 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
596 if (p == (const Quantum *) NULL)
598 metacontent=GetVirtualMetacontent(image);
599 count=dpc_send(file,length,metacontent);
600 if (count != (MagickOffsetType) length)
605 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
606 int file,const MagickSizeType session_key,ExceptionInfo *exception)
620 register const Quantum
623 register unsigned char
627 message[MaxTextExtent];
630 Read distributed pixel cache pixels.
632 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
633 if (image == (Image *) NULL)
635 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
636 sizeof(region.y)+sizeof(length);
637 count=dpc_read(file,length,message);
638 if (count != (MagickOffsetType) length)
641 (void) memcpy(®ion.width,q,sizeof(region.width));
642 q+=sizeof(region.width);
643 (void) memcpy(®ion.height,q,sizeof(region.height));
644 q+=sizeof(region.height);
645 (void) memcpy(®ion.x,q,sizeof(region.x));
647 (void) memcpy(®ion.y,q,sizeof(region.y));
649 (void) memcpy(&length,q,sizeof(length));
651 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
653 if (p == (const Quantum *) NULL)
655 count=dpc_send(file,length,(unsigned char *) p);
656 if (count != (MagickOffsetType) length)
661 static void *RelinquishImageRegistry(void *image)
663 return((void *) DestroyImageList((Image *) image));
666 static MagickBooleanType WriteDistributeCacheMetacontent(
667 SplayTreeInfo *registry,int file,const MagickSizeType session_key,
668 ExceptionInfo *exception)
685 register unsigned char
689 message[MaxTextExtent],
693 Write distributed pixel cache metacontent.
695 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
696 if (image == (Image *) NULL)
698 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
699 sizeof(region.y)+sizeof(length);
700 count=dpc_read(file,length,message);
701 if (count != (MagickOffsetType) length)
704 (void) memcpy(®ion.width,p,sizeof(region.width));
705 p+=sizeof(region.width);
706 (void) memcpy(®ion.height,p,sizeof(region.height));
707 p+=sizeof(region.height);
708 (void) memcpy(®ion.x,p,sizeof(region.x));
710 (void) memcpy(®ion.y,p,sizeof(region.y));
712 (void) memcpy(&length,p,sizeof(length));
714 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
716 if (q == (Quantum *) NULL)
718 metacontent=GetAuthenticMetacontent(image);
719 count=dpc_read(file,length,metacontent);
720 if (count != (MagickOffsetType) length)
722 return(SyncAuthenticPixels(image,exception));
725 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
726 int file,const MagickSizeType session_key,ExceptionInfo *exception)
743 register unsigned char
747 message[MaxTextExtent];
750 Write distributed pixel cache pixels.
752 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
753 if (image == (Image *) NULL)
755 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
756 sizeof(region.y)+sizeof(length);
757 count=dpc_read(file,length,message);
758 if (count != (MagickOffsetType) length)
761 (void) memcpy(®ion.width,p,sizeof(region.width));
762 p+=sizeof(region.width);
763 (void) memcpy(®ion.height,p,sizeof(region.height));
764 p+=sizeof(region.height);
765 (void) memcpy(®ion.x,p,sizeof(region.x));
767 (void) memcpy(®ion.y,p,sizeof(region.y));
769 (void) memcpy(&length,p,sizeof(length));
771 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
773 if (q == (Quantum *) NULL)
775 count=dpc_read(file,length,(unsigned char *) q);
776 if (count != (MagickOffsetType) length)
778 return(SyncAuthenticPixels(image,exception));
781 static void *DistributePixelCacheClient(void *socket)
803 register unsigned char
817 session[2*MaxTextExtent];
820 Distributed pixel cache client.
822 shared_secret=GetPolicyValue("shared-secret");
823 if (shared_secret == (const char *) NULL)
824 ThrowFatalException(CacheFatalError,"shared secret expected");
826 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
827 p+=strlen(shared_secret);
828 random_info=AcquireRandomInfo();
829 secret=GetRandomKey(random_info,DPCSessionKeyLength);
830 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
831 p+=DPCSessionKeyLength;
832 signature=MagickLibVersion;
833 (void) memcpy(p,&signature,sizeof(signature));
834 p+=sizeof(signature);
835 signature=MAGICKCORE_QUANTUM_DEPTH;
836 (void) memcpy(p,&signature,sizeof(signature));
837 p+=sizeof(signature);
838 signature=MAGICKCORE_HDRI_ENABLE;
839 (void) memcpy(p,&signature,sizeof(signature));
840 p+=sizeof(signature);
841 session_key=CRC64(session,p-session);
842 random_info=DestroyRandomInfo(random_info);
843 exception=AcquireExceptionInfo();
844 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
845 (void *(*)(void *)) NULL,RelinquishImageRegistry);
846 client_socket=(*(int *) socket);
847 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
848 secret=DestroyStringInfo(secret);
851 count=dpc_read(client_socket,1,(unsigned char *) &command);
854 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
855 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
862 status=OpenDistributeCache(registry,client_socket,session_key,
864 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
869 status=ReadDistributeCachePixels(registry,client_socket,session_key,
875 status=ReadDistributeCacheMetacontent(registry,client_socket,
876 session_key,exception);
881 status=WriteDistributeCachePixels(registry,client_socket,session_key,
887 status=WriteDistributeCacheMetacontent(registry,client_socket,
888 session_key,exception);
893 status=DestroyDistributeCache(registry,client_socket,session_key);
899 if (status == MagickFalse)
904 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
905 (void) close(client_socket);
906 exception=DestroyExceptionInfo(exception);
907 registry=DestroySplayTree(registry);
908 return((void *) NULL);
911 MagickExport void DistributePixelCacheServer(const int port,
912 ExceptionInfo *exception)
914 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
916 service[MaxTextExtent];
928 register struct addrinfo
939 Launch distributed pixel cache server.
941 (void) ResetMagickMemory(&hint,0,sizeof(hint));
942 hint.ai_family=AF_INET;
943 hint.ai_socktype=SOCK_STREAM;
944 hint.ai_flags=AI_PASSIVE;
945 (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
946 status=getaddrinfo((const char *) NULL,service,&hint,&result);
948 ThrowFatalException(CacheFatalError,"UnableToListen");
949 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
954 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
955 if (server_socket == -1)
958 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
962 status=bind(server_socket,p->ai_addr,p->ai_addrlen);
965 (void) close(status);
970 if (p == (struct addrinfo *) NULL)
971 ThrowFatalException(CacheFatalError,"UnableToBind");
972 freeaddrinfo(result);
973 status=listen(server_socket,DPCPendingConnections);
975 ThrowFatalException(CacheFatalError,"UnableToListen");
976 pthread_attr_init(&attributes);
985 length=(socklen_t) sizeof(address);
986 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
987 if (client_socket == -1)
988 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
989 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
990 (void *) &client_socket);
992 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
994 (void) close(server_socket);
996 ThrowFatalException(MissingDelegateError,"distributed pixel cache");
1001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1005 + G e t D i s t r i b u t e C a c h e F i l e %
1009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1011 % GetDistributeCacheFile() returns the file associated with this
1012 % DistributeCacheInfo structure.
1014 % The format of the GetDistributeCacheFile method is:
1016 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1018 % A description of each parameter follows:
1020 % o server_info: the distributed cache info.
1023 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1025 assert(server_info != (DistributeCacheInfo *) NULL);
1026 assert(server_info->signature == MagickSignature);
1027 return(server_info->file);
1031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 + 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 %
1039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % GetDistributeCacheHostname() returns the hostname associated with this
1042 % DistributeCacheInfo structure.
1044 % The format of the GetDistributeCacheHostname method is:
1046 % const char *GetDistributeCacheHostname(
1047 % const DistributeCacheInfo *server_info)
1049 % A description of each parameter follows:
1051 % o server_info: the distributed cache info.
1054 MagickPrivate const char *GetDistributeCacheHostname(
1055 const DistributeCacheInfo *server_info)
1057 assert(server_info != (DistributeCacheInfo *) NULL);
1058 assert(server_info->signature == MagickSignature);
1059 return(server_info->hostname);
1063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067 + G e t D i s t r i b u t e C a c h e P o r t %
1071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073 % GetDistributeCachePort() returns the port associated with this
1074 % DistributeCacheInfo structure.
1076 % The format of the GetDistributeCachePort method is:
1078 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1080 % A description of each parameter follows:
1082 % o server_info: the distributed cache info.
1085 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1087 assert(server_info != (DistributeCacheInfo *) NULL);
1088 assert(server_info->signature == MagickSignature);
1089 return(server_info->port);
1093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1097 + O p e n D i s t r i b u t e P i x e l C a c h e %
1101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1103 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1105 % The format of the OpenDistributePixelCache method is:
1107 % MagickBooleanType *OpenDistributePixelCache(
1108 % DistributeCacheInfo *server_info,Image *image)
1110 % A description of each parameter follows:
1112 % o server_info: the distributed cache info.
1114 % o image: the image.
1117 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1118 DistributeCacheInfo *server_info,Image *image)
1126 register unsigned char
1130 message[MaxTextExtent];
1133 Open distributed pixel cache.
1135 assert(server_info != (DistributeCacheInfo *) NULL);
1136 assert(server_info->signature == MagickSignature);
1137 assert(image != (Image *) NULL);
1138 assert(image->signature == MagickSignature);
1140 *p++='o'; /* open */
1142 Serialize image attributes (see ValidatePixelCacheMorphology()).
1144 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1145 p+=sizeof(server_info->session_key);
1146 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1147 p+=sizeof(image->storage_class);
1148 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1149 p+=sizeof(image->colorspace);
1150 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1151 p+=sizeof(image->alpha_trait);
1152 (void) memcpy(p,&image->mask,sizeof(image->mask));
1153 p+=sizeof(image->mask);
1154 (void) memcpy(p,&image->columns,sizeof(image->columns));
1155 p+=sizeof(image->columns);
1156 (void) memcpy(p,&image->rows,sizeof(image->rows));
1157 p+=sizeof(image->rows);
1158 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1159 p+=sizeof(image->number_channels);
1160 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1161 sizeof(*image->channel_map));
1162 p+=MaxPixelChannels*sizeof(*image->channel_map);
1163 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1164 p+=sizeof(image->metacontent_extent);
1165 count=dpc_send(server_info->file,p-message,message);
1166 if (count != (MagickOffsetType) (p-message))
1167 return(MagickFalse);
1169 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1170 if (count != (MagickOffsetType) sizeof(status))
1171 return(MagickFalse);
1176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180 + 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 %
1184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1186 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1187 % region of the distributed pixel cache.
1189 % The format of the ReadDistributePixelCacheMetacontents method is:
1191 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1192 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1193 % const MagickSizeType length,unsigned char *metacontent)
1195 % A description of each parameter follows:
1197 % o server_info: the distributed cache info.
1199 % o image: the image.
1201 % o region: read the metacontent from this region of the image.
1203 % o length: the length in bytes of the metacontent.
1205 % o metacontent: read these metacontent from the pixel cache.
1208 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1209 DistributeCacheInfo *server_info,const RectangleInfo *region,
1210 const MagickSizeType length,unsigned char *metacontent)
1215 register unsigned char
1219 message[MaxTextExtent];
1222 Read distributed pixel cache metacontent.
1224 assert(server_info != (DistributeCacheInfo *) NULL);
1225 assert(server_info->signature == MagickSignature);
1226 assert(region != (RectangleInfo *) NULL);
1227 assert(metacontent != (unsigned char *) NULL);
1228 if (length > (MagickSizeType) SSIZE_MAX)
1232 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1233 p+=sizeof(server_info->session_key);
1234 (void) memcpy(p,®ion->width,sizeof(region->width));
1235 p+=sizeof(region->width);
1236 (void) memcpy(p,®ion->height,sizeof(region->height));
1237 p+=sizeof(region->height);
1238 (void) memcpy(p,®ion->x,sizeof(region->x));
1239 p+=sizeof(region->x);
1240 (void) memcpy(p,®ion->y,sizeof(region->y));
1241 p+=sizeof(region->y);
1242 (void) memcpy(p,&length,sizeof(length));
1244 count=dpc_send(server_info->file,p-message,message);
1245 if (count != (MagickOffsetType) (p-message))
1247 return(dpc_read(server_info->file,length,metacontent));
1251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1255 + 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 %
1259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1262 % the distributed pixel cache.
1264 % The format of the ReadDistributePixelCachePixels method is:
1266 % MagickOffsetType ReadDistributePixelCachePixels(
1267 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1268 % const MagickSizeType length,unsigned char *pixels)
1270 % A description of each parameter follows:
1272 % o server_info: the distributed cache info.
1274 % o image: the image.
1276 % o region: read the pixels from this region of the image.
1278 % o length: the length in bytes of the pixels.
1280 % o pixels: read these pixels from the pixel cache.
1283 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1284 DistributeCacheInfo *server_info,const RectangleInfo *region,
1285 const MagickSizeType length,unsigned char *pixels)
1290 register unsigned char
1294 message[MaxTextExtent];
1297 Read distributed pixel cache pixels.
1299 assert(server_info != (DistributeCacheInfo *) NULL);
1300 assert(server_info->signature == MagickSignature);
1301 assert(region != (RectangleInfo *) NULL);
1302 assert(pixels != (unsigned char *) NULL);
1303 if (length > (MagickSizeType) SSIZE_MAX)
1307 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1308 p+=sizeof(server_info->session_key);
1309 (void) memcpy(p,®ion->width,sizeof(region->width));
1310 p+=sizeof(region->width);
1311 (void) memcpy(p,®ion->height,sizeof(region->height));
1312 p+=sizeof(region->height);
1313 (void) memcpy(p,®ion->x,sizeof(region->x));
1314 p+=sizeof(region->x);
1315 (void) memcpy(p,®ion->y,sizeof(region->y));
1316 p+=sizeof(region->y);
1317 (void) memcpy(p,&length,sizeof(length));
1319 count=dpc_send(server_info->file,p-message,message);
1320 if (count != (MagickOffsetType) (p-message))
1322 return(dpc_read(server_info->file,length,pixels));
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 + 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 %
1334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1336 % RelinquishDistributePixelCache() frees resources acquired with
1337 % OpenDistributePixelCache().
1339 % The format of the RelinquishDistributePixelCache method is:
1341 % MagickBooleanType RelinquishDistributePixelCache(
1342 % DistributeCacheInfo *server_info)
1344 % A description of each parameter follows:
1346 % o server_info: the distributed cache info.
1349 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1350 DistributeCacheInfo *server_info)
1358 register unsigned char
1362 message[MaxTextExtent];
1365 Delete distributed pixel cache.
1367 assert(server_info != (DistributeCacheInfo *) NULL);
1368 assert(server_info->signature == MagickSignature);
1371 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1372 p+=sizeof(server_info->session_key);
1373 count=dpc_send(server_info->file,p-message,message);
1374 if (count != (MagickOffsetType) (p-message))
1375 return(MagickFalse);
1376 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1377 if (count != (MagickOffsetType) sizeof(status))
1378 return(MagickFalse);
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 + 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 %
1391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1394 % specified region of the distributed pixel cache.
1396 % The format of the WriteDistributePixelCacheMetacontents method is:
1398 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1399 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1400 % const MagickSizeType length,const unsigned char *metacontent)
1402 % A description of each parameter follows:
1404 % o server_info: the distributed cache info.
1406 % o image: the image.
1408 % o region: write the metacontent to this region of the image.
1410 % o length: the length in bytes of the metacontent.
1412 % o metacontent: write these metacontent to the pixel cache.
1415 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1416 DistributeCacheInfo *server_info,const RectangleInfo *region,
1417 const MagickSizeType length,const unsigned char *metacontent)
1422 register unsigned char
1426 message[MaxTextExtent];
1429 Write distributed pixel cache metacontent.
1431 assert(server_info != (DistributeCacheInfo *) NULL);
1432 assert(server_info->signature == MagickSignature);
1433 assert(region != (RectangleInfo *) NULL);
1434 assert(metacontent != (unsigned char *) NULL);
1435 if (length > (MagickSizeType) SSIZE_MAX)
1439 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1440 p+=sizeof(server_info->session_key);
1441 (void) memcpy(p,®ion->width,sizeof(region->width));
1442 p+=sizeof(region->width);
1443 (void) memcpy(p,®ion->height,sizeof(region->height));
1444 p+=sizeof(region->height);
1445 (void) memcpy(p,®ion->x,sizeof(region->x));
1446 p+=sizeof(region->x);
1447 (void) memcpy(p,®ion->y,sizeof(region->y));
1448 p+=sizeof(region->y);
1449 (void) memcpy(p,&length,sizeof(length));
1451 count=dpc_send(server_info->file,p-message,message);
1452 if (count != (MagickOffsetType) (p-message))
1454 return(dpc_send(server_info->file,length,metacontent));
1458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462 + 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 %
1466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468 % WriteDistributePixelCachePixels() writes image pixels to the specified
1469 % region of the distributed pixel cache.
1471 % The format of the WriteDistributePixelCachePixels method is:
1473 % MagickBooleanType WriteDistributePixelCachePixels(
1474 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1475 % const MagickSizeType length,const unsigned char *pixels)
1477 % A description of each parameter follows:
1479 % o server_info: the distributed cache info.
1481 % o image: the image.
1483 % o region: write the pixels to this region of the image.
1485 % o length: the length in bytes of the pixels.
1487 % o pixels: write these pixels to the pixel cache.
1490 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1491 DistributeCacheInfo *server_info,const RectangleInfo *region,
1492 const MagickSizeType length,const unsigned char *pixels)
1497 register unsigned char
1501 message[MaxTextExtent];
1504 Write distributed pixel cache pixels.
1506 assert(server_info != (DistributeCacheInfo *) NULL);
1507 assert(server_info->signature == MagickSignature);
1508 assert(region != (RectangleInfo *) NULL);
1509 assert(pixels != (const unsigned char *) NULL);
1510 if (length > (MagickSizeType) SSIZE_MAX)
1514 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1515 p+=sizeof(server_info->session_key);
1516 (void) memcpy(p,®ion->width,sizeof(region->width));
1517 p+=sizeof(region->width);
1518 (void) memcpy(p,®ion->height,sizeof(region->height));
1519 p+=sizeof(region->height);
1520 (void) memcpy(p,®ion->x,sizeof(region->x));
1521 p+=sizeof(region->x);
1522 (void) memcpy(p,®ion->y,sizeof(region->y));
1523 p+=sizeof(region->y);
1524 (void) memcpy(p,&length,sizeof(length));
1526 count=dpc_send(server_info->file,p-message,message);
1527 if (count != (MagickOffsetType) (p-message))
1529 return(dpc_send(server_info->file,length,pixels));