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-2018 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 % https://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/image-private.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/locale_.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/memory-private.h"
68 #include "MagickCore/nt-base-private.h"
69 #include "MagickCore/pixel.h"
70 #include "MagickCore/policy.h"
71 #include "MagickCore/random_.h"
72 #include "MagickCore/registry.h"
73 #include "MagickCore/splay-tree.h"
74 #include "MagickCore/string_.h"
75 #include "MagickCore/string-private.h"
76 #include "MagickCore/version.h"
77 #include "MagickCore/version-private.h"
78 #undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
79 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
80 #include <netinet/in.h>
82 #include <sys/socket.h>
83 #include <arpa/inet.h>
84 #define CHAR_TYPE_CAST
85 #define CLOSE_SOCKET(socket) (void) close(socket)
86 #define HANDLER_RETURN_TYPE void *
87 #define HANDLER_RETURN_VALUE (void *) NULL
88 #define SOCKET_TYPE int
89 #define LENGTH_TYPE size_t
90 #define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
91 #elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
92 #define CHAR_TYPE_CAST (char *)
93 #define CLOSE_SOCKET(socket) (void) closesocket(socket)
94 #define HANDLER_RETURN_TYPE DWORD WINAPI
95 #define HANDLER_RETURN_VALUE 0
96 #define SOCKET_TYPE SOCKET
97 #define LENGTH_TYPE int
98 #define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
101 #define CLOSE_SOCKET(socket) (void) close(socket)
103 #define CLOSE_SOCKET(socket)
105 #define HANDLER_RETURN_TYPE void *
106 #define HANDLER_RETURN_VALUE (void *) NULL
107 #define SOCKET_TYPE int
110 #define send(file,buffer,length,flags) 0
111 #define recv(file,buffer,length,flags) 0
117 #define DPCHostname "127.0.0.1"
118 #define DPCPendingConnections 10
120 #define DPCSessionKeyLength 8
122 # define MSG_NOSIGNAL 0
126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 + 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 %
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 % AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
138 % The format of the AcquireDistributeCacheInfo method is:
140 % DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
142 % A description of each parameter follows:
144 % o exception: return any errors or warnings in this structure.
148 static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
149 unsigned char *magick_restrict message)
151 register MagickOffsetType
157 #if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
158 magick_unreferenced(file);
159 magick_unreferenced(message);
163 for (i=0; i < (MagickOffsetType) length; i+=count)
165 count=recv(file,CHAR_TYPE_CAST message+i,(LENGTH_TYPE) MagickMin(length-i,
166 (MagickSizeType) SSIZE_MAX),0);
177 static int ConnectPixelCacheServer(const char *hostname,const int port,
178 size_t *session_key,ExceptionInfo *exception)
180 #if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
182 service[MagickPathExtent],
199 secret[MagickPathExtent];
202 Connect to distributed pixel cache and get session key.
205 shared_secret=GetPolicyValue("cache:shared-secret");
206 if (shared_secret == (char *) NULL)
208 shared_secret=DestroyString(shared_secret);
209 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
210 "DistributedPixelCache","'%s'","shared secret expected");
213 shared_secret=DestroyString(shared_secret);
214 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
215 NTInitializeWinsock(MagickTrue);
217 (void) memset(&hint,0,sizeof(hint));
218 hint.ai_family=AF_INET;
219 hint.ai_socktype=SOCK_STREAM;
220 hint.ai_flags=AI_PASSIVE;
221 (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
222 status=getaddrinfo(hostname,service,&hint,&result);
225 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
226 "DistributedPixelCache","'%s'",hostname);
229 client_socket=socket(result->ai_family,result->ai_socktype,
230 result->ai_protocol);
231 if (client_socket == -1)
233 freeaddrinfo(result);
234 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
235 "DistributedPixelCache","'%s'",hostname);
238 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
241 CLOSE_SOCKET(client_socket);
242 freeaddrinfo(result);
243 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
244 "DistributedPixelCache","'%s'",hostname);
247 count=recv(client_socket,CHAR_TYPE_CAST secret,MagickPathExtent,0);
253 nonce=AcquireStringInfo((size_t) count);
254 (void) memcpy(GetStringInfoDatum(nonce),secret,(size_t) count);
255 *session_key=GetMagickSignature(nonce);
256 nonce=DestroyStringInfo(nonce);
258 if (*session_key == 0)
260 CLOSE_SOCKET(client_socket);
261 client_socket=(SOCKET_TYPE) (-1);
263 freeaddrinfo(result);
264 return(client_socket);
266 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
267 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
272 static char *GetHostname(int *port,ExceptionInfo *exception)
289 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
291 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",exception);
292 if (hosts == (char *) NULL)
295 return(AcquireString(DPCHostname));
297 (void) SubstituteString(&hosts,","," ");
298 hostlist=StringToArgv(hosts,&argc);
299 hosts=DestroyString(hosts);
300 if (hostlist == (char **) NULL)
303 return(AcquireString(DPCHostname));
305 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
306 for (i=0; i < (ssize_t) argc; i++)
307 hostlist[i]=DestroyString(hostlist[i]);
308 hostlist=(char **) RelinquishMagickMemory(hostlist);
309 (void) SubstituteString(&hosts,":"," ");
310 hostlist=StringToArgv(hosts,&argc);
311 if (hostlist == (char **) NULL)
314 return(AcquireString(DPCHostname));
316 host=AcquireString(hostlist[1]);
317 if (hostlist[2] == (char *) NULL)
320 *port=StringToLong(hostlist[2]);
321 for (i=0; i < (ssize_t) argc; i++)
322 hostlist[i]=DestroyString(hostlist[i]);
323 hostlist=(char **) RelinquishMagickMemory(hostlist);
327 MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
328 ExceptionInfo *exception)
340 Connect to the distributed pixel cache server.
342 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
343 sizeof(*server_info));
344 (void) memset(server_info,0,sizeof(*server_info));
345 server_info->signature=MagickCoreSignature;
347 hostname=GetHostname(&server_info->port,exception);
349 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
350 &session_key,exception);
351 if (server_info->file == -1)
352 server_info=DestroyDistributeCacheInfo(server_info);
355 server_info->session_key=session_key;
356 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
357 server_info->debug=IsEventLogging();
359 hostname=DestroyString(hostname);
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368 + D e s t r o y D i s t r i b u t e C a c h e I n f o %
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 % DestroyDistributeCacheInfo() deallocates memory associated with an
375 % DistributeCacheInfo structure.
377 % The format of the DestroyDistributeCacheInfo method is:
379 % DistributeCacheInfo *DestroyDistributeCacheInfo(
380 % DistributeCacheInfo *server_info)
382 % A description of each parameter follows:
384 % o server_info: the distributed cache info.
387 MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
388 DistributeCacheInfo *server_info)
390 assert(server_info != (DistributeCacheInfo *) NULL);
391 assert(server_info->signature == MagickCoreSignature);
392 if (server_info->file > 0)
393 CLOSE_SOCKET(server_info->file);
394 server_info->signature=(~MagickCoreSignature);
395 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 + D i s t r i b u t e P i x e l C a c h e S e r v e r %
408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410 % DistributePixelCacheServer() waits on the specified port for commands to
411 % create, read, update, or destroy a pixel cache.
413 % The format of the DistributePixelCacheServer() method is:
415 % void DistributePixelCacheServer(const int port)
417 % A description of each parameter follows:
419 % o port: connect the distributed pixel cache at this port.
421 % o exception: return any errors or warnings in this structure.
425 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
426 const size_t session_key)
429 Destroy distributed pixel cache.
431 return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
434 static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
435 const unsigned char *magick_restrict message)
440 register MagickOffsetType
443 #if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
444 magick_unreferenced(file);
445 magick_unreferenced(message);
449 Ensure a complete message is sent.
452 for (i=0; i < (MagickOffsetType) length; i+=count)
454 count=(MagickOffsetType) send(file,CHAR_TYPE_CAST message+i,(LENGTH_TYPE)
455 MagickMin(length-i,(MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
466 static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,int file,
467 const size_t session_key,ExceptionInfo *exception)
481 register unsigned char
485 message[MagickPathExtent];
488 Open distributed pixel cache.
490 image=AcquireImage((ImageInfo *) NULL,exception);
491 if (image == (Image *) NULL)
493 length=sizeof(image->storage_class)+sizeof(image->colorspace)+
494 sizeof(image->alpha_trait)+sizeof(image->channels)+sizeof(image->columns)+
495 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
496 sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
497 count=dpc_read(file,length,message);
498 if (count != (MagickOffsetType) length)
501 Deserialize the image attributes.
504 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
505 p+=sizeof(image->storage_class);
506 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
507 p+=sizeof(image->colorspace);
508 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
509 p+=sizeof(image->alpha_trait);
510 (void) memcpy(&image->channels,p,sizeof(image->channels));
511 p+=sizeof(image->channels);
512 (void) memcpy(&image->channels,p,sizeof(image->channels));
513 p+=sizeof(image->channels);
514 (void) memcpy(&image->columns,p,sizeof(image->columns));
515 p+=sizeof(image->columns);
516 (void) memcpy(&image->rows,p,sizeof(image->rows));
517 p+=sizeof(image->rows);
518 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
519 p+=sizeof(image->number_channels);
520 (void) memcpy(image->channel_map,p,MaxPixelChannels*
521 sizeof(*image->channel_map));
522 p+=MaxPixelChannels*sizeof(*image->channel_map);
523 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
524 p+=sizeof(image->metacontent_extent);
525 if (SyncImagePixelCache(image,exception) == MagickFalse)
527 status=AddValueToSplayTree(registry,(const void *) session_key,image);
531 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
532 int file,const size_t session_key,ExceptionInfo *exception)
549 register const Quantum
552 register unsigned char
556 message[MagickPathExtent];
559 Read distributed pixel cache metacontent.
561 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
562 if (image == (Image *) NULL)
564 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
565 sizeof(region.y)+sizeof(length);
566 count=dpc_read(file,length,message);
567 if (count != (MagickOffsetType) length)
570 (void) memcpy(®ion.width,q,sizeof(region.width));
571 q+=sizeof(region.width);
572 (void) memcpy(®ion.height,q,sizeof(region.height));
573 q+=sizeof(region.height);
574 (void) memcpy(®ion.x,q,sizeof(region.x));
576 (void) memcpy(®ion.y,q,sizeof(region.y));
578 (void) memcpy(&length,q,sizeof(length));
580 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
582 if (p == (const Quantum *) NULL)
584 metacontent=(const unsigned char *) GetVirtualMetacontent(image);
585 count=dpc_send(file,length,metacontent);
586 if (count != (MagickOffsetType) length)
591 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
592 int file,const size_t session_key,ExceptionInfo *exception)
606 register const Quantum
609 register unsigned char
613 message[MagickPathExtent];
616 Read distributed pixel cache pixels.
618 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
619 if (image == (Image *) NULL)
621 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
622 sizeof(region.y)+sizeof(length);
623 count=dpc_read(file,length,message);
624 if (count != (MagickOffsetType) length)
627 (void) memcpy(®ion.width,q,sizeof(region.width));
628 q+=sizeof(region.width);
629 (void) memcpy(®ion.height,q,sizeof(region.height));
630 q+=sizeof(region.height);
631 (void) memcpy(®ion.x,q,sizeof(region.x));
633 (void) memcpy(®ion.y,q,sizeof(region.y));
635 (void) memcpy(&length,q,sizeof(length));
637 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
639 if (p == (const Quantum *) NULL)
641 count=dpc_send(file,length,(unsigned char *) p);
642 if (count != (MagickOffsetType) length)
647 static void *RelinquishImageRegistry(void *image)
649 return((void *) DestroyImageList((Image *) image));
652 static MagickBooleanType WriteDistributeCacheMetacontent(
653 SplayTreeInfo *registry,int file,const size_t session_key,
654 ExceptionInfo *exception)
671 register unsigned char
675 message[MagickPathExtent],
679 Write distributed pixel cache metacontent.
681 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
682 if (image == (Image *) NULL)
684 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
685 sizeof(region.y)+sizeof(length);
686 count=dpc_read(file,length,message);
687 if (count != (MagickOffsetType) length)
690 (void) memcpy(®ion.width,p,sizeof(region.width));
691 p+=sizeof(region.width);
692 (void) memcpy(®ion.height,p,sizeof(region.height));
693 p+=sizeof(region.height);
694 (void) memcpy(®ion.x,p,sizeof(region.x));
696 (void) memcpy(®ion.y,p,sizeof(region.y));
698 (void) memcpy(&length,p,sizeof(length));
700 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
702 if (q == (Quantum *) NULL)
704 metacontent=(unsigned char *) GetAuthenticMetacontent(image);
705 count=dpc_read(file,length,metacontent);
706 if (count != (MagickOffsetType) length)
708 return(SyncAuthenticPixels(image,exception));
711 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
712 int file,const size_t session_key,ExceptionInfo *exception)
729 register unsigned char
733 message[MagickPathExtent];
736 Write distributed pixel cache pixels.
738 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
739 if (image == (Image *) NULL)
741 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
742 sizeof(region.y)+sizeof(length);
743 count=dpc_read(file,length,message);
744 if (count != (MagickOffsetType) length)
747 (void) memcpy(®ion.width,p,sizeof(region.width));
748 p+=sizeof(region.width);
749 (void) memcpy(®ion.height,p,sizeof(region.height));
750 p+=sizeof(region.height);
751 (void) memcpy(®ion.x,p,sizeof(region.x));
753 (void) memcpy(®ion.y,p,sizeof(region.y));
755 (void) memcpy(&length,p,sizeof(length));
757 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
759 if (q == (Quantum *) NULL)
761 count=dpc_read(file,length,(unsigned char *) q);
762 if (count != (MagickOffsetType) length)
764 return(SyncAuthenticPixels(image,exception));
767 static HANDLER_RETURN_TYPE DistributePixelCacheClient(void *socket)
781 register unsigned char
802 session[2*MagickPathExtent];
805 Distributed pixel cache client.
807 shared_secret=GetPolicyValue("cache:shared-secret");
808 if (shared_secret == (char *) NULL)
809 ThrowFatalException(CacheFatalError,"shared secret expected");
811 (void) CopyMagickString((char *) p,shared_secret,MagickPathExtent);
812 p+=strlen(shared_secret);
813 shared_secret=DestroyString(shared_secret);
814 random_info=AcquireRandomInfo();
815 secret=GetRandomKey(random_info,DPCSessionKeyLength);
816 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
817 session_key=GetMagickSignature(secret);
818 random_info=DestroyRandomInfo(random_info);
819 exception=AcquireExceptionInfo();
820 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
821 (void *(*)(void *)) NULL,RelinquishImageRegistry);
822 client_socket=(*(SOCKET_TYPE *) socket);
823 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
824 secret=DestroyStringInfo(secret);
827 count=dpc_read(client_socket,1,(unsigned char *) &command);
830 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
831 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
838 status=OpenDistributeCache(registry,client_socket,session_key,
840 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
845 status=ReadDistributeCachePixels(registry,client_socket,session_key,
851 status=ReadDistributeCacheMetacontent(registry,client_socket,
852 session_key,exception);
857 status=WriteDistributeCachePixels(registry,client_socket,session_key,
863 status=WriteDistributeCacheMetacontent(registry,client_socket,
864 session_key,exception);
869 status=DestroyDistributeCache(registry,session_key);
875 if (status == MagickFalse)
880 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
881 CLOSE_SOCKET(client_socket);
882 exception=DestroyExceptionInfo(exception);
883 registry=DestroySplayTree(registry);
884 return(HANDLER_RETURN_VALUE);
887 MagickExport void DistributePixelCacheServer(const int port,
888 ExceptionInfo *exception)
890 #if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
892 service[MagickPathExtent];
897 #if defined(MAGICKCORE_THREAD_SUPPORT)
903 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
910 register struct addrinfo
924 Launch distributed pixel cache server.
926 assert(exception != (ExceptionInfo *) NULL);
927 assert(exception->signature == MagickCoreSignature);
928 magick_unreferenced(exception);
929 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
930 NTInitializeWinsock(MagickFalse);
932 (void) memset(&hint,0,sizeof(hint));
933 hint.ai_family=AF_INET;
934 hint.ai_socktype=SOCK_STREAM;
935 hint.ai_flags=AI_PASSIVE;
936 (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
937 status=getaddrinfo((const char *) NULL,service,&hint,&result);
939 ThrowFatalException(CacheFatalError,"UnableToListen");
940 server_socket=(SOCKET_TYPE) 0;
941 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
946 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
947 if (server_socket == -1)
950 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,
951 CHAR_TYPE_CAST &one,(socklen_t) sizeof(one));
954 CLOSE_SOCKET(server_socket);
957 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
960 CLOSE_SOCKET(server_socket);
965 if (p == (struct addrinfo *) NULL)
966 ThrowFatalException(CacheFatalError,"UnableToBind");
967 freeaddrinfo(result);
968 status=listen(server_socket,DPCPendingConnections);
970 ThrowFatalException(CacheFatalError,"UnableToListen");
971 #if defined(MAGICKCORE_THREAD_SUPPORT)
972 pthread_attr_init(&attributes);
982 length=(socklen_t) sizeof(address);
983 client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
984 if (client_socket == -1)
985 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
986 #if defined(MAGICKCORE_THREAD_SUPPORT)
987 status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
988 (void *) &client_socket);
990 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
991 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
992 if (CreateThread(0,0,DistributePixelCacheClient,(void*) &client_socket,0,
993 &threadID) == (HANDLE) NULL)
994 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
1000 magick_unreferenced(port);
1001 ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
1006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1010 + G e t D i s t r i b u t e C a c h e F i l e %
1014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 % GetDistributeCacheFile() returns the file associated with this
1017 % DistributeCacheInfo structure.
1019 % The format of the GetDistributeCacheFile method is:
1021 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1023 % A description of each parameter follows:
1025 % o server_info: the distributed cache info.
1028 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1030 assert(server_info != (DistributeCacheInfo *) NULL);
1031 assert(server_info->signature == MagickCoreSignature);
1032 return(server_info->file);
1036 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1040 + 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 %
1044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1046 % GetDistributeCacheHostname() returns the hostname associated with this
1047 % DistributeCacheInfo structure.
1049 % The format of the GetDistributeCacheHostname method is:
1051 % const char *GetDistributeCacheHostname(
1052 % const DistributeCacheInfo *server_info)
1054 % A description of each parameter follows:
1056 % o server_info: the distributed cache info.
1059 MagickPrivate const char *GetDistributeCacheHostname(
1060 const DistributeCacheInfo *server_info)
1062 assert(server_info != (DistributeCacheInfo *) NULL);
1063 assert(server_info->signature == MagickCoreSignature);
1064 return(server_info->hostname);
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 + G e t D i s t r i b u t e C a c h e P o r t %
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 % GetDistributeCachePort() returns the port associated with this
1079 % DistributeCacheInfo structure.
1081 % The format of the GetDistributeCachePort method is:
1083 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1085 % A description of each parameter follows:
1087 % o server_info: the distributed cache info.
1090 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1092 assert(server_info != (DistributeCacheInfo *) NULL);
1093 assert(server_info->signature == MagickCoreSignature);
1094 return(server_info->port);
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102 + O p e n D i s t r i b u t e P i x e l C a c h e %
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1108 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1110 % The format of the OpenDistributePixelCache method is:
1112 % MagickBooleanType *OpenDistributePixelCache(
1113 % DistributeCacheInfo *server_info,Image *image)
1115 % A description of each parameter follows:
1117 % o server_info: the distributed cache info.
1119 % o image: the image.
1122 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1123 DistributeCacheInfo *server_info,Image *image)
1135 register unsigned char
1139 message[MagickPathExtent];
1142 Open distributed pixel cache.
1144 assert(server_info != (DistributeCacheInfo *) NULL);
1145 assert(server_info->signature == MagickCoreSignature);
1146 assert(image != (Image *) NULL);
1147 assert(image->signature == MagickCoreSignature);
1149 *p++='o'; /* open */
1151 Serialize image attributes (see ValidatePixelCacheMorphology()).
1153 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1154 p+=sizeof(server_info->session_key);
1155 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1156 p+=sizeof(image->storage_class);
1157 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1158 p+=sizeof(image->colorspace);
1159 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1160 p+=sizeof(image->alpha_trait);
1161 (void) memcpy(p,&image->channels,sizeof(image->channels));
1162 p+=sizeof(image->channels);
1163 (void) memcpy(p,&image->columns,sizeof(image->columns));
1164 p+=sizeof(image->columns);
1165 (void) memcpy(p,&image->rows,sizeof(image->rows));
1166 p+=sizeof(image->rows);
1167 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1168 p+=sizeof(image->number_channels);
1169 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1170 sizeof(*image->channel_map));
1171 p+=MaxPixelChannels*sizeof(*image->channel_map);
1172 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1173 p+=sizeof(image->metacontent_extent);
1174 count=dpc_send(server_info->file,p-message,message);
1175 if (count != (MagickOffsetType) (p-message))
1176 return(MagickFalse);
1178 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1179 if (count != (MagickOffsetType) sizeof(status))
1180 return(MagickFalse);
1185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189 + 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 %
1193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1195 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1196 % region of the distributed pixel cache.
1198 % The format of the ReadDistributePixelCacheMetacontents method is:
1200 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1201 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1202 % const MagickSizeType length,unsigned char *metacontent)
1204 % A description of each parameter follows:
1206 % o server_info: the distributed cache info.
1208 % o image: the image.
1210 % o region: read the metacontent from this region of the image.
1212 % o length: the length in bytes of the metacontent.
1214 % o metacontent: read these metacontent from the pixel cache.
1217 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1218 DistributeCacheInfo *server_info,const RectangleInfo *region,
1219 const MagickSizeType length,unsigned char *metacontent)
1224 register unsigned char
1228 message[MagickPathExtent];
1231 Read distributed pixel cache metacontent.
1233 assert(server_info != (DistributeCacheInfo *) NULL);
1234 assert(server_info->signature == MagickCoreSignature);
1235 assert(region != (RectangleInfo *) NULL);
1236 assert(metacontent != (unsigned char *) NULL);
1237 if (length > (MagickSizeType) SSIZE_MAX)
1241 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1242 p+=sizeof(server_info->session_key);
1243 (void) memcpy(p,®ion->width,sizeof(region->width));
1244 p+=sizeof(region->width);
1245 (void) memcpy(p,®ion->height,sizeof(region->height));
1246 p+=sizeof(region->height);
1247 (void) memcpy(p,®ion->x,sizeof(region->x));
1248 p+=sizeof(region->x);
1249 (void) memcpy(p,®ion->y,sizeof(region->y));
1250 p+=sizeof(region->y);
1251 (void) memcpy(p,&length,sizeof(length));
1253 count=dpc_send(server_info->file,p-message,message);
1254 if (count != (MagickOffsetType) (p-message))
1256 return(dpc_read(server_info->file,length,metacontent));
1260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264 + 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 %
1268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1270 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1271 % the distributed pixel cache.
1273 % The format of the ReadDistributePixelCachePixels method is:
1275 % MagickOffsetType ReadDistributePixelCachePixels(
1276 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1277 % const MagickSizeType length,unsigned char *magick_restrict pixels)
1279 % A description of each parameter follows:
1281 % o server_info: the distributed cache info.
1283 % o image: the image.
1285 % o region: read the pixels from this region of the image.
1287 % o length: the length in bytes of the pixels.
1289 % o pixels: read these pixels from the pixel cache.
1292 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1293 DistributeCacheInfo *server_info,const RectangleInfo *region,
1294 const MagickSizeType length,unsigned char *magick_restrict pixels)
1299 register unsigned char
1303 message[MagickPathExtent];
1306 Read distributed pixel cache pixels.
1308 assert(server_info != (DistributeCacheInfo *) NULL);
1309 assert(server_info->signature == MagickCoreSignature);
1310 assert(region != (RectangleInfo *) NULL);
1311 assert(pixels != (unsigned char *) NULL);
1312 if (length > (MagickSizeType) SSIZE_MAX)
1316 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1317 p+=sizeof(server_info->session_key);
1318 (void) memcpy(p,®ion->width,sizeof(region->width));
1319 p+=sizeof(region->width);
1320 (void) memcpy(p,®ion->height,sizeof(region->height));
1321 p+=sizeof(region->height);
1322 (void) memcpy(p,®ion->x,sizeof(region->x));
1323 p+=sizeof(region->x);
1324 (void) memcpy(p,®ion->y,sizeof(region->y));
1325 p+=sizeof(region->y);
1326 (void) memcpy(p,&length,sizeof(length));
1328 count=dpc_send(server_info->file,p-message,message);
1329 if (count != (MagickOffsetType) (p-message))
1331 return(dpc_read(server_info->file,length,pixels));
1335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1339 + 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 %
1343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345 % RelinquishDistributePixelCache() frees resources acquired with
1346 % OpenDistributePixelCache().
1348 % The format of the RelinquishDistributePixelCache method is:
1350 % MagickBooleanType RelinquishDistributePixelCache(
1351 % DistributeCacheInfo *server_info)
1353 % A description of each parameter follows:
1355 % o server_info: the distributed cache info.
1358 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1359 DistributeCacheInfo *server_info)
1363 status = MagickTrue;
1371 register unsigned char
1375 message[MagickPathExtent];
1378 Delete distributed pixel cache.
1380 assert(server_info != (DistributeCacheInfo *) NULL);
1381 assert(server_info->signature == MagickCoreSignature);
1384 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1385 p+=sizeof(server_info->session_key);
1386 count=dpc_send(server_info->file,p-message,message);
1387 if (count != (MagickOffsetType) (p-message))
1388 return(MagickFalse);
1389 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1390 if (count != (MagickOffsetType) sizeof(status))
1391 return(MagickFalse);
1396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1400 + 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 %
1404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1407 % specified region of the distributed pixel cache.
1409 % The format of the WriteDistributePixelCacheMetacontents method is:
1411 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1412 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1413 % const MagickSizeType length,const unsigned char *metacontent)
1415 % A description of each parameter follows:
1417 % o server_info: the distributed cache info.
1419 % o image: the image.
1421 % o region: write the metacontent to this region of the image.
1423 % o length: the length in bytes of the metacontent.
1425 % o metacontent: write these metacontent to the pixel cache.
1428 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1429 DistributeCacheInfo *server_info,const RectangleInfo *region,
1430 const MagickSizeType length,const unsigned char *metacontent)
1435 register unsigned char
1439 message[MagickPathExtent];
1442 Write distributed pixel cache metacontent.
1444 assert(server_info != (DistributeCacheInfo *) NULL);
1445 assert(server_info->signature == MagickCoreSignature);
1446 assert(region != (RectangleInfo *) NULL);
1447 assert(metacontent != (unsigned char *) NULL);
1448 if (length > (MagickSizeType) SSIZE_MAX)
1452 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1453 p+=sizeof(server_info->session_key);
1454 (void) memcpy(p,®ion->width,sizeof(region->width));
1455 p+=sizeof(region->width);
1456 (void) memcpy(p,®ion->height,sizeof(region->height));
1457 p+=sizeof(region->height);
1458 (void) memcpy(p,®ion->x,sizeof(region->x));
1459 p+=sizeof(region->x);
1460 (void) memcpy(p,®ion->y,sizeof(region->y));
1461 p+=sizeof(region->y);
1462 (void) memcpy(p,&length,sizeof(length));
1464 count=dpc_send(server_info->file,p-message,message);
1465 if (count != (MagickOffsetType) (p-message))
1467 return(dpc_send(server_info->file,length,metacontent));
1471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475 + 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 %
1479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481 % WriteDistributePixelCachePixels() writes image pixels to the specified
1482 % region of the distributed pixel cache.
1484 % The format of the WriteDistributePixelCachePixels method is:
1486 % MagickBooleanType WriteDistributePixelCachePixels(
1487 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1488 % const MagickSizeType length,
1489 % const unsigned char *magick_restrict pixels)
1491 % A description of each parameter follows:
1493 % o server_info: the distributed cache info.
1495 % o image: the image.
1497 % o region: write the pixels to this region of the image.
1499 % o length: the length in bytes of the pixels.
1501 % o pixels: write these pixels to the pixel cache.
1504 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1505 DistributeCacheInfo *server_info,const RectangleInfo *region,
1506 const MagickSizeType length,const unsigned char *magick_restrict pixels)
1511 register unsigned char
1515 message[MagickPathExtent];
1518 Write distributed pixel cache pixels.
1520 assert(server_info != (DistributeCacheInfo *) NULL);
1521 assert(server_info->signature == MagickCoreSignature);
1522 assert(region != (RectangleInfo *) NULL);
1523 assert(pixels != (const unsigned char *) NULL);
1524 if (length > (MagickSizeType) SSIZE_MAX)
1528 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1529 p+=sizeof(server_info->session_key);
1530 (void) memcpy(p,®ion->width,sizeof(region->width));
1531 p+=sizeof(region->width);
1532 (void) memcpy(p,®ion->height,sizeof(region->height));
1533 p+=sizeof(region->height);
1534 (void) memcpy(p,®ion->x,sizeof(region->x));
1535 p+=sizeof(region->x);
1536 (void) memcpy(p,®ion->y,sizeof(region->y));
1537 p+=sizeof(region->y);
1538 (void) memcpy(p,&length,sizeof(length));
1540 count=dpc_send(server_info->file,p-message,message);
1541 if (count != (MagickOffsetType) (p-message))
1543 return(dpc_send(server_info->file,length,pixels));