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 DPCMaxClientWorkers 128
107#define DPCMaxUnauthenticatedClientWorkers 16
108#define DPCPendingConnections 10
110#define DPCSessionKeyLength 16
112# define MSG_NOSIGNAL 0
118#ifdef MAGICKCORE_HAVE_WINSOCK2
123 *wsaData = (WSADATA*) NULL;
126#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
131 *dpc_shared_secret = (
char *) NULL;
135 dpc_unauthenticated_clients = 0;
161#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
162static inline MagickOffsetType dpc_receive(SOCKET_TYPE magick_unused(file),
163 const MagickSizeType magick_unused(length),
164 unsigned char *magick_restrict magick_unused(message))
166 magick_unreferenced(file);
167 magick_unreferenced(length);
168 magick_unreferenced(message);
172static void SetSocketReceiveTimeout(SOCKET_TYPE file,
double seconds)
177#if defined(MAGICKCORE_HAVE_WINSOCK2)
179 DWORD timeout = (DWORD) (seconds*1000.0);
180 (void) setsockopt(file,SOL_SOCKET,SO_RCVTIMEO,
181 (
const char *) &timeout,
sizeof(timeout));
186 tv.tv_sec=(int) seconds;
187 tv.tv_usec=(int) ((seconds-(
double) tv.tv_sec)*1000000.0);
188 (void) setsockopt(file,SOL_SOCKET,SO_RCVTIMEO,&tv,
sizeof(tv));
193static inline MagickOffsetType dpc_receive(SOCKET_TYPE file,
194 const MagickSizeType length,
unsigned char *magick_restrict message)
196 MagickOffsetType offset = 0;
197 while (offset < (MagickOffsetType) length)
199 MagickSizeType chunk = MagickMin(length-offset,(MagickSizeType)
200 MagickMaxBufferExtent);
201 ssize_t count = recv(file,(
char *) message+offset,(LENGTH_TYPE) chunk,0);
203 offset+=(MagickOffsetType) count;
209#ifdef MAGICKCORE_HAVE_WINSOCK2
210 int wsa_err = WSAGetLastError();
211 if ((wsa_err == WSAEINTR) || (wsa_err == WSAEWOULDBLOCK))
213 if (wsa_err == WSAECONNRESET)
216 if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
218 if (errno == ECONNRESET)
227static inline MagickOffsetType dpc_receive_deadline(SOCKET_TYPE file,
228 MagickSizeType length,
unsigned char *message,
double deadline)
233 MagickOffsetType offset = 0;
234 while (offset < (MagickOffsetType) length)
237 now = (double) time((time_t *) NULL),
238 remaining = deadline-now;
248 if (remaining < 0.001)
250 SetSocketReceiveTimeout(file,remaining);
251 chunk=MagickMin(length-offset,(MagickSizeType) MagickMaxBufferExtent);
252 count=recv(file,(
char *) message+offset,(LENGTH_TYPE) chunk,0);
254 offset+=(MagickOffsetType) count;
260#ifdef MAGICKCORE_HAVE_WINSOCK2
261 int wsa_err = WSAGetLastError();
262 if ((wsa_err == WSAEINTR) || (wsa_err == WSAEWOULDBLOCK))
264 if (wsa_err == WSAECONNRESET)
268 if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
270 if (errno == ECONNRESET)
280#if defined(MAGICKCORE_HAVE_WINSOCK2)
281static void InitializeWinsock2(MagickBooleanType use_lock)
283 if (use_lock != MagickFalse)
286 ActivateSemaphoreInfo(&winsock_semaphore);
287 LockSemaphoreInfo(winsock_semaphore);
289 if (wsaData == (WSADATA *) NULL)
291 wsaData=(WSADATA *) AcquireMagickMemory(
sizeof(WSADATA));
292 if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
293 ThrowFatalException(CacheFatalError,
"WSAStartup failed");
295 if (use_lock != MagickFalse)
296 UnlockSemaphoreInfo(winsock_semaphore);
300#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
301static int ConnectPixelCacheServer(
const char *magick_unused(hostname),
302 const int magick_unused(port),uint64_t *magick_unused(session_key),
303 ExceptionInfo *exception)
305 magick_unreferenced(hostname);
306 magick_unreferenced(port);
307 magick_unreferenced(session_key);
308 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
309 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
313static inline uint64_t ROTL(uint64_t x,
int b)
315 return((x << b) | (x >> (64-b)));
318static inline uint64_t U8TO64_LE(
const uint8_t *p)
320 return(((uint64_t) p[0] << 0) | ((uint64_t) p[1] << 8) |
321 ((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
322 ((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
323 ((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
326static inline uint64_t SIPHash24(
const uint8_t key[16],
const uint8_t *message,
330 *end = message+length-(length % 8);
336 b = ((uint64_t) length) << 56,
338 k1 = U8TO64_LE(key+8),
340 v0 = 0x736f6d6570736575ULL ^ k0,
341 v1 = 0x646f72616e646f6dULL ^ k1,
342 v2 = 0x6c7967656e657261ULL ^ k0,
343 v3 = 0x7465646279746573ULL ^ k1;
345 for ( ; message != end; message+=8)
347 m=U8TO64_LE(message);
349 for (i=0; i < 2; i++)
351 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
352 v2+=v3; v3=ROTL(v3,16); v3^=v2;
353 v0+=v3; v3=ROTL(v3,21); v3^=v0;
354 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
358 switch (length & 0x07)
360 case 7: b|=((uint64_t) message[6]) << 48; magick_fallthrough;
361 case 6: b|=((uint64_t) message[5]) << 40; magick_fallthrough;
362 case 5: b|=((uint64_t) message[4]) << 32; magick_fallthrough;
363 case 4: b|=((uint64_t) message[3]) << 24; magick_fallthrough;
364 case 3: b|=((uint64_t) message[2]) << 16; magick_fallthrough;
365 case 2: b|=((uint64_t) message[1]) << 8; magick_fallthrough;
366 case 1: b|=((uint64_t) message[0]); magick_fallthrough;
370 for (i=0; i < 2; i++)
372 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
373 v2+=v3; v3=ROTL(v3,16); v3^=v2;
374 v0+=v3; v3=ROTL(v3,21); v3^=v0;
375 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
379 for (i=0; i < 4; i++)
381 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
382 v2+=v3; v3=ROTL(v3,16); v3^=v2;
383 v0+=v3; v3=ROTL(v3,21); v3^=v0;
384 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
389static inline void DeriveSIPKeyFromSecret(
const char *shared_secret,
397 k0 = 0x0706050403020100ULL,
398 k1 = 0x0f0e0d0c0b0a0908ULL;
400 length=strlen(shared_secret);
401 for (i=0; i < length; i++)
404 b = (uint8_t) shared_secret[i];
407 k0*=0x100000001b3ULL;
408 k1^=(uint64_t) b << ((i & 7)*8);
409 k1=(k1 << 5) | (k1 >> (64-5));
411 (void) memcpy(key,&k0,8);
412 (void) memcpy(key+8,&k1,8);
415static inline uint64_t GenerateSessionKey(
const char *shared_secret,
416 const unsigned char *nonce,
size_t length)
421 DeriveSIPKeyFromSecret(shared_secret,key);
422 return(SIPHash24(key,nonce,length));
425static int ConnectPixelCacheServer(
const char *hostname,
const int port,
426 uint64_t *session_key,ExceptionInfo *exception)
428#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
431 service[MagickPathExtent],
448 nonce[DPCSessionKeyLength];
454#if defined(MAGICKCORE_HAVE_WINSOCK2)
455 InitializeWinsock2(MagickTrue);
457 (void) memset(&hints,0,
sizeof(hints));
458 hints.ai_family=AF_INET;
459 hints.ai_socktype=SOCK_STREAM;
460 hints.ai_flags=AI_PASSIVE;
461 (void) FormatLocaleString(service,MagickPathExtent,
"%d",port);
462 status=getaddrinfo(hostname,service,&hints,&result);
465 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
466 "DistributedPixelCache",
"'%s': %s",hostname,gai_strerror(status));
469 client_socket=(SOCKET_TYPE) socket(result->ai_family,result->ai_socktype,
470 result->ai_protocol);
471 if (client_socket == -1)
473 freeaddrinfo(result);
474 message=GetExceptionMessage(errno);
475 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
476 "DistributedPixelCache",
"'%s': %s",hostname,message);
477 message=DestroyString(message);
480 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
481 freeaddrinfo(result);
484 CLOSE_SOCKET(client_socket);
485 message=GetExceptionMessage(errno);
486 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
487 "DistributedPixelCache",
"'%s': %s",hostname,message);
488 message=DestroyString(message);
494 count=recv(client_socket,(
char *) nonce,
sizeof(nonce),0);
495 if (count != (ssize_t)
sizeof(nonce))
497 CLOSE_SOCKET(client_socket);
498 message=GetExceptionMessage(errno);
499 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
500 "DistributedPixelCache",
"'%s': %s",hostname,message);
501 message=DestroyString(message);
507 shared_secret=GetPolicyValue(
"cache:shared-secret");
508 if (shared_secret == (
const char *) NULL)
510 CLOSE_SOCKET(client_socket);
511 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
512 "DistributedPixelCache",
"'%s': shared secret required",hostname);
515 *session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
516 shared_secret=DestroyString(shared_secret);
520 count=send(client_socket,(
char *) session_key,
sizeof(*session_key),
522 if (count != (ssize_t)
sizeof(*session_key))
524 CLOSE_SOCKET(client_socket);
525 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
526 "DistributedPixelCache",
"'%s': authentication failed",hostname);
529 return((
int) client_socket);
531 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
532 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
538static char *GetHostname(
int *port,ExceptionInfo *exception)
557 hosts=(
char *) GetImageRegistry(StringRegistryType,
"cache:hosts",exception);
558 if (hosts == (
char *) NULL)
561 return(AcquireString(DPCHostname));
563 (void) SubstituteString(&hosts,
",",
" ");
564 hostlist=StringToArgv(hosts,&argc);
565 hosts=DestroyString(hosts);
566 if ((hostlist == (
char **) NULL) || ((argc-1) == 0))
569 return(AcquireString(DPCHostname));
572 size_t host_count = (size_t) argc-1;
573 size_t index = (
id++ % host_count)+1;
574 hosts=AcquireString(hostlist[index]);
576 for (i=0; i < (ssize_t) argc; i++)
577 hostlist[i]=DestroyString(hostlist[i]);
578 hostlist=(
char **) RelinquishMagickMemory(hostlist);
579 (void) SubstituteString(&hosts,
":",
" ");
580 hostlist=StringToArgv(hosts,&argc);
581 if (hostlist == (
char **) NULL)
584 return(AcquireString(DPCHostname));
586 host=AcquireString(hostlist[1]);
587 if (hostlist[2] == (
char *) NULL)
590 *port=(int) StringToLong(hostlist[2]);
591 for (i=0; i < (ssize_t) argc; i++)
592 hostlist[i]=DestroyString(hostlist[i]);
593 hostlist=(
char **) RelinquishMagickMemory(hostlist);
597MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
598 ExceptionInfo *exception)
612 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
613 sizeof(*server_info));
614 (void) memset(server_info,0,
sizeof(*server_info));
615 server_info->signature=MagickCoreSignature;
617 hostname=GetHostname(&server_info->port,exception);
619 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
620 &session_key,exception);
621 if (server_info->file == -1)
622 server_info=DestroyDistributeCacheInfo(server_info);
625 server_info->session_key=session_key;
626 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
627 server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
630 hostname=DestroyString(hostname);
658MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
659 DistributeCacheInfo *server_info)
661 assert(server_info != (DistributeCacheInfo *) NULL);
662 assert(server_info->signature == MagickCoreSignature);
663#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
664 if (server_info->file >= 0)
665 CLOSE_SOCKET(server_info->file);
667 server_info->signature=(~MagickCoreSignature);
668 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
698#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
699static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
700 const MagickSizeType magick_unused(length),
701 const void *magick_restrict magick_unused(message))
703 magick_unreferenced(file);
704 magick_unreferenced(length);
705 magick_unreferenced(message);
709static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
710 const MagickSizeType length,
const void *magick_restrict message)
722 for (i=0; i < (MagickOffsetType) length; i+=count)
724 count=(ssize_t) send(file,(
const char *) message+i,(LENGTH_TYPE) MagickMin(
725 length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
738#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
739MagickExport
void DistributePixelCacheServer(
const int magick_unused(port),
740 ExceptionInfo *magick_unused(exception))
742 magick_unreferenced(port);
743 magick_unreferenced(exception);
744 ThrowFatalException(MissingDelegateError,
"DelegateLibrarySupportNotBuiltIn");
747static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
748 const uint64_t session_key)
751 key = (MagickAddressType) session_key;
756 return(DeleteNodeFromSplayTree(registry,(
const void *) key));
759static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
760 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
766 key = (MagickAddressType) session_key;
778 message[MagickPathExtent],
784 image=AcquireImage((ImageInfo *) NULL,exception);
785 if (image == (Image *) NULL)
787 length=
sizeof(image->storage_class)+
sizeof(image->colorspace)+
788 sizeof(image->alpha_trait)+
sizeof(image->channels)+
sizeof(image->columns)+
789 sizeof(image->rows)+
sizeof(image->number_channels)+MaxPixelChannels*
790 sizeof(*image->channel_map)+
sizeof(image->metacontent_extent);
791 count=dpc_receive(file,length,message);
792 if (count != (MagickOffsetType) length)
794 image=DestroyImage(image);
801 (void) memcpy(&image->storage_class,p,
sizeof(image->storage_class));
802 p+=(ptrdiff_t)
sizeof(image->storage_class);
803 (void) memcpy(&image->colorspace,p,
sizeof(image->colorspace));
804 p+=(ptrdiff_t)
sizeof(image->colorspace);
805 (void) memcpy(&image->alpha_trait,p,
sizeof(image->alpha_trait));
806 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
807 (void) memcpy(&image->channels,p,
sizeof(image->channels));
808 p+=(ptrdiff_t)
sizeof(image->channels);
809 (void) memcpy(&image->columns,p,
sizeof(image->columns));
810 p+=(ptrdiff_t)
sizeof(image->columns);
811 (void) memcpy(&image->rows,p,
sizeof(image->rows));
812 p+=(ptrdiff_t)
sizeof(image->rows);
813 (void) memcpy(&image->number_channels,p,
sizeof(image->number_channels));
814 p+=(ptrdiff_t)
sizeof(image->number_channels);
815 (void) memcpy(image->channel_map,p,MaxPixelChannels*
816 sizeof(*image->channel_map));
817 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
818 (void) memcpy(&image->metacontent_extent,p,
sizeof(image->metacontent_extent));
819 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
820 if (SyncImagePixelCache(image,exception) == MagickFalse)
822 image=DestroyImage(image);
825 status=AddValueToSplayTree(registry,(
const void *) key,image);
826 if (status == MagickFalse)
828 image=DestroyImage(image);
834static inline MagickBooleanType ValidateDistributedPixelCache(
835 const RectangleInfo *region,
const size_t per_pixel,
836 const MagickSizeType length)
842 if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
844 if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
846 if (length > (MagickSizeType) extent)
851static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
852 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
864 key = (MagickAddressType) session_key;
879 message[MagickPathExtent],
885 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
886 if (image == (Image *) NULL)
888 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
889 sizeof(region.y)+
sizeof(length);
890 count=dpc_receive(file,length,message);
891 if (count != (MagickOffsetType) length)
894 (void) memcpy(®ion.width,q,
sizeof(region.width));
895 q+=(ptrdiff_t)
sizeof(region.width);
896 (void) memcpy(®ion.height,q,
sizeof(region.height));
897 q+=(ptrdiff_t)
sizeof(region.height);
898 (void) memcpy(®ion.x,q,
sizeof(region.x));
899 q+=(ptrdiff_t)
sizeof(region.x);
900 (void) memcpy(®ion.y,q,
sizeof(region.y));
901 q+=(ptrdiff_t)
sizeof(region.y);
902 (void) memcpy(&length,q,
sizeof(length));
903 q+=(ptrdiff_t)
sizeof(length);
904 per_pixel=image->number_meta_channels*
sizeof(Quantum);
905 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
907 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
909 if (p == (
const Quantum *) NULL)
911 metacontent=(
const unsigned char *) GetVirtualMetacontent(image);
912 count=dpc_send(file,length,metacontent);
913 if (count != (MagickOffsetType) length)
918static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
919 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
928 key = (MagickAddressType) session_key;
943 message[MagickPathExtent],
949 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
950 if (image == (Image *) NULL)
952 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
953 sizeof(region.y)+
sizeof(length);
954 count=dpc_receive(file,length,message);
955 if (count != (MagickOffsetType) length)
958 (void) memcpy(®ion.width,q,
sizeof(region.width));
959 q+=(ptrdiff_t)
sizeof(region.width);
960 (void) memcpy(®ion.height,q,
sizeof(region.height));
961 q+=(ptrdiff_t)
sizeof(region.height);
962 (void) memcpy(®ion.x,q,
sizeof(region.x));
963 q+=(ptrdiff_t)
sizeof(region.x);
964 (void) memcpy(®ion.y,q,
sizeof(region.y));
965 q+=(ptrdiff_t)
sizeof(region.y);
966 (void) memcpy(&length,q,
sizeof(length));
967 per_pixel=image->number_channels*
sizeof(Quantum);
968 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
970 q+=(ptrdiff_t)
sizeof(length);
971 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
973 if (p == (
const Quantum *) NULL)
975 count=dpc_send(file,length,p);
976 if (count != (MagickOffsetType) length)
981static void *RelinquishImageRegistry(
void *image)
983 return((
void *) DestroyImageList((Image *) image));
986static MagickBooleanType WriteDistributeCacheMetacontent(
987 SplayTreeInfo *registry,SOCKET_TYPE file,
const uint64_t session_key,
988 ExceptionInfo *exception)
994 key = (MagickAddressType) session_key;
1012 message[MagickPathExtent],
1019 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
1020 if (image == (Image *) NULL)
1021 return(MagickFalse);
1022 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
1023 sizeof(region.y)+
sizeof(length);
1024 count=dpc_receive(file,length,message);
1025 if (count != (MagickOffsetType) length)
1026 return(MagickFalse);
1028 (void) memcpy(®ion.width,p,
sizeof(region.width));
1029 p+=(ptrdiff_t)
sizeof(region.width);
1030 (void) memcpy(®ion.height,p,
sizeof(region.height));
1031 p+=(ptrdiff_t)
sizeof(region.height);
1032 (void) memcpy(®ion.x,p,
sizeof(region.x));
1033 p+=(ptrdiff_t)
sizeof(region.x);
1034 (void) memcpy(®ion.y,p,
sizeof(region.y));
1035 p+=(ptrdiff_t)
sizeof(region.y);
1036 (void) memcpy(&length,p,
sizeof(length));
1037 per_pixel=image->number_meta_channels*
sizeof(Quantum);
1038 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
1039 return(MagickFalse);
1040 p+=(ptrdiff_t)
sizeof(length);
1041 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1043 if (q == (Quantum *) NULL)
1044 return(MagickFalse);
1045 metacontent=(
unsigned char *) GetAuthenticMetacontent(image);
1046 count=dpc_receive(file,length,metacontent);
1047 if (count != (MagickOffsetType) length)
1048 return(MagickFalse);
1049 return(SyncAuthenticPixels(image,exception));
1052static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
1053 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
1059 key = (MagickAddressType) session_key;
1077 message[MagickPathExtent],
1083 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
1084 if (image == (Image *) NULL)
1085 return(MagickFalse);
1086 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
1087 sizeof(region.y)+
sizeof(length);
1088 count=dpc_receive(file,length,message);
1089 if (count != (MagickOffsetType) length)
1090 return(MagickFalse);
1092 (void) memcpy(®ion.width,p,
sizeof(region.width));
1093 p+=(ptrdiff_t)
sizeof(region.width);
1094 (void) memcpy(®ion.height,p,
sizeof(region.height));
1095 p+=(ptrdiff_t)
sizeof(region.height);
1096 (void) memcpy(®ion.x,p,
sizeof(region.x));
1097 p+=(ptrdiff_t)
sizeof(region.x);
1098 (void) memcpy(®ion.y,p,
sizeof(region.y));
1099 p+=(ptrdiff_t)
sizeof(region.y);
1100 (void) memcpy(&length,p,
sizeof(length));
1101 per_pixel=image->number_channels*
sizeof(Quantum);
1102 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
1103 return(MagickFalse);
1104 p+=(ptrdiff_t)
sizeof(length);
1105 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1107 if (q == (Quantum *) NULL)
1108 return(MagickFalse);
1109 count=dpc_receive(file,length,(
unsigned char *) q);
1110 if (count != (MagickOffsetType) length)
1111 return(MagickFalse);
1112 return(SyncAuthenticPixels(image,exception));
1115static void LockDPCSemaphore(
void)
1118 ActivateSemaphoreInfo(&dpc_semaphore);
1119 LockSemaphoreInfo(dpc_semaphore);
1122static void AuthenticateDPCClient(
void)
1125 if (dpc_unauthenticated_clients != 0)
1126 dpc_unauthenticated_clients--;
1127 UnlockSemaphoreInfo(dpc_semaphore);
1130static void RelinquishDPCClient(
const MagickBooleanType unauthenticated)
1133 if ((unauthenticated != MagickFalse) && (dpc_unauthenticated_clients != 0))
1134 dpc_unauthenticated_clients--;
1135 if (dpc_clients != 0)
1137 UnlockSemaphoreInfo(dpc_semaphore);
1140static HANDLER_RETURN_TYPE DistributePixelCacheConnectionHandler(
void *socket_arg)
1146 authenticated = MagickFalse,
1147 status = MagickFalse;
1157 *client_socket_ptr = (SOCKET_TYPE *) socket_arg;
1171 nonce[DPCSessionKeyLength];
1173 client_socket=(*client_socket_ptr);
1174 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
1178 random_info=AcquireRandomInfo();
1179 entropy=GetRandomKey(random_info,
sizeof(nonce));
1180 (void) memcpy(nonce,GetStringInfoDatum(entropy),
sizeof(nonce));
1181 entropy=DestroyStringInfo(entropy);
1182 random_info=DestroyRandomInfo(random_info);
1186 session_key=GenerateSessionKey(dpc_shared_secret,nonce,
sizeof(nonce));
1190 count=dpc_send(client_socket,
sizeof(nonce),nonce);
1191 if (count != (MagickOffsetType)
sizeof(nonce))
1193 CLOSE_SOCKET(client_socket);
1194 RelinquishDPCClient(MagickTrue);
1195 return(HANDLER_RETURN_VALUE);
1200 count=dpc_receive_deadline(client_socket,
sizeof(key),(
unsigned char *) &key,
1201 (
double) time((time_t *) NULL)+5.0);
1202 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1204 CLOSE_SOCKET(client_socket);
1205 RelinquishDPCClient(MagickTrue);
1206 return(HANDLER_RETURN_VALUE);
1208 AuthenticateDPCClient();
1209 authenticated=MagickTrue;
1210 exception=AcquireExceptionInfo();
1211 registry=NewSplayTree((
int (*)(
const void *,
const void *)) NULL,
1212 (
void *(*)(
void *)) NULL,RelinquishImageRegistry);
1216 for (status=MagickFalse; ; )
1221 count=dpc_receive_deadline(client_socket,1,(
unsigned char *) &command,
1222 (
double) time((time_t *) NULL)+5.0);
1225 count=dpc_receive_deadline(client_socket,
sizeof(key),(
unsigned char *) &key,
1226 (
double) time((time_t *) NULL)+5.0);
1227 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1233 status=OpenDistributeCache(registry,client_socket,session_key,
1235 dpc_send(client_socket,
sizeof(status),&status);
1240 status=ReadDistributeCachePixels(registry,client_socket,session_key,
1246 status=ReadDistributeCacheMetacontent(registry,client_socket,
1247 session_key,exception);
1252 status=WriteDistributeCachePixels(registry,client_socket,session_key,
1258 status=WriteDistributeCacheMetacontent(registry,client_socket,
1259 session_key,exception);
1264 status=DestroyDistributeCache(registry,session_key);
1270 if ((status == MagickFalse) || (command ==
'd'))
1273 count=dpc_send(client_socket,
sizeof(status),&status);
1274 CLOSE_SOCKET(client_socket);
1275 exception=DestroyExceptionInfo(exception);
1276 registry=DestroySplayTree(registry);
1277 RelinquishDPCClient(authenticated == MagickFalse ? MagickTrue :
1279 return(HANDLER_RETURN_VALUE);
1282static size_t GetDPCPolicyLimit(
const char *name,
const size_t default_limit)
1285 policy_name[MagickPathExtent],
1291 limit=default_limit;
1292 (void) FormatLocaleString(policy_name,MagickPathExtent,
"cache:%s",name);
1293 policy_value=GetPolicyValue(policy_name);
1294 if (policy_value != (
char *) NULL)
1303 policy_limit=strtoul(policy_value,&q,10);
1304 if ((errno == 0) && (q != policy_value) && (policy_limit != 0))
1305 limit=(size_t) policy_limit;
1306 policy_value=DestroyString(policy_value);
1311static size_t GetMaxDPCClients(
void)
1313 return(GetDPCPolicyLimit(
"max-dpc-clients",DPCMaxClientWorkers));
1316static size_t GetMaxDPCUnauthenticatedClients(
void)
1320 unauthenticated_workers;
1322 client_workers=GetMaxDPCClients();
1323 unauthenticated_workers=GetDPCPolicyLimit(
"max-dpc-unauthenticated-clients",
1324 DPCMaxUnauthenticatedClientWorkers);
1325 return(MagickMin(unauthenticated_workers,client_workers));
1328static MagickBooleanType AcquireDPCClientWorker(
void)
1335 unauthenticated_worker_limit;
1338 max_dpc_clients=GetMaxDPCClients();
1339 unauthenticated_worker_limit=GetMaxDPCUnauthenticatedClients();
1341 if ((dpc_clients < max_dpc_clients) &&
1342 (dpc_unauthenticated_clients < unauthenticated_worker_limit))
1345 dpc_unauthenticated_clients++;
1348 UnlockSemaphoreInfo(dpc_semaphore);
1352MagickExport
void DistributePixelCacheServer(
const int port,
1353 ExceptionInfo *exception)
1356 service[MagickPathExtent];
1361#if defined(MAGICKCORE_THREAD_SUPPORT)
1367#elif defined(_MSC_VER)
1390 assert(exception != (ExceptionInfo *) NULL);
1391 assert(exception->signature == MagickCoreSignature);
1392 magick_unreferenced(exception);
1393 dpc_shared_secret=GetPolicyValue(
"cache:shared-secret");
1394 if (dpc_shared_secret == (
char *) NULL)
1395 ThrowFatalException(CacheFatalError,
"no shared secret");
1396#if defined(MAGICKCORE_HAVE_WINSOCK2)
1397 InitializeWinsock2(MagickFalse);
1399 (void) memset(&hint,0,
sizeof(hint));
1400 hint.ai_family=AF_INET;
1401 hint.ai_socktype=SOCK_STREAM;
1402 hint.ai_flags=AI_PASSIVE;
1403 FormatLocaleString(service,MagickPathExtent,
"%d",port);
1404 status=getaddrinfo(NULL,service,&hint,&result);
1406 ThrowFatalException(CacheFatalError,
"UnableToListen");
1407 server_socket=(SOCKET_TYPE) 0;
1408 for (p=result; p != NULL; p=p->ai_next)
1413 server_socket=(SOCKET_TYPE) socket(p->ai_family,p->ai_socktype,
1415 if (server_socket == -1)
1417 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(
char *) &one,
1418 (socklen_t)
sizeof(one));
1421 CLOSE_SOCKET(server_socket);
1424 SetSocketReceiveTimeout(server_socket,5.0);
1425 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1428 CLOSE_SOCKET(server_socket);
1433 if (p == (
struct addrinfo *) NULL)
1434 ThrowFatalException(CacheFatalError,
"UnableToBind");
1435 freeaddrinfo(result);
1436 status=listen(server_socket,DPCPendingConnections);
1438 ThrowFatalException(CacheFatalError,
"UnableToListen");
1439#if defined(MAGICKCORE_THREAD_SUPPORT)
1440 pthread_attr_init(&attributes);
1441 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1449 length = (socklen_t)
sizeof(address);
1451 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(
sizeof(SOCKET_TYPE));
1452 if (client_socket_ptr == NULL)
1454 *client_socket_ptr=(SOCKET_TYPE) accept(server_socket,(
struct sockaddr *)
1456 if (*client_socket_ptr == -1)
1458 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1462 if (AcquireDPCClientWorker() == MagickFalse)
1464 CLOSE_SOCKET(*client_socket_ptr);
1465 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1469 SetSocketReceiveTimeout(*client_socket_ptr,5.0);
1472 CLOSE_SOCKET(*client_socket_ptr);
1473 RelinquishDPCClient(MagickTrue);
1474 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1478#if defined(MAGICKCORE_THREAD_SUPPORT)
1479 status=pthread_create(&thread_id,&attributes,DistributePixelCacheConnectionHandler,
1480 (
void *) client_socket_ptr);
1483 CLOSE_SOCKET(*client_socket_ptr);
1484 RelinquishDPCClient(MagickTrue);
1485 RelinquishMagickMemory(client_socket_ptr);
1488#elif defined(_MSC_VER)
1489 if (CreateThread(0,0,DistributePixelCacheConnectionHandler,(
void*) client_socket_ptr,
1490 0,&threadID) == (HANDLE) NULL)
1492 CLOSE_SOCKET(*client_socket_ptr);
1493 RelinquishDPCClient(MagickTrue);
1494 RelinquishMagickMemory(client_socket_ptr);
1518MagickPrivate
void DistributeCacheTerminus(
void)
1520#ifdef MAGICKCORE_HAVE_WINSOCK2
1522 ActivateSemaphoreInfo(&winsock_semaphore);
1523 LockSemaphoreInfo(winsock_semaphore);
1524 if (wsaData != (WSADATA *) NULL)
1527 wsaData=(WSADATA *) RelinquishMagickMemory((
void *) wsaData);
1529 UnlockSemaphoreInfo(winsock_semaphore);
1530 RelinquishSemaphoreInfo(&winsock_semaphore);
1532#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
1533 if (dpc_shared_secret != (
char *) NULL)
1534 dpc_shared_secret=DestroyString(dpc_shared_secret);
1536 RelinquishSemaphoreInfo(&dpc_semaphore);
1563MagickPrivate
int GetDistributeCacheFile(
const DistributeCacheInfo *server_info)
1565 assert(server_info != (DistributeCacheInfo *) NULL);
1566 assert(server_info->signature == MagickCoreSignature);
1567 return(server_info->file);
1594MagickPrivate
const char *GetDistributeCacheHostname(
1595 const DistributeCacheInfo *server_info)
1597 assert(server_info != (DistributeCacheInfo *) NULL);
1598 assert(server_info->signature == MagickCoreSignature);
1599 return(server_info->hostname);
1625MagickPrivate
int GetDistributeCachePort(
const DistributeCacheInfo *server_info)
1627 assert(server_info != (DistributeCacheInfo *) NULL);
1628 assert(server_info->signature == MagickCoreSignature);
1629 return(server_info->port);
1657MagickPrivate MagickBooleanType OpenDistributePixelCache(
1658 DistributeCacheInfo *server_info,Image *image)
1667 message[MagickPathExtent],
1673 assert(server_info != (DistributeCacheInfo *) NULL);
1674 assert(server_info->signature == MagickCoreSignature);
1675 assert(image != (Image *) NULL);
1676 assert(image->signature == MagickCoreSignature);
1682 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1683 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1684 (void) memcpy(p,&image->storage_class,
sizeof(image->storage_class));
1685 p+=(ptrdiff_t)
sizeof(image->storage_class);
1686 (void) memcpy(p,&image->colorspace,
sizeof(image->colorspace));
1687 p+=(ptrdiff_t)
sizeof(image->colorspace);
1688 (void) memcpy(p,&image->alpha_trait,
sizeof(image->alpha_trait));
1689 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
1690 (void) memcpy(p,&image->channels,
sizeof(image->channels));
1691 p+=(ptrdiff_t)
sizeof(image->channels);
1692 (void) memcpy(p,&image->columns,
sizeof(image->columns));
1693 p+=(ptrdiff_t)
sizeof(image->columns);
1694 (void) memcpy(p,&image->rows,
sizeof(image->rows));
1695 p+=(ptrdiff_t)
sizeof(image->rows);
1696 (void) memcpy(p,&image->number_channels,
sizeof(image->number_channels));
1697 p+=(ptrdiff_t)
sizeof(image->number_channels);
1698 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1699 sizeof(*image->channel_map));
1700 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
1701 (void) memcpy(p,&image->metacontent_extent,
sizeof(image->metacontent_extent));
1702 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
1703 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1704 if (count != (MagickOffsetType) (p-message))
1705 return(MagickFalse);
1707 count=dpc_receive(server_info->file,
sizeof(status),(
unsigned char *) &status);
1708 if (count != (MagickOffsetType)
sizeof(status))
1709 return(MagickFalse);
1746MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1747 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1748 const MagickSizeType length,
unsigned char *metacontent)
1754 message[MagickPathExtent],
1760 assert(server_info != (DistributeCacheInfo *) NULL);
1761 assert(server_info->signature == MagickCoreSignature);
1762 assert(region != (RectangleInfo *) NULL);
1763 assert(metacontent != (
unsigned char *) NULL);
1764 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1768 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1769 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1770 (void) memcpy(p,®ion->width,
sizeof(region->width));
1771 p+=(ptrdiff_t)
sizeof(region->width);
1772 (void) memcpy(p,®ion->height,
sizeof(region->height));
1773 p+=(ptrdiff_t)
sizeof(region->height);
1774 (void) memcpy(p,®ion->x,
sizeof(region->x));
1775 p+=(ptrdiff_t)
sizeof(region->x);
1776 (void) memcpy(p,®ion->y,
sizeof(region->y));
1777 p+=(ptrdiff_t)
sizeof(region->y);
1778 (void) memcpy(p,&length,
sizeof(length));
1779 p+=(ptrdiff_t)
sizeof(length);
1780 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1781 if (count != (MagickOffsetType) (p-message))
1783 return(dpc_receive(server_info->file,length,metacontent));
1819MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1820 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1821 const MagickSizeType length,
unsigned char *magick_restrict pixels)
1827 message[MagickPathExtent],
1833 assert(server_info != (DistributeCacheInfo *) NULL);
1834 assert(server_info->signature == MagickCoreSignature);
1835 assert(region != (RectangleInfo *) NULL);
1836 assert(pixels != (
unsigned char *) NULL);
1837 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1841 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1842 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1843 (void) memcpy(p,®ion->width,
sizeof(region->width));
1844 p+=(ptrdiff_t)
sizeof(region->width);
1845 (void) memcpy(p,®ion->height,
sizeof(region->height));
1846 p+=(ptrdiff_t)
sizeof(region->height);
1847 (void) memcpy(p,®ion->x,
sizeof(region->x));
1848 p+=(ptrdiff_t)
sizeof(region->x);
1849 (void) memcpy(p,®ion->y,
sizeof(region->y));
1850 p+=(ptrdiff_t)
sizeof(region->y);
1851 (void) memcpy(p,&length,
sizeof(length));
1852 p+=(ptrdiff_t)
sizeof(length);
1853 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1854 if (count != (MagickOffsetType) (p-message))
1856 return(dpc_receive(server_info->file,length,pixels));
1883MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1884 DistributeCacheInfo *server_info)
1893 message[MagickPathExtent],
1899 assert(server_info != (DistributeCacheInfo *) NULL);
1900 assert(server_info->signature == MagickCoreSignature);
1903 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1904 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1905 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1906 if (count != (MagickOffsetType) (p-message))
1907 return(MagickFalse);
1909 count=dpc_receive(server_info->file,
sizeof(status),(
unsigned char *) &status);
1910 if (count != (MagickOffsetType)
sizeof(status))
1911 return(MagickFalse);
1948MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1949 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1950 const MagickSizeType length,
const unsigned char *metacontent)
1956 message[MagickPathExtent],
1962 assert(server_info != (DistributeCacheInfo *) NULL);
1963 assert(server_info->signature == MagickCoreSignature);
1964 assert(region != (RectangleInfo *) NULL);
1965 assert(metacontent != (
unsigned char *) NULL);
1966 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1970 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1971 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1972 (void) memcpy(p,®ion->width,
sizeof(region->width));
1973 p+=(ptrdiff_t)
sizeof(region->width);
1974 (void) memcpy(p,®ion->height,
sizeof(region->height));
1975 p+=(ptrdiff_t)
sizeof(region->height);
1976 (void) memcpy(p,®ion->x,
sizeof(region->x));
1977 p+=(ptrdiff_t)
sizeof(region->x);
1978 (void) memcpy(p,®ion->y,
sizeof(region->y));
1979 p+=(ptrdiff_t)
sizeof(region->y);
1980 (void) memcpy(p,&length,
sizeof(length));
1981 p+=(ptrdiff_t)
sizeof(length);
1982 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1983 if (count != (MagickOffsetType) (p-message))
1985 return(dpc_send(server_info->file,length,metacontent));
2022MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
2023 DistributeCacheInfo *server_info,
const RectangleInfo *region,
2024 const MagickSizeType length,
const unsigned char *magick_restrict pixels)
2030 message[MagickPathExtent],
2036 assert(server_info != (DistributeCacheInfo *) NULL);
2037 assert(server_info->signature == MagickCoreSignature);
2038 assert(region != (RectangleInfo *) NULL);
2039 assert(pixels != (
const unsigned char *) NULL);
2040 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
2044 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
2045 p+=(ptrdiff_t)
sizeof(server_info->session_key);
2046 (void) memcpy(p,®ion->width,
sizeof(region->width));
2047 p+=(ptrdiff_t)
sizeof(region->width);
2048 (void) memcpy(p,®ion->height,
sizeof(region->height));
2049 p+=(ptrdiff_t)
sizeof(region->height);
2050 (void) memcpy(p,®ion->x,
sizeof(region->x));
2051 p+=(ptrdiff_t)
sizeof(region->x);
2052 (void) memcpy(p,®ion->y,
sizeof(region->y));
2053 p+=(ptrdiff_t)
sizeof(region->y);
2054 (void) memcpy(p,&length,
sizeof(length));
2055 p+=(ptrdiff_t)
sizeof(length);
2056 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
2057 if (count != (MagickOffsetType) (p-message))
2059 return(dpc_send(server_info->file,length,pixels));