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)
132 dpc_unauthenticated_clients = 0;
158#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
159static inline MagickOffsetType dpc_read(SOCKET_TYPE magick_unused(file),
160 const MagickSizeType magick_unused(length),
161 unsigned char *magick_restrict magick_unused(message))
163 magick_unreferenced(file);
164 magick_unreferenced(length);
165 magick_unreferenced(message);
169static inline MagickOffsetType dpc_read(SOCKET_TYPE file,
170 const MagickSizeType length,
unsigned char *magick_restrict message)
172 MagickOffsetType offset = 0;
173 while (offset < (MagickOffsetType) length)
175 MagickSizeType remaining = length-(MagickSizeType) offset;
176 ssize_t count = recv(file,(
char *) message+offset,(LENGTH_TYPE)
177 MagickMin(remaining,(MagickSizeType) MagickMaxBufferExtent),0);
179 offset+=(MagickOffsetType) count;
193#if defined(MAGICKCORE_HAVE_WINSOCK2)
194static void InitializeWinsock2(MagickBooleanType use_lock)
196 if (use_lock != MagickFalse)
199 ActivateSemaphoreInfo(&winsock_semaphore);
200 LockSemaphoreInfo(winsock_semaphore);
202 if (wsaData == (WSADATA *) NULL)
204 wsaData=(WSADATA *) AcquireMagickMemory(
sizeof(WSADATA));
205 if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
206 ThrowFatalException(CacheFatalError,
"WSAStartup failed");
208 if (use_lock != MagickFalse)
209 UnlockSemaphoreInfo(winsock_semaphore);
213#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
214static int ConnectPixelCacheServer(
const char *magick_unused(hostname),
215 const int magick_unused(port),uint64_t *magick_unused(session_key),
216 ExceptionInfo *exception)
218 magick_unreferenced(hostname);
219 magick_unreferenced(port);
220 magick_unreferenced(session_key);
221 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
222 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
226static inline uint64_t ROTL(uint64_t x,
int b)
228 return((x << b) | (x >> (64-b)));
231static inline uint64_t U8TO64_LE(
const uint8_t *p)
233 return(((uint64_t) p[0] << 0) | ((uint64_t) p[1] << 8) |
234 ((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
235 ((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
236 ((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
239static inline uint64_t SIPHash24(
const uint8_t key[16],
const uint8_t *message,
243 *end = message+length-(length % 8);
249 b = ((uint64_t) length) << 56,
251 k1 = U8TO64_LE(key+8),
253 v0 = 0x736f6d6570736575ULL ^ k0,
254 v1 = 0x646f72616e646f6dULL ^ k1,
255 v2 = 0x6c7967656e657261ULL ^ k0,
256 v3 = 0x7465646279746573ULL ^ k1;
258 for ( ; message != end; message+=8)
260 m=U8TO64_LE(message);
262 for (i=0; i < 2; i++)
264 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
265 v2+=v3; v3=ROTL(v3,16); v3^=v2;
266 v0+=v3; v3=ROTL(v3,21); v3^=v0;
267 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
271 switch (length & 0x07)
273 case 7: b|=((uint64_t) message[6]) << 48; magick_fallthrough;
274 case 6: b|=((uint64_t) message[5]) << 40; magick_fallthrough;
275 case 5: b|=((uint64_t) message[4]) << 32; magick_fallthrough;
276 case 4: b|=((uint64_t) message[3]) << 24; magick_fallthrough;
277 case 3: b|=((uint64_t) message[2]) << 16; magick_fallthrough;
278 case 2: b|=((uint64_t) message[1]) << 8; magick_fallthrough;
279 case 1: b|=((uint64_t) message[0]); magick_fallthrough;
283 for (i=0; i < 2; i++)
285 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
286 v2+=v3; v3=ROTL(v3,16); v3^=v2;
287 v0+=v3; v3=ROTL(v3,21); v3^=v0;
288 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
292 for (i=0; i < 4; i++)
294 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
295 v2+=v3; v3=ROTL(v3,16); v3^=v2;
296 v0+=v3; v3=ROTL(v3,21); v3^=v0;
297 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
302static inline void DeriveSIPKeyFromSecret(
const char *shared_secret,
310 k0 = 0x0706050403020100ULL,
311 k1 = 0x0f0e0d0c0b0a0908ULL;
313 length=strlen(shared_secret);
314 for (i=0; i < length; i++)
317 b = shared_secret[i];
320 k0*=0x100000001b3ULL;
321 k1^=(uint64_t) b << ((i & 7)*8);
322 k1=(k1 << 5) | (k1 >> (64-5));
324 (void) memcpy(key,&k0,8);
325 (void) memcpy(key+8,&k1,8);
328static inline uint64_t GenerateSessionKey(
const char *shared_secret,
329 const unsigned char *nonce,
size_t length)
334 DeriveSIPKeyFromSecret(shared_secret,key);
335 return(SIPHash24(key,nonce,length));
338static int ConnectPixelCacheServer(
const char *hostname,
const int port,
339 uint64_t *session_key,ExceptionInfo *exception)
341#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
344 service[MagickPathExtent],
361 nonce[DPCSessionKeyLength];
367#if defined(MAGICKCORE_HAVE_WINSOCK2)
368 InitializeWinsock2(MagickTrue);
370 (void) memset(&hints,0,
sizeof(hints));
371 hints.ai_family=AF_INET;
372 hints.ai_socktype=SOCK_STREAM;
373 hints.ai_flags=AI_PASSIVE;
374 (void) FormatLocaleString(service,MagickPathExtent,
"%d",port);
375 status=getaddrinfo(hostname,service,&hints,&result);
378 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
379 "DistributedPixelCache",
"'%s': %s",hostname,gai_strerror(status));
382 client_socket=(SOCKET_TYPE) socket(result->ai_family,result->ai_socktype,
383 result->ai_protocol);
384 if (client_socket == -1)
386 freeaddrinfo(result);
387 message=GetExceptionMessage(errno);
388 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
389 "DistributedPixelCache",
"'%s': %s",hostname,message);
390 message=DestroyString(message);
393 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
394 freeaddrinfo(result);
397 CLOSE_SOCKET(client_socket);
398 message=GetExceptionMessage(errno);
399 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
400 "DistributedPixelCache",
"'%s': %s",hostname,message);
401 message=DestroyString(message);
407 count=recv(client_socket,(
char *) nonce,
sizeof(nonce),0);
408 if (count != (ssize_t)
sizeof(nonce))
410 CLOSE_SOCKET(client_socket);
411 message=GetExceptionMessage(errno);
412 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
413 "DistributedPixelCache",
"'%s': %s",hostname,message);
414 message=DestroyString(message);
420 shared_secret=GetPolicyValue(
"cache:shared-secret");
421 if (shared_secret == (
char*) NULL)
423 CLOSE_SOCKET(client_socket);
424 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
425 "DistributedPixelCache",
"'%s': shared secret required",hostname);
428 *session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
429 shared_secret=DestroyString(shared_secret);
433 count=send(client_socket,(
char *) session_key,
sizeof(*session_key),
435 if (count != (ssize_t)
sizeof(*session_key))
437 CLOSE_SOCKET(client_socket);
438 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
439 "DistributedPixelCache",
"'%s': authentication failed",hostname);
442 return((
int) client_socket);
444 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
445 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
451static char *GetHostname(
int *port,ExceptionInfo *exception)
470 hosts=(
char *) GetImageRegistry(StringRegistryType,
"cache:hosts",exception);
471 if (hosts == (
char *) NULL)
474 return(AcquireString(DPCHostname));
476 (void) SubstituteString(&hosts,
",",
" ");
477 hostlist=StringToArgv(hosts,&argc);
478 hosts=DestroyString(hosts);
479 if ((hostlist == (
char **) NULL) || ((argc-1) == 0))
482 return(AcquireString(DPCHostname));
485 size_t host_count = (size_t) argc-1;
486 size_t index = (
id++ % host_count)+1;
487 hosts=AcquireString(hostlist[index]);
489 for (i=0; i < (ssize_t) argc; i++)
490 hostlist[i]=DestroyString(hostlist[i]);
491 hostlist=(
char **) RelinquishMagickMemory(hostlist);
492 (void) SubstituteString(&hosts,
":",
" ");
493 hostlist=StringToArgv(hosts,&argc);
494 if (hostlist == (
char **) NULL)
497 return(AcquireString(DPCHostname));
499 host=AcquireString(hostlist[1]);
500 if (hostlist[2] == (
char *) NULL)
503 *port=StringToLong(hostlist[2]);
504 for (i=0; i < (ssize_t) argc; i++)
505 hostlist[i]=DestroyString(hostlist[i]);
506 hostlist=(
char **) RelinquishMagickMemory(hostlist);
510MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
511 ExceptionInfo *exception)
525 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
526 sizeof(*server_info));
527 (void) memset(server_info,0,
sizeof(*server_info));
528 server_info->signature=MagickCoreSignature;
530 hostname=GetHostname(&server_info->port,exception);
532 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
533 &session_key,exception);
534 if (server_info->file == -1)
535 server_info=DestroyDistributeCacheInfo(server_info);
538 server_info->session_key=session_key;
539 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
540 server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
543 hostname=DestroyString(hostname);
571MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
572 DistributeCacheInfo *server_info)
574 assert(server_info != (DistributeCacheInfo *) NULL);
575 assert(server_info->signature == MagickCoreSignature);
576#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
577 if (server_info->file >= 0)
578 CLOSE_SOCKET(server_info->file);
580 server_info->signature=(~MagickCoreSignature);
581 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
611#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
612static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
613 const MagickSizeType magick_unused(length),
614 const void *magick_restrict magick_unused(message))
616 magick_unreferenced(file);
617 magick_unreferenced(length);
618 magick_unreferenced(message);
622static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
623 const MagickSizeType length,
const void *magick_restrict message)
635 for (i=0; i < (MagickOffsetType) length; i+=count)
637 count=(ssize_t) send(file,(
char *) message+i,(LENGTH_TYPE) MagickMin(
638 length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
651#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
652MagickExport
void DistributePixelCacheServer(
const int magick_unused(port),
653 ExceptionInfo *magick_unused(exception))
655 magick_unreferenced(port);
656 magick_unreferenced(exception);
657 ThrowFatalException(MissingDelegateError,
"DelegateLibrarySupportNotBuiltIn");
660static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
661 const uint64_t session_key)
664 key = (MagickAddressType) session_key;
669 return(DeleteNodeFromSplayTree(registry,(
const void *) key));
672static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
673 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
679 key = (MagickAddressType) session_key;
691 message[MagickPathExtent],
697 image=AcquireImage((ImageInfo *) NULL,exception);
698 if (image == (Image *) NULL)
700 length=
sizeof(image->storage_class)+
sizeof(image->colorspace)+
701 sizeof(image->alpha_trait)+
sizeof(image->channels)+
sizeof(image->columns)+
702 sizeof(image->rows)+
sizeof(image->number_channels)+MaxPixelChannels*
703 sizeof(*image->channel_map)+
sizeof(image->metacontent_extent);
704 count=dpc_read(file,length,message);
705 if (count != (MagickOffsetType) length)
707 image=DestroyImage(image);
714 (void) memcpy(&image->storage_class,p,
sizeof(image->storage_class));
715 p+=(ptrdiff_t)
sizeof(image->storage_class);
716 (void) memcpy(&image->colorspace,p,
sizeof(image->colorspace));
717 p+=(ptrdiff_t)
sizeof(image->colorspace);
718 (void) memcpy(&image->alpha_trait,p,
sizeof(image->alpha_trait));
719 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
720 (void) memcpy(&image->channels,p,
sizeof(image->channels));
721 p+=(ptrdiff_t)
sizeof(image->channels);
722 (void) memcpy(&image->columns,p,
sizeof(image->columns));
723 p+=(ptrdiff_t)
sizeof(image->columns);
724 (void) memcpy(&image->rows,p,
sizeof(image->rows));
725 p+=(ptrdiff_t)
sizeof(image->rows);
726 (void) memcpy(&image->number_channels,p,
sizeof(image->number_channels));
727 p+=(ptrdiff_t)
sizeof(image->number_channels);
728 (void) memcpy(image->channel_map,p,MaxPixelChannels*
729 sizeof(*image->channel_map));
730 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
731 (void) memcpy(&image->metacontent_extent,p,
sizeof(image->metacontent_extent));
732 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
733 if (SyncImagePixelCache(image,exception) == MagickFalse)
735 image=DestroyImage(image);
738 status=AddValueToSplayTree(registry,(
const void *) key,image);
739 if (status == MagickFalse)
741 image=DestroyImage(image);
747static inline MagickBooleanType ValidateDistributedPixelCache(
748 const RectangleInfo *region,
const size_t per_pixel,
749 const MagickSizeType length)
755 if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
757 if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
759 if (length > (MagickSizeType) extent)
764static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
765 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
777 key = (MagickAddressType) session_key;
792 message[MagickPathExtent],
798 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
799 if (image == (Image *) NULL)
801 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
802 sizeof(region.y)+
sizeof(length);
803 count=dpc_read(file,length,message);
804 if (count != (MagickOffsetType) length)
807 (void) memcpy(®ion.width,q,
sizeof(region.width));
808 q+=(ptrdiff_t)
sizeof(region.width);
809 (void) memcpy(®ion.height,q,
sizeof(region.height));
810 q+=(ptrdiff_t)
sizeof(region.height);
811 (void) memcpy(®ion.x,q,
sizeof(region.x));
812 q+=(ptrdiff_t)
sizeof(region.x);
813 (void) memcpy(®ion.y,q,
sizeof(region.y));
814 q+=(ptrdiff_t)
sizeof(region.y);
815 (void) memcpy(&length,q,
sizeof(length));
816 q+=(ptrdiff_t)
sizeof(length);
817 per_pixel=image->number_meta_channels*
sizeof(Quantum);
818 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
820 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
822 if (p == (
const Quantum *) NULL)
824 metacontent=(
const unsigned char *) GetVirtualMetacontent(image);
825 count=dpc_send(file,length,metacontent);
826 if (count != (MagickOffsetType) length)
831static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
832 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
841 key = (MagickAddressType) session_key;
856 message[MagickPathExtent],
862 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
863 if (image == (Image *) NULL)
865 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
866 sizeof(region.y)+
sizeof(length);
867 count=dpc_read(file,length,message);
868 if (count != (MagickOffsetType) length)
871 (void) memcpy(®ion.width,q,
sizeof(region.width));
872 q+=(ptrdiff_t)
sizeof(region.width);
873 (void) memcpy(®ion.height,q,
sizeof(region.height));
874 q+=(ptrdiff_t)
sizeof(region.height);
875 (void) memcpy(®ion.x,q,
sizeof(region.x));
876 q+=(ptrdiff_t)
sizeof(region.x);
877 (void) memcpy(®ion.y,q,
sizeof(region.y));
878 q+=(ptrdiff_t)
sizeof(region.y);
879 (void) memcpy(&length,q,
sizeof(length));
880 per_pixel=image->number_channels*
sizeof(Quantum);
881 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
883 q+=(ptrdiff_t)
sizeof(length);
884 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
886 if (p == (
const Quantum *) NULL)
888 count=dpc_send(file,length,p);
889 if (count != (MagickOffsetType) length)
894static void *RelinquishImageRegistry(
void *image)
896 return((
void *) DestroyImageList((Image *) image));
899static MagickBooleanType WriteDistributeCacheMetacontent(
900 SplayTreeInfo *registry,SOCKET_TYPE file,
const uint64_t session_key,
901 ExceptionInfo *exception)
907 key = (MagickAddressType) session_key;
925 message[MagickPathExtent],
932 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
933 if (image == (Image *) NULL)
935 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
936 sizeof(region.y)+
sizeof(length);
937 count=dpc_read(file,length,message);
938 if (count != (MagickOffsetType) length)
941 (void) memcpy(®ion.width,p,
sizeof(region.width));
942 p+=(ptrdiff_t)
sizeof(region.width);
943 (void) memcpy(®ion.height,p,
sizeof(region.height));
944 p+=(ptrdiff_t)
sizeof(region.height);
945 (void) memcpy(®ion.x,p,
sizeof(region.x));
946 p+=(ptrdiff_t)
sizeof(region.x);
947 (void) memcpy(®ion.y,p,
sizeof(region.y));
948 p+=(ptrdiff_t)
sizeof(region.y);
949 (void) memcpy(&length,p,
sizeof(length));
950 per_pixel=image->number_meta_channels*
sizeof(Quantum);
951 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
953 p+=(ptrdiff_t)
sizeof(length);
954 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
956 if (q == (Quantum *) NULL)
958 metacontent=(
unsigned char *) GetAuthenticMetacontent(image);
959 count=dpc_read(file,length,metacontent);
960 if (count != (MagickOffsetType) length)
962 return(SyncAuthenticPixels(image,exception));
965static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
966 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
972 key = (MagickAddressType) session_key;
990 message[MagickPathExtent],
996 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
997 if (image == (Image *) NULL)
999 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
1000 sizeof(region.y)+
sizeof(length);
1001 count=dpc_read(file,length,message);
1002 if (count != (MagickOffsetType) length)
1003 return(MagickFalse);
1005 (void) memcpy(®ion.width,p,
sizeof(region.width));
1006 p+=(ptrdiff_t)
sizeof(region.width);
1007 (void) memcpy(®ion.height,p,
sizeof(region.height));
1008 p+=(ptrdiff_t)
sizeof(region.height);
1009 (void) memcpy(®ion.x,p,
sizeof(region.x));
1010 p+=(ptrdiff_t)
sizeof(region.x);
1011 (void) memcpy(®ion.y,p,
sizeof(region.y));
1012 p+=(ptrdiff_t)
sizeof(region.y);
1013 (void) memcpy(&length,p,
sizeof(length));
1014 per_pixel=image->number_channels*
sizeof(Quantum);
1015 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
1016 return(MagickFalse);
1017 p+=(ptrdiff_t)
sizeof(length);
1018 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1020 if (q == (Quantum *) NULL)
1021 return(MagickFalse);
1022 count=dpc_read(file,length,(
unsigned char *) q);
1023 if (count != (MagickOffsetType) length)
1024 return(MagickFalse);
1025 return(SyncAuthenticPixels(image,exception));
1028static void LockDPCSemaphore(
void)
1031 ActivateSemaphoreInfo(&dpc_semaphore);
1032 LockSemaphoreInfo(dpc_semaphore);
1035static void AuthenticateDPCClient(
void)
1038 if (dpc_unauthenticated_clients != 0)
1039 dpc_unauthenticated_clients--;
1040 UnlockSemaphoreInfo(dpc_semaphore);
1043static void RelinquishDPCClient(
const MagickBooleanType unauthenticated)
1046 if ((unauthenticated != MagickFalse) && (dpc_unauthenticated_clients != 0))
1047 dpc_unauthenticated_clients--;
1048 if (dpc_clients != 0)
1050 UnlockSemaphoreInfo(dpc_semaphore);
1053static HANDLER_RETURN_TYPE DistributePixelCacheClient(
void *socket_arg)
1062 authenticated = MagickFalse,
1063 status = MagickFalse;
1073 *client_socket_ptr = (SOCKET_TYPE *) socket_arg;
1087 nonce[DPCSessionKeyLength];
1092 client_socket=(*client_socket_ptr);
1093 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
1094 shared_secret=GetPolicyValue(
"cache:shared-secret");
1095 if (shared_secret == NULL)
1096 ThrowFatalException(CacheFatalError,
"shared secret required");
1100 random_info=AcquireRandomInfo();
1101 entropy=GetRandomKey(random_info,
sizeof(nonce));
1102 (void) memcpy(nonce,GetStringInfoDatum(entropy),
sizeof(nonce));
1103 entropy=DestroyStringInfo(entropy);
1104 random_info=DestroyRandomInfo(random_info);
1108 session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
1109 shared_secret=DestroyString(shared_secret);
1113 count=dpc_send(client_socket,
sizeof(nonce),nonce);
1114 if (count != (MagickOffsetType)
sizeof(nonce))
1116 CLOSE_SOCKET(client_socket);
1117 RelinquishDPCClient(MagickTrue);
1118 return(HANDLER_RETURN_VALUE);
1123 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1124 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1126 CLOSE_SOCKET(client_socket);
1127 RelinquishDPCClient(MagickTrue);
1128 return(HANDLER_RETURN_VALUE);
1130 AuthenticateDPCClient();
1131 authenticated=MagickTrue;
1132 exception=AcquireExceptionInfo();
1133 registry=NewSplayTree((
int (*)(
const void *,
const void *)) NULL,
1134 (
void *(*)(
void *)) NULL,RelinquishImageRegistry);
1138 for (status=MagickFalse; ; )
1143 count=dpc_read(client_socket,1,(
unsigned char *) &command);
1146 count=dpc_read(client_socket,
sizeof(key),(
unsigned char *) &key);
1147 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1153 status=OpenDistributeCache(registry,client_socket,session_key,
1155 dpc_send(client_socket,
sizeof(status),&status);
1160 status=ReadDistributeCachePixels(registry,client_socket,session_key,
1166 status=ReadDistributeCacheMetacontent(registry,client_socket,
1167 session_key,exception);
1172 status=WriteDistributeCachePixels(registry,client_socket,session_key,
1178 status=WriteDistributeCacheMetacontent(registry,client_socket,
1179 session_key,exception);
1184 status=DestroyDistributeCache(registry,session_key);
1190 if ((status == MagickFalse) || (command ==
'd'))
1193 count=dpc_send(client_socket,
sizeof(status),&status);
1194 CLOSE_SOCKET(client_socket);
1195 exception=DestroyExceptionInfo(exception);
1196 registry=DestroySplayTree(registry);
1197 RelinquishDPCClient(authenticated == MagickFalse ? MagickTrue :
1199 return(HANDLER_RETURN_VALUE);
1202static size_t GetDPCPolicyLimit(
const char *name,
const size_t default_limit)
1205 policy_name[MagickPathExtent],
1211 limit=default_limit;
1212 (void) FormatLocaleString(policy_name,MagickPathExtent,
"cache:%s",name);
1213 policy_value=GetPolicyValue(policy_name);
1214 if (policy_value != (
char *) NULL)
1223 policy_limit=strtoul(policy_value,&q,10);
1224 if ((errno == 0) && (q != policy_value) && (policy_limit != 0))
1225 limit=(size_t) policy_limit;
1226 policy_value=DestroyString(policy_value);
1231static size_t GetMaxDPCClients(
void)
1233 return(GetDPCPolicyLimit(
"max-dpc-clients",DPCMaxClientWorkers));
1236static size_t GetMaxDPCUnauthenticatedClients(
void)
1240 unauthenticated_workers;
1242 client_workers=GetMaxDPCClients();
1243 unauthenticated_workers=GetDPCPolicyLimit(
"max-dpc-unauthenticated-clients",
1244 DPCMaxUnauthenticatedClientWorkers);
1245 return(MagickMin(unauthenticated_workers,client_workers));
1248static MagickBooleanType AcquireDPCClientWorker(
void)
1255 unauthenticated_worker_limit;
1258 max_dpc_clients=GetMaxDPCClients();
1259 unauthenticated_worker_limit=GetMaxDPCUnauthenticatedClients();
1261 if ((dpc_clients < max_dpc_clients) &&
1262 (dpc_unauthenticated_clients < unauthenticated_worker_limit))
1265 dpc_unauthenticated_clients++;
1268 UnlockSemaphoreInfo(dpc_semaphore);
1272MagickExport
void DistributePixelCacheServer(
const int port,
1273 ExceptionInfo *exception)
1276 service[MagickPathExtent];
1281#if defined(MAGICKCORE_THREAD_SUPPORT)
1287#elif defined(_MSC_VER)
1310 assert(exception != (ExceptionInfo *) NULL);
1311 assert(exception->signature == MagickCoreSignature);
1312 magick_unreferenced(exception);
1313#if defined(MAGICKCORE_HAVE_WINSOCK2)
1314 InitializeWinsock2(MagickFalse);
1316 (void) memset(&hint,0,
sizeof(hint));
1317 hint.ai_family=AF_INET;
1318 hint.ai_socktype=SOCK_STREAM;
1319 hint.ai_flags=AI_PASSIVE;
1320 FormatLocaleString(service,MagickPathExtent,
"%d",port);
1321 status=getaddrinfo(NULL,service,&hint,&result);
1323 ThrowFatalException(CacheFatalError,
"UnableToListen");
1324 server_socket=(SOCKET_TYPE) 0;
1325 for (p=result; p != NULL; p=p->ai_next)
1330 server_socket=(SOCKET_TYPE) socket(p->ai_family,p->ai_socktype,
1332 if (server_socket == -1)
1334 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(
char *) &one,
1335 (socklen_t)
sizeof(one));
1338#if defined(MAGICKCORE_HAVE_WINSOCK2)
1339 DWORD timeout = 5000;
1340 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,(
const char *)
1341 &timeout,
sizeof(timeout));
1346 status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,&tv,
sizeof(tv));
1351 CLOSE_SOCKET(server_socket);
1354 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1357 CLOSE_SOCKET(server_socket);
1362 if (p == (
struct addrinfo *) NULL)
1363 ThrowFatalException(CacheFatalError,
"UnableToBind");
1364 freeaddrinfo(result);
1365 status=listen(server_socket,DPCPendingConnections);
1367 ThrowFatalException(CacheFatalError,
"UnableToListen");
1368#if defined(MAGICKCORE_THREAD_SUPPORT)
1369 pthread_attr_init(&attributes);
1370 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1378 length = (socklen_t)
sizeof(address);
1380 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(
sizeof(SOCKET_TYPE));
1381 if (client_socket_ptr == NULL)
1383 *client_socket_ptr=(SOCKET_TYPE) accept(server_socket,(
struct sockaddr *)
1385 if (*client_socket_ptr == -1)
1387 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1391 if (AcquireDPCClientWorker() == MagickFalse)
1393 CLOSE_SOCKET(*client_socket_ptr);
1394 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1398#if defined(MAGICKCORE_HAVE_WINSOCK2)
1403 status=setsockopt(*client_socket_ptr,SOL_SOCKET,SO_RCVTIMEO,
1404 (
const char *) &timeout,
sizeof(timeout));
1413 status=setsockopt(*client_socket_ptr,SOL_SOCKET,SO_RCVTIMEO,&tv,
1419 CLOSE_SOCKET(*client_socket_ptr);
1420 RelinquishDPCClient(MagickTrue);
1421 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1425#if defined(MAGICKCORE_THREAD_SUPPORT)
1426 status=pthread_create(&thread_id,&attributes,DistributePixelCacheClient,
1427 (
void *) client_socket_ptr);
1430 CLOSE_SOCKET(*client_socket_ptr);
1431 RelinquishDPCClient(MagickTrue);
1432 RelinquishMagickMemory(client_socket_ptr);
1435#elif defined(_MSC_VER)
1436 if (CreateThread(0,0,DistributePixelCacheClient,(
void*) client_socket_ptr,0,&threadID) == (HANDLE) NULL)
1438 CLOSE_SOCKET(*client_socket_ptr);
1439 RelinquishDPCClient(MagickTrue);
1440 RelinquishMagickMemory(client_socket_ptr);
1464MagickPrivate
void DistributeCacheTerminus(
void)
1466#ifdef MAGICKCORE_HAVE_WINSOCK2
1468 ActivateSemaphoreInfo(&winsock_semaphore);
1469 LockSemaphoreInfo(winsock_semaphore);
1470 if (wsaData != (WSADATA *) NULL)
1473 wsaData=(WSADATA *) RelinquishMagickMemory((
void *) wsaData);
1475 UnlockSemaphoreInfo(winsock_semaphore);
1476 RelinquishSemaphoreInfo(&winsock_semaphore);
1478#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
1480 RelinquishSemaphoreInfo(&dpc_semaphore);
1507MagickPrivate
int GetDistributeCacheFile(
const DistributeCacheInfo *server_info)
1509 assert(server_info != (DistributeCacheInfo *) NULL);
1510 assert(server_info->signature == MagickCoreSignature);
1511 return(server_info->file);
1538MagickPrivate
const char *GetDistributeCacheHostname(
1539 const DistributeCacheInfo *server_info)
1541 assert(server_info != (DistributeCacheInfo *) NULL);
1542 assert(server_info->signature == MagickCoreSignature);
1543 return(server_info->hostname);
1569MagickPrivate
int GetDistributeCachePort(
const DistributeCacheInfo *server_info)
1571 assert(server_info != (DistributeCacheInfo *) NULL);
1572 assert(server_info->signature == MagickCoreSignature);
1573 return(server_info->port);
1601MagickPrivate MagickBooleanType OpenDistributePixelCache(
1602 DistributeCacheInfo *server_info,Image *image)
1611 message[MagickPathExtent],
1617 assert(server_info != (DistributeCacheInfo *) NULL);
1618 assert(server_info->signature == MagickCoreSignature);
1619 assert(image != (Image *) NULL);
1620 assert(image->signature == MagickCoreSignature);
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,&image->storage_class,
sizeof(image->storage_class));
1629 p+=(ptrdiff_t)
sizeof(image->storage_class);
1630 (void) memcpy(p,&image->colorspace,
sizeof(image->colorspace));
1631 p+=(ptrdiff_t)
sizeof(image->colorspace);
1632 (void) memcpy(p,&image->alpha_trait,
sizeof(image->alpha_trait));
1633 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
1634 (void) memcpy(p,&image->channels,
sizeof(image->channels));
1635 p+=(ptrdiff_t)
sizeof(image->channels);
1636 (void) memcpy(p,&image->columns,
sizeof(image->columns));
1637 p+=(ptrdiff_t)
sizeof(image->columns);
1638 (void) memcpy(p,&image->rows,
sizeof(image->rows));
1639 p+=(ptrdiff_t)
sizeof(image->rows);
1640 (void) memcpy(p,&image->number_channels,
sizeof(image->number_channels));
1641 p+=(ptrdiff_t)
sizeof(image->number_channels);
1642 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1643 sizeof(*image->channel_map));
1644 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
1645 (void) memcpy(p,&image->metacontent_extent,
sizeof(image->metacontent_extent));
1646 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
1647 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1648 if (count != (MagickOffsetType) (p-message))
1649 return(MagickFalse);
1651 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1652 if (count != (MagickOffsetType)
sizeof(status))
1653 return(MagickFalse);
1690MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1691 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1692 const MagickSizeType length,
unsigned char *metacontent)
1698 message[MagickPathExtent],
1704 assert(server_info != (DistributeCacheInfo *) NULL);
1705 assert(server_info->signature == MagickCoreSignature);
1706 assert(region != (RectangleInfo *) NULL);
1707 assert(metacontent != (
unsigned char *) NULL);
1708 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1712 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1713 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1714 (void) memcpy(p,®ion->width,
sizeof(region->width));
1715 p+=(ptrdiff_t)
sizeof(region->width);
1716 (void) memcpy(p,®ion->height,
sizeof(region->height));
1717 p+=(ptrdiff_t)
sizeof(region->height);
1718 (void) memcpy(p,®ion->x,
sizeof(region->x));
1719 p+=(ptrdiff_t)
sizeof(region->x);
1720 (void) memcpy(p,®ion->y,
sizeof(region->y));
1721 p+=(ptrdiff_t)
sizeof(region->y);
1722 (void) memcpy(p,&length,
sizeof(length));
1723 p+=(ptrdiff_t)
sizeof(length);
1724 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1725 if (count != (MagickOffsetType) (p-message))
1727 return(dpc_read(server_info->file,length,metacontent));
1763MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1764 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1765 const MagickSizeType length,
unsigned char *magick_restrict pixels)
1771 message[MagickPathExtent],
1777 assert(server_info != (DistributeCacheInfo *) NULL);
1778 assert(server_info->signature == MagickCoreSignature);
1779 assert(region != (RectangleInfo *) NULL);
1780 assert(pixels != (
unsigned char *) NULL);
1781 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1785 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1786 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1787 (void) memcpy(p,®ion->width,
sizeof(region->width));
1788 p+=(ptrdiff_t)
sizeof(region->width);
1789 (void) memcpy(p,®ion->height,
sizeof(region->height));
1790 p+=(ptrdiff_t)
sizeof(region->height);
1791 (void) memcpy(p,®ion->x,
sizeof(region->x));
1792 p+=(ptrdiff_t)
sizeof(region->x);
1793 (void) memcpy(p,®ion->y,
sizeof(region->y));
1794 p+=(ptrdiff_t)
sizeof(region->y);
1795 (void) memcpy(p,&length,
sizeof(length));
1796 p+=(ptrdiff_t)
sizeof(length);
1797 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1798 if (count != (MagickOffsetType) (p-message))
1800 return(dpc_read(server_info->file,length,pixels));
1827MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1828 DistributeCacheInfo *server_info)
1837 message[MagickPathExtent],
1843 assert(server_info != (DistributeCacheInfo *) NULL);
1844 assert(server_info->signature == MagickCoreSignature);
1847 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1848 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1849 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1850 if (count != (MagickOffsetType) (p-message))
1851 return(MagickFalse);
1853 count=dpc_read(server_info->file,
sizeof(status),(
unsigned char *) &status);
1854 if (count != (MagickOffsetType)
sizeof(status))
1855 return(MagickFalse);
1892MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1893 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1894 const MagickSizeType length,
const unsigned char *metacontent)
1900 message[MagickPathExtent],
1906 assert(server_info != (DistributeCacheInfo *) NULL);
1907 assert(server_info->signature == MagickCoreSignature);
1908 assert(region != (RectangleInfo *) NULL);
1909 assert(metacontent != (
unsigned char *) NULL);
1910 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1914 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1915 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1916 (void) memcpy(p,®ion->width,
sizeof(region->width));
1917 p+=(ptrdiff_t)
sizeof(region->width);
1918 (void) memcpy(p,®ion->height,
sizeof(region->height));
1919 p+=(ptrdiff_t)
sizeof(region->height);
1920 (void) memcpy(p,®ion->x,
sizeof(region->x));
1921 p+=(ptrdiff_t)
sizeof(region->x);
1922 (void) memcpy(p,®ion->y,
sizeof(region->y));
1923 p+=(ptrdiff_t)
sizeof(region->y);
1924 (void) memcpy(p,&length,
sizeof(length));
1925 p+=(ptrdiff_t)
sizeof(length);
1926 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1927 if (count != (MagickOffsetType) (p-message))
1929 return(dpc_send(server_info->file,length,metacontent));
1966MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1967 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1968 const MagickSizeType length,
const unsigned char *magick_restrict pixels)
1974 message[MagickPathExtent],
1980 assert(server_info != (DistributeCacheInfo *) NULL);
1981 assert(server_info->signature == MagickCoreSignature);
1982 assert(region != (RectangleInfo *) NULL);
1983 assert(pixels != (
const unsigned char *) NULL);
1984 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1988 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1989 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1990 (void) memcpy(p,®ion->width,
sizeof(region->width));
1991 p+=(ptrdiff_t)
sizeof(region->width);
1992 (void) memcpy(p,®ion->height,
sizeof(region->height));
1993 p+=(ptrdiff_t)
sizeof(region->height);
1994 (void) memcpy(p,®ion->x,
sizeof(region->x));
1995 p+=(ptrdiff_t)
sizeof(region->x);
1996 (void) memcpy(p,®ion->y,
sizeof(region->y));
1997 p+=(ptrdiff_t)
sizeof(region->y);
1998 (void) memcpy(p,&length,
sizeof(length));
1999 p+=(ptrdiff_t)
sizeof(length);
2000 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
2001 if (count != (MagickOffsetType) (p-message))
2003 return(dpc_send(server_info->file,length,pixels));