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)
334 service[MagickPathExtent],
351 nonce[DPCSessionKeyLength];
357#if defined(MAGICKCORE_HAVE_WINSOCK2)
358 InitializeWinsock2(MagickTrue);
360 (void) memset(&hints,0,
sizeof(hints));
361 hints.ai_family=AF_INET;
362 hints.ai_socktype=SOCK_STREAM;
363 hints.ai_flags=AI_PASSIVE;
364 (void) FormatLocaleString(service,MagickPathExtent,
"%d",port);
365 status=getaddrinfo(hostname,service,&hints,&result);
368 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
369 "DistributedPixelCache",
"'%s': %s",hostname,gai_strerror(status));
372 client_socket=(SOCKET_TYPE) socket(result->ai_family,result->ai_socktype,
373 result->ai_protocol);
374 if (client_socket == -1)
376 freeaddrinfo(result);
377 message=GetExceptionMessage(errno);
378 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
379 "DistributedPixelCache",
"'%s': %s",hostname,message);
380 message=DestroyString(message);
383 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
384 freeaddrinfo(result);
387 CLOSE_SOCKET(client_socket);
388 message=GetExceptionMessage(errno);
389 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
390 "DistributedPixelCache",
"'%s': %s",hostname,message);
391 message=DestroyString(message);
397 count=recv(client_socket,(
char *) nonce,
sizeof(nonce),0);
398 if (count != (ssize_t)
sizeof(nonce))
400 CLOSE_SOCKET(client_socket);
401 message=GetExceptionMessage(errno);
402 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
403 "DistributedPixelCache",
"'%s': %s",hostname,message);
404 message=DestroyString(message);
410 shared_secret=GetPolicyValue(
"cache:shared-secret");
411 if (shared_secret == (
char*) NULL)
413 CLOSE_SOCKET(client_socket);
414 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
415 "DistributedPixelCache",
"'%s': shared secret required",hostname);
418 *session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
419 shared_secret=DestroyString(shared_secret);
423 count=send(client_socket,(
char *) session_key,
sizeof(*session_key),
425 if (count != (ssize_t)
sizeof(*session_key))
427 CLOSE_SOCKET(client_socket);
428 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
429 "DistributedPixelCache",
"'%s': authentication failed",hostname);
432 return((
int) client_socket);
434 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
435 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
441static char *GetHostname(
int *port,ExceptionInfo *exception)
460 hosts=(
char *) GetImageRegistry(StringRegistryType,
"cache:hosts",exception);
461 if (hosts == (
char *) NULL)
464 return(AcquireString(DPCHostname));
466 (void) SubstituteString(&hosts,
",",
" ");
467 hostlist=StringToArgv(hosts,&argc);
468 hosts=DestroyString(hosts);
469 if (hostlist == (
char **) NULL)
472 return(AcquireString(DPCHostname));
475 size_t host_count = (size_t) argc-1;
476 size_t index = (
id++ % host_count)+1;
477 hosts=AcquireString(hostlist[index]);
479 for (i=0; i < (ssize_t) argc; i++)
480 hostlist[i]=DestroyString(hostlist[i]);
481 hostlist=(
char **) RelinquishMagickMemory(hostlist);
482 (void) SubstituteString(&hosts,
":",
" ");
483 hostlist=StringToArgv(hosts,&argc);
484 if (hostlist == (
char **) NULL)
487 return(AcquireString(DPCHostname));
489 host=AcquireString(hostlist[1]);
490 if (hostlist[2] == (
char *) NULL)
493 *port=StringToLong(hostlist[2]);
494 for (i=0; i < (ssize_t) argc; i++)
495 hostlist[i]=DestroyString(hostlist[i]);
496 hostlist=(
char **) RelinquishMagickMemory(hostlist);
500MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
501 ExceptionInfo *exception)
515 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
516 sizeof(*server_info));
517 (void) memset(server_info,0,
sizeof(*server_info));
518 server_info->signature=MagickCoreSignature;
520 hostname=GetHostname(&server_info->port,exception);
522 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
523 &session_key,exception);
524 if (server_info->file == -1)
525 server_info=DestroyDistributeCacheInfo(server_info);
528 server_info->session_key=session_key;
529 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
530 server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
533 hostname=DestroyString(hostname);
561MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
562 DistributeCacheInfo *server_info)
564 assert(server_info != (DistributeCacheInfo *) NULL);
565 assert(server_info->signature == MagickCoreSignature);
566#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
567 if (server_info->file >= 0)
568 CLOSE_SOCKET(server_info->file);
570 server_info->signature=(~MagickCoreSignature);
571 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
601#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
602static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
603 const MagickSizeType magick_unused(length),
604 const void *magick_restrict magick_unused(message))
606 magick_unreferenced(file);
607 magick_unreferenced(length);
608 magick_unreferenced(message);
612static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
613 const MagickSizeType length,
const void *magick_restrict message)
625 for (i=0; i < (MagickOffsetType) length; i+=count)
627 count=(ssize_t) send(file,(
char *) message+i,(LENGTH_TYPE) MagickMin(
628 length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
641#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
642MagickExport
void DistributePixelCacheServer(
const int magick_unused(port),
643 ExceptionInfo *magick_unused(exception))
645 magick_unreferenced(port);
646 magick_unreferenced(exception);
647 ThrowFatalException(MissingDelegateError,
"DelegateLibrarySupportNotBuiltIn");
650static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
651 const uint64_t session_key)
654 key = (MagickAddressType) session_key;
659 return(DeleteNodeFromSplayTree(registry,(
const void *) key));
662static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
663 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
669 key = (MagickAddressType) session_key;
681 message[MagickPathExtent],
687 image=AcquireImage((ImageInfo *) NULL,exception);
688 if (image == (Image *) NULL)
690 length=
sizeof(image->storage_class)+
sizeof(image->colorspace)+
691 sizeof(image->alpha_trait)+
sizeof(image->channels)+
sizeof(image->columns)+
692 sizeof(image->rows)+
sizeof(image->number_channels)+MaxPixelChannels*
693 sizeof(*image->channel_map)+
sizeof(image->metacontent_extent);
694 count=dpc_read(file,length,message);
695 if (count != (MagickOffsetType) length)
697 image=DestroyImage(image);
704 (void) memcpy(&image->storage_class,p,
sizeof(image->storage_class));
705 p+=(ptrdiff_t)
sizeof(image->storage_class);
706 (void) memcpy(&image->colorspace,p,
sizeof(image->colorspace));
707 p+=(ptrdiff_t)
sizeof(image->colorspace);
708 (void) memcpy(&image->alpha_trait,p,
sizeof(image->alpha_trait));
709 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
710 (void) memcpy(&image->channels,p,
sizeof(image->channels));
711 p+=(ptrdiff_t)
sizeof(image->channels);
712 (void) memcpy(&image->columns,p,
sizeof(image->columns));
713 p+=(ptrdiff_t)
sizeof(image->columns);
714 (void) memcpy(&image->rows,p,
sizeof(image->rows));
715 p+=(ptrdiff_t)
sizeof(image->rows);
716 (void) memcpy(&image->number_channels,p,
sizeof(image->number_channels));
717 p+=(ptrdiff_t)
sizeof(image->number_channels);
718 (void) memcpy(image->channel_map,p,MaxPixelChannels*
719 sizeof(*image->channel_map));
720 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
721 (void) memcpy(&image->metacontent_extent,p,
sizeof(image->metacontent_extent));
722 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
723 if (SyncImagePixelCache(image,exception) == MagickFalse)
725 image=DestroyImage(image);
728 status=AddValueToSplayTree(registry,(
const void *) key,image);
729 if (status == MagickFalse)
731 image=DestroyImage(image);
737static inline MagickBooleanType ValidateDistributedPixelCache(
738 const RectangleInfo *region,
const size_t per_pixel,
739 const MagickSizeType length)
745 if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
747 if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
749 if (length > (MagickSizeType) extent)
754static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
755 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
767 key = (MagickAddressType) session_key;
782 message[MagickPathExtent],
788 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
789 if (image == (Image *) NULL)
791 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
792 sizeof(region.y)+
sizeof(length);
793 count=dpc_read(file,length,message);
794 if (count != (MagickOffsetType) length)
797 (void) memcpy(®ion.width,q,
sizeof(region.width));
798 q+=(ptrdiff_t)
sizeof(region.width);
799 (void) memcpy(®ion.height,q,
sizeof(region.height));
800 q+=(ptrdiff_t)
sizeof(region.height);
801 (void) memcpy(®ion.x,q,
sizeof(region.x));
802 q+=(ptrdiff_t)
sizeof(region.x);
803 (void) memcpy(®ion.y,q,
sizeof(region.y));
804 q+=(ptrdiff_t)
sizeof(region.y);
805 (void) memcpy(&length,q,
sizeof(length));
806 q+=(ptrdiff_t)
sizeof(length);
807 per_pixel=image->number_meta_channels*
sizeof(Quantum);
808 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
810 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
812 if (p == (
const Quantum *) NULL)
814 metacontent=(
const unsigned char *) GetVirtualMetacontent(image);
815 count=dpc_send(file,length,metacontent);
816 if (count != (MagickOffsetType) length)
821static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
822 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
831 key = (MagickAddressType) session_key;
846 message[MagickPathExtent],
852 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
853 if (image == (Image *) NULL)
855 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
856 sizeof(region.y)+
sizeof(length);
857 count=dpc_read(file,length,message);
858 if (count != (MagickOffsetType) length)
861 (void) memcpy(®ion.width,q,
sizeof(region.width));
862 q+=(ptrdiff_t)
sizeof(region.width);
863 (void) memcpy(®ion.height,q,
sizeof(region.height));
864 q+=(ptrdiff_t)
sizeof(region.height);
865 (void) memcpy(®ion.x,q,
sizeof(region.x));
866 q+=(ptrdiff_t)
sizeof(region.x);
867 (void) memcpy(®ion.y,q,
sizeof(region.y));
868 q+=(ptrdiff_t)
sizeof(region.y);
869 (void) memcpy(&length,q,
sizeof(length));
870 per_pixel=image->number_channels*
sizeof(Quantum);
871 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
873 q+=(ptrdiff_t)
sizeof(length);
874 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
876 if (p == (
const Quantum *) NULL)
878 count=dpc_send(file,length,p);
879 if (count != (MagickOffsetType) length)
884static void *RelinquishImageRegistry(
void *image)
886 return((
void *) DestroyImageList((Image *) image));
889static MagickBooleanType WriteDistributeCacheMetacontent(
890 SplayTreeInfo *registry,SOCKET_TYPE file,
const uint64_t session_key,
891 ExceptionInfo *exception)
897 key = (MagickAddressType) session_key;
915 message[MagickPathExtent],
922 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
923 if (image == (Image *) NULL)
925 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
926 sizeof(region.y)+
sizeof(length);
927 count=dpc_read(file,length,message);
928 if (count != (MagickOffsetType) length)
931 (void) memcpy(®ion.width,p,
sizeof(region.width));
932 p+=(ptrdiff_t)
sizeof(region.width);
933 (void) memcpy(®ion.height,p,
sizeof(region.height));
934 p+=(ptrdiff_t)
sizeof(region.height);
935 (void) memcpy(®ion.x,p,
sizeof(region.x));
936 p+=(ptrdiff_t)
sizeof(region.x);
937 (void) memcpy(®ion.y,p,
sizeof(region.y));
938 p+=(ptrdiff_t)
sizeof(region.y);
939 (void) memcpy(&length,p,
sizeof(length));
940 per_pixel=image->number_meta_channels*
sizeof(Quantum);
941 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
943 p+=(ptrdiff_t)
sizeof(length);
944 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
946 if (q == (Quantum *) NULL)
948 metacontent=(
unsigned char *) GetAuthenticMetacontent(image);
949 count=dpc_read(file,length,metacontent);
950 if (count != (MagickOffsetType) length)
952 return(SyncAuthenticPixels(image,exception));
955static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
956 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
962 key = (MagickAddressType) session_key;
980 message[MagickPathExtent],
986 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
987 if (image == (Image *) NULL)
989 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
990 sizeof(region.y)+
sizeof(length);
991 count=dpc_read(file,length,message);
992 if (count != (MagickOffsetType) length)
995 (void) memcpy(®ion.width,p,
sizeof(region.width));
996 p+=(ptrdiff_t)
sizeof(region.width);
997 (void) memcpy(®ion.height,p,
sizeof(region.height));
998 p+=(ptrdiff_t)
sizeof(region.height);
999 (void) memcpy(®ion.x,p,
sizeof(region.x));
1000 p+=(ptrdiff_t)
sizeof(region.x);
1001 (void) memcpy(®ion.y,p,
sizeof(region.y));
1002 p+=(ptrdiff_t)
sizeof(region.y);
1003 (void) memcpy(&length,p,
sizeof(length));
1004 per_pixel=image->number_channels*
sizeof(Quantum);
1005 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
1006 return(MagickFalse);
1007 p+=(ptrdiff_t)
sizeof(length);
1008 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1010 if (q == (Quantum *) NULL)
1011 return(MagickFalse);
1012 count=dpc_read(file,length,(
unsigned char *) q);
1013 if (count != (MagickOffsetType) length)
1014 return(MagickFalse);
1015 return(SyncAuthenticPixels(image,exception));
1018static HANDLER_RETURN_TYPE DistributePixelCacheClient(
void *socket_arg)
1027 status = MagickFalse;
1037 *client_socket_ptr = (SOCKET_TYPE *) socket_arg;
1051 nonce[DPCSessionKeyLength];
1056 client_socket=(*client_socket_ptr);
1057 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
1058 shared_secret=GetPolicyValue(
"cache:shared-secret");
1059 if (shared_secret == NULL)
1060 ThrowFatalException(CacheFatalError,
"shared secret required");
1064 random_info=AcquireRandomInfo();
1065 entropy=GetRandomKey(random_info,
sizeof(nonce));
1066 (void) memcpy(nonce,GetStringInfoDatum(entropy),
sizeof(nonce));
1067 entropy=DestroyStringInfo(entropy);
1068 random_info=DestroyRandomInfo(random_info);
1072 session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
1073 shared_secret=DestroyString(shared_secret);
1077 count=dpc_send(client_socket,
sizeof(nonce),nonce);
1078 if (count != (MagickOffsetType)
sizeof(nonce))
1080 CLOSE_SOCKET(client_socket);
1081 return(HANDLER_RETURN_VALUE);
1086 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1087 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1089 CLOSE_SOCKET(client_socket);
1090 return(HANDLER_RETURN_VALUE);
1092 exception=AcquireExceptionInfo();
1093 registry=NewSplayTree((
int (*)(
const void *,
const void *)) NULL,
1094 (
void *(*)(
void *)) NULL,RelinquishImageRegistry);
1098 for (status=MagickFalse; ; )
1103 count=dpc_read(client_socket,1,(
unsigned char *) &command);
1106 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1107 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1113 status=OpenDistributeCache(registry,client_socket,session_key,
1115 dpc_send(client_socket,
sizeof(status),&status);
1120 status=ReadDistributeCachePixels(registry,client_socket,session_key,
1126 status=ReadDistributeCacheMetacontent(registry,client_socket,
1127 session_key,exception);
1132 status=WriteDistributeCachePixels(registry,client_socket,session_key,
1138 status=WriteDistributeCacheMetacontent(registry,client_socket,
1139 session_key,exception);
1144 status=DestroyDistributeCache(registry,session_key);
1150 if ((status == MagickFalse) || (command ==
'd'))
1153 count=dpc_send(client_socket,
sizeof(status),&status);
1154 CLOSE_SOCKET(client_socket);
1155 exception=DestroyExceptionInfo(exception);
1156 registry=DestroySplayTree(registry);
1157 return(HANDLER_RETURN_VALUE);
1160MagickExport
void DistributePixelCacheServer(
const int port,
1161 ExceptionInfo *exception)
1164 service[MagickPathExtent];
1169#if defined(MAGICKCORE_THREAD_SUPPORT)
1175#elif defined(_MSC_VER)
1198 assert(exception != (ExceptionInfo *) NULL);
1199 assert(exception->signature == MagickCoreSignature);
1200 magick_unreferenced(exception);
1201#if defined(MAGICKCORE_HAVE_WINSOCK2)
1202 InitializeWinsock2(MagickFalse);
1204 (void) memset(&hint,0,
sizeof(hint));
1205 hint.ai_family=AF_INET;
1206 hint.ai_socktype=SOCK_STREAM;
1207 hint.ai_flags=AI_PASSIVE;
1208 FormatLocaleString(service,MagickPathExtent,
"%d",port);
1209 status=getaddrinfo(NULL,service,&hint,&result);
1211 ThrowFatalException(CacheFatalError,
"UnableToListen");
1212 server_socket=(SOCKET_TYPE) 0;
1213 for (p=result; p != NULL; p=p->ai_next)
1218 server_socket=(SOCKET_TYPE) socket(p->ai_family,p->ai_socktype,
1220 if (server_socket == -1)
1222 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(
char *) &one,
1223 (socklen_t)
sizeof(one));
1226#if defined(MAGICKCORE_HAVE_WINSOCK2)
1227 DWORD timeout = 5000;
1228 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,(
const char *)
1229 &timeout,
sizeof(timeout));
1234 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,&tv,
sizeof(tv));
1239 CLOSE_SOCKET(server_socket);
1242 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1245 CLOSE_SOCKET(server_socket);
1250 if (p == (
struct addrinfo *) NULL)
1251 ThrowFatalException(CacheFatalError,
"UnableToBind");
1252 freeaddrinfo(result);
1253 status=listen(server_socket,DPCPendingConnections);
1255 ThrowFatalException(CacheFatalError,
"UnableToListen");
1256#if defined(MAGICKCORE_THREAD_SUPPORT)
1257 pthread_attr_init(&attributes);
1258 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1266 length = (socklen_t)
sizeof(address);
1268 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(
sizeof(SOCKET_TYPE));
1269 if (client_socket_ptr == NULL)
1271 *client_socket_ptr=(SOCKET_TYPE) accept(server_socket,(
struct sockaddr *)
1273 if (*client_socket_ptr == -1)
1275 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1279#if defined(MAGICKCORE_THREAD_SUPPORT)
1280 status=pthread_create(&thread_id,&attributes,DistributePixelCacheClient,
1281 (
void *) client_socket_ptr);
1284 CLOSE_SOCKET(*client_socket_ptr);
1285 RelinquishMagickMemory(client_socket_ptr);
1286 ThrowFatalException(CacheFatalError,
"UnableToCreateClientThread");
1288#elif defined(_MSC_VER)
1289 if (CreateThread(0,0,DistributePixelCacheClient,(
void*) client_socket_ptr,0,&threadID) == (HANDLE) NULL)
1291 CLOSE_SOCKET(*client_socket_ptr);
1292 RelinquishMagickMemory(client_socket_ptr);
1293 ThrowFatalException(CacheFatalError,
"UnableToCreateClientThread");
1316MagickPrivate
void DistributeCacheTerminus(
void)
1318#ifdef MAGICKCORE_HAVE_WINSOCK2
1320 ActivateSemaphoreInfo(&winsock2_semaphore);
1321 LockSemaphoreInfo(winsock2_semaphore);
1322 if (wsaData != (WSADATA *) NULL)
1325 wsaData=(WSADATA *) RelinquishMagickMemory((
void *) wsaData);
1327 UnlockSemaphoreInfo(winsock2_semaphore);
1328 RelinquishSemaphoreInfo(&winsock2_semaphore);
1355MagickPrivate
int GetDistributeCacheFile(
const DistributeCacheInfo *server_info)
1357 assert(server_info != (DistributeCacheInfo *) NULL);
1358 assert(server_info->signature == MagickCoreSignature);
1359 return(server_info->file);
1386MagickPrivate
const char *GetDistributeCacheHostname(
1387 const DistributeCacheInfo *server_info)
1389 assert(server_info != (DistributeCacheInfo *) NULL);
1390 assert(server_info->signature == MagickCoreSignature);
1391 return(server_info->hostname);
1417MagickPrivate
int GetDistributeCachePort(
const DistributeCacheInfo *server_info)
1419 assert(server_info != (DistributeCacheInfo *) NULL);
1420 assert(server_info->signature == MagickCoreSignature);
1421 return(server_info->port);
1449MagickPrivate MagickBooleanType OpenDistributePixelCache(
1450 DistributeCacheInfo *server_info,Image *image)
1459 message[MagickPathExtent],
1465 assert(server_info != (DistributeCacheInfo *) NULL);
1466 assert(server_info->signature == MagickCoreSignature);
1467 assert(image != (Image *) NULL);
1468 assert(image->signature == MagickCoreSignature);
1474 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1475 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1476 (void) memcpy(p,&image->storage_class,
sizeof(image->storage_class));
1477 p+=(ptrdiff_t)
sizeof(image->storage_class);
1478 (void) memcpy(p,&image->colorspace,
sizeof(image->colorspace));
1479 p+=(ptrdiff_t)
sizeof(image->colorspace);
1480 (void) memcpy(p,&image->alpha_trait,
sizeof(image->alpha_trait));
1481 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
1482 (void) memcpy(p,&image->channels,
sizeof(image->channels));
1483 p+=(ptrdiff_t)
sizeof(image->channels);
1484 (void) memcpy(p,&image->columns,
sizeof(image->columns));
1485 p+=(ptrdiff_t)
sizeof(image->columns);
1486 (void) memcpy(p,&image->rows,
sizeof(image->rows));
1487 p+=(ptrdiff_t)
sizeof(image->rows);
1488 (void) memcpy(p,&image->number_channels,
sizeof(image->number_channels));
1489 p+=(ptrdiff_t)
sizeof(image->number_channels);
1490 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1491 sizeof(*image->channel_map));
1492 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
1493 (void) memcpy(p,&image->metacontent_extent,
sizeof(image->metacontent_extent));
1494 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
1495 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1496 if (count != (MagickOffsetType) (p-message))
1497 return(MagickFalse);
1499 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1500 if (count != (MagickOffsetType)
sizeof(status))
1501 return(MagickFalse);
1538MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1539 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1540 const MagickSizeType length,
unsigned char *metacontent)
1546 message[MagickPathExtent],
1552 assert(server_info != (DistributeCacheInfo *) NULL);
1553 assert(server_info->signature == MagickCoreSignature);
1554 assert(region != (RectangleInfo *) NULL);
1555 assert(metacontent != (
unsigned char *) NULL);
1556 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1560 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1561 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1562 (void) memcpy(p,®ion->width,
sizeof(region->width));
1563 p+=(ptrdiff_t)
sizeof(region->width);
1564 (void) memcpy(p,®ion->height,
sizeof(region->height));
1565 p+=(ptrdiff_t)
sizeof(region->height);
1566 (void) memcpy(p,®ion->x,
sizeof(region->x));
1567 p+=(ptrdiff_t)
sizeof(region->x);
1568 (void) memcpy(p,®ion->y,
sizeof(region->y));
1569 p+=(ptrdiff_t)
sizeof(region->y);
1570 (void) memcpy(p,&length,
sizeof(length));
1571 p+=(ptrdiff_t)
sizeof(length);
1572 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1573 if (count != (MagickOffsetType) (p-message))
1575 return(dpc_read(server_info->file,length,metacontent));
1611MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1612 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1613 const MagickSizeType length,
unsigned char *magick_restrict pixels)
1619 message[MagickPathExtent],
1625 assert(server_info != (DistributeCacheInfo *) NULL);
1626 assert(server_info->signature == MagickCoreSignature);
1627 assert(region != (RectangleInfo *) NULL);
1628 assert(pixels != (
unsigned char *) NULL);
1629 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1633 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1634 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1635 (void) memcpy(p,®ion->width,
sizeof(region->width));
1636 p+=(ptrdiff_t)
sizeof(region->width);
1637 (void) memcpy(p,®ion->height,
sizeof(region->height));
1638 p+=(ptrdiff_t)
sizeof(region->height);
1639 (void) memcpy(p,®ion->x,
sizeof(region->x));
1640 p+=(ptrdiff_t)
sizeof(region->x);
1641 (void) memcpy(p,®ion->y,
sizeof(region->y));
1642 p+=(ptrdiff_t)
sizeof(region->y);
1643 (void) memcpy(p,&length,
sizeof(length));
1644 p+=(ptrdiff_t)
sizeof(length);
1645 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1646 if (count != (MagickOffsetType) (p-message))
1648 return(dpc_read(server_info->file,length,pixels));
1675MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1676 DistributeCacheInfo *server_info)
1685 message[MagickPathExtent],
1691 assert(server_info != (DistributeCacheInfo *) NULL);
1692 assert(server_info->signature == MagickCoreSignature);
1695 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1696 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1697 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1698 if (count != (MagickOffsetType) (p-message))
1699 return(MagickFalse);
1701 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1702 if (count != (MagickOffsetType)
sizeof(status))
1703 return(MagickFalse);
1740MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1741 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1742 const MagickSizeType length,
const unsigned char *metacontent)
1748 message[MagickPathExtent],
1754 assert(server_info != (DistributeCacheInfo *) NULL);
1755 assert(server_info->signature == MagickCoreSignature);
1756 assert(region != (RectangleInfo *) NULL);
1757 assert(metacontent != (
unsigned char *) NULL);
1758 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1762 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1763 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1764 (void) memcpy(p,®ion->width,
sizeof(region->width));
1765 p+=(ptrdiff_t)
sizeof(region->width);
1766 (void) memcpy(p,®ion->height,
sizeof(region->height));
1767 p+=(ptrdiff_t)
sizeof(region->height);
1768 (void) memcpy(p,®ion->x,
sizeof(region->x));
1769 p+=(ptrdiff_t)
sizeof(region->x);
1770 (void) memcpy(p,®ion->y,
sizeof(region->y));
1771 p+=(ptrdiff_t)
sizeof(region->y);
1772 (void) memcpy(p,&length,
sizeof(length));
1773 p+=(ptrdiff_t)
sizeof(length);
1774 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1775 if (count != (MagickOffsetType) (p-message))
1777 return(dpc_send(server_info->file,length,metacontent));
1814MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1815 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1816 const MagickSizeType length,
const unsigned char *magick_restrict pixels)
1822 message[MagickPathExtent],
1828 assert(server_info != (DistributeCacheInfo *) NULL);
1829 assert(server_info->signature == MagickCoreSignature);
1830 assert(region != (RectangleInfo *) NULL);
1831 assert(pixels != (
const unsigned char *) NULL);
1832 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1836 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1837 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1838 (void) memcpy(p,®ion->width,
sizeof(region->width));
1839 p+=(ptrdiff_t)
sizeof(region->width);
1840 (void) memcpy(p,®ion->height,
sizeof(region->height));
1841 p+=(ptrdiff_t)
sizeof(region->height);
1842 (void) memcpy(p,®ion->x,
sizeof(region->x));
1843 p+=(ptrdiff_t)
sizeof(region->x);
1844 (void) memcpy(p,®ion->y,
sizeof(region->y));
1845 p+=(ptrdiff_t)
sizeof(region->y);
1846 (void) memcpy(p,&length,
sizeof(length));
1847 p+=(ptrdiff_t)
sizeof(length);
1848 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1849 if (count != (MagickOffsetType) (p-message))
1851 return(dpc_send(server_info->file,length,pixels));