54#include "magick/studio.h"
55#include "magick/cache.h"
56#include "magick/cache-private.h"
57#include "magick/distribute-cache.h"
58#include "magick/distribute-cache-private.h"
59#include "magick/exception.h"
60#include "magick/exception-private.h"
61#include "magick/geometry.h"
62#include "magick/image.h"
63#include "magick/image-private.h"
64#include "magick/list.h"
65#include "magick/locale_.h"
66#include "magick/memory_.h"
67#include "magick/nt-base-private.h"
68#include "magick/policy.h"
69#include "magick/random_.h"
70#include "magick/registry.h"
71#include "magick/splay-tree.h"
72#include "magick/string_.h"
73#include "magick/string-private.h"
74#include "magick/version.h"
75#include "magick/version-private.h"
76#undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
77#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
78#include <netinet/in.h>
80#include <sys/socket.h>
82#define CLOSE_SOCKET(socket) (void) close(socket)
83#define HANDLER_RETURN_TYPE void *
84#define HANDLER_RETURN_VALUE (void *) NULL
85#define SOCKET_TYPE int
86#define LENGTH_TYPE size_t
87#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
88#elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__) && !defined(__MINGW64__)
89#define CLOSE_SOCKET(socket) (void) closesocket(socket)
90#define HANDLER_RETURN_TYPE DWORD WINAPI
91#define HANDLER_RETURN_VALUE 0
92#define SOCKET_TYPE SOCKET
93#define LENGTH_TYPE int
94#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE
97#define CLOSE_SOCKET(socket) (void) close(socket)
99#define CLOSE_SOCKET(socket)
101#define HANDLER_RETURN_TYPE void *
102#define HANDLER_RETURN_VALUE (void *) NULL
103#define SOCKET_TYPE int
104#define LENGTH_TYPE size_t
107#define send(file,buffer,length,flags) 0
108#define recv(file,buffer,length,flags) 0
114#define DPCHostname "127.0.0.1"
115#define DPCPendingConnections 10
117#define DPCSessionKeyLength 8
119# define MSG_NOSIGNAL 0
122#ifdef MAGICKCORE_HAVE_WINSOCK2
127 *wsaData = (WSADATA*) NULL;
153static inline MagickOffsetType dpc_read(
int file,
const MagickSizeType length,
154 unsigned char *magick_restrict message)
162#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
163 magick_unreferenced(file);
164 magick_unreferenced(message);
167 for (i=0; i < (MagickOffsetType) length; i+=count)
169 count=recv(file,(
char *) message+i,(LENGTH_TYPE) MagickMin(length-i,
170 (MagickSizeType) MagickMaxBufferExtent),0);
181#if defined(MAGICKCORE_HAVE_WINSOCK2)
182static void InitializeWinsock2(MagickBooleanType use_lock)
184 if (use_lock != MagickFalse)
187 ActivateSemaphoreInfo(&winsock2_semaphore);
188 LockSemaphoreInfo(winsock2_semaphore);
190 if (wsaData == (WSADATA *) NULL)
192 wsaData=(WSADATA *) AcquireMagickMemory(
sizeof(WSADATA));
193 if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
194 ThrowFatalException(CacheFatalError,
"WSAStartup failed");
196 if (use_lock != MagickFalse)
197 UnlockSemaphoreInfo(winsock2_semaphore);
201static inline uint64_t ROTL(uint64_t x,
int b)
203 return((x << b) | (x >> (64-b)));
206static inline uint64_t U8TO64_LE(
const uint8_t *p)
208 return(((uint64_t) p[0] << 0) | ((uint64_t) p[1] << 8) |
209 ((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
210 ((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
211 ((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
214static inline uint64_t SIPHash24(
const uint8_t key[16],
const uint8_t *message,
218 *end = message+length-(length % 8);
224 b = ((uint64_t) length) << 56,
226 k1 = U8TO64_LE(key+8),
228 v0 = 0x736f6d6570736575ULL^k0,
229 v1 = 0x646f72616e646f6dULL^k1,
230 v2 = 0x6c7967656e657261ULL^k0,
231 v3 = 0x7465646279746573ULL^k1;
233 for ( ; message != end; message+=8)
235 m=U8TO64_LE(message);
237 for (i=0; i < 2; i++)
239 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
240 v2+=v3; v3=ROTL(v3,16); v3^=v2;
241 v0+=v3; v3=ROTL(v3,21); v3^=v0;
242 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
246 switch (length & 0x07)
248 case 7: b|=((uint64_t) message[6]) << 48; magick_fallthrough;
249 case 6: b|=((uint64_t) message[5]) << 40; magick_fallthrough;
250 case 5: b|=((uint64_t) message[4]) << 32; magick_fallthrough;
251 case 4: b|=((uint64_t) message[3]) << 24; magick_fallthrough;
252 case 3: b|=((uint64_t) message[2]) << 16; magick_fallthrough;
253 case 2: b|=((uint64_t) message[1]) << 8; magick_fallthrough;
254 case 1: b|=((uint64_t) message[0]); magick_fallthrough;
258 for (i=0; i < 2; i++)
260 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
261 v2+=v3; v3=ROTL(v3,16); v3^=v2;
262 v0+=v3; v3=ROTL(v3,21); v3^=v0;
263 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
267 for (i=0; i < 4; i++)
269 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
270 v2+=v3; v3=ROTL(v3,16); v3^=v2;
271 v0+=v3; v3=ROTL(v3,21); v3^=v0;
272 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
277static inline void DeriveSipKeyFromSecret(
const char *shared_secret,
285 k0 = 0x0706050403020100ULL,
286 k1 = 0x0f0e0d0c0b0a0908ULL;
288 length=strlen(shared_secret);
289 for (i=0; i < length; i++)
292 b = shared_secret[i];
295 k0*=0x100000001b3ULL;
296 k1^=(uint64_t) b << ((i & 7)*8);
297 k1=(k1 << 5) | (k1 >> (64-5));
299 (void) memcpy(key,&k0,8);
300 (void) memcpy(key+8,&k1,8);
303static inline uint64_t GenerateSessionKey(
const char *shared_secret,
304 const unsigned char *nonce,
size_t length)
309 DeriveSipKeyFromSecret(shared_secret,key);
310 return(SIPHash24(key,nonce,length));
313static int ConnectPixelCacheServer(
const char *hostname,
const int port,
314 uint64_t *session_key,ExceptionInfo *exception)
316#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
318 service[MagickPathExtent],
335 nonce[DPCSessionKeyLength];
341#if defined(MAGICKCORE_HAVE_WINSOCK2)
342 InitializeWinsock2(MagickTrue);
344 (void) memset(&hints,0,
sizeof(hints));
345 hints.ai_family=AF_INET;
346 hints.ai_socktype=SOCK_STREAM;
347 hints.ai_flags=AI_PASSIVE;
348 (void) FormatLocaleString(service,MagickPathExtent,
"%d",port);
349 status=getaddrinfo(hostname,service,&hints,&result);
352 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
353 "DistributedPixelCache",
"'%s': %s",hostname,gai_strerror(status));
356 client_socket=socket(result->ai_family,result->ai_socktype,
357 result->ai_protocol);
358 if (client_socket == -1)
360 freeaddrinfo(result);
361 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
362 "DistributedPixelCache",
"'%s': %s",hostname,GetExceptionMessage(errno));
365 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
366 freeaddrinfo(result);
369 CLOSE_SOCKET(client_socket);
370 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
371 "DistributedPixelCache",
"'%s': %s",hostname,GetExceptionMessage(errno));
377 count=recv(client_socket,(
char *) nonce,
sizeof(nonce),0);
378 if (count != (ssize_t)
sizeof(nonce))
380 CLOSE_SOCKET(client_socket);
381 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
382 "DistributedPixelCache",
"'%s': %s",hostname,GetExceptionMessage(errno));
388 shared_secret=GetPolicyValue(
"cache:shared-secret");
389 if (shared_secret == (
char*) NULL)
391 CLOSE_SOCKET(client_socket);
392 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
393 "DistributedPixelCache",
"'%s': shared secret required",hostname);
396 *session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
397 shared_secret=DestroyString(shared_secret);
401 count=send(client_socket,(
char *) session_key,
sizeof(*session_key),
403 if (count != (ssize_t)
sizeof(*session_key))
405 CLOSE_SOCKET(client_socket);
406 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
407 "DistributedPixelCache",
"'%s': authentication failed",hostname);
410 return((
int) client_socket);
412 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
413 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
418static char *GetHostname(
int *port,ExceptionInfo *exception)
437 hosts=(
char *) GetImageRegistry(StringRegistryType,
"cache:hosts",exception);
438 if (hosts == (
char *) NULL)
441 return(AcquireString(DPCHostname));
443 (void) SubstituteString(&hosts,
",",
" ");
444 hostlist=StringToArgv(hosts,&argc);
445 hosts=DestroyString(hosts);
446 if (hostlist == (
char **) NULL)
449 return(AcquireString(DPCHostname));
452 size_t host_count = (size_t) argc-1;
453 size_t index = (
id++ % host_count)+1;
454 hosts=AcquireString(hostlist[index]);
456 for (i=0; i < (ssize_t) argc; i++)
457 hostlist[i]=DestroyString(hostlist[i]);
458 hostlist=(
char **) RelinquishMagickMemory(hostlist);
459 (void) SubstituteString(&hosts,
":",
" ");
460 hostlist=StringToArgv(hosts,&argc);
461 if (hostlist == (
char **) NULL)
464 return(AcquireString(DPCHostname));
466 host=AcquireString(hostlist[1]);
467 if (hostlist[2] == (
char *) NULL)
470 *port=StringToLong(hostlist[2]);
471 for (i=0; i < (ssize_t) argc; i++)
472 hostlist[i]=DestroyString(hostlist[i]);
473 hostlist=(
char **) RelinquishMagickMemory(hostlist);
477MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
478 ExceptionInfo *exception)
492 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
493 sizeof(*server_info));
494 (void) memset(server_info,0,
sizeof(*server_info));
495 server_info->signature=MagickCoreSignature;
497 hostname=GetHostname(&server_info->port,exception);
499 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
500 &session_key,exception);
501 if (server_info->file == -1)
502 server_info=DestroyDistributeCacheInfo(server_info);
505 server_info->session_key=session_key;
506 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
507 server_info->debug=GetLogEventMask() & CacheEvent ? MagickTrue :
510 hostname=DestroyString(hostname);
538MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
539 DistributeCacheInfo *server_info)
541 assert(server_info != (DistributeCacheInfo *) NULL);
542 assert(server_info->signature == MagickCoreSignature);
543 if (server_info->file >= 0)
544 CLOSE_SOCKET(server_info->file);
545 server_info->signature=(~MagickCoreSignature);
546 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
576static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
577 const uint64_t session_key)
580 key = (MagickAddressType) session_key;
585 return(DeleteNodeFromSplayTree(registry,(
const void *) key));
588static inline MagickOffsetType dpc_send(
int file,
const MagickSizeType length,
589 const void *magick_restrict message)
597#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
598 magick_unreferenced(file);
599 magick_unreferenced(message);
606 for (i=0; i < (MagickOffsetType) length; i+=count)
608 count=(MagickOffsetType) send(file,(
char *) message+i,(LENGTH_TYPE)
609 MagickMin(length-i,(MagickSizeType) MagickMaxBufferExtent),MSG_NOSIGNAL);
620static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
int file,
621 const uint64_t session_key,ExceptionInfo *exception)
627 key = (MagickAddressType) session_key;
639 message[MagickPathExtent],
645 image=AcquireImage((ImageInfo *) NULL);
646 if (image == (Image *) NULL)
648 length=
sizeof(image->storage_class)+
sizeof(image->colorspace)+
649 sizeof(image->channels)+
sizeof(image->columns)+
sizeof(image->rows);
650 count=dpc_read(file,length,message);
651 if (count != (MagickOffsetType) length)
653 image=DestroyImage(image);
660 (void) memcpy(&image->storage_class,p,
sizeof(image->storage_class));
661 p+=(ptrdiff_t)
sizeof(image->storage_class);
662 (void) memcpy(&image->colorspace,p,
sizeof(image->colorspace));
663 p+=(ptrdiff_t)
sizeof(image->colorspace);
664 (void) memcpy(&image->channels,p,
sizeof(image->channels));
665 p+=(ptrdiff_t)
sizeof(image->channels);
666 (void) memcpy(&image->columns,p,
sizeof(image->columns));
667 p+=(ptrdiff_t)
sizeof(image->columns);
668 (void) memcpy(&image->rows,p,
sizeof(image->rows));
669 p+=(ptrdiff_t)
sizeof(image->rows);
670 if (SyncImagePixelCache(image,exception) == MagickFalse)
672 image=DestroyImage(image);
675 status=AddValueToSplayTree(registry,(
const void *) key,image);
676 if (status == MagickFalse)
678 image=DestroyImage(image);
684static inline MagickBooleanType ValidateDistributedPixelCache(
685 const RectangleInfo *region,
const size_t per_pixel,
686 const MagickSizeType length)
692 if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
694 if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
696 if (length > (MagickSizeType) extent)
701static MagickBooleanType ReadDistributeCacheIndexes(SplayTreeInfo *registry,
702 int file,
const uint64_t session_key,ExceptionInfo *exception)
714 key = (MagickAddressType) session_key;
729 message[MagickPathExtent],
735 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
736 if (image == (Image *) NULL)
738 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
739 sizeof(region.y)+
sizeof(length);
740 count=dpc_read(file,length,message);
741 if (count != (MagickOffsetType) length)
744 (void) memcpy(®ion.width,q,
sizeof(region.width));
745 q+=(ptrdiff_t)
sizeof(region.width);
746 (void) memcpy(®ion.height,q,
sizeof(region.height));
747 q+=(ptrdiff_t)
sizeof(region.height);
748 (void) memcpy(®ion.x,q,
sizeof(region.x));
749 q+=(ptrdiff_t)
sizeof(region.x);
750 (void) memcpy(®ion.y,q,
sizeof(region.y));
751 q+=(ptrdiff_t)
sizeof(region.y);
752 (void) memcpy(&length,q,
sizeof(length));
753 per_pixel=
sizeof(IndexPacket);
754 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
756 q+=(ptrdiff_t)
sizeof(length);
757 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
759 if (p == (
const PixelPacket *) NULL)
761 indexes=GetVirtualIndexQueue(image);
762 count=dpc_send(file,length,indexes);
763 if (count != (MagickOffsetType) length)
768static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
769 int file,
const uint64_t session_key,ExceptionInfo *exception)
778 key = (MagickAddressType) session_key;
793 message[MagickPathExtent],
799 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
800 if (image == (Image *) NULL)
802 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
803 sizeof(region.y)+
sizeof(length);
804 count=dpc_read(file,length,message);
805 if (count != (MagickOffsetType) length)
808 (void) memcpy(®ion.width,q,
sizeof(region.width));
809 q+=(ptrdiff_t)
sizeof(region.width);
810 (void) memcpy(®ion.height,q,
sizeof(region.height));
811 q+=(ptrdiff_t)
sizeof(region.height);
812 (void) memcpy(®ion.x,q,
sizeof(region.x));
813 q+=(ptrdiff_t)
sizeof(region.x);
814 (void) memcpy(®ion.y,q,
sizeof(region.y));
815 q+=(ptrdiff_t)
sizeof(region.y);
816 (void) memcpy(&length,q,
sizeof(length));
817 q+=(ptrdiff_t)
sizeof(length);
818 per_pixel=
sizeof(PixelPacket);
819 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
821 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
823 if (p == (
const PixelPacket *) NULL)
825 count=dpc_send(file,length,p);
826 if (count != (MagickOffsetType) length)
831static void *RelinquishImageRegistry(
void *image)
833 return((
void *) DestroyImageList((Image *) image));
836static MagickBooleanType WriteDistributeCacheIndexes(SplayTreeInfo *registry,
837 int file,
const uint64_t session_key,ExceptionInfo *exception)
846 key = (MagickAddressType) session_key;
864 message[MagickPathExtent],
870 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
871 if (image == (Image *) NULL)
873 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
874 sizeof(region.y)+
sizeof(length);
875 count=dpc_read(file,length,message);
876 if (count != (MagickOffsetType) length)
879 (void) memcpy(®ion.width,p,
sizeof(region.width));
880 p+=(ptrdiff_t)
sizeof(region.width);
881 (void) memcpy(®ion.height,p,
sizeof(region.height));
882 p+=(ptrdiff_t)
sizeof(region.height);
883 (void) memcpy(®ion.x,p,
sizeof(region.x));
884 p+=(ptrdiff_t)
sizeof(region.x);
885 (void) memcpy(®ion.y,p,
sizeof(region.y));
886 p+=(ptrdiff_t)
sizeof(region.y);
887 (void) memcpy(&length,p,
sizeof(length));
888 per_pixel=
sizeof(IndexPacket);
889 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
891 p+=(ptrdiff_t)
sizeof(length);
892 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
894 if (q == (PixelPacket *) NULL)
896 indexes=GetAuthenticIndexQueue(image);
897 count=dpc_read(file,length,(
unsigned char *) indexes);
898 if (count != (MagickOffsetType) length)
900 return(SyncAuthenticPixels(image,exception));
903static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
904 int file,
const uint64_t session_key,ExceptionInfo *exception)
910 key = (MagickAddressType) session_key;
928 message[MagickPathExtent],
934 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
935 if (image == (Image *) NULL)
937 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
938 sizeof(region.y)+
sizeof(length);
939 count=dpc_read(file,length,message);
940 if (count != (MagickOffsetType) length)
943 (void) memcpy(®ion.width,p,
sizeof(region.width));
944 p+=(ptrdiff_t)
sizeof(region.width);
945 (void) memcpy(®ion.height,p,
sizeof(region.height));
946 p+=(ptrdiff_t)
sizeof(region.height);
947 (void) memcpy(®ion.x,p,
sizeof(region.x));
948 p+=(ptrdiff_t)
sizeof(region.x);
949 (void) memcpy(®ion.y,p,
sizeof(region.y));
950 p+=(ptrdiff_t)
sizeof(region.y);
951 (void) memcpy(&length,p,
sizeof(length));
952 p+=(ptrdiff_t)
sizeof(length);
953 per_pixel=
sizeof(PixelPacket);
954 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
956 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
958 if (q == (PixelPacket *) NULL)
960 count=dpc_read(file,length,(
unsigned char *) q);
961 if (count != (MagickOffsetType) length)
963 return(SyncAuthenticPixels(image,exception));
966static HANDLER_RETURN_TYPE DistributePixelCacheClient(
void *socket_arg)
975 status = MagickFalse;
985 *client_socket_ptr = (SOCKET_TYPE *) socket_arg;
999 nonce[DPCSessionKeyLength];
1004 client_socket=(*client_socket_ptr);
1005 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
1006 shared_secret=GetPolicyValue(
"cache:shared-secret");
1007 if (shared_secret == NULL)
1008 ThrowFatalException(CacheFatalError,
"shared secret required");
1012 random_info=AcquireRandomInfo();
1013 entropy=GetRandomKey(random_info,
sizeof(nonce));
1014 (void) memcpy(nonce,GetStringInfoDatum(entropy),
sizeof(nonce));
1015 entropy=DestroyStringInfo(entropy);
1016 random_info=DestroyRandomInfo(random_info);
1020 session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
1021 shared_secret=DestroyString(shared_secret);
1025 count=dpc_send(client_socket,
sizeof(nonce),nonce);
1026 if (count != (MagickOffsetType)
sizeof(nonce))
1028 CLOSE_SOCKET(client_socket);
1029 return(HANDLER_RETURN_VALUE);
1034 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1035 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1037 CLOSE_SOCKET(client_socket);
1038 return(HANDLER_RETURN_VALUE);
1040 exception=AcquireExceptionInfo();
1041 registry=NewSplayTree((
int (*)(
const void *,
const void *)) NULL,
1042 (
void *(*)(
void *)) NULL,RelinquishImageRegistry);
1046 for (status=MagickFalse; ; )
1051 count=dpc_read(client_socket,1,(
unsigned char *) &command);
1054 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1055 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1061 status=OpenDistributeCache(registry,client_socket,session_key,
1063 dpc_send(client_socket,
sizeof(status),&status);
1068 status=ReadDistributeCachePixels(registry,client_socket,session_key,
1074 status=ReadDistributeCacheIndexes(registry,client_socket,session_key,
1080 status=WriteDistributeCachePixels(registry,client_socket,session_key,
1086 status=WriteDistributeCacheIndexes(registry,client_socket,session_key,
1092 status=DestroyDistributeCache(registry,session_key);
1098 if ((status == MagickFalse) || (command ==
'd'))
1101 count=dpc_send(client_socket,
sizeof(status),&status);
1102 CLOSE_SOCKET(client_socket);
1103 exception=DestroyExceptionInfo(exception);
1104 registry=DestroySplayTree(registry);
1105 return(HANDLER_RETURN_VALUE);
1108MagickExport
void DistributePixelCacheServer(
const int port,
1109 ExceptionInfo *exception)
1112 service[MagickPathExtent];
1117#if defined(MAGICKCORE_THREAD_SUPPORT)
1123#elif defined(_MSC_VER)
1146 assert(exception != (ExceptionInfo *) NULL);
1147 assert(exception->signature == MagickCoreSignature);
1148 magick_unreferenced(exception);
1149#if defined(MAGICKCORE_HAVE_WINSOCK2)
1150 InitializeWinsock2(MagickFalse);
1152 memset(&hint,0,
sizeof(hint));
1153 hint.ai_family=AF_INET;
1154 hint.ai_socktype=SOCK_STREAM;
1155 hint.ai_flags=AI_PASSIVE;
1156 FormatLocaleString(service,MagickPathExtent,
"%d",port);
1157 status=getaddrinfo(NULL,service,&hint,&result);
1159 ThrowFatalException(CacheFatalError,
"UnableToListen");
1160 server_socket=(SOCKET_TYPE) 0;
1161 for (p=result; p != NULL; p=p->ai_next)
1166 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
1167 if (server_socket == -1)
1169 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(
char *) &one,
1170 (socklen_t)
sizeof(one));
1173#if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__) && !defined(__MINGW64__)
1174 DWORD timeout = 5000;
1175 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,(
const char *)
1176 &timeout,
sizeof(timeout));
1181 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,&tv,
sizeof(tv));
1186 CLOSE_SOCKET(server_socket);
1189 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1192 CLOSE_SOCKET(server_socket);
1197 if (p == (
struct addrinfo *) NULL)
1198 ThrowFatalException(CacheFatalError,
"UnableToBind");
1199 freeaddrinfo(result);
1200 status=listen(server_socket,DPCPendingConnections);
1202 ThrowFatalException(CacheFatalError,
"UnableToListen");
1203#if defined(MAGICKCORE_THREAD_SUPPORT)
1204 pthread_attr_init(&attributes);
1205 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1213 length = (socklen_t)
sizeof(address);
1215 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(
sizeof(SOCKET_TYPE));
1216 if (client_socket_ptr == NULL)
1218 *client_socket_ptr=accept(server_socket,(
struct sockaddr *) &address,
1220 if (*client_socket_ptr == -1)
1222 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1226#if defined(MAGICKCORE_THREAD_SUPPORT)
1227 status=pthread_create(&thread_id, &attributes,DistributePixelCacheClient,
1228 (
void *) client_socket_ptr);
1231 CLOSE_SOCKET(*client_socket_ptr);
1232 RelinquishMagickMemory(client_socket_ptr);
1233 ThrowFatalException(CacheFatalError,
"UnableToCreateClientThread");
1235#elif defined(_MSC_VER)
1236 if (CreateThread(0,0,DistributePixelCacheClient,(
void*) client_socket_ptr,0,&threadID) == (HANDLE) NULL)
1238 CLOSE_SOCKET(*client_socket_ptr);
1239 RelinquishMagickMemory(client_socket_ptr);
1240 ThrowFatalException(CacheFatalError,
"UnableToCreateClientThread");
1271MagickPrivate
int GetDistributeCacheFile(
const DistributeCacheInfo *server_info)
1273 assert(server_info != (DistributeCacheInfo *) NULL);
1274 assert(server_info->signature == MagickCoreSignature);
1275 return(server_info->file);
1302MagickPrivate
const char *GetDistributeCacheHostname(
1303 const DistributeCacheInfo *server_info)
1305 assert(server_info != (DistributeCacheInfo *) NULL);
1306 assert(server_info->signature == MagickCoreSignature);
1307 return(server_info->hostname);
1333MagickPrivate
int GetDistributeCachePort(
const DistributeCacheInfo *server_info)
1335 assert(server_info != (DistributeCacheInfo *) NULL);
1336 assert(server_info->signature == MagickCoreSignature);
1337 return(server_info->port);
1365MagickPrivate MagickBooleanType OpenDistributePixelCache(
1366 DistributeCacheInfo *server_info,Image *image)
1375 message[MagickPathExtent],
1381 assert(server_info != (DistributeCacheInfo *) NULL);
1382 assert(server_info->signature == MagickCoreSignature);
1383 assert(image != (Image *) NULL);
1384 assert(image->signature == MagickCoreSignature);
1390 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1391 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1392 (void) memcpy(p,&image->storage_class,
sizeof(image->storage_class));
1393 p+=(ptrdiff_t)
sizeof(image->storage_class);
1394 (void) memcpy(p,&image->colorspace,
sizeof(image->colorspace));
1395 p+=(ptrdiff_t)
sizeof(image->colorspace);
1396 (void) memcpy(p,&image->channels,
sizeof(image->channels));
1397 p+=(ptrdiff_t)
sizeof(image->channels);
1398 (void) memcpy(p,&image->columns,
sizeof(image->columns));
1399 p+=(ptrdiff_t)
sizeof(image->columns);
1400 (void) memcpy(p,&image->rows,
sizeof(image->rows));
1401 p+=(ptrdiff_t)
sizeof(image->rows);
1402 count=dpc_send(server_info->file,p-message,message);
1403 if (count != (MagickOffsetType) (p-message))
1404 return(MagickFalse);
1406 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1407 if (count != (MagickOffsetType)
sizeof(status))
1408 return(MagickFalse);
1445MagickPrivate MagickOffsetType ReadDistributePixelCacheIndexes(
1446 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1447 const MagickSizeType length,
unsigned char *indexes)
1453 message[MagickPathExtent],
1459 assert(server_info != (DistributeCacheInfo *) NULL);
1460 assert(server_info->signature == MagickCoreSignature);
1461 assert(region != (RectangleInfo *) NULL);
1462 assert(indexes != (
unsigned char *) NULL);
1463 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1467 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1468 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1469 (void) memcpy(p,®ion->width,
sizeof(region->width));
1470 p+=(ptrdiff_t)
sizeof(region->width);
1471 (void) memcpy(p,®ion->height,
sizeof(region->height));
1472 p+=(ptrdiff_t)
sizeof(region->height);
1473 (void) memcpy(p,®ion->x,
sizeof(region->x));
1474 p+=(ptrdiff_t)
sizeof(region->x);
1475 (void) memcpy(p,®ion->y,
sizeof(region->y));
1476 p+=(ptrdiff_t)
sizeof(region->y);
1477 (void) memcpy(p,&length,
sizeof(length));
1478 p+=(ptrdiff_t)
sizeof(length);
1479 count=dpc_send(server_info->file,p-message,message);
1480 if (count != (MagickOffsetType) (p-message))
1482 return(dpc_read(server_info->file,length,indexes));
1518MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1519 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1520 const MagickSizeType length,
unsigned char *magick_restrict pixels)
1526 message[MagickPathExtent],
1532 assert(server_info != (DistributeCacheInfo *) NULL);
1533 assert(server_info->signature == MagickCoreSignature);
1534 assert(region != (RectangleInfo *) NULL);
1535 assert(pixels != (
unsigned char *) NULL);
1536 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1540 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1541 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1542 (void) memcpy(p,®ion->width,
sizeof(region->width));
1543 p+=(ptrdiff_t)
sizeof(region->width);
1544 (void) memcpy(p,®ion->height,
sizeof(region->height));
1545 p+=(ptrdiff_t)
sizeof(region->height);
1546 (void) memcpy(p,®ion->x,
sizeof(region->x));
1547 p+=(ptrdiff_t)
sizeof(region->x);
1548 (void) memcpy(p,®ion->y,
sizeof(region->y));
1549 p+=(ptrdiff_t)
sizeof(region->y);
1550 (void) memcpy(p,&length,
sizeof(length));
1551 p+=(ptrdiff_t)
sizeof(length);
1552 count=dpc_send(server_info->file,p-message,message);
1553 if (count != (MagickOffsetType) (p-message))
1555 return(dpc_read(server_info->file,length,pixels));
1582MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1583 DistributeCacheInfo *server_info)
1592 message[MagickPathExtent],
1598 assert(server_info != (DistributeCacheInfo *) NULL);
1599 assert(server_info->signature == MagickCoreSignature);
1602 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1603 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1604 count=dpc_send(server_info->file,p-message,message);
1605 if (count != (MagickOffsetType) (p-message))
1606 return(MagickFalse);
1608 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1609 if (count != (MagickOffsetType)
sizeof(status))
1610 return(MagickFalse);
1647MagickPrivate MagickOffsetType WriteDistributePixelCacheIndexes(
1648 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1649 const MagickSizeType length,
const unsigned char *indexes)
1655 message[MagickPathExtent],
1661 assert(server_info != (DistributeCacheInfo *) NULL);
1662 assert(server_info->signature == MagickCoreSignature);
1663 assert(region != (RectangleInfo *) NULL);
1664 assert(indexes != (
unsigned char *) NULL);
1665 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1669 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1670 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1671 (void) memcpy(p,®ion->width,
sizeof(region->width));
1672 p+=(ptrdiff_t)
sizeof(region->width);
1673 (void) memcpy(p,®ion->height,
sizeof(region->height));
1674 p+=(ptrdiff_t)
sizeof(region->height);
1675 (void) memcpy(p,®ion->x,
sizeof(region->x));
1676 p+=(ptrdiff_t)
sizeof(region->x);
1677 (void) memcpy(p,®ion->y,
sizeof(region->y));
1678 p+=(ptrdiff_t)
sizeof(region->y);
1679 (void) memcpy(p,&length,
sizeof(length));
1680 p+=(ptrdiff_t)
sizeof(length);
1681 count=dpc_send(server_info->file,p-message,message);
1682 if (count != (MagickOffsetType) (p-message))
1684 return(dpc_send(server_info->file,length,indexes));
1721MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1722 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1723 const MagickSizeType length,
const unsigned char *magick_restrict pixels)
1729 message[MagickPathExtent],
1735 assert(server_info != (DistributeCacheInfo *) NULL);
1736 assert(server_info->signature == MagickCoreSignature);
1737 assert(region != (RectangleInfo *) NULL);
1738 assert(pixels != (
const unsigned char *) NULL);
1739 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1743 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1744 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1745 (void) memcpy(p,®ion->width,
sizeof(region->width));
1746 p+=(ptrdiff_t)
sizeof(region->width);
1747 (void) memcpy(p,®ion->height,
sizeof(region->height));
1748 p+=(ptrdiff_t)
sizeof(region->height);
1749 (void) memcpy(p,®ion->x,
sizeof(region->x));
1750 p+=(ptrdiff_t)
sizeof(region->x);
1751 (void) memcpy(p,®ion->y,
sizeof(region->y));
1752 p+=(ptrdiff_t)
sizeof(region->y);
1753 (void) memcpy(p,&length,
sizeof(length));
1754 p+=(ptrdiff_t)
sizeof(length);
1755 count=dpc_send(server_info->file,p-message,message);
1756 if (count != (MagickOffsetType) (p-message))
1758 return(dpc_send(server_info->file,length,pixels));