mirror of
https://github.com/ImageMagick/ImageMagick.git
synced 2026-05-25 11:24:54 +02:00
1846 lines
59 KiB
C
1846 lines
59 KiB
C
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% DDDD IIIII SSSSS TTTTT RRRR IIIII BBBB U U TTTTT EEEEE %
|
|
% D D I SS T R R I B B U U T E %
|
|
% D D I SSS T RRRR I BBBB U U T EEE %
|
|
% D D I SS T R R I B B U U T E %
|
|
% DDDDA IIIII SSSSS T R R IIIII BBBB UUU T EEEEE %
|
|
% %
|
|
% CCCC AAA CCCC H H EEEEE %
|
|
% C A A C H H E %
|
|
% C AAAAA C HHHHH EEE %
|
|
% C A A C H H E %
|
|
% CCCC A A CCCC H H EEEEE %
|
|
% %
|
|
% %
|
|
% MagickCore Distributed Pixel Cache Methods %
|
|
% %
|
|
% Software Design %
|
|
% Cristy %
|
|
% January 2013 %
|
|
% %
|
|
% %
|
|
% Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
|
|
% dedicated to making software imaging solutions freely available. %
|
|
% %
|
|
% You may not use this file except in compliance with the License. You may %
|
|
% obtain a copy of the License at %
|
|
% %
|
|
% https://imagemagick.org/license/ %
|
|
% %
|
|
% Unless required by applicable law or agreed to in writing, software %
|
|
% distributed under the License is distributed on an "AS IS" BASIS, %
|
|
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
|
|
% See the License for the specific language governing permissions and %
|
|
% limitations under the License. %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% A distributed pixel cache is an extension of the traditional pixel cache
|
|
% available on a single host. The distributed pixel cache may span multiple
|
|
% servers so that it can grow in size and transactional capacity to support
|
|
% very large images. Start up the pixel cache server on one or more machines.
|
|
% When you read or operate on an image and the local pixel cache resources are
|
|
% exhausted, ImageMagick contacts one or more of these remote pixel servers to
|
|
% store or retrieve pixels.
|
|
%
|
|
*/
|
|
|
|
/*
|
|
Include declarations.
|
|
*/
|
|
#include "MagickCore/studio.h"
|
|
#include "MagickCore/cache.h"
|
|
#include "MagickCore/cache-private.h"
|
|
#include "MagickCore/distribute-cache.h"
|
|
#include "MagickCore/distribute-cache-private.h"
|
|
#include "MagickCore/exception.h"
|
|
#include "MagickCore/exception-private.h"
|
|
#include "MagickCore/geometry.h"
|
|
#include "MagickCore/image.h"
|
|
#include "MagickCore/image-private.h"
|
|
#include "MagickCore/list.h"
|
|
#include "MagickCore/locale_.h"
|
|
#include "MagickCore/memory_.h"
|
|
#include "MagickCore/nt-base-private.h"
|
|
#include "MagickCore/pixel.h"
|
|
#include "MagickCore/policy.h"
|
|
#include "MagickCore/random_.h"
|
|
#include "MagickCore/registry.h"
|
|
#include "MagickCore/splay-tree.h"
|
|
#include "MagickCore/string_.h"
|
|
#include "MagickCore/string-private.h"
|
|
#include "MagickCore/utility-private.h"
|
|
#include "MagickCore/version.h"
|
|
#include "MagickCore/version-private.h"
|
|
#define SOCKET_TYPE int
|
|
#undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
|
|
#if defined(MAGICKCORE_DPC_SUPPORT)
|
|
#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#define CLOSE_SOCKET(socket) (void) close_utf8(socket)
|
|
#define HANDLER_RETURN_TYPE void *
|
|
#define HANDLER_RETURN_VALUE (void *) NULL
|
|
#define SOCKET_TYPE int
|
|
#define LENGTH_TYPE size_t
|
|
#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
|
|
#elif defined(_MSC_VER)
|
|
#define CLOSE_SOCKET(socket) (void) closesocket(socket)
|
|
#define HANDLER_RETURN_TYPE DWORD WINAPI
|
|
#define HANDLER_RETURN_VALUE 0
|
|
#define LENGTH_TYPE int
|
|
#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
|
|
#define MAGICKCORE_HAVE_WINSOCK2 1
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
Define declarations.
|
|
*/
|
|
#define DPCHostname "127.0.0.1"
|
|
#define DPCPendingConnections 10
|
|
#define DPCPort 6668
|
|
#define DPCSessionKeyLength 16
|
|
#ifndef MSG_NOSIGNAL
|
|
# define MSG_NOSIGNAL 0
|
|
#endif
|
|
|
|
/*
|
|
Static declarations.
|
|
*/
|
|
#ifdef MAGICKCORE_HAVE_WINSOCK2
|
|
static SemaphoreInfo
|
|
*winsock2_semaphore = (SemaphoreInfo *) NULL;
|
|
|
|
static WSADATA
|
|
*wsaData = (WSADATA*) NULL;
|
|
#endif
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ A c q u i r e D i s t r i b u t e C a c h e I n f o %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
|
|
%
|
|
% The format of the AcquireDistributeCacheInfo method is:
|
|
%
|
|
% DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o exception: return any errors or warnings in this structure.
|
|
%
|
|
*/
|
|
|
|
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
|
|
static inline MagickOffsetType dpc_read(SOCKET_TYPE magick_unused(file),
|
|
const MagickSizeType magick_unused(length),
|
|
unsigned char *magick_restrict magick_unused(message))
|
|
{
|
|
magick_unreferenced(file);
|
|
magick_unreferenced(length);
|
|
magick_unreferenced(message);
|
|
return(-1);
|
|
}
|
|
#else
|
|
static inline MagickOffsetType dpc_read(SOCKET_TYPE file,
|
|
const MagickSizeType length,unsigned char *magick_restrict message)
|
|
{
|
|
MagickOffsetType
|
|
i;
|
|
|
|
ssize_t
|
|
count;
|
|
|
|
count=0;
|
|
for (i=0; i < (MagickOffsetType) length; i+=count)
|
|
{
|
|
count=recv(file,(char *) message+i,(LENGTH_TYPE) MagickMin(length-
|
|
(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),0);
|
|
if (count <= 0)
|
|
{
|
|
count=0;
|
|
if (errno != EINTR)
|
|
break;
|
|
}
|
|
}
|
|
return(i);
|
|
}
|
|
#endif
|
|
|
|
#if defined(MAGICKCORE_HAVE_WINSOCK2)
|
|
static void InitializeWinsock2(MagickBooleanType use_lock)
|
|
{
|
|
if (use_lock != MagickFalse)
|
|
{
|
|
if (winsock2_semaphore == (SemaphoreInfo *) NULL)
|
|
ActivateSemaphoreInfo(&winsock2_semaphore);
|
|
LockSemaphoreInfo(winsock2_semaphore);
|
|
}
|
|
if (wsaData == (WSADATA *) NULL)
|
|
{
|
|
wsaData=(WSADATA *) AcquireMagickMemory(sizeof(WSADATA));
|
|
if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
|
|
ThrowFatalException(CacheFatalError,"WSAStartup failed");
|
|
}
|
|
if (use_lock != MagickFalse)
|
|
UnlockSemaphoreInfo(winsock2_semaphore);
|
|
}
|
|
#endif
|
|
|
|
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
|
|
static int ConnectPixelCacheServer(const char *magick_unused(hostname),
|
|
const int magick_unused(port),uint64_t *magick_unused(session_key),
|
|
ExceptionInfo *exception)
|
|
{
|
|
magick_unreferenced(hostname);
|
|
magick_unreferenced(port);
|
|
magick_unreferenced(session_key);
|
|
(void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
|
|
"DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
|
|
return(MagickFalse);
|
|
}
|
|
#else
|
|
static inline uint64_t ROTL(uint64_t x,int b)
|
|
{
|
|
return((x << b) | (x >> (64-b)));
|
|
}
|
|
|
|
static inline uint64_t U8TO64_LE(const uint8_t *p)
|
|
{
|
|
return(((uint64_t) p[0] << 0) | ((uint64_t) p[1] << 8) |
|
|
((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
|
|
((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
|
|
((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
|
|
}
|
|
|
|
static inline uint64_t SIPHash24(const uint8_t key[16],const uint8_t *message,
|
|
const size_t length)
|
|
{
|
|
const uint8_t
|
|
*end = message+length-(length % 8);
|
|
|
|
size_t
|
|
i;
|
|
|
|
uint64_t
|
|
b = ((uint64_t) length) << 56,
|
|
k0 = U8TO64_LE(key),
|
|
k1 = U8TO64_LE(key+8),
|
|
m,
|
|
v0 = 0x736f6d6570736575ULL^k0,
|
|
v1 = 0x646f72616e646f6dULL^k1,
|
|
v2 = 0x6c7967656e657261ULL^k0,
|
|
v3 = 0x7465646279746573ULL^k1;
|
|
|
|
for ( ; message != end; message+=8)
|
|
{
|
|
m=U8TO64_LE(message);
|
|
v3^=m;
|
|
for (i=0; i < 2; i++)
|
|
{
|
|
v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
|
|
v2+=v3; v3=ROTL(v3,16); v3^=v2;
|
|
v0+=v3; v3=ROTL(v3,21); v3^=v0;
|
|
v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
|
|
}
|
|
v0^=m;
|
|
}
|
|
switch (length & 0x07)
|
|
{
|
|
case 7: b|=((uint64_t) message[6]) << 48; magick_fallthrough;
|
|
case 6: b|=((uint64_t) message[5]) << 40; magick_fallthrough;
|
|
case 5: b|=((uint64_t) message[4]) << 32; magick_fallthrough;
|
|
case 4: b|=((uint64_t) message[3]) << 24; magick_fallthrough;
|
|
case 3: b|=((uint64_t) message[2]) << 16; magick_fallthrough;
|
|
case 2: b|=((uint64_t) message[1]) << 8; magick_fallthrough;
|
|
case 1: b|=((uint64_t) message[0]); magick_fallthrough;
|
|
default: break;
|
|
}
|
|
v3^=b;
|
|
for (i=0; i < 2; i++)
|
|
{
|
|
v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
|
|
v2+=v3; v3=ROTL(v3,16); v3^=v2;
|
|
v0+=v3; v3=ROTL(v3,21); v3^=v0;
|
|
v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
|
|
}
|
|
v0^=b;
|
|
v2^=0xff;
|
|
for (i=0; i < 4; i++)
|
|
{
|
|
v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
|
|
v2+=v3; v3=ROTL(v3,16); v3^=v2;
|
|
v0+=v3; v3=ROTL(v3,21); v3^=v0;
|
|
v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
|
|
}
|
|
return(v0^v1^v2^v3);
|
|
}
|
|
|
|
static inline void DeriveSipKeyFromSecret(const char *shared_secret,
|
|
uint8_t key[16])
|
|
{
|
|
size_t
|
|
i,
|
|
length;
|
|
|
|
uint64_t
|
|
k0 = 0x0706050403020100ULL,
|
|
k1 = 0x0f0e0d0c0b0a0908ULL;
|
|
|
|
length=strlen(shared_secret);
|
|
for (i=0; i < length; i++)
|
|
{
|
|
uint8_t
|
|
b = shared_secret[i];
|
|
|
|
k0^=b;
|
|
k0*=0x100000001b3ULL;
|
|
k1^=(uint64_t) b << ((i & 7)*8);
|
|
k1=(k1 << 5) | (k1 >> (64-5));
|
|
}
|
|
(void) memcpy(key,&k0,8);
|
|
(void) memcpy(key+8,&k1,8);
|
|
}
|
|
|
|
static inline uint64_t GenerateSessionKey(const char *shared_secret,
|
|
const unsigned char *nonce,size_t length)
|
|
{
|
|
uint8_t
|
|
key[16];
|
|
|
|
DeriveSipKeyFromSecret(shared_secret,key);
|
|
return(SIPHash24(key,nonce,length));
|
|
}
|
|
|
|
static int ConnectPixelCacheServer(const char *hostname,const int port,
|
|
uint64_t *session_key,ExceptionInfo *exception)
|
|
{
|
|
#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
|
|
char
|
|
service[MagickPathExtent],
|
|
*shared_secret;
|
|
|
|
int
|
|
status;
|
|
|
|
SOCKET_TYPE
|
|
client_socket;
|
|
|
|
ssize_t
|
|
count;
|
|
|
|
struct addrinfo
|
|
hints,
|
|
*result;
|
|
|
|
unsigned char
|
|
nonce[DPCSessionKeyLength];
|
|
|
|
/*
|
|
Connect to distributed pixel cache server and get session key.
|
|
*/
|
|
*session_key=0;
|
|
#if defined(MAGICKCORE_HAVE_WINSOCK2)
|
|
InitializeWinsock2(MagickTrue);
|
|
#endif
|
|
(void) memset(&hints,0,sizeof(hints));
|
|
hints.ai_family=AF_INET;
|
|
hints.ai_socktype=SOCK_STREAM;
|
|
hints.ai_flags=AI_PASSIVE;
|
|
(void) FormatLocaleString(service,MagickPathExtent,"%d",port);
|
|
status=getaddrinfo(hostname,service,&hints,&result);
|
|
if (status != 0)
|
|
{
|
|
(void) ThrowMagickException(exception,GetMagickModule(),CacheError,
|
|
"DistributedPixelCache","'%s': %s",hostname,gai_strerror(status));
|
|
return(-1);
|
|
}
|
|
client_socket=(SOCKET_TYPE) socket(result->ai_family,result->ai_socktype,
|
|
result->ai_protocol);
|
|
if (client_socket == -1)
|
|
{
|
|
freeaddrinfo(result);
|
|
(void) ThrowMagickException(exception,GetMagickModule(),CacheError,
|
|
"DistributedPixelCache","'%s': %s",hostname,GetExceptionMessage(errno));
|
|
return(-1);
|
|
}
|
|
status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
|
|
freeaddrinfo(result);
|
|
if (status == -1)
|
|
{
|
|
CLOSE_SOCKET(client_socket);
|
|
(void) ThrowMagickException(exception,GetMagickModule(),CacheError,
|
|
"DistributedPixelCache","'%s': %s",hostname,GetExceptionMessage(errno));
|
|
return(-1);
|
|
}
|
|
/*
|
|
Receive server nonce.
|
|
*/
|
|
count=recv(client_socket,(char *) nonce,sizeof(nonce),0);
|
|
if (count != (ssize_t) sizeof(nonce))
|
|
{
|
|
CLOSE_SOCKET(client_socket);
|
|
(void) ThrowMagickException(exception,GetMagickModule(),CacheError,
|
|
"DistributedPixelCache","'%s': %s",hostname,GetExceptionMessage(errno));
|
|
return(-1);
|
|
}
|
|
/*
|
|
Compute keyed hash(shared_secret,nonce).
|
|
*/
|
|
shared_secret=GetPolicyValue("cache:shared-secret");
|
|
if (shared_secret == (char*) NULL)
|
|
{
|
|
CLOSE_SOCKET(client_socket);
|
|
(void) ThrowMagickException(exception,GetMagickModule(),CacheError,
|
|
"DistributedPixelCache","'%s': shared secret required",hostname);
|
|
return(-1);
|
|
}
|
|
*session_key=GenerateSessionKey(shared_secret,nonce,sizeof(nonce));
|
|
shared_secret=DestroyString(shared_secret);
|
|
/*
|
|
Send keyed hash back to client.
|
|
*/
|
|
count=send(client_socket,(char *) session_key,sizeof(*session_key),
|
|
MSG_NOSIGNAL);
|
|
if (count != (ssize_t) sizeof(*session_key))
|
|
{
|
|
CLOSE_SOCKET(client_socket);
|
|
(void) ThrowMagickException(exception,GetMagickModule(),CacheError,
|
|
"DistributedPixelCache","'%s': authentication failed",hostname);
|
|
return(-1);
|
|
}
|
|
return((int) client_socket);
|
|
#else
|
|
(void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
|
|
"DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
|
|
return(-1);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
static char *GetHostname(int *port,ExceptionInfo *exception)
|
|
{
|
|
char
|
|
*host,
|
|
*hosts,
|
|
**hostlist;
|
|
|
|
int
|
|
argc;
|
|
|
|
ssize_t
|
|
i;
|
|
|
|
static size_t
|
|
id = 0;
|
|
|
|
/*
|
|
Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
|
|
*/
|
|
hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",exception);
|
|
if (hosts == (char *) NULL)
|
|
{
|
|
*port=DPCPort;
|
|
return(AcquireString(DPCHostname));
|
|
}
|
|
(void) SubstituteString(&hosts,","," ");
|
|
hostlist=StringToArgv(hosts,&argc);
|
|
hosts=DestroyString(hosts);
|
|
if (hostlist == (char **) NULL)
|
|
{
|
|
*port=DPCPort;
|
|
return(AcquireString(DPCHostname));
|
|
}
|
|
{
|
|
size_t host_count = (size_t) argc-1;
|
|
size_t index = (id++ % host_count)+1;
|
|
hosts=AcquireString(hostlist[index]);
|
|
}
|
|
for (i=0; i < (ssize_t) argc; i++)
|
|
hostlist[i]=DestroyString(hostlist[i]);
|
|
hostlist=(char **) RelinquishMagickMemory(hostlist);
|
|
(void) SubstituteString(&hosts,":"," ");
|
|
hostlist=StringToArgv(hosts,&argc);
|
|
if (hostlist == (char **) NULL)
|
|
{
|
|
*port=DPCPort;
|
|
return(AcquireString(DPCHostname));
|
|
}
|
|
host=AcquireString(hostlist[1]);
|
|
if (hostlist[2] == (char *) NULL)
|
|
*port=DPCPort;
|
|
else
|
|
*port=StringToLong(hostlist[2]);
|
|
for (i=0; i < (ssize_t) argc; i++)
|
|
hostlist[i]=DestroyString(hostlist[i]);
|
|
hostlist=(char **) RelinquishMagickMemory(hostlist);
|
|
return(host);
|
|
}
|
|
|
|
MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
|
|
ExceptionInfo *exception)
|
|
{
|
|
char
|
|
*hostname;
|
|
|
|
DistributeCacheInfo
|
|
*server_info;
|
|
|
|
uint64_t
|
|
session_key;
|
|
|
|
/*
|
|
Connect to the distributed pixel cache server.
|
|
*/
|
|
server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
|
|
sizeof(*server_info));
|
|
(void) memset(server_info,0,sizeof(*server_info));
|
|
server_info->signature=MagickCoreSignature;
|
|
server_info->port=0;
|
|
hostname=GetHostname(&server_info->port,exception);
|
|
session_key=0;
|
|
server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
|
|
&session_key,exception);
|
|
if (server_info->file == -1)
|
|
server_info=DestroyDistributeCacheInfo(server_info);
|
|
else
|
|
{
|
|
server_info->session_key=session_key;
|
|
(void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
|
|
server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
|
|
MagickFalse;
|
|
}
|
|
hostname=DestroyString(hostname);
|
|
return(server_info);
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ D e s t r o y D i s t r i b u t e C a c h e I n f o %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% DestroyDistributeCacheInfo() deallocates memory associated with an
|
|
% DistributeCacheInfo structure.
|
|
%
|
|
% The format of the DestroyDistributeCacheInfo method is:
|
|
%
|
|
% DistributeCacheInfo *DestroyDistributeCacheInfo(
|
|
% DistributeCacheInfo *server_info)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
*/
|
|
MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
|
|
DistributeCacheInfo *server_info)
|
|
{
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
|
|
if (server_info->file >= 0)
|
|
CLOSE_SOCKET(server_info->file);
|
|
#endif
|
|
server_info->signature=(~MagickCoreSignature);
|
|
server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
|
|
return(server_info);
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ D i s t r i b u t e P i x e l C a c h e S e r v e r %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% DistributePixelCacheServer() waits on the specified port for commands to
|
|
% create, read, update, or destroy a pixel cache.
|
|
%
|
|
% The format of the DistributePixelCacheServer() method is:
|
|
%
|
|
% void DistributePixelCacheServer(const int port)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o port: connect the distributed pixel cache at this port.
|
|
%
|
|
% o exception: return any errors or warnings in this structure.
|
|
%
|
|
*/
|
|
|
|
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
|
|
static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
|
|
const MagickSizeType magick_unused(length),
|
|
const void *magick_restrict magick_unused(message))
|
|
{
|
|
magick_unreferenced(file);
|
|
magick_unreferenced(length);
|
|
magick_unreferenced(message);
|
|
return(-1);
|
|
}
|
|
#else
|
|
static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
|
|
const MagickSizeType length,const void *magick_restrict message)
|
|
{
|
|
MagickOffsetType
|
|
i;
|
|
|
|
ssize_t
|
|
count;
|
|
|
|
/*
|
|
Ensure a complete message is sent.
|
|
*/
|
|
count=0;
|
|
for (i=0; i < (MagickOffsetType) length; i+=count)
|
|
{
|
|
count=(ssize_t) send(file,(char *) message+i,(LENGTH_TYPE) MagickMin(
|
|
length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
|
|
MSG_NOSIGNAL);
|
|
if (count <= 0)
|
|
{
|
|
count=0;
|
|
if (errno != EINTR)
|
|
break;
|
|
}
|
|
}
|
|
return(i);
|
|
}
|
|
#endif
|
|
|
|
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
|
|
MagickExport void DistributePixelCacheServer(const int magick_unused(port),
|
|
ExceptionInfo *magick_unused(exception))
|
|
{
|
|
magick_unreferenced(port);
|
|
magick_unreferenced(exception);
|
|
ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
|
|
}
|
|
#else
|
|
static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
|
|
const uint64_t session_key)
|
|
{
|
|
MagickAddressType
|
|
key = (MagickAddressType) session_key;
|
|
|
|
/*
|
|
Destroy distributed pixel cache.
|
|
*/
|
|
return(DeleteNodeFromSplayTree(registry,(const void *) key));
|
|
}
|
|
|
|
static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
|
|
SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
|
|
{
|
|
Image
|
|
*image;
|
|
|
|
MagickAddressType
|
|
key = (MagickAddressType) session_key;
|
|
|
|
MagickBooleanType
|
|
status;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
MagickSizeType
|
|
length;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Open distributed pixel cache.
|
|
*/
|
|
image=AcquireImage((ImageInfo *) NULL,exception);
|
|
if (image == (Image *) NULL)
|
|
return(MagickFalse);
|
|
length=sizeof(image->storage_class)+sizeof(image->colorspace)+
|
|
sizeof(image->alpha_trait)+sizeof(image->channels)+sizeof(image->columns)+
|
|
sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
|
|
sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
|
|
count=dpc_read(file,length,message);
|
|
if (count != (MagickOffsetType) length)
|
|
{
|
|
image=DestroyImage(image);
|
|
return(MagickFalse);
|
|
}
|
|
/*
|
|
Deserialize the image attributes.
|
|
*/
|
|
p=message;
|
|
(void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
|
|
p+=(ptrdiff_t) sizeof(image->storage_class);
|
|
(void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
|
|
p+=(ptrdiff_t) sizeof(image->colorspace);
|
|
(void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
|
|
p+=(ptrdiff_t) sizeof(image->alpha_trait);
|
|
(void) memcpy(&image->channels,p,sizeof(image->channels));
|
|
p+=(ptrdiff_t) sizeof(image->channels);
|
|
(void) memcpy(&image->columns,p,sizeof(image->columns));
|
|
p+=(ptrdiff_t) sizeof(image->columns);
|
|
(void) memcpy(&image->rows,p,sizeof(image->rows));
|
|
p+=(ptrdiff_t) sizeof(image->rows);
|
|
(void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
|
|
p+=(ptrdiff_t) sizeof(image->number_channels);
|
|
(void) memcpy(image->channel_map,p,MaxPixelChannels*
|
|
sizeof(*image->channel_map));
|
|
p+=(ptrdiff_t) MaxPixelChannels*sizeof(*image->channel_map);
|
|
(void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
|
|
p+=(ptrdiff_t) sizeof(image->metacontent_extent);
|
|
if (SyncImagePixelCache(image,exception) == MagickFalse)
|
|
{
|
|
image=DestroyImage(image);
|
|
return(MagickFalse);
|
|
}
|
|
status=AddValueToSplayTree(registry,(const void *) key,image);
|
|
if (status == MagickFalse)
|
|
{
|
|
image=DestroyImage(image);
|
|
return(MagickFalse);
|
|
}
|
|
return(status);
|
|
}
|
|
|
|
static inline MagickBooleanType ValidateDistributedPixelCache(
|
|
const RectangleInfo *region,const size_t per_pixel,
|
|
const MagickSizeType length)
|
|
{
|
|
size_t
|
|
extent = 0,
|
|
pixels = 0;
|
|
|
|
if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
|
|
return(MagickFalse);
|
|
if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
|
|
return(MagickFalse);
|
|
if (length > (MagickSizeType) extent)
|
|
return(MagickFalse);
|
|
return(MagickTrue);
|
|
}
|
|
|
|
static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
|
|
SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
|
|
{
|
|
const Quantum
|
|
*p;
|
|
|
|
const unsigned char
|
|
*metacontent;
|
|
|
|
Image
|
|
*image;
|
|
|
|
MagickAddressType
|
|
key = (MagickAddressType) session_key;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
MagickSizeType
|
|
length;
|
|
|
|
RectangleInfo
|
|
region;
|
|
|
|
size_t
|
|
per_pixel;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*q;
|
|
|
|
/*
|
|
Read distributed pixel cache metacontent.
|
|
*/
|
|
image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
|
|
if (image == (Image *) NULL)
|
|
return(MagickFalse);
|
|
length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
|
|
sizeof(region.y)+sizeof(length);
|
|
count=dpc_read(file,length,message);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
q=message;
|
|
(void) memcpy(®ion.width,q,sizeof(region.width));
|
|
q+=(ptrdiff_t) sizeof(region.width);
|
|
(void) memcpy(®ion.height,q,sizeof(region.height));
|
|
q+=(ptrdiff_t) sizeof(region.height);
|
|
(void) memcpy(®ion.x,q,sizeof(region.x));
|
|
q+=(ptrdiff_t) sizeof(region.x);
|
|
(void) memcpy(®ion.y,q,sizeof(region.y));
|
|
q+=(ptrdiff_t) sizeof(region.y);
|
|
(void) memcpy(&length,q,sizeof(length));
|
|
q+=(ptrdiff_t) sizeof(length);
|
|
per_pixel=image->number_meta_channels*sizeof(Quantum);
|
|
if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
|
|
return(MagickFalse);
|
|
p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
|
|
exception);
|
|
if (p == (const Quantum *) NULL)
|
|
return(MagickFalse);
|
|
metacontent=(const unsigned char *) GetVirtualMetacontent(image);
|
|
count=dpc_send(file,length,metacontent);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
return(MagickTrue);
|
|
}
|
|
|
|
static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
|
|
SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
|
|
{
|
|
const Quantum
|
|
*p;
|
|
|
|
Image
|
|
*image;
|
|
|
|
MagickAddressType
|
|
key = (MagickAddressType) session_key;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
MagickSizeType
|
|
length;
|
|
|
|
RectangleInfo
|
|
region;
|
|
|
|
size_t
|
|
per_pixel;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*q;
|
|
|
|
/*
|
|
Read distributed pixel cache pixels.
|
|
*/
|
|
image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
|
|
if (image == (Image *) NULL)
|
|
return(MagickFalse);
|
|
length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
|
|
sizeof(region.y)+sizeof(length);
|
|
count=dpc_read(file,length,message);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
q=message;
|
|
(void) memcpy(®ion.width,q,sizeof(region.width));
|
|
q+=(ptrdiff_t) sizeof(region.width);
|
|
(void) memcpy(®ion.height,q,sizeof(region.height));
|
|
q+=(ptrdiff_t) sizeof(region.height);
|
|
(void) memcpy(®ion.x,q,sizeof(region.x));
|
|
q+=(ptrdiff_t) sizeof(region.x);
|
|
(void) memcpy(®ion.y,q,sizeof(region.y));
|
|
q+=(ptrdiff_t) sizeof(region.y);
|
|
(void) memcpy(&length,q,sizeof(length));
|
|
per_pixel=image->number_channels*sizeof(Quantum);
|
|
if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
|
|
return(MagickFalse);
|
|
q+=(ptrdiff_t) sizeof(length);
|
|
p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
|
|
exception);
|
|
if (p == (const Quantum *) NULL)
|
|
return(MagickFalse);
|
|
count=dpc_send(file,length,p);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
return(MagickTrue);
|
|
}
|
|
|
|
static void *RelinquishImageRegistry(void *image)
|
|
{
|
|
return((void *) DestroyImageList((Image *) image));
|
|
}
|
|
|
|
static MagickBooleanType WriteDistributeCacheMetacontent(
|
|
SplayTreeInfo *registry,SOCKET_TYPE file,const uint64_t session_key,
|
|
ExceptionInfo *exception)
|
|
{
|
|
Image
|
|
*image;
|
|
|
|
MagickAddressType
|
|
key = (MagickAddressType) session_key;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
MagickSizeType
|
|
length;
|
|
|
|
Quantum
|
|
*q;
|
|
|
|
RectangleInfo
|
|
region;
|
|
|
|
size_t
|
|
per_pixel;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*metacontent,
|
|
*p;
|
|
|
|
/*
|
|
Write distributed pixel cache metacontent.
|
|
*/
|
|
image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
|
|
if (image == (Image *) NULL)
|
|
return(MagickFalse);
|
|
length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
|
|
sizeof(region.y)+sizeof(length);
|
|
count=dpc_read(file,length,message);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
p=message;
|
|
(void) memcpy(®ion.width,p,sizeof(region.width));
|
|
p+=(ptrdiff_t) sizeof(region.width);
|
|
(void) memcpy(®ion.height,p,sizeof(region.height));
|
|
p+=(ptrdiff_t) sizeof(region.height);
|
|
(void) memcpy(®ion.x,p,sizeof(region.x));
|
|
p+=(ptrdiff_t) sizeof(region.x);
|
|
(void) memcpy(®ion.y,p,sizeof(region.y));
|
|
p+=(ptrdiff_t) sizeof(region.y);
|
|
(void) memcpy(&length,p,sizeof(length));
|
|
per_pixel=image->number_meta_channels*sizeof(Quantum);
|
|
if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
|
|
return(MagickFalse);
|
|
p+=(ptrdiff_t) sizeof(length);
|
|
q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
|
|
exception);
|
|
if (q == (Quantum *) NULL)
|
|
return(MagickFalse);
|
|
metacontent=(unsigned char *) GetAuthenticMetacontent(image);
|
|
count=dpc_read(file,length,metacontent);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
return(SyncAuthenticPixels(image,exception));
|
|
}
|
|
|
|
static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
|
|
SOCKET_TYPE file,const uint64_t session_key,ExceptionInfo *exception)
|
|
{
|
|
Image
|
|
*image;
|
|
|
|
MagickAddressType
|
|
key = (MagickAddressType) session_key;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
MagickSizeType
|
|
length;
|
|
|
|
Quantum
|
|
*q;
|
|
|
|
RectangleInfo
|
|
region;
|
|
|
|
size_t
|
|
per_pixel;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Write distributed pixel cache pixels.
|
|
*/
|
|
image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
|
|
if (image == (Image *) NULL)
|
|
return(MagickFalse);
|
|
length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
|
|
sizeof(region.y)+sizeof(length);
|
|
count=dpc_read(file,length,message);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
p=message;
|
|
(void) memcpy(®ion.width,p,sizeof(region.width));
|
|
p+=(ptrdiff_t) sizeof(region.width);
|
|
(void) memcpy(®ion.height,p,sizeof(region.height));
|
|
p+=(ptrdiff_t) sizeof(region.height);
|
|
(void) memcpy(®ion.x,p,sizeof(region.x));
|
|
p+=(ptrdiff_t) sizeof(region.x);
|
|
(void) memcpy(®ion.y,p,sizeof(region.y));
|
|
p+=(ptrdiff_t) sizeof(region.y);
|
|
(void) memcpy(&length,p,sizeof(length));
|
|
per_pixel=image->number_channels*sizeof(Quantum);
|
|
if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
|
|
return(MagickFalse);
|
|
p+=(ptrdiff_t) sizeof(length);
|
|
q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
|
|
exception);
|
|
if (q == (Quantum *) NULL)
|
|
return(MagickFalse);
|
|
count=dpc_read(file,length,(unsigned char *) q);
|
|
if (count != (MagickOffsetType) length)
|
|
return(MagickFalse);
|
|
return(SyncAuthenticPixels(image,exception));
|
|
}
|
|
|
|
static HANDLER_RETURN_TYPE DistributePixelCacheClient(void *socket_arg)
|
|
{
|
|
char
|
|
*shared_secret;
|
|
|
|
ExceptionInfo
|
|
*exception;
|
|
|
|
MagickBooleanType
|
|
status = MagickFalse;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
RandomInfo
|
|
*random_info;
|
|
|
|
SOCKET_TYPE
|
|
client_socket,
|
|
*client_socket_ptr = (SOCKET_TYPE *) socket_arg;
|
|
|
|
SplayTreeInfo
|
|
*registry;
|
|
|
|
StringInfo
|
|
*entropy;
|
|
|
|
uint64_t
|
|
key,
|
|
session_key;
|
|
|
|
unsigned char
|
|
command,
|
|
nonce[DPCSessionKeyLength];
|
|
|
|
/*
|
|
Load shared secret.
|
|
*/
|
|
client_socket=(*client_socket_ptr);
|
|
client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
|
|
shared_secret=GetPolicyValue("cache:shared-secret");
|
|
if (shared_secret == NULL)
|
|
ThrowFatalException(CacheFatalError,"shared secret required");
|
|
/*
|
|
Generate random nonce.
|
|
*/
|
|
random_info=AcquireRandomInfo();
|
|
entropy=GetRandomKey(random_info,sizeof(nonce));
|
|
(void) memcpy(nonce,GetStringInfoDatum(entropy),sizeof(nonce));
|
|
entropy=DestroyStringInfo(entropy);
|
|
random_info=DestroyRandomInfo(random_info);
|
|
/*
|
|
Derive session key.
|
|
*/
|
|
session_key=GenerateSessionKey(shared_secret,nonce,sizeof(nonce));
|
|
shared_secret=DestroyString(shared_secret);
|
|
/*
|
|
Send nonce to client.
|
|
*/
|
|
count=dpc_send(client_socket,sizeof(nonce),nonce);
|
|
if (count != (MagickOffsetType) sizeof(nonce))
|
|
{
|
|
CLOSE_SOCKET(client_socket);
|
|
return(HANDLER_RETURN_VALUE);
|
|
}
|
|
/*
|
|
Receive client's keyed hash.
|
|
*/
|
|
count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
|
|
if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
|
|
{
|
|
CLOSE_SOCKET(client_socket);
|
|
return(HANDLER_RETURN_VALUE);
|
|
}
|
|
exception=AcquireExceptionInfo();
|
|
registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
|
|
(void *(*)(void *)) NULL,RelinquishImageRegistry);
|
|
/*
|
|
Command loop.
|
|
*/
|
|
for (status=MagickFalse; ; )
|
|
{
|
|
/*
|
|
Each command must echo the authenticated session key.
|
|
*/
|
|
count=dpc_read(client_socket,1,(unsigned char *) &command);
|
|
if (count <= 0)
|
|
break;
|
|
count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
|
|
if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
|
|
break;
|
|
switch (command)
|
|
{
|
|
case 'o':
|
|
{
|
|
status=OpenDistributeCache(registry,client_socket,session_key,
|
|
exception);
|
|
dpc_send(client_socket,sizeof(status),&status);
|
|
break;
|
|
}
|
|
case 'r':
|
|
{
|
|
status=ReadDistributeCachePixels(registry,client_socket,session_key,
|
|
exception);
|
|
break;
|
|
}
|
|
case 'R':
|
|
{
|
|
status=ReadDistributeCacheMetacontent(registry,client_socket,
|
|
session_key,exception);
|
|
break;
|
|
}
|
|
case 'w':
|
|
{
|
|
status=WriteDistributeCachePixels(registry,client_socket,session_key,
|
|
exception);
|
|
break;
|
|
}
|
|
case 'W':
|
|
{
|
|
status=WriteDistributeCacheMetacontent(registry,client_socket,
|
|
session_key,exception);
|
|
break;
|
|
}
|
|
case 'd':
|
|
{
|
|
status=DestroyDistributeCache(registry,session_key);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if ((status == MagickFalse) || (command == 'd'))
|
|
break;
|
|
}
|
|
count=dpc_send(client_socket,sizeof(status),&status);
|
|
CLOSE_SOCKET(client_socket);
|
|
exception=DestroyExceptionInfo(exception);
|
|
registry=DestroySplayTree(registry);
|
|
return(HANDLER_RETURN_VALUE);
|
|
}
|
|
|
|
MagickExport void DistributePixelCacheServer(const int port,
|
|
ExceptionInfo *exception)
|
|
{
|
|
char
|
|
service[MagickPathExtent];
|
|
|
|
int
|
|
status;
|
|
|
|
#if defined(MAGICKCORE_THREAD_SUPPORT)
|
|
pthread_attr_t
|
|
attributes;
|
|
|
|
pthread_t
|
|
thread_id;
|
|
#elif defined(_MSC_VER)
|
|
DWORD
|
|
threadID;
|
|
#else
|
|
Not implemented!
|
|
#endif
|
|
|
|
SOCKET_TYPE
|
|
server_socket;
|
|
|
|
struct addrinfo
|
|
*p;
|
|
|
|
struct addrinfo
|
|
hint,
|
|
*result;
|
|
|
|
struct sockaddr_in
|
|
address;
|
|
|
|
/*
|
|
Launch distributed pixel cache server.
|
|
*/
|
|
assert(exception != (ExceptionInfo *) NULL);
|
|
assert(exception->signature == MagickCoreSignature);
|
|
magick_unreferenced(exception);
|
|
#if defined(MAGICKCORE_HAVE_WINSOCK2)
|
|
InitializeWinsock2(MagickFalse);
|
|
#endif
|
|
(void) memset(&hint,0,sizeof(hint));
|
|
hint.ai_family=AF_INET;
|
|
hint.ai_socktype=SOCK_STREAM;
|
|
hint.ai_flags=AI_PASSIVE;
|
|
FormatLocaleString(service,MagickPathExtent,"%d",port);
|
|
status=getaddrinfo(NULL,service,&hint,&result);
|
|
if (status != 0)
|
|
ThrowFatalException(CacheFatalError, "UnableToListen");
|
|
server_socket=(SOCKET_TYPE) 0;
|
|
for (p=result; p != NULL; p=p->ai_next)
|
|
{
|
|
int
|
|
one = 1;
|
|
|
|
server_socket=(SOCKET_TYPE) socket(p->ai_family,p->ai_socktype,
|
|
p->ai_protocol);
|
|
if (server_socket == -1)
|
|
continue;
|
|
status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(char *) &one,
|
|
(socklen_t) sizeof(one));
|
|
if (status != -1)
|
|
{
|
|
#if defined(MAGICKCORE_HAVE_WINSOCK2)
|
|
DWORD timeout = 5000; // ms
|
|
status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,(const char *)
|
|
&timeout,sizeof(timeout));
|
|
#else
|
|
struct timeval tv;
|
|
tv.tv_sec=5;
|
|
tv.tv_usec=0;
|
|
status=setsockopt(server_socket,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));
|
|
#endif
|
|
}
|
|
if (status == -1)
|
|
{
|
|
CLOSE_SOCKET(server_socket);
|
|
continue;
|
|
}
|
|
status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
|
|
if (status == -1)
|
|
{
|
|
CLOSE_SOCKET(server_socket);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (p == (struct addrinfo *) NULL)
|
|
ThrowFatalException(CacheFatalError,"UnableToBind");
|
|
freeaddrinfo(result);
|
|
status=listen(server_socket,DPCPendingConnections);
|
|
if (status != 0)
|
|
ThrowFatalException(CacheFatalError,"UnableToListen");
|
|
#if defined(MAGICKCORE_THREAD_SUPPORT)
|
|
pthread_attr_init(&attributes);
|
|
pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
|
|
#endif
|
|
for ( ; ; )
|
|
{
|
|
SOCKET_TYPE
|
|
*client_socket_ptr;
|
|
|
|
socklen_t
|
|
length = (socklen_t) sizeof(address);
|
|
|
|
client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(sizeof(SOCKET_TYPE));
|
|
if (client_socket_ptr == NULL)
|
|
continue; /* skip connection */
|
|
*client_socket_ptr=(SOCKET_TYPE) accept(server_socket,(struct sockaddr *)
|
|
&address,&length);
|
|
if (*client_socket_ptr == -1)
|
|
{
|
|
client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
|
|
client_socket_ptr);
|
|
continue;
|
|
}
|
|
#if defined(MAGICKCORE_THREAD_SUPPORT)
|
|
status=pthread_create(&thread_id,&attributes,DistributePixelCacheClient,
|
|
(void *) client_socket_ptr);
|
|
if (status != 0)
|
|
{
|
|
CLOSE_SOCKET(*client_socket_ptr);
|
|
RelinquishMagickMemory(client_socket_ptr);
|
|
ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
|
|
}
|
|
#elif defined(_MSC_VER)
|
|
if (CreateThread(0,0,DistributePixelCacheClient,(void*) client_socket_ptr,0,&threadID) == (HANDLE) NULL)
|
|
{
|
|
CLOSE_SOCKET(*client_socket_ptr);
|
|
RelinquishMagickMemory(client_socket_ptr);
|
|
ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
|
|
}
|
|
#else
|
|
Not implemented!
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ D i s t r i b u t e C a c h e T e r m i n u s %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% DistributeCacheTerminus() destroys the Distributed Cache.
|
|
%
|
|
*/
|
|
MagickPrivate void DistributeCacheTerminus(void)
|
|
{
|
|
#ifdef MAGICKCORE_HAVE_WINSOCK2
|
|
if (winsock2_semaphore == (SemaphoreInfo *) NULL)
|
|
ActivateSemaphoreInfo(&winsock2_semaphore);
|
|
LockSemaphoreInfo(winsock2_semaphore);
|
|
if (wsaData != (WSADATA *) NULL)
|
|
{
|
|
WSACleanup();
|
|
wsaData=(WSADATA *) RelinquishMagickMemory((void *) wsaData);
|
|
}
|
|
UnlockSemaphoreInfo(winsock2_semaphore);
|
|
RelinquishSemaphoreInfo(&winsock2_semaphore);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ G e t D i s t r i b u t e C a c h e F i l e %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% GetDistributeCacheFile() returns the file associated with this
|
|
% DistributeCacheInfo structure.
|
|
%
|
|
% The format of the GetDistributeCacheFile method is:
|
|
%
|
|
% int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
*/
|
|
MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
|
|
{
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
return(server_info->file);
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ G e t D i s t r i b u t e C a c h e H o s t n a m e %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% GetDistributeCacheHostname() returns the hostname associated with this
|
|
% DistributeCacheInfo structure.
|
|
%
|
|
% The format of the GetDistributeCacheHostname method is:
|
|
%
|
|
% const char *GetDistributeCacheHostname(
|
|
% const DistributeCacheInfo *server_info)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
*/
|
|
MagickPrivate const char *GetDistributeCacheHostname(
|
|
const DistributeCacheInfo *server_info)
|
|
{
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
return(server_info->hostname);
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ G e t D i s t r i b u t e C a c h e P o r t %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% GetDistributeCachePort() returns the port associated with this
|
|
% DistributeCacheInfo structure.
|
|
%
|
|
% The format of the GetDistributeCachePort method is:
|
|
%
|
|
% int GetDistributeCachePort(const DistributeCacheInfo *server_info)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
*/
|
|
MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
|
|
{
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
return(server_info->port);
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ O p e n D i s t r i b u t e P i x e l C a c h e %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% OpenDistributePixelCache() opens a pixel cache on a remote server.
|
|
%
|
|
% The format of the OpenDistributePixelCache method is:
|
|
%
|
|
% MagickBooleanType *OpenDistributePixelCache(
|
|
% DistributeCacheInfo *server_info,Image *image)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
% o image: the image.
|
|
%
|
|
*/
|
|
MagickPrivate MagickBooleanType OpenDistributePixelCache(
|
|
DistributeCacheInfo *server_info,Image *image)
|
|
{
|
|
MagickBooleanType
|
|
status;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Open distributed pixel cache.
|
|
*/
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
assert(image != (Image *) NULL);
|
|
assert(image->signature == MagickCoreSignature);
|
|
p=message;
|
|
*p++='o'; /* open */
|
|
/*
|
|
Serialize image attributes (see ValidatePixelCacheMorphology()).
|
|
*/
|
|
(void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
|
|
p+=(ptrdiff_t) sizeof(server_info->session_key);
|
|
(void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
|
|
p+=(ptrdiff_t) sizeof(image->storage_class);
|
|
(void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
|
|
p+=(ptrdiff_t) sizeof(image->colorspace);
|
|
(void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
|
|
p+=(ptrdiff_t) sizeof(image->alpha_trait);
|
|
(void) memcpy(p,&image->channels,sizeof(image->channels));
|
|
p+=(ptrdiff_t) sizeof(image->channels);
|
|
(void) memcpy(p,&image->columns,sizeof(image->columns));
|
|
p+=(ptrdiff_t) sizeof(image->columns);
|
|
(void) memcpy(p,&image->rows,sizeof(image->rows));
|
|
p+=(ptrdiff_t) sizeof(image->rows);
|
|
(void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
|
|
p+=(ptrdiff_t) sizeof(image->number_channels);
|
|
(void) memcpy(p,image->channel_map,MaxPixelChannels*
|
|
sizeof(*image->channel_map));
|
|
p+=(ptrdiff_t) MaxPixelChannels*sizeof(*image->channel_map);
|
|
(void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
|
|
p+=(ptrdiff_t) sizeof(image->metacontent_extent);
|
|
count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
|
|
if (count != (MagickOffsetType) (p-message))
|
|
return(MagickFalse);
|
|
status=MagickFalse;
|
|
count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
|
|
if (count != (MagickOffsetType) sizeof(status))
|
|
return(MagickFalse);
|
|
return(status);
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ R e a d D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% ReadDistributePixelCacheMetacontents() reads metacontent from the specified
|
|
% region of the distributed pixel cache.
|
|
%
|
|
% The format of the ReadDistributePixelCacheMetacontents method is:
|
|
%
|
|
% MagickOffsetType ReadDistributePixelCacheMetacontents(
|
|
% DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
% const MagickSizeType length,unsigned char *metacontent)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
% o image: the image.
|
|
%
|
|
% o region: read the metacontent from this region of the image.
|
|
%
|
|
% o length: the length in bytes of the metacontent.
|
|
%
|
|
% o metacontent: read these metacontent from the pixel cache.
|
|
%
|
|
*/
|
|
MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
|
|
DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
const MagickSizeType length,unsigned char *metacontent)
|
|
{
|
|
MagickOffsetType
|
|
count;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Read distributed pixel cache metacontent.
|
|
*/
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
assert(region != (RectangleInfo *) NULL);
|
|
assert(metacontent != (unsigned char *) NULL);
|
|
if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
|
|
return(-1);
|
|
p=message;
|
|
*p++='R';
|
|
(void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
|
|
p+=(ptrdiff_t) sizeof(server_info->session_key);
|
|
(void) memcpy(p,®ion->width,sizeof(region->width));
|
|
p+=(ptrdiff_t) sizeof(region->width);
|
|
(void) memcpy(p,®ion->height,sizeof(region->height));
|
|
p+=(ptrdiff_t) sizeof(region->height);
|
|
(void) memcpy(p,®ion->x,sizeof(region->x));
|
|
p+=(ptrdiff_t) sizeof(region->x);
|
|
(void) memcpy(p,®ion->y,sizeof(region->y));
|
|
p+=(ptrdiff_t) sizeof(region->y);
|
|
(void) memcpy(p,&length,sizeof(length));
|
|
p+=(ptrdiff_t) sizeof(length);
|
|
count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
|
|
if (count != (MagickOffsetType) (p-message))
|
|
return(-1);
|
|
return(dpc_read(server_info->file,length,metacontent));
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ R e a d D i s t r i b u t e P i x e l C a c h e P i x e l s %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% ReadDistributePixelCachePixels() reads pixels from the specified region of
|
|
% the distributed pixel cache.
|
|
%
|
|
% The format of the ReadDistributePixelCachePixels method is:
|
|
%
|
|
% MagickOffsetType ReadDistributePixelCachePixels(
|
|
% DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
% const MagickSizeType length,unsigned char *magick_restrict pixels)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
% o image: the image.
|
|
%
|
|
% o region: read the pixels from this region of the image.
|
|
%
|
|
% o length: the length in bytes of the pixels.
|
|
%
|
|
% o pixels: read these pixels from the pixel cache.
|
|
%
|
|
*/
|
|
MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
|
|
DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
const MagickSizeType length,unsigned char *magick_restrict pixels)
|
|
{
|
|
MagickOffsetType
|
|
count;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Read distributed pixel cache pixels.
|
|
*/
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
assert(region != (RectangleInfo *) NULL);
|
|
assert(pixels != (unsigned char *) NULL);
|
|
if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
|
|
return(-1);
|
|
p=message;
|
|
*p++='r';
|
|
(void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
|
|
p+=(ptrdiff_t) sizeof(server_info->session_key);
|
|
(void) memcpy(p,®ion->width,sizeof(region->width));
|
|
p+=(ptrdiff_t) sizeof(region->width);
|
|
(void) memcpy(p,®ion->height,sizeof(region->height));
|
|
p+=(ptrdiff_t) sizeof(region->height);
|
|
(void) memcpy(p,®ion->x,sizeof(region->x));
|
|
p+=(ptrdiff_t) sizeof(region->x);
|
|
(void) memcpy(p,®ion->y,sizeof(region->y));
|
|
p+=(ptrdiff_t) sizeof(region->y);
|
|
(void) memcpy(p,&length,sizeof(length));
|
|
p+=(ptrdiff_t) sizeof(length);
|
|
count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
|
|
if (count != (MagickOffsetType) (p-message))
|
|
return(-1);
|
|
return(dpc_read(server_info->file,length,pixels));
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ R e l i n q u i s h D i s t r i b u t e P i x e l C a c h e %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% RelinquishDistributePixelCache() frees resources acquired with
|
|
% OpenDistributePixelCache().
|
|
%
|
|
% The format of the RelinquishDistributePixelCache method is:
|
|
%
|
|
% MagickBooleanType RelinquishDistributePixelCache(
|
|
% DistributeCacheInfo *server_info)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
*/
|
|
MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
|
|
DistributeCacheInfo *server_info)
|
|
{
|
|
MagickBooleanType
|
|
status;
|
|
|
|
MagickOffsetType
|
|
count;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Delete distributed pixel cache.
|
|
*/
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
p=message;
|
|
*p++='d';
|
|
(void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
|
|
p+=(ptrdiff_t) sizeof(server_info->session_key);
|
|
count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
|
|
if (count != (MagickOffsetType) (p-message))
|
|
return(MagickFalse);
|
|
status=MagickFalse;
|
|
count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
|
|
if (count != (MagickOffsetType) sizeof(status))
|
|
return(MagickFalse);
|
|
return(status);
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ W r i t e D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% WriteDistributePixelCacheMetacontents() writes image metacontent to the
|
|
% specified region of the distributed pixel cache.
|
|
%
|
|
% The format of the WriteDistributePixelCacheMetacontents method is:
|
|
%
|
|
% MagickOffsetType WriteDistributePixelCacheMetacontents(
|
|
% DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
% const MagickSizeType length,const unsigned char *metacontent)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
% o image: the image.
|
|
%
|
|
% o region: write the metacontent to this region of the image.
|
|
%
|
|
% o length: the length in bytes of the metacontent.
|
|
%
|
|
% o metacontent: write these metacontent to the pixel cache.
|
|
%
|
|
*/
|
|
MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
|
|
DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
const MagickSizeType length,const unsigned char *metacontent)
|
|
{
|
|
MagickOffsetType
|
|
count;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Write distributed pixel cache metacontent.
|
|
*/
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
assert(region != (RectangleInfo *) NULL);
|
|
assert(metacontent != (unsigned char *) NULL);
|
|
if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
|
|
return(-1);
|
|
p=message;
|
|
*p++='W';
|
|
(void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
|
|
p+=(ptrdiff_t) sizeof(server_info->session_key);
|
|
(void) memcpy(p,®ion->width,sizeof(region->width));
|
|
p+=(ptrdiff_t) sizeof(region->width);
|
|
(void) memcpy(p,®ion->height,sizeof(region->height));
|
|
p+=(ptrdiff_t) sizeof(region->height);
|
|
(void) memcpy(p,®ion->x,sizeof(region->x));
|
|
p+=(ptrdiff_t) sizeof(region->x);
|
|
(void) memcpy(p,®ion->y,sizeof(region->y));
|
|
p+=(ptrdiff_t) sizeof(region->y);
|
|
(void) memcpy(p,&length,sizeof(length));
|
|
p+=(ptrdiff_t) sizeof(length);
|
|
count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
|
|
if (count != (MagickOffsetType) (p-message))
|
|
return(-1);
|
|
return(dpc_send(server_info->file,length,metacontent));
|
|
}
|
|
|
|
/*
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% %
|
|
% %
|
|
% %
|
|
+ W r i t e D i s t r i b u t e P i x e l C a c h e P i x e l s %
|
|
% %
|
|
% %
|
|
% %
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% WriteDistributePixelCachePixels() writes image pixels to the specified
|
|
% region of the distributed pixel cache.
|
|
%
|
|
% The format of the WriteDistributePixelCachePixels method is:
|
|
%
|
|
% MagickBooleanType WriteDistributePixelCachePixels(
|
|
% DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
% const MagickSizeType length,
|
|
% const unsigned char *magick_restrict pixels)
|
|
%
|
|
% A description of each parameter follows:
|
|
%
|
|
% o server_info: the distributed cache info.
|
|
%
|
|
% o image: the image.
|
|
%
|
|
% o region: write the pixels to this region of the image.
|
|
%
|
|
% o length: the length in bytes of the pixels.
|
|
%
|
|
% o pixels: write these pixels to the pixel cache.
|
|
%
|
|
*/
|
|
MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
|
|
DistributeCacheInfo *server_info,const RectangleInfo *region,
|
|
const MagickSizeType length,const unsigned char *magick_restrict pixels)
|
|
{
|
|
MagickOffsetType
|
|
count;
|
|
|
|
unsigned char
|
|
message[MagickPathExtent],
|
|
*p;
|
|
|
|
/*
|
|
Write distributed pixel cache pixels.
|
|
*/
|
|
assert(server_info != (DistributeCacheInfo *) NULL);
|
|
assert(server_info->signature == MagickCoreSignature);
|
|
assert(region != (RectangleInfo *) NULL);
|
|
assert(pixels != (const unsigned char *) NULL);
|
|
if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
|
|
return(-1);
|
|
p=message;
|
|
*p++='w';
|
|
(void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
|
|
p+=(ptrdiff_t) sizeof(server_info->session_key);
|
|
(void) memcpy(p,®ion->width,sizeof(region->width));
|
|
p+=(ptrdiff_t) sizeof(region->width);
|
|
(void) memcpy(p,®ion->height,sizeof(region->height));
|
|
p+=(ptrdiff_t) sizeof(region->height);
|
|
(void) memcpy(p,®ion->x,sizeof(region->x));
|
|
p+=(ptrdiff_t) sizeof(region->x);
|
|
(void) memcpy(p,®ion->y,sizeof(region->y));
|
|
p+=(ptrdiff_t) sizeof(region->y);
|
|
(void) memcpy(p,&length,sizeof(length));
|
|
p+=(ptrdiff_t) sizeof(length);
|
|
count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
|
|
if (count != (MagickOffsetType) (p-message))
|
|
return(-1);
|
|
return(dpc_send(server_info->file,length,pixels));
|
|
}
|