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-2017 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) ResetMagickMemory(&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(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) ResetMagickMemory(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->read_mask)+
495 sizeof(image->write_mask)+sizeof(image->columns)+sizeof(image->rows)+
496 sizeof(image->number_channels)+MaxPixelChannels*sizeof(*image->channel_map)+
497 sizeof(image->metacontent_extent);
498 count=dpc_read(file,length,message);
499 if (count != (MagickOffsetType) length)
502 Deserialize the image attributes.
505 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
506 p+=sizeof(image->storage_class);
507 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
508 p+=sizeof(image->colorspace);
509 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
510 p+=sizeof(image->alpha_trait);
511 (void) memcpy(&image->read_mask,p,sizeof(image->read_mask));
512 p+=sizeof(image->read_mask);
513 (void) memcpy(&image->write_mask,p,sizeof(image->write_mask));
514 p+=sizeof(image->write_mask);
515 (void) memcpy(&image->columns,p,sizeof(image->columns));
516 p+=sizeof(image->columns);
517 (void) memcpy(&image->rows,p,sizeof(image->rows));
518 p+=sizeof(image->rows);
519 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
520 p+=sizeof(image->number_channels);
521 (void) memcpy(image->channel_map,p,MaxPixelChannels*
522 sizeof(*image->channel_map));
523 p+=MaxPixelChannels*sizeof(*image->channel_map);
524 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
525 p+=sizeof(image->metacontent_extent);
526 if (SyncImagePixelCache(image,exception) == MagickFalse)
528 status=AddValueToSplayTree(registry,(const void *) session_key,image);
532 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
533 int file,const size_t session_key,ExceptionInfo *exception)
550 register const Quantum
553 register unsigned char
557 message[MagickPathExtent];
560 Read distributed pixel cache metacontent.
562 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
563 if (image == (Image *) NULL)
565 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
566 sizeof(region.y)+sizeof(length);
567 count=dpc_read(file,length,message);
568 if (count != (MagickOffsetType) length)
571 (void) memcpy(®ion.width,q,sizeof(region.width));
572 q+=sizeof(region.width);
573 (void) memcpy(®ion.height,q,sizeof(region.height));
574 q+=sizeof(region.height);
575 (void) memcpy(®ion.x,q,sizeof(region.x));
577 (void) memcpy(®ion.y,q,sizeof(region.y));
579 (void) memcpy(&length,q,sizeof(length));
581 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
583 if (p == (const Quantum *) NULL)
585 metacontent=(const unsigned char *) GetVirtualMetacontent(image);
586 count=dpc_send(file,length,metacontent);
587 if (count != (MagickOffsetType) length)
592 static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
593 int file,const size_t session_key,ExceptionInfo *exception)
607 register const Quantum
610 register unsigned char
614 message[MagickPathExtent];
617 Read distributed pixel cache pixels.
619 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
620 if (image == (Image *) NULL)
622 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
623 sizeof(region.y)+sizeof(length);
624 count=dpc_read(file,length,message);
625 if (count != (MagickOffsetType) length)
628 (void) memcpy(®ion.width,q,sizeof(region.width));
629 q+=sizeof(region.width);
630 (void) memcpy(®ion.height,q,sizeof(region.height));
631 q+=sizeof(region.height);
632 (void) memcpy(®ion.x,q,sizeof(region.x));
634 (void) memcpy(®ion.y,q,sizeof(region.y));
636 (void) memcpy(&length,q,sizeof(length));
638 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
640 if (p == (const Quantum *) NULL)
642 count=dpc_send(file,length,(unsigned char *) p);
643 if (count != (MagickOffsetType) length)
648 static void *RelinquishImageRegistry(void *image)
650 return((void *) DestroyImageList((Image *) image));
653 static MagickBooleanType WriteDistributeCacheMetacontent(
654 SplayTreeInfo *registry,int file,const size_t session_key,
655 ExceptionInfo *exception)
672 register unsigned char
676 message[MagickPathExtent],
680 Write distributed pixel cache metacontent.
682 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
683 if (image == (Image *) NULL)
685 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
686 sizeof(region.y)+sizeof(length);
687 count=dpc_read(file,length,message);
688 if (count != (MagickOffsetType) length)
691 (void) memcpy(®ion.width,p,sizeof(region.width));
692 p+=sizeof(region.width);
693 (void) memcpy(®ion.height,p,sizeof(region.height));
694 p+=sizeof(region.height);
695 (void) memcpy(®ion.x,p,sizeof(region.x));
697 (void) memcpy(®ion.y,p,sizeof(region.y));
699 (void) memcpy(&length,p,sizeof(length));
701 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
703 if (q == (Quantum *) NULL)
705 metacontent=(unsigned char *) GetAuthenticMetacontent(image);
706 count=dpc_read(file,length,metacontent);
707 if (count != (MagickOffsetType) length)
709 return(SyncAuthenticPixels(image,exception));
712 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
713 int file,const size_t session_key,ExceptionInfo *exception)
730 register unsigned char
734 message[MagickPathExtent];
737 Write distributed pixel cache pixels.
739 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
740 if (image == (Image *) NULL)
742 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
743 sizeof(region.y)+sizeof(length);
744 count=dpc_read(file,length,message);
745 if (count != (MagickOffsetType) length)
748 (void) memcpy(®ion.width,p,sizeof(region.width));
749 p+=sizeof(region.width);
750 (void) memcpy(®ion.height,p,sizeof(region.height));
751 p+=sizeof(region.height);
752 (void) memcpy(®ion.x,p,sizeof(region.x));
754 (void) memcpy(®ion.y,p,sizeof(region.y));
756 (void) memcpy(&length,p,sizeof(length));
758 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
760 if (q == (Quantum *) NULL)
762 count=dpc_read(file,length,(unsigned char *) q);
763 if (count != (MagickOffsetType) length)
765 return(SyncAuthenticPixels(image,exception));
768 static HANDLER_RETURN_TYPE DistributePixelCacheClient(void *socket)
782 register unsigned char
803 session[2*MagickPathExtent];
806 Distributed pixel cache client.
808 shared_secret=GetPolicyValue("cache:shared-secret");
809 if (shared_secret == (char *) NULL)
810 ThrowFatalException(CacheFatalError,"shared secret expected");
812 (void) CopyMagickString((char *) p,shared_secret,MagickPathExtent);
813 p+=strlen(shared_secret);
814 shared_secret=DestroyString(shared_secret);
815 random_info=AcquireRandomInfo();
816 secret=GetRandomKey(random_info,DPCSessionKeyLength);
817 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
818 session_key=GetMagickSignature(secret);
819 random_info=DestroyRandomInfo(random_info);
820 exception=AcquireExceptionInfo();
821 registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
822 (void *(*)(void *)) NULL,RelinquishImageRegistry);
823 client_socket=(*(SOCKET_TYPE *) socket);
824 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
825 secret=DestroyStringInfo(secret);
828 count=dpc_read(client_socket,1,(unsigned char *) &command);
831 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
832 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
839 status=OpenDistributeCache(registry,client_socket,session_key,
841 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
846 status=ReadDistributeCachePixels(registry,client_socket,session_key,
852 status=ReadDistributeCacheMetacontent(registry,client_socket,
853 session_key,exception);
858 status=WriteDistributeCachePixels(registry,client_socket,session_key,
864 status=WriteDistributeCacheMetacontent(registry,client_socket,
865 session_key,exception);
870 status=DestroyDistributeCache(registry,session_key);
876 if (status == MagickFalse)
881 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
882 CLOSE_SOCKET(client_socket);
883 exception=DestroyExceptionInfo(exception);
884 registry=DestroySplayTree(registry);
885 return(HANDLER_RETURN_VALUE);
888 MagickExport void DistributePixelCacheServer(const int port,
889 ExceptionInfo *exception)
891 #if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
893 service[MagickPathExtent];
898 #if defined(MAGICKCORE_THREAD_SUPPORT)
904 #elif defined(MAGICKCORE_WINDOWS_SUPPORT)
911 register struct addrinfo
925 Launch distributed pixel cache server.
927 assert(exception != (ExceptionInfo *) NULL);
928 assert(exception->signature == MagickCoreSignature);
929 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
930 NTInitializeWinsock(MagickFalse);
932 (void) ResetMagickMemory(&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 magick_unreferenced(exception);
1002 ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
1007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1011 + G e t D i s t r i b u t e C a c h e F i l e %
1015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1017 % GetDistributeCacheFile() returns the file associated with this
1018 % DistributeCacheInfo structure.
1020 % The format of the GetDistributeCacheFile method is:
1022 % int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1024 % A description of each parameter follows:
1026 % o server_info: the distributed cache info.
1029 MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1031 assert(server_info != (DistributeCacheInfo *) NULL);
1032 assert(server_info->signature == MagickCoreSignature);
1033 return(server_info->file);
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 + 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 %
1045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1047 % GetDistributeCacheHostname() returns the hostname associated with this
1048 % DistributeCacheInfo structure.
1050 % The format of the GetDistributeCacheHostname method is:
1052 % const char *GetDistributeCacheHostname(
1053 % const DistributeCacheInfo *server_info)
1055 % A description of each parameter follows:
1057 % o server_info: the distributed cache info.
1060 MagickPrivate const char *GetDistributeCacheHostname(
1061 const DistributeCacheInfo *server_info)
1063 assert(server_info != (DistributeCacheInfo *) NULL);
1064 assert(server_info->signature == MagickCoreSignature);
1065 return(server_info->hostname);
1069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073 + G e t D i s t r i b u t e C a c h e P o r t %
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079 % GetDistributeCachePort() returns the port associated with this
1080 % DistributeCacheInfo structure.
1082 % The format of the GetDistributeCachePort method is:
1084 % int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1086 % A description of each parameter follows:
1088 % o server_info: the distributed cache info.
1091 MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1093 assert(server_info != (DistributeCacheInfo *) NULL);
1094 assert(server_info->signature == MagickCoreSignature);
1095 return(server_info->port);
1099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1103 + O p e n D i s t r i b u t e P i x e l C a c h e %
1107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 % OpenDistributePixelCache() opens a pixel cache on a remote server.
1111 % The format of the OpenDistributePixelCache method is:
1113 % MagickBooleanType *OpenDistributePixelCache(
1114 % DistributeCacheInfo *server_info,Image *image)
1116 % A description of each parameter follows:
1118 % o server_info: the distributed cache info.
1120 % o image: the image.
1123 MagickPrivate MagickBooleanType OpenDistributePixelCache(
1124 DistributeCacheInfo *server_info,Image *image)
1136 register unsigned char
1140 message[MagickPathExtent];
1143 Open distributed pixel cache.
1145 assert(server_info != (DistributeCacheInfo *) NULL);
1146 assert(server_info->signature == MagickCoreSignature);
1147 assert(image != (Image *) NULL);
1148 assert(image->signature == MagickCoreSignature);
1150 *p++='o'; /* open */
1152 Serialize image attributes (see ValidatePixelCacheMorphology()).
1154 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1155 p+=sizeof(server_info->session_key);
1156 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1157 p+=sizeof(image->storage_class);
1158 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1159 p+=sizeof(image->colorspace);
1160 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1161 p+=sizeof(image->alpha_trait);
1162 (void) memcpy(p,&image->read_mask,sizeof(image->read_mask));
1163 p+=sizeof(image->read_mask);
1164 (void) memcpy(p,&image->write_mask,sizeof(image->write_mask));
1165 p+=sizeof(image->write_mask);
1166 (void) memcpy(p,&image->columns,sizeof(image->columns));
1167 p+=sizeof(image->columns);
1168 (void) memcpy(p,&image->rows,sizeof(image->rows));
1169 p+=sizeof(image->rows);
1170 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1171 p+=sizeof(image->number_channels);
1172 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1173 sizeof(*image->channel_map));
1174 p+=MaxPixelChannels*sizeof(*image->channel_map);
1175 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1176 p+=sizeof(image->metacontent_extent);
1177 count=dpc_send(server_info->file,p-message,message);
1178 if (count != (MagickOffsetType) (p-message))
1179 return(MagickFalse);
1181 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1182 if (count != (MagickOffsetType) sizeof(status))
1183 return(MagickFalse);
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 + 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 %
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198 % ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1199 % region of the distributed pixel cache.
1201 % The format of the ReadDistributePixelCacheMetacontents method is:
1203 % MagickOffsetType ReadDistributePixelCacheMetacontents(
1204 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1205 % const MagickSizeType length,unsigned char *metacontent)
1207 % A description of each parameter follows:
1209 % o server_info: the distributed cache info.
1211 % o image: the image.
1213 % o region: read the metacontent from this region of the image.
1215 % o length: the length in bytes of the metacontent.
1217 % o metacontent: read these metacontent from the pixel cache.
1220 MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1221 DistributeCacheInfo *server_info,const RectangleInfo *region,
1222 const MagickSizeType length,unsigned char *metacontent)
1227 register unsigned char
1231 message[MagickPathExtent];
1234 Read distributed pixel cache metacontent.
1236 assert(server_info != (DistributeCacheInfo *) NULL);
1237 assert(server_info->signature == MagickCoreSignature);
1238 assert(region != (RectangleInfo *) NULL);
1239 assert(metacontent != (unsigned char *) NULL);
1240 if (length > (MagickSizeType) SSIZE_MAX)
1244 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1245 p+=sizeof(server_info->session_key);
1246 (void) memcpy(p,®ion->width,sizeof(region->width));
1247 p+=sizeof(region->width);
1248 (void) memcpy(p,®ion->height,sizeof(region->height));
1249 p+=sizeof(region->height);
1250 (void) memcpy(p,®ion->x,sizeof(region->x));
1251 p+=sizeof(region->x);
1252 (void) memcpy(p,®ion->y,sizeof(region->y));
1253 p+=sizeof(region->y);
1254 (void) memcpy(p,&length,sizeof(length));
1256 count=dpc_send(server_info->file,p-message,message);
1257 if (count != (MagickOffsetType) (p-message))
1259 return(dpc_read(server_info->file,length,metacontent));
1263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1267 + 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 %
1271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1273 % ReadDistributePixelCachePixels() reads pixels from the specified region of
1274 % the distributed pixel cache.
1276 % The format of the ReadDistributePixelCachePixels method is:
1278 % MagickOffsetType ReadDistributePixelCachePixels(
1279 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1280 % const MagickSizeType length,unsigned char *magick_restrict pixels)
1282 % A description of each parameter follows:
1284 % o server_info: the distributed cache info.
1286 % o image: the image.
1288 % o region: read the pixels from this region of the image.
1290 % o length: the length in bytes of the pixels.
1292 % o pixels: read these pixels from the pixel cache.
1295 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1296 DistributeCacheInfo *server_info,const RectangleInfo *region,
1297 const MagickSizeType length,unsigned char *magick_restrict pixels)
1302 register unsigned char
1306 message[MagickPathExtent];
1309 Read distributed pixel cache pixels.
1311 assert(server_info != (DistributeCacheInfo *) NULL);
1312 assert(server_info->signature == MagickCoreSignature);
1313 assert(region != (RectangleInfo *) NULL);
1314 assert(pixels != (unsigned char *) NULL);
1315 if (length > (MagickSizeType) SSIZE_MAX)
1319 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1320 p+=sizeof(server_info->session_key);
1321 (void) memcpy(p,®ion->width,sizeof(region->width));
1322 p+=sizeof(region->width);
1323 (void) memcpy(p,®ion->height,sizeof(region->height));
1324 p+=sizeof(region->height);
1325 (void) memcpy(p,®ion->x,sizeof(region->x));
1326 p+=sizeof(region->x);
1327 (void) memcpy(p,®ion->y,sizeof(region->y));
1328 p+=sizeof(region->y);
1329 (void) memcpy(p,&length,sizeof(length));
1331 count=dpc_send(server_info->file,p-message,message);
1332 if (count != (MagickOffsetType) (p-message))
1334 return(dpc_read(server_info->file,length,pixels));
1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342 + 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 %
1346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 % RelinquishDistributePixelCache() frees resources acquired with
1349 % OpenDistributePixelCache().
1351 % The format of the RelinquishDistributePixelCache method is:
1353 % MagickBooleanType RelinquishDistributePixelCache(
1354 % DistributeCacheInfo *server_info)
1356 % A description of each parameter follows:
1358 % o server_info: the distributed cache info.
1361 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1362 DistributeCacheInfo *server_info)
1366 status = MagickTrue;
1374 register unsigned char
1378 message[MagickPathExtent];
1381 Delete distributed pixel cache.
1383 assert(server_info != (DistributeCacheInfo *) NULL);
1384 assert(server_info->signature == MagickCoreSignature);
1387 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1388 p+=sizeof(server_info->session_key);
1389 count=dpc_send(server_info->file,p-message,message);
1390 if (count != (MagickOffsetType) (p-message))
1391 return(MagickFalse);
1392 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1393 if (count != (MagickOffsetType) sizeof(status))
1394 return(MagickFalse);
1399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403 + 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 %
1407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409 % WriteDistributePixelCacheMetacontents() writes image metacontent to the
1410 % specified region of the distributed pixel cache.
1412 % The format of the WriteDistributePixelCacheMetacontents method is:
1414 % MagickOffsetType WriteDistributePixelCacheMetacontents(
1415 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1416 % const MagickSizeType length,const unsigned char *metacontent)
1418 % A description of each parameter follows:
1420 % o server_info: the distributed cache info.
1422 % o image: the image.
1424 % o region: write the metacontent to this region of the image.
1426 % o length: the length in bytes of the metacontent.
1428 % o metacontent: write these metacontent to the pixel cache.
1431 MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1432 DistributeCacheInfo *server_info,const RectangleInfo *region,
1433 const MagickSizeType length,const unsigned char *metacontent)
1438 register unsigned char
1442 message[MagickPathExtent];
1445 Write distributed pixel cache metacontent.
1447 assert(server_info != (DistributeCacheInfo *) NULL);
1448 assert(server_info->signature == MagickCoreSignature);
1449 assert(region != (RectangleInfo *) NULL);
1450 assert(metacontent != (unsigned char *) NULL);
1451 if (length > (MagickSizeType) SSIZE_MAX)
1455 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1456 p+=sizeof(server_info->session_key);
1457 (void) memcpy(p,®ion->width,sizeof(region->width));
1458 p+=sizeof(region->width);
1459 (void) memcpy(p,®ion->height,sizeof(region->height));
1460 p+=sizeof(region->height);
1461 (void) memcpy(p,®ion->x,sizeof(region->x));
1462 p+=sizeof(region->x);
1463 (void) memcpy(p,®ion->y,sizeof(region->y));
1464 p+=sizeof(region->y);
1465 (void) memcpy(p,&length,sizeof(length));
1467 count=dpc_send(server_info->file,p-message,message);
1468 if (count != (MagickOffsetType) (p-message))
1470 return(dpc_send(server_info->file,length,metacontent));
1474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1478 + 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 %
1482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1484 % WriteDistributePixelCachePixels() writes image pixels to the specified
1485 % region of the distributed pixel cache.
1487 % The format of the WriteDistributePixelCachePixels method is:
1489 % MagickBooleanType WriteDistributePixelCachePixels(
1490 % DistributeCacheInfo *server_info,const RectangleInfo *region,
1491 % const MagickSizeType length,
1492 % const unsigned char *magick_restrict pixels)
1494 % A description of each parameter follows:
1496 % o server_info: the distributed cache info.
1498 % o image: the image.
1500 % o region: write the pixels to this region of the image.
1502 % o length: the length in bytes of the pixels.
1504 % o pixels: write these pixels to the pixel cache.
1507 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1508 DistributeCacheInfo *server_info,const RectangleInfo *region,
1509 const MagickSizeType length,const unsigned char *magick_restrict pixels)
1514 register unsigned char
1518 message[MagickPathExtent];
1521 Write distributed pixel cache pixels.
1523 assert(server_info != (DistributeCacheInfo *) NULL);
1524 assert(server_info->signature == MagickCoreSignature);
1525 assert(region != (RectangleInfo *) NULL);
1526 assert(pixels != (const unsigned char *) NULL);
1527 if (length > (MagickSizeType) SSIZE_MAX)
1531 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1532 p+=sizeof(server_info->session_key);
1533 (void) memcpy(p,®ion->width,sizeof(region->width));
1534 p+=sizeof(region->width);
1535 (void) memcpy(p,®ion->height,sizeof(region->height));
1536 p+=sizeof(region->height);
1537 (void) memcpy(p,®ion->x,sizeof(region->x));
1538 p+=sizeof(region->x);
1539 (void) memcpy(p,®ion->y,sizeof(region->y));
1540 p+=sizeof(region->y);
1541 (void) memcpy(p,&length,sizeof(length));
1543 count=dpc_send(server_info->file,p-message,message);
1544 if (count != (MagickOffsetType) (p-message))
1546 return(dpc_send(server_info->file,length,pixels));