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/nt-base-private.h"
68#include "MagickCore/pixel.h"
69#include "MagickCore/policy.h"
70#include "MagickCore/random_.h"
71#include "MagickCore/registry.h"
72#include "MagickCore/splay-tree.h"
73#include "MagickCore/string_.h"
74#include "MagickCore/string-private.h"
75#include "MagickCore/utility-private.h"
76#include "MagickCore/version.h"
77#include "MagickCore/version-private.h"
78#define SOCKET_TYPE int
79#undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
80#if defined(MAGICKCORE_DPC_SUPPORT)
81#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
82#include <netinet/in.h>
84#include <sys/socket.h>
86#define CLOSE_SOCKET(socket) (void) close_utf8(socket)
87#define HANDLER_RETURN_TYPE void *
88#define HANDLER_RETURN_VALUE (void *) NULL
89#define SOCKET_TYPE int
90#define LENGTH_TYPE size_t
91#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
92#elif defined(_MSC_VER)
93#define CLOSE_SOCKET(socket) (void) closesocket(socket)
94#define HANDLER_RETURN_TYPE DWORD WINAPI
95#define HANDLER_RETURN_VALUE 0
96#define LENGTH_TYPE int
97#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
98#define MAGICKCORE_HAVE_WINSOCK2 1
105#define DPCHostname "127.0.0.1"
106#define DPCPendingConnections 10
108#define DPCSessionKeyLength 16
110# define MSG_NOSIGNAL 0
116#ifdef MAGICKCORE_HAVE_WINSOCK2
121 *wsaData = (WSADATA*) NULL;
147#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
148static inline MagickOffsetType dpc_read(SOCKET_TYPE magick_unused(file),
149 const MagickSizeType magick_unused(length),
150 unsigned char *magick_restrict magick_unused(message))
152 magick_unreferenced(file);
153 magick_unreferenced(length);
154 magick_unreferenced(message);
158static inline MagickOffsetType dpc_read(SOCKET_TYPE file,
159 const MagickSizeType length,
unsigned char *magick_restrict message)
168 for (i=0; i < (MagickOffsetType) length; i+=count)
170 count=recv(file,(
char *) message+i,(LENGTH_TYPE) MagickMin(length-
171 (MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),0);
183#if defined(MAGICKCORE_HAVE_WINSOCK2)
184static void InitializeWinsock2(MagickBooleanType use_lock)
186 if (use_lock != MagickFalse)
189 ActivateSemaphoreInfo(&winsock2_semaphore);
190 LockSemaphoreInfo(winsock2_semaphore);
192 if (wsaData == (WSADATA *) NULL)
194 wsaData=(WSADATA *) AcquireMagickMemory(
sizeof(WSADATA));
195 if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
196 ThrowFatalException(CacheFatalError,
"WSAStartup failed");
198 if (use_lock != MagickFalse)
199 UnlockSemaphoreInfo(winsock2_semaphore);
203#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
204static int ConnectPixelCacheServer(
const char *magick_unused(hostname),
205 const int magick_unused(port),uint64_t *magick_unused(session_key),
206 ExceptionInfo *exception)
208 magick_unreferenced(hostname);
209 magick_unreferenced(port);
210 magick_unreferenced(session_key);
211 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
212 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
216static inline uint64_t ROTL(uint64_t x,
int b)
218 return((x << b) | (x >> (64-b)));
221static inline uint64_t U8TO64_LE(
const uint8_t *p)
223 return(((uint64_t) p[0] << 0) | ((uint64_t) p[1] << 8) |
224 ((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
225 ((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
226 ((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
229static inline uint64_t SIPHash24(
const uint8_t key[16],
const uint8_t *message,
233 *end = message+length-(length % 8);
239 b = ((uint64_t) length) << 56,
241 k1 = U8TO64_LE(key+8),
243 v0 = 0x736f6d6570736575ULL^k0,
244 v1 = 0x646f72616e646f6dULL^k1,
245 v2 = 0x6c7967656e657261ULL^k0,
246 v3 = 0x7465646279746573ULL^k1;
248 for ( ; message != end; message+=8)
250 m=U8TO64_LE(message);
252 for (i=0; i < 2; i++)
254 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
255 v2+=v3; v3=ROTL(v3,16); v3^=v2;
256 v0+=v3; v3=ROTL(v3,21); v3^=v0;
257 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
261 switch (length & 0x07)
263 case 7: b|=((uint64_t) message[6]) << 48; magick_fallthrough;
264 case 6: b|=((uint64_t) message[5]) << 40; magick_fallthrough;
265 case 5: b|=((uint64_t) message[4]) << 32; magick_fallthrough;
266 case 4: b|=((uint64_t) message[3]) << 24; magick_fallthrough;
267 case 3: b|=((uint64_t) message[2]) << 16; magick_fallthrough;
268 case 2: b|=((uint64_t) message[1]) << 8; magick_fallthrough;
269 case 1: b|=((uint64_t) message[0]); magick_fallthrough;
273 for (i=0; i < 2; i++)
275 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
276 v2+=v3; v3=ROTL(v3,16); v3^=v2;
277 v0+=v3; v3=ROTL(v3,21); v3^=v0;
278 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
282 for (i=0; i < 4; i++)
284 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
285 v2+=v3; v3=ROTL(v3,16); v3^=v2;
286 v0+=v3; v3=ROTL(v3,21); v3^=v0;
287 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
292static inline void DeriveSipKeyFromSecret(
const char *shared_secret,
300 k0 = 0x0706050403020100ULL,
301 k1 = 0x0f0e0d0c0b0a0908ULL;
303 length=strlen(shared_secret);
304 for (i=0; i < length; i++)
307 b = shared_secret[i];
310 k0*=0x100000001b3ULL;
311 k1^=(uint64_t) b << ((i & 7)*8);
312 k1=(k1 << 5) | (k1 >> (64-5));
314 (void) memcpy(key,&k0,8);
315 (void) memcpy(key+8,&k1,8);
318static inline uint64_t GenerateSessionKey(
const char *shared_secret,
319 const unsigned char *nonce,
size_t length)
324 DeriveSipKeyFromSecret(shared_secret,key);
325 return(SIPHash24(key,nonce,length));
328static int ConnectPixelCacheServer(
const char *hostname,
const int port,
329 uint64_t *session_key,ExceptionInfo *exception)
331#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
333 service[MagickPathExtent],
350 nonce[DPCSessionKeyLength];
356#if defined(MAGICKCORE_HAVE_WINSOCK2)
357 InitializeWinsock2(MagickTrue);
359 (void) memset(&hints,0,
sizeof(hints));
360 hints.ai_family=AF_INET;
361 hints.ai_socktype=SOCK_STREAM;
362 hints.ai_flags=AI_PASSIVE;
363 (void) FormatLocaleString(service,MagickPathExtent,
"%d",port);
364 status=getaddrinfo(hostname,service,&hints,&result);
367 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
368 "DistributedPixelCache",
"'%s': %s",hostname,gai_strerror(status));
371 client_socket=(SOCKET_TYPE) socket(result->ai_family,result->ai_socktype,
372 result->ai_protocol);
373 if (client_socket == -1)
375 freeaddrinfo(result);
376 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
377 "DistributedPixelCache",
"'%s': %s",hostname,GetExceptionMessage(errno));
380 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
381 freeaddrinfo(result);
384 CLOSE_SOCKET(client_socket);
385 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
386 "DistributedPixelCache",
"'%s': %s",hostname,GetExceptionMessage(errno));
392 count=recv(client_socket,(
char *) nonce,
sizeof(nonce),0);
393 if (count != (ssize_t)
sizeof(nonce))
395 CLOSE_SOCKET(client_socket);
396 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
397 "DistributedPixelCache",
"'%s': %s",hostname,GetExceptionMessage(errno));
403 shared_secret=GetPolicyValue(
"cache:shared-secret");
404 if (shared_secret == (
char*) NULL)
406 CLOSE_SOCKET(client_socket);
407 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
408 "DistributedPixelCache",
"'%s': shared secret required",hostname);
411 *session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
412 shared_secret=DestroyString(shared_secret);
416 count=send(client_socket,(
char *) session_key,
sizeof(*session_key),
418 if (count != (ssize_t)
sizeof(*session_key))
420 CLOSE_SOCKET(client_socket);
421 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
422 "DistributedPixelCache",
"'%s': authentication failed",hostname);
425 return((
int) client_socket);
427 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
428 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
434static char *GetHostname(
int *port,ExceptionInfo *exception)
453 hosts=(
char *) GetImageRegistry(StringRegistryType,
"cache:hosts",exception);
454 if (hosts == (
char *) NULL)
457 return(AcquireString(DPCHostname));
459 (void) SubstituteString(&hosts,
",",
" ");
460 hostlist=StringToArgv(hosts,&argc);
461 hosts=DestroyString(hosts);
462 if (hostlist == (
char **) NULL)
465 return(AcquireString(DPCHostname));
468 size_t host_count = (size_t) argc-1;
469 size_t index = (
id++ % host_count)+1;
470 hosts=AcquireString(hostlist[index]);
472 for (i=0; i < (ssize_t) argc; i++)
473 hostlist[i]=DestroyString(hostlist[i]);
474 hostlist=(
char **) RelinquishMagickMemory(hostlist);
475 (void) SubstituteString(&hosts,
":",
" ");
476 hostlist=StringToArgv(hosts,&argc);
477 if (hostlist == (
char **) NULL)
480 return(AcquireString(DPCHostname));
482 host=AcquireString(hostlist[1]);
483 if (hostlist[2] == (
char *) NULL)
486 *port=StringToLong(hostlist[2]);
487 for (i=0; i < (ssize_t) argc; i++)
488 hostlist[i]=DestroyString(hostlist[i]);
489 hostlist=(
char **) RelinquishMagickMemory(hostlist);
493MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
494 ExceptionInfo *exception)
508 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
509 sizeof(*server_info));
510 (void) memset(server_info,0,
sizeof(*server_info));
511 server_info->signature=MagickCoreSignature;
513 hostname=GetHostname(&server_info->port,exception);
515 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
516 &session_key,exception);
517 if (server_info->file == -1)
518 server_info=DestroyDistributeCacheInfo(server_info);
521 server_info->session_key=session_key;
522 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
523 server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
526 hostname=DestroyString(hostname);
554MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
555 DistributeCacheInfo *server_info)
557 assert(server_info != (DistributeCacheInfo *) NULL);
558 assert(server_info->signature == MagickCoreSignature);
559#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
560 if (server_info->file >= 0)
561 CLOSE_SOCKET(server_info->file);
563 server_info->signature=(~MagickCoreSignature);
564 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
594#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
595static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
596 const MagickSizeType magick_unused(length),
597 const void *magick_restrict magick_unused(message))
599 magick_unreferenced(file);
600 magick_unreferenced(length);
601 magick_unreferenced(message);
605static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
606 const MagickSizeType length,
const void *magick_restrict message)
618 for (i=0; i < (MagickOffsetType) length; i+=count)
620 count=(ssize_t) send(file,(
char *) message+i,(LENGTH_TYPE) MagickMin(
621 length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
634#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
635MagickExport
void DistributePixelCacheServer(
const int magick_unused(port),
636 ExceptionInfo *magick_unused(exception))
638 magick_unreferenced(port);
639 magick_unreferenced(exception);
640 ThrowFatalException(MissingDelegateError,
"DelegateLibrarySupportNotBuiltIn");
643static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
644 const uint64_t session_key)
647 key = (MagickAddressType) session_key;
652 return(DeleteNodeFromSplayTree(registry,(
const void *) key));
655static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
656 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
662 key = (MagickAddressType) session_key;
674 message[MagickPathExtent],
680 image=AcquireImage((ImageInfo *) NULL,exception);
681 if (image == (Image *) NULL)
683 length=
sizeof(image->storage_class)+
sizeof(image->colorspace)+
684 sizeof(image->alpha_trait)+
sizeof(image->channels)+
sizeof(image->columns)+
685 sizeof(image->rows)+
sizeof(image->number_channels)+MaxPixelChannels*
686 sizeof(*image->channel_map)+
sizeof(image->metacontent_extent);
687 count=dpc_read(file,length,message);
688 if (count != (MagickOffsetType) length)
690 image=DestroyImage(image);
697 (void) memcpy(&image->storage_class,p,
sizeof(image->storage_class));
698 p+=(ptrdiff_t)
sizeof(image->storage_class);
699 (void) memcpy(&image->colorspace,p,
sizeof(image->colorspace));
700 p+=(ptrdiff_t)
sizeof(image->colorspace);
701 (void) memcpy(&image->alpha_trait,p,
sizeof(image->alpha_trait));
702 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
703 (void) memcpy(&image->channels,p,
sizeof(image->channels));
704 p+=(ptrdiff_t)
sizeof(image->channels);
705 (void) memcpy(&image->columns,p,
sizeof(image->columns));
706 p+=(ptrdiff_t)
sizeof(image->columns);
707 (void) memcpy(&image->rows,p,
sizeof(image->rows));
708 p+=(ptrdiff_t)
sizeof(image->rows);
709 (void) memcpy(&image->number_channels,p,
sizeof(image->number_channels));
710 p+=(ptrdiff_t)
sizeof(image->number_channels);
711 (void) memcpy(image->channel_map,p,MaxPixelChannels*
712 sizeof(*image->channel_map));
713 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
714 (void) memcpy(&image->metacontent_extent,p,
sizeof(image->metacontent_extent));
715 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
716 if (SyncImagePixelCache(image,exception) == MagickFalse)
718 image=DestroyImage(image);
721 status=AddValueToSplayTree(registry,(
const void *) key,image);
722 if (status == MagickFalse)
724 image=DestroyImage(image);
730static inline MagickBooleanType ValidateDistributedPixelCache(
731 const RectangleInfo *region,
const size_t per_pixel,
732 const MagickSizeType length)
738 if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
740 if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
742 if (length > (MagickSizeType) extent)
747static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
748 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
760 key = (MagickAddressType) session_key;
775 message[MagickPathExtent],
781 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
782 if (image == (Image *) NULL)
784 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
785 sizeof(region.y)+
sizeof(length);
786 count=dpc_read(file,length,message);
787 if (count != (MagickOffsetType) length)
790 (void) memcpy(®ion.width,q,
sizeof(region.width));
791 q+=(ptrdiff_t)
sizeof(region.width);
792 (void) memcpy(®ion.height,q,
sizeof(region.height));
793 q+=(ptrdiff_t)
sizeof(region.height);
794 (void) memcpy(®ion.x,q,
sizeof(region.x));
795 q+=(ptrdiff_t)
sizeof(region.x);
796 (void) memcpy(®ion.y,q,
sizeof(region.y));
797 q+=(ptrdiff_t)
sizeof(region.y);
798 (void) memcpy(&length,q,
sizeof(length));
799 q+=(ptrdiff_t)
sizeof(length);
800 per_pixel=image->number_meta_channels*
sizeof(Quantum);
801 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
803 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
805 if (p == (
const Quantum *) NULL)
807 metacontent=(
const unsigned char *) GetVirtualMetacontent(image);
808 count=dpc_send(file,length,metacontent);
809 if (count != (MagickOffsetType) length)
814static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
815 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
824 key = (MagickAddressType) session_key;
839 message[MagickPathExtent],
845 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
846 if (image == (Image *) NULL)
848 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
849 sizeof(region.y)+
sizeof(length);
850 count=dpc_read(file,length,message);
851 if (count != (MagickOffsetType) length)
854 (void) memcpy(®ion.width,q,
sizeof(region.width));
855 q+=(ptrdiff_t)
sizeof(region.width);
856 (void) memcpy(®ion.height,q,
sizeof(region.height));
857 q+=(ptrdiff_t)
sizeof(region.height);
858 (void) memcpy(®ion.x,q,
sizeof(region.x));
859 q+=(ptrdiff_t)
sizeof(region.x);
860 (void) memcpy(®ion.y,q,
sizeof(region.y));
861 q+=(ptrdiff_t)
sizeof(region.y);
862 (void) memcpy(&length,q,
sizeof(length));
863 per_pixel=image->number_channels*
sizeof(Quantum);
864 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
866 q+=(ptrdiff_t)
sizeof(length);
867 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
869 if (p == (
const Quantum *) NULL)
871 count=dpc_send(file,length,p);
872 if (count != (MagickOffsetType) length)
877static void *RelinquishImageRegistry(
void *image)
879 return((
void *) DestroyImageList((Image *) image));
882static MagickBooleanType WriteDistributeCacheMetacontent(
883 SplayTreeInfo *registry,SOCKET_TYPE file,
const uint64_t session_key,
884 ExceptionInfo *exception)
890 key = (MagickAddressType) session_key;
908 message[MagickPathExtent],
915 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
916 if (image == (Image *) NULL)
918 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
919 sizeof(region.y)+
sizeof(length);
920 count=dpc_read(file,length,message);
921 if (count != (MagickOffsetType) length)
924 (void) memcpy(®ion.width,p,
sizeof(region.width));
925 p+=(ptrdiff_t)
sizeof(region.width);
926 (void) memcpy(®ion.height,p,
sizeof(region.height));
927 p+=(ptrdiff_t)
sizeof(region.height);
928 (void) memcpy(®ion.x,p,
sizeof(region.x));
929 p+=(ptrdiff_t)
sizeof(region.x);
930 (void) memcpy(®ion.y,p,
sizeof(region.y));
931 p+=(ptrdiff_t)
sizeof(region.y);
932 (void) memcpy(&length,p,
sizeof(length));
933 per_pixel=image->number_meta_channels*
sizeof(Quantum);
934 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
936 p+=(ptrdiff_t)
sizeof(length);
937 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
939 if (q == (Quantum *) NULL)
941 metacontent=(
unsigned char *) GetAuthenticMetacontent(image);
942 count=dpc_read(file,length,metacontent);
943 if (count != (MagickOffsetType) length)
945 return(SyncAuthenticPixels(image,exception));
948static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
949 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
955 key = (MagickAddressType) session_key;
973 message[MagickPathExtent],
979 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
980 if (image == (Image *) NULL)
982 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
983 sizeof(region.y)+
sizeof(length);
984 count=dpc_read(file,length,message);
985 if (count != (MagickOffsetType) length)
988 (void) memcpy(®ion.width,p,
sizeof(region.width));
989 p+=(ptrdiff_t)
sizeof(region.width);
990 (void) memcpy(®ion.height,p,
sizeof(region.height));
991 p+=(ptrdiff_t)
sizeof(region.height);
992 (void) memcpy(®ion.x,p,
sizeof(region.x));
993 p+=(ptrdiff_t)
sizeof(region.x);
994 (void) memcpy(®ion.y,p,
sizeof(region.y));
995 p+=(ptrdiff_t)
sizeof(region.y);
996 (void) memcpy(&length,p,
sizeof(length));
997 per_pixel=image->number_channels*
sizeof(Quantum);
998 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
1000 p+=(ptrdiff_t)
sizeof(length);
1001 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1003 if (q == (Quantum *) NULL)
1004 return(MagickFalse);
1005 count=dpc_read(file,length,(
unsigned char *) q);
1006 if (count != (MagickOffsetType) length)
1007 return(MagickFalse);
1008 return(SyncAuthenticPixels(image,exception));
1011static HANDLER_RETURN_TYPE DistributePixelCacheClient(
void *socket_arg)
1020 status = MagickFalse;
1030 *client_socket_ptr = (SOCKET_TYPE *) socket_arg;
1044 nonce[DPCSessionKeyLength];
1049 client_socket=(*client_socket_ptr);
1050 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
1051 shared_secret=GetPolicyValue(
"cache:shared-secret");
1052 if (shared_secret == NULL)
1053 ThrowFatalException(CacheFatalError,
"shared secret required");
1057 random_info=AcquireRandomInfo();
1058 entropy=GetRandomKey(random_info,
sizeof(nonce));
1059 (void) memcpy(nonce,GetStringInfoDatum(entropy),
sizeof(nonce));
1060 entropy=DestroyStringInfo(entropy);
1061 random_info=DestroyRandomInfo(random_info);
1065 session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
1066 shared_secret=DestroyString(shared_secret);
1070 count=dpc_send(client_socket,
sizeof(nonce),nonce);
1071 if (count != (MagickOffsetType)
sizeof(nonce))
1073 CLOSE_SOCKET(client_socket);
1074 return(HANDLER_RETURN_VALUE);
1079 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1080 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1082 CLOSE_SOCKET(client_socket);
1083 return(HANDLER_RETURN_VALUE);
1085 exception=AcquireExceptionInfo();
1086 registry=NewSplayTree((
int (*)(
const void *,
const void *)) NULL,
1087 (
void *(*)(
void *)) NULL,RelinquishImageRegistry);
1091 for (status=MagickFalse; ; )
1096 count=dpc_read(client_socket,1,(
unsigned char *) &command);
1099 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1100 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1106 status=OpenDistributeCache(registry,client_socket,session_key,
1108 dpc_send(client_socket,
sizeof(status),&status);
1113 status=ReadDistributeCachePixels(registry,client_socket,session_key,
1119 status=ReadDistributeCacheMetacontent(registry,client_socket,
1120 session_key,exception);
1125 status=WriteDistributeCachePixels(registry,client_socket,session_key,
1131 status=WriteDistributeCacheMetacontent(registry,client_socket,
1132 session_key,exception);
1137 status=DestroyDistributeCache(registry,session_key);
1143 if ((status == MagickFalse) || (command ==
'd'))
1146 count=dpc_send(client_socket,
sizeof(status),&status);
1147 CLOSE_SOCKET(client_socket);
1148 exception=DestroyExceptionInfo(exception);
1149 registry=DestroySplayTree(registry);
1150 return(HANDLER_RETURN_VALUE);
1153MagickExport
void DistributePixelCacheServer(
const int port,
1154 ExceptionInfo *exception)
1157 service[MagickPathExtent];
1162#if defined(MAGICKCORE_THREAD_SUPPORT)
1168#elif defined(_MSC_VER)
1191 assert(exception != (ExceptionInfo *) NULL);
1192 assert(exception->signature == MagickCoreSignature);
1193 magick_unreferenced(exception);
1194#if defined(MAGICKCORE_HAVE_WINSOCK2)
1195 InitializeWinsock2(MagickFalse);
1197 (void) memset(&hint,0,
sizeof(hint));
1198 hint.ai_family=AF_INET;
1199 hint.ai_socktype=SOCK_STREAM;
1200 hint.ai_flags=AI_PASSIVE;
1201 FormatLocaleString(service,MagickPathExtent,
"%d",port);
1202 status=getaddrinfo(NULL,service,&hint,&result);
1204 ThrowFatalException(CacheFatalError,
"UnableToListen");
1205 server_socket=(SOCKET_TYPE) 0;
1206 for (p=result; p != NULL; p=p->ai_next)
1211 server_socket=(SOCKET_TYPE) socket(p->ai_family,p->ai_socktype,
1213 if (server_socket == -1)
1215 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(
char *) &one,
1216 (socklen_t)
sizeof(one));
1219#if defined(MAGICKCORE_HAVE_WINSOCK2)
1220 DWORD timeout = 5000;
1221 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,(
const char *)
1222 &timeout,
sizeof(timeout));
1227 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,&tv,
sizeof(tv));
1232 CLOSE_SOCKET(server_socket);
1235 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1238 CLOSE_SOCKET(server_socket);
1243 if (p == (
struct addrinfo *) NULL)
1244 ThrowFatalException(CacheFatalError,
"UnableToBind");
1245 freeaddrinfo(result);
1246 status=listen(server_socket,DPCPendingConnections);
1248 ThrowFatalException(CacheFatalError,
"UnableToListen");
1249#if defined(MAGICKCORE_THREAD_SUPPORT)
1250 pthread_attr_init(&attributes);
1251 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1259 length = (socklen_t)
sizeof(address);
1261 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(
sizeof(SOCKET_TYPE));
1262 if (client_socket_ptr == NULL)
1264 *client_socket_ptr=(SOCKET_TYPE) accept(server_socket,(
struct sockaddr *)
1266 if (*client_socket_ptr == -1)
1268 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1272#if defined(MAGICKCORE_THREAD_SUPPORT)
1273 status=pthread_create(&thread_id,&attributes,DistributePixelCacheClient,
1274 (
void *) client_socket_ptr);
1277 CLOSE_SOCKET(*client_socket_ptr);
1278 RelinquishMagickMemory(client_socket_ptr);
1279 ThrowFatalException(CacheFatalError,
"UnableToCreateClientThread");
1281#elif defined(_MSC_VER)
1282 if (CreateThread(0,0,DistributePixelCacheClient,(
void*) client_socket_ptr,0,&threadID) == (HANDLE) NULL)
1284 CLOSE_SOCKET(*client_socket_ptr);
1285 RelinquishMagickMemory(client_socket_ptr);
1286 ThrowFatalException(CacheFatalError,
"UnableToCreateClientThread");
1309MagickPrivate
void DistributeCacheTerminus(
void)
1311#ifdef MAGICKCORE_HAVE_WINSOCK2
1313 ActivateSemaphoreInfo(&winsock2_semaphore);
1314 LockSemaphoreInfo(winsock2_semaphore);
1315 if (wsaData != (WSADATA *) NULL)
1318 wsaData=(WSADATA *) RelinquishMagickMemory((
void *) wsaData);
1320 UnlockSemaphoreInfo(winsock2_semaphore);
1321 RelinquishSemaphoreInfo(&winsock2_semaphore);
1348MagickPrivate
int GetDistributeCacheFile(
const DistributeCacheInfo *server_info)
1350 assert(server_info != (DistributeCacheInfo *) NULL);
1351 assert(server_info->signature == MagickCoreSignature);
1352 return(server_info->file);
1379MagickPrivate
const char *GetDistributeCacheHostname(
1380 const DistributeCacheInfo *server_info)
1382 assert(server_info != (DistributeCacheInfo *) NULL);
1383 assert(server_info->signature == MagickCoreSignature);
1384 return(server_info->hostname);
1410MagickPrivate
int GetDistributeCachePort(
const DistributeCacheInfo *server_info)
1412 assert(server_info != (DistributeCacheInfo *) NULL);
1413 assert(server_info->signature == MagickCoreSignature);
1414 return(server_info->port);
1442MagickPrivate MagickBooleanType OpenDistributePixelCache(
1443 DistributeCacheInfo *server_info,Image *image)
1452 message[MagickPathExtent],
1458 assert(server_info != (DistributeCacheInfo *) NULL);
1459 assert(server_info->signature == MagickCoreSignature);
1460 assert(image != (Image *) NULL);
1461 assert(image->signature == MagickCoreSignature);
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,&image->storage_class,
sizeof(image->storage_class));
1470 p+=(ptrdiff_t)
sizeof(image->storage_class);
1471 (void) memcpy(p,&image->colorspace,
sizeof(image->colorspace));
1472 p+=(ptrdiff_t)
sizeof(image->colorspace);
1473 (void) memcpy(p,&image->alpha_trait,
sizeof(image->alpha_trait));
1474 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
1475 (void) memcpy(p,&image->channels,
sizeof(image->channels));
1476 p+=(ptrdiff_t)
sizeof(image->channels);
1477 (void) memcpy(p,&image->columns,
sizeof(image->columns));
1478 p+=(ptrdiff_t)
sizeof(image->columns);
1479 (void) memcpy(p,&image->rows,
sizeof(image->rows));
1480 p+=(ptrdiff_t)
sizeof(image->rows);
1481 (void) memcpy(p,&image->number_channels,
sizeof(image->number_channels));
1482 p+=(ptrdiff_t)
sizeof(image->number_channels);
1483 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1484 sizeof(*image->channel_map));
1485 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
1486 (void) memcpy(p,&image->metacontent_extent,
sizeof(image->metacontent_extent));
1487 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
1488 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1489 if (count != (MagickOffsetType) (p-message))
1490 return(MagickFalse);
1492 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1493 if (count != (MagickOffsetType)
sizeof(status))
1494 return(MagickFalse);
1531MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1532 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1533 const MagickSizeType length,
unsigned char *metacontent)
1539 message[MagickPathExtent],
1545 assert(server_info != (DistributeCacheInfo *) NULL);
1546 assert(server_info->signature == MagickCoreSignature);
1547 assert(region != (RectangleInfo *) NULL);
1548 assert(metacontent != (
unsigned char *) NULL);
1549 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1553 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1554 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1555 (void) memcpy(p,®ion->width,
sizeof(region->width));
1556 p+=(ptrdiff_t)
sizeof(region->width);
1557 (void) memcpy(p,®ion->height,
sizeof(region->height));
1558 p+=(ptrdiff_t)
sizeof(region->height);
1559 (void) memcpy(p,®ion->x,
sizeof(region->x));
1560 p+=(ptrdiff_t)
sizeof(region->x);
1561 (void) memcpy(p,®ion->y,
sizeof(region->y));
1562 p+=(ptrdiff_t)
sizeof(region->y);
1563 (void) memcpy(p,&length,
sizeof(length));
1564 p+=(ptrdiff_t)
sizeof(length);
1565 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1566 if (count != (MagickOffsetType) (p-message))
1568 return(dpc_read(server_info->file,length,metacontent));
1604MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1605 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1606 const MagickSizeType length,
unsigned char *magick_restrict pixels)
1612 message[MagickPathExtent],
1618 assert(server_info != (DistributeCacheInfo *) NULL);
1619 assert(server_info->signature == MagickCoreSignature);
1620 assert(region != (RectangleInfo *) NULL);
1621 assert(pixels != (
unsigned char *) NULL);
1622 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1626 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1627 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1628 (void) memcpy(p,®ion->width,
sizeof(region->width));
1629 p+=(ptrdiff_t)
sizeof(region->width);
1630 (void) memcpy(p,®ion->height,
sizeof(region->height));
1631 p+=(ptrdiff_t)
sizeof(region->height);
1632 (void) memcpy(p,®ion->x,
sizeof(region->x));
1633 p+=(ptrdiff_t)
sizeof(region->x);
1634 (void) memcpy(p,®ion->y,
sizeof(region->y));
1635 p+=(ptrdiff_t)
sizeof(region->y);
1636 (void) memcpy(p,&length,
sizeof(length));
1637 p+=(ptrdiff_t)
sizeof(length);
1638 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1639 if (count != (MagickOffsetType) (p-message))
1641 return(dpc_read(server_info->file,length,pixels));
1668MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1669 DistributeCacheInfo *server_info)
1678 message[MagickPathExtent],
1684 assert(server_info != (DistributeCacheInfo *) NULL);
1685 assert(server_info->signature == MagickCoreSignature);
1688 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1689 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1690 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1691 if (count != (MagickOffsetType) (p-message))
1692 return(MagickFalse);
1694 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1695 if (count != (MagickOffsetType)
sizeof(status))
1696 return(MagickFalse);
1733MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1734 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1735 const MagickSizeType length,
const unsigned char *metacontent)
1741 message[MagickPathExtent],
1747 assert(server_info != (DistributeCacheInfo *) NULL);
1748 assert(server_info->signature == MagickCoreSignature);
1749 assert(region != (RectangleInfo *) NULL);
1750 assert(metacontent != (
unsigned char *) NULL);
1751 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1755 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1756 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1757 (void) memcpy(p,®ion->width,
sizeof(region->width));
1758 p+=(ptrdiff_t)
sizeof(region->width);
1759 (void) memcpy(p,®ion->height,
sizeof(region->height));
1760 p+=(ptrdiff_t)
sizeof(region->height);
1761 (void) memcpy(p,®ion->x,
sizeof(region->x));
1762 p+=(ptrdiff_t)
sizeof(region->x);
1763 (void) memcpy(p,®ion->y,
sizeof(region->y));
1764 p+=(ptrdiff_t)
sizeof(region->y);
1765 (void) memcpy(p,&length,
sizeof(length));
1766 p+=(ptrdiff_t)
sizeof(length);
1767 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1768 if (count != (MagickOffsetType) (p-message))
1770 return(dpc_send(server_info->file,length,metacontent));
1807MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1808 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1809 const MagickSizeType length,
const unsigned char *magick_restrict pixels)
1815 message[MagickPathExtent],
1821 assert(server_info != (DistributeCacheInfo *) NULL);
1822 assert(server_info->signature == MagickCoreSignature);
1823 assert(region != (RectangleInfo *) NULL);
1824 assert(pixels != (
const unsigned char *) NULL);
1825 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1829 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1830 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1831 (void) memcpy(p,®ion->width,
sizeof(region->width));
1832 p+=(ptrdiff_t)
sizeof(region->width);
1833 (void) memcpy(p,®ion->height,
sizeof(region->height));
1834 p+=(ptrdiff_t)
sizeof(region->height);
1835 (void) memcpy(p,®ion->x,
sizeof(region->x));
1836 p+=(ptrdiff_t)
sizeof(region->x);
1837 (void) memcpy(p,®ion->y,
sizeof(region->y));
1838 p+=(ptrdiff_t)
sizeof(region->y);
1839 (void) memcpy(p,&length,
sizeof(length));
1840 p+=(ptrdiff_t)
sizeof(length);
1841 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1842 if (count != (MagickOffsetType) (p-message))
1844 return(dpc_send(server_info->file,length,pixels));