54#include "MagickCore/studio.h"
55#include "MagickCore/cache.h"
56#include "MagickCore/cache-private.h"
57#include "MagickCore/distribute-cache.h"
58#include "MagickCore/distribute-cache-private.h"
59#include "MagickCore/exception.h"
60#include "MagickCore/exception-private.h"
61#include "MagickCore/geometry.h"
62#include "MagickCore/image.h"
63#include "MagickCore/image-private.h"
64#include "MagickCore/list.h"
65#include "MagickCore/locale_.h"
66#include "MagickCore/memory_.h"
67#include "MagickCore/nt-base-private.h"
68#include "MagickCore/pixel.h"
69#include "MagickCore/policy.h"
70#include "MagickCore/random_.h"
71#include "MagickCore/registry.h"
72#include "MagickCore/splay-tree.h"
73#include "MagickCore/string_.h"
74#include "MagickCore/string-private.h"
75#include "MagickCore/utility-private.h"
76#include "MagickCore/version.h"
77#include "MagickCore/version-private.h"
78#define SOCKET_TYPE int
79#undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
80#if defined(MAGICKCORE_DPC_SUPPORT)
81#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
82#include <netinet/in.h>
84#include <sys/socket.h>
86#define CLOSE_SOCKET(socket) (void) close_utf8(socket)
87#define HANDLER_RETURN_TYPE void *
88#define HANDLER_RETURN_VALUE (void *) NULL
89#define SOCKET_TYPE int
90#define LENGTH_TYPE size_t
91#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
92#elif defined(_MSC_VER)
93#define CLOSE_SOCKET(socket) (void) closesocket(socket)
94#define HANDLER_RETURN_TYPE DWORD WINAPI
95#define HANDLER_RETURN_VALUE 0
96#define LENGTH_TYPE int
97#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
98#define MAGICKCORE_HAVE_WINSOCK2 1
105#define DPCHostname "127.0.0.1"
106#define DPCMaxClientWorkers 128
107#define DPCMaxUnauthenticatedClientWorkers 16
108#define DPCPendingConnections 10
110#define DPCSessionKeyLength 16
112# define MSG_NOSIGNAL 0
118#ifdef MAGICKCORE_HAVE_WINSOCK2
123 *wsaData = (WSADATA*) NULL;
126#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
131 *dpc_shared_secret = (
char *) NULL;
135 dpc_unauthenticated_clients = 0;
161#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
162static inline MagickOffsetType dpc_receive(SOCKET_TYPE magick_unused(file),
163 const MagickSizeType magick_unused(length),
164 unsigned char *magick_restrict magick_unused(message))
166 magick_unreferenced(file);
167 magick_unreferenced(length);
168 magick_unreferenced(message);
172static inline MagickOffsetType dpc_receive_deadline(SOCKET_TYPE
173 magick_unused(file),
const MagickSizeType magick_unused(length),
174 unsigned char *magick_restrict magick_unused(message),
175 double magick_unused(deadline))
177 magick_unreferenced(file);
178 magick_unreferenced(length);
179 magick_unreferenced(message);
180 magick_unreferenced(deadline);
184static void SetSocketReceiveTimeout(SOCKET_TYPE file,
double seconds)
189#if defined(MAGICKCORE_HAVE_WINSOCK2)
191 DWORD timeout = (DWORD) (seconds*1000.0);
192 (void) setsockopt(file,SOL_SOCKET,SO_RCVTIMEO,
193 (
const char *) &timeout,
sizeof(timeout));
198 tv.tv_sec=(int) seconds;
199 tv.tv_usec=(int) ((seconds-(
double) tv.tv_sec)*1000000.0);
200 (void) setsockopt(file,SOL_SOCKET,SO_RCVTIMEO,&tv,
sizeof(tv));
205static inline MagickOffsetType dpc_receive(SOCKET_TYPE file,
206 const MagickSizeType length,
unsigned char *magick_restrict message)
208 MagickOffsetType offset = 0;
209 while (offset < (MagickOffsetType) length)
211 MagickSizeType chunk = MagickMin(length-offset,(MagickSizeType)
212 MagickMaxBufferExtent);
213 ssize_t count = recv(file,(
char *) message+offset,(LENGTH_TYPE) chunk,0);
215 offset+=(MagickOffsetType) count;
221#ifdef MAGICKCORE_HAVE_WINSOCK2
222 int wsa_err = WSAGetLastError();
223 if ((wsa_err == WSAEINTR) || (wsa_err == WSAEWOULDBLOCK))
225 if (wsa_err == WSAECONNRESET)
228 if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
230 if (errno == ECONNRESET)
239static inline MagickOffsetType dpc_receive_deadline(SOCKET_TYPE file,
240 MagickSizeType length,
unsigned char *message,
double deadline)
245 MagickOffsetType offset = 0;
246 while (offset < (MagickOffsetType) length)
249 now = (double) time((time_t *) NULL),
250 remaining = deadline-now;
260 if (remaining < 0.001)
262 SetSocketReceiveTimeout(file,remaining);
263 chunk=MagickMin(length-offset,(MagickSizeType) MagickMaxBufferExtent);
264 count=recv(file,(
char *) message+offset,(LENGTH_TYPE) chunk,0);
266 offset+=(MagickOffsetType) count;
272#ifdef MAGICKCORE_HAVE_WINSOCK2
273 int wsa_err = WSAGetLastError();
274 if ((wsa_err == WSAEINTR) || (wsa_err == WSAEWOULDBLOCK))
276 if (wsa_err == WSAECONNRESET)
280 if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
282 if (errno == ECONNRESET)
292#if defined(MAGICKCORE_HAVE_WINSOCK2)
293static void InitializeWinsock2(MagickBooleanType use_lock)
295 if (use_lock != MagickFalse)
298 ActivateSemaphoreInfo(&winsock_semaphore);
299 LockSemaphoreInfo(winsock_semaphore);
301 if (wsaData == (WSADATA *) NULL)
303 wsaData=(WSADATA *) AcquireMagickMemory(
sizeof(WSADATA));
304 if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
305 ThrowFatalException(CacheFatalError,
"WSAStartup failed");
307 if (use_lock != MagickFalse)
308 UnlockSemaphoreInfo(winsock_semaphore);
312#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
313static int ConnectPixelCacheServer(
const char *magick_unused(hostname),
314 const int magick_unused(port),uint64_t *magick_unused(session_key),
315 ExceptionInfo *exception)
317 magick_unreferenced(hostname);
318 magick_unreferenced(port);
319 magick_unreferenced(session_key);
320 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
321 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
325static inline uint64_t ROTL(uint64_t x,
int b)
327 return((x << b) | (x >> (64-b)));
330static inline uint64_t U8TO64_LE(
const uint8_t *p)
332 return(((uint64_t) p[0] << 0) | ((uint64_t) p[1] << 8) |
333 ((uint64_t) p[2] << 16) | ((uint64_t) p[3] << 24) |
334 ((uint64_t) p[4] << 32) | ((uint64_t) p[5] << 40) |
335 ((uint64_t) p[6] << 48) | ((uint64_t) p[7] << 56));
338static inline uint64_t SIPHash24(
const uint8_t key[16],
const uint8_t *message,
342 *end = message+length-(length % 8);
348 b = ((uint64_t) length) << 56,
350 k1 = U8TO64_LE(key+8),
352 v0 = 0x736f6d6570736575ULL ^ k0,
353 v1 = 0x646f72616e646f6dULL ^ k1,
354 v2 = 0x6c7967656e657261ULL ^ k0,
355 v3 = 0x7465646279746573ULL ^ k1;
357 for ( ; message != end; message+=8)
359 m=U8TO64_LE(message);
361 for (i=0; i < 2; i++)
363 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
364 v2+=v3; v3=ROTL(v3,16); v3^=v2;
365 v0+=v3; v3=ROTL(v3,21); v3^=v0;
366 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
370 switch (length & 0x07)
372 case 7: b|=((uint64_t) message[6]) << 48; magick_fallthrough;
373 case 6: b|=((uint64_t) message[5]) << 40; magick_fallthrough;
374 case 5: b|=((uint64_t) message[4]) << 32; magick_fallthrough;
375 case 4: b|=((uint64_t) message[3]) << 24; magick_fallthrough;
376 case 3: b|=((uint64_t) message[2]) << 16; magick_fallthrough;
377 case 2: b|=((uint64_t) message[1]) << 8; magick_fallthrough;
378 case 1: b|=((uint64_t) message[0]); magick_fallthrough;
382 for (i=0; i < 2; i++)
384 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
385 v2+=v3; v3=ROTL(v3,16); v3^=v2;
386 v0+=v3; v3=ROTL(v3,21); v3^=v0;
387 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
391 for (i=0; i < 4; i++)
393 v0+=v1; v1=ROTL(v1,13); v1^=v0; v0=ROTL(v0,32);
394 v2+=v3; v3=ROTL(v3,16); v3^=v2;
395 v0+=v3; v3=ROTL(v3,21); v3^=v0;
396 v2+=v1; v1=ROTL(v1,17); v1^=v2; v2=ROTL(v2,32);
401static inline void DeriveSIPKeyFromSecret(
const char *shared_secret,
409 k0 = 0x0706050403020100ULL,
410 k1 = 0x0f0e0d0c0b0a0908ULL;
412 length=strlen(shared_secret);
413 for (i=0; i < length; i++)
416 b = (uint8_t) shared_secret[i];
419 k0*=0x100000001b3ULL;
420 k1^=(uint64_t) b << ((i & 7)*8);
421 k1=(k1 << 5) | (k1 >> (64-5));
423 (void) memcpy(key,&k0,8);
424 (void) memcpy(key+8,&k1,8);
427static inline uint64_t GenerateSessionKey(
const char *shared_secret,
428 const unsigned char *nonce,
size_t length)
433 DeriveSIPKeyFromSecret(shared_secret,key);
434 return(SIPHash24(key,nonce,length));
437static int ConnectPixelCacheServer(
const char *hostname,
const int port,
438 uint64_t *session_key,ExceptionInfo *exception)
440#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
443 service[MagickPathExtent],
460 nonce[DPCSessionKeyLength];
466#if defined(MAGICKCORE_HAVE_WINSOCK2)
467 InitializeWinsock2(MagickTrue);
469 (void) memset(&hints,0,
sizeof(hints));
470 hints.ai_family=AF_INET;
471 hints.ai_socktype=SOCK_STREAM;
472 hints.ai_flags=AI_PASSIVE;
473 (void) FormatLocaleString(service,MagickPathExtent,
"%d",port);
474 status=getaddrinfo(hostname,service,&hints,&result);
477 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
478 "DistributedPixelCache",
"'%s': %s",hostname,gai_strerror(status));
481 client_socket=(SOCKET_TYPE) socket(result->ai_family,result->ai_socktype,
482 result->ai_protocol);
483 if (client_socket == -1)
485 freeaddrinfo(result);
486 message=GetExceptionMessage(errno);
487 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
488 "DistributedPixelCache",
"'%s': %s",hostname,message);
489 message=DestroyString(message);
492 status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
493 freeaddrinfo(result);
496 CLOSE_SOCKET(client_socket);
497 message=GetExceptionMessage(errno);
498 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
499 "DistributedPixelCache",
"'%s': %s",hostname,message);
500 message=DestroyString(message);
506 count=recv(client_socket,(
char *) nonce,
sizeof(nonce),0);
507 if (count != (ssize_t)
sizeof(nonce))
509 CLOSE_SOCKET(client_socket);
510 message=GetExceptionMessage(errno);
511 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
512 "DistributedPixelCache",
"'%s': %s",hostname,message);
513 message=DestroyString(message);
519 shared_secret=GetPolicyValue(
"cache:shared-secret");
520 if (shared_secret == (
const char *) NULL)
522 CLOSE_SOCKET(client_socket);
523 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
524 "DistributedPixelCache",
"'%s': shared secret required",hostname);
527 *session_key=GenerateSessionKey(shared_secret,nonce,
sizeof(nonce));
528 shared_secret=DestroyString(shared_secret);
532 count=send(client_socket,(
char *) session_key,
sizeof(*session_key),
534 if (count != (ssize_t)
sizeof(*session_key))
536 CLOSE_SOCKET(client_socket);
537 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
538 "DistributedPixelCache",
"'%s': authentication failed",hostname);
541 return((
int) client_socket);
543 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
544 "DelegateLibrarySupportNotBuiltIn",
"distributed pixel cache");
550static char *GetHostname(
int *port,ExceptionInfo *exception)
569 hosts=(
char *) GetImageRegistry(StringRegistryType,
"cache:hosts",exception);
570 if (hosts == (
char *) NULL)
573 return(AcquireString(DPCHostname));
575 (void) SubstituteString(&hosts,
",",
" ");
576 hostlist=StringToArgv(hosts,&argc);
577 hosts=DestroyString(hosts);
578 if ((hostlist == (
char **) NULL) || ((argc-1) == 0))
581 return(AcquireString(DPCHostname));
584 size_t host_count = (size_t) argc-1;
585 size_t index = (
id++ % host_count)+1;
586 hosts=AcquireString(hostlist[index]);
588 for (i=0; i < (ssize_t) argc; i++)
589 hostlist[i]=DestroyString(hostlist[i]);
590 hostlist=(
char **) RelinquishMagickMemory(hostlist);
591 (void) SubstituteString(&hosts,
":",
" ");
592 hostlist=StringToArgv(hosts,&argc);
593 if (hostlist == (
char **) NULL)
596 return(AcquireString(DPCHostname));
598 host=AcquireString(hostlist[1]);
599 if (hostlist[2] == (
char *) NULL)
602 *port=(int) StringToLong(hostlist[2]);
603 for (i=0; i < (ssize_t) argc; i++)
604 hostlist[i]=DestroyString(hostlist[i]);
605 hostlist=(
char **) RelinquishMagickMemory(hostlist);
609MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
610 ExceptionInfo *exception)
624 server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
625 sizeof(*server_info));
626 (void) memset(server_info,0,
sizeof(*server_info));
627 server_info->signature=MagickCoreSignature;
629 hostname=GetHostname(&server_info->port,exception);
631 server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
632 &session_key,exception);
633 if (server_info->file == -1)
634 server_info=DestroyDistributeCacheInfo(server_info);
637 server_info->session_key=session_key;
638 (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
639 server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
642 hostname=DestroyString(hostname);
670MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
671 DistributeCacheInfo *server_info)
673 assert(server_info != (DistributeCacheInfo *) NULL);
674 assert(server_info->signature == MagickCoreSignature);
675#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
676 if (server_info->file >= 0)
677 CLOSE_SOCKET(server_info->file);
679 server_info->signature=(~MagickCoreSignature);
680 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
710#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
711static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
712 const MagickSizeType magick_unused(length),
713 const void *magick_restrict magick_unused(message))
715 magick_unreferenced(file);
716 magick_unreferenced(length);
717 magick_unreferenced(message);
721static inline MagickOffsetType dpc_send(SOCKET_TYPE file,
722 const MagickSizeType length,
const void *magick_restrict message)
734 for (i=0; i < (MagickOffsetType) length; i+=count)
736 count=(ssize_t) send(file,(
const char *) message+i,(LENGTH_TYPE) MagickMin(
737 length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
750#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
751MagickExport
void DistributePixelCacheServer(
const int magick_unused(port),
752 ExceptionInfo *magick_unused(exception))
754 magick_unreferenced(port);
755 magick_unreferenced(exception);
756 ThrowFatalException(MissingDelegateError,
"DelegateLibrarySupportNotBuiltIn");
759static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
760 const uint64_t session_key)
763 key = (MagickAddressType) session_key;
768 return(DeleteNodeFromSplayTree(registry,(
const void *) key));
771static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
772 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
778 key = (MagickAddressType) session_key;
790 message[MagickPathExtent],
796 image=AcquireImage((ImageInfo *) NULL,exception);
797 if (image == (Image *) NULL)
799 length=
sizeof(image->storage_class)+
sizeof(image->colorspace)+
800 sizeof(image->alpha_trait)+
sizeof(image->channels)+
sizeof(image->columns)+
801 sizeof(image->rows)+
sizeof(image->number_channels)+MaxPixelChannels*
802 sizeof(*image->channel_map)+
sizeof(image->metacontent_extent);
803 count=dpc_receive(file,length,message);
804 if (count != (MagickOffsetType) length)
806 image=DestroyImage(image);
813 (void) memcpy(&image->storage_class,p,
sizeof(image->storage_class));
814 p+=(ptrdiff_t)
sizeof(image->storage_class);
815 (void) memcpy(&image->colorspace,p,
sizeof(image->colorspace));
816 p+=(ptrdiff_t)
sizeof(image->colorspace);
817 (void) memcpy(&image->alpha_trait,p,
sizeof(image->alpha_trait));
818 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
819 (void) memcpy(&image->channels,p,
sizeof(image->channels));
820 p+=(ptrdiff_t)
sizeof(image->channels);
821 (void) memcpy(&image->columns,p,
sizeof(image->columns));
822 p+=(ptrdiff_t)
sizeof(image->columns);
823 (void) memcpy(&image->rows,p,
sizeof(image->rows));
824 p+=(ptrdiff_t)
sizeof(image->rows);
825 (void) memcpy(&image->number_channels,p,
sizeof(image->number_channels));
826 p+=(ptrdiff_t)
sizeof(image->number_channels);
827 (void) memcpy(image->channel_map,p,MaxPixelChannels*
828 sizeof(*image->channel_map));
829 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
830 (void) memcpy(&image->metacontent_extent,p,
sizeof(image->metacontent_extent));
831 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
832 if (SyncImagePixelCache(image,exception) == MagickFalse)
834 image=DestroyImage(image);
837 status=AddValueToSplayTree(registry,(
const void *) key,image);
838 if (status == MagickFalse)
840 image=DestroyImage(image);
846static inline MagickBooleanType ValidateDistributedPixelCache(
847 const RectangleInfo *region,
const size_t per_pixel,
848 const MagickSizeType length)
854 if (HeapOverflowSanityCheckGetSize(region->width,region->height,&pixels) != MagickFalse)
856 if (HeapOverflowSanityCheckGetSize(pixels,per_pixel,&extent) != MagickFalse)
858 if (length > (MagickSizeType) extent)
863static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
864 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
876 key = (MagickAddressType) session_key;
891 message[MagickPathExtent],
897 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
898 if (image == (Image *) NULL)
900 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
901 sizeof(region.y)+
sizeof(length);
902 count=dpc_receive(file,length,message);
903 if (count != (MagickOffsetType) length)
906 (void) memcpy(®ion.width,q,
sizeof(region.width));
907 q+=(ptrdiff_t)
sizeof(region.width);
908 (void) memcpy(®ion.height,q,
sizeof(region.height));
909 q+=(ptrdiff_t)
sizeof(region.height);
910 (void) memcpy(®ion.x,q,
sizeof(region.x));
911 q+=(ptrdiff_t)
sizeof(region.x);
912 (void) memcpy(®ion.y,q,
sizeof(region.y));
913 q+=(ptrdiff_t)
sizeof(region.y);
914 (void) memcpy(&length,q,
sizeof(length));
915 q+=(ptrdiff_t)
sizeof(length);
916 per_pixel=image->number_meta_channels*
sizeof(Quantum);
917 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
919 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
921 if (p == (
const Quantum *) NULL)
923 metacontent=(
const unsigned char *) GetVirtualMetacontent(image);
924 count=dpc_send(file,length,metacontent);
925 if (count != (MagickOffsetType) length)
930static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
931 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
940 key = (MagickAddressType) session_key;
955 message[MagickPathExtent],
961 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
962 if (image == (Image *) NULL)
964 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
965 sizeof(region.y)+
sizeof(length);
966 count=dpc_receive(file,length,message);
967 if (count != (MagickOffsetType) length)
970 (void) memcpy(®ion.width,q,
sizeof(region.width));
971 q+=(ptrdiff_t)
sizeof(region.width);
972 (void) memcpy(®ion.height,q,
sizeof(region.height));
973 q+=(ptrdiff_t)
sizeof(region.height);
974 (void) memcpy(®ion.x,q,
sizeof(region.x));
975 q+=(ptrdiff_t)
sizeof(region.x);
976 (void) memcpy(®ion.y,q,
sizeof(region.y));
977 q+=(ptrdiff_t)
sizeof(region.y);
978 (void) memcpy(&length,q,
sizeof(length));
979 per_pixel=image->number_channels*
sizeof(Quantum);
980 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
982 q+=(ptrdiff_t)
sizeof(length);
983 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
985 if (p == (
const Quantum *) NULL)
987 count=dpc_send(file,length,p);
988 if (count != (MagickOffsetType) length)
993static void *RelinquishImageRegistry(
void *image)
995 return((
void *) DestroyImageList((Image *) image));
998static MagickBooleanType WriteDistributeCacheMetacontent(
999 SplayTreeInfo *registry,SOCKET_TYPE file,
const uint64_t session_key,
1000 ExceptionInfo *exception)
1006 key = (MagickAddressType) session_key;
1024 message[MagickPathExtent],
1031 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
1032 if (image == (Image *) NULL)
1033 return(MagickFalse);
1034 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
1035 sizeof(region.y)+
sizeof(length);
1036 count=dpc_receive(file,length,message);
1037 if (count != (MagickOffsetType) length)
1038 return(MagickFalse);
1040 (void) memcpy(®ion.width,p,
sizeof(region.width));
1041 p+=(ptrdiff_t)
sizeof(region.width);
1042 (void) memcpy(®ion.height,p,
sizeof(region.height));
1043 p+=(ptrdiff_t)
sizeof(region.height);
1044 (void) memcpy(®ion.x,p,
sizeof(region.x));
1045 p+=(ptrdiff_t)
sizeof(region.x);
1046 (void) memcpy(®ion.y,p,
sizeof(region.y));
1047 p+=(ptrdiff_t)
sizeof(region.y);
1048 (void) memcpy(&length,p,
sizeof(length));
1049 per_pixel=image->number_meta_channels*
sizeof(Quantum);
1050 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
1051 return(MagickFalse);
1052 p+=(ptrdiff_t)
sizeof(length);
1053 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1055 if (q == (Quantum *) NULL)
1056 return(MagickFalse);
1057 metacontent=(
unsigned char *) GetAuthenticMetacontent(image);
1058 count=dpc_receive(file,length,metacontent);
1059 if (count != (MagickOffsetType) length)
1060 return(MagickFalse);
1061 return(SyncAuthenticPixels(image,exception));
1064static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
1065 SOCKET_TYPE file,
const uint64_t session_key,ExceptionInfo *exception)
1071 key = (MagickAddressType) session_key;
1089 message[MagickPathExtent],
1095 image=(Image *) GetValueFromSplayTree(registry,(
const void *) key);
1096 if (image == (Image *) NULL)
1097 return(MagickFalse);
1098 length=
sizeof(region.width)+
sizeof(region.height)+
sizeof(region.x)+
1099 sizeof(region.y)+
sizeof(length);
1100 count=dpc_receive(file,length,message);
1101 if (count != (MagickOffsetType) length)
1102 return(MagickFalse);
1104 (void) memcpy(®ion.width,p,
sizeof(region.width));
1105 p+=(ptrdiff_t)
sizeof(region.width);
1106 (void) memcpy(®ion.height,p,
sizeof(region.height));
1107 p+=(ptrdiff_t)
sizeof(region.height);
1108 (void) memcpy(®ion.x,p,
sizeof(region.x));
1109 p+=(ptrdiff_t)
sizeof(region.x);
1110 (void) memcpy(®ion.y,p,
sizeof(region.y));
1111 p+=(ptrdiff_t)
sizeof(region.y);
1112 (void) memcpy(&length,p,
sizeof(length));
1113 per_pixel=image->number_channels*
sizeof(Quantum);
1114 if (ValidateDistributedPixelCache(®ion,per_pixel,length) == MagickFalse)
1115 return(MagickFalse);
1116 p+=(ptrdiff_t)
sizeof(length);
1117 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
1119 if (q == (Quantum *) NULL)
1120 return(MagickFalse);
1121 count=dpc_receive(file,length,(
unsigned char *) q);
1122 if (count != (MagickOffsetType) length)
1123 return(MagickFalse);
1124 return(SyncAuthenticPixels(image,exception));
1127static void LockDPCSemaphore(
void)
1130 ActivateSemaphoreInfo(&dpc_semaphore);
1131 LockSemaphoreInfo(dpc_semaphore);
1134static void AuthenticateDPCClient(
void)
1137 if (dpc_unauthenticated_clients != 0)
1138 dpc_unauthenticated_clients--;
1139 UnlockSemaphoreInfo(dpc_semaphore);
1142static void RelinquishDPCClient(
const MagickBooleanType unauthenticated)
1145 if ((unauthenticated != MagickFalse) && (dpc_unauthenticated_clients != 0))
1146 dpc_unauthenticated_clients--;
1147 if (dpc_clients != 0)
1149 UnlockSemaphoreInfo(dpc_semaphore);
1152static HANDLER_RETURN_TYPE DistributePixelCacheConnectionHandler(
void *socket_arg)
1158 authenticated = MagickFalse,
1159 status = MagickFalse;
1169 *client_socket_ptr = (SOCKET_TYPE *) socket_arg;
1183 nonce[DPCSessionKeyLength];
1185 client_socket=(*client_socket_ptr);
1186 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(client_socket_ptr);
1190 random_info=AcquireRandomInfo();
1191 entropy=GetRandomKey(random_info,
sizeof(nonce));
1192 (void) memcpy(nonce,GetStringInfoDatum(entropy),
sizeof(nonce));
1193 entropy=DestroyStringInfo(entropy);
1194 random_info=DestroyRandomInfo(random_info);
1198 session_key=GenerateSessionKey(dpc_shared_secret,nonce,
sizeof(nonce));
1202 count=dpc_send(client_socket,
sizeof(nonce),nonce);
1203 if (count != (MagickOffsetType)
sizeof(nonce))
1205 CLOSE_SOCKET(client_socket);
1206 RelinquishDPCClient(MagickTrue);
1207 return(HANDLER_RETURN_VALUE);
1212 count=dpc_receive_deadline(client_socket,
sizeof(key),(
unsigned char *) &key,
1213 (
double) time((time_t *) NULL)+5.0);
1214 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1216 CLOSE_SOCKET(client_socket);
1217 RelinquishDPCClient(MagickTrue);
1218 return(HANDLER_RETURN_VALUE);
1220 AuthenticateDPCClient();
1221 authenticated=MagickTrue;
1222 exception=AcquireExceptionInfo();
1223 registry=NewSplayTree((
int (*)(
const void *,
const void *)) NULL,
1224 (
void *(*)(
void *)) NULL,RelinquishImageRegistry);
1228 for (status=MagickFalse; ; )
1233 count=dpc_receive(client_socket,1,(
unsigned char *) &command);
1236 count=dpc_receive(client_socket,
sizeof(key),(
unsigned char *) &key);
1237 if ((count != (MagickOffsetType)
sizeof(key)) || (key != session_key))
1243 status=OpenDistributeCache(registry,client_socket,session_key,
1245 dpc_send(client_socket,
sizeof(status),&status);
1250 status=ReadDistributeCachePixels(registry,client_socket,session_key,
1256 status=ReadDistributeCacheMetacontent(registry,client_socket,
1257 session_key,exception);
1262 status=WriteDistributeCachePixels(registry,client_socket,session_key,
1268 status=WriteDistributeCacheMetacontent(registry,client_socket,
1269 session_key,exception);
1274 status=DestroyDistributeCache(registry,session_key);
1280 if ((status == MagickFalse) || (command ==
'd'))
1283 count=dpc_send(client_socket,
sizeof(status),&status);
1284 CLOSE_SOCKET(client_socket);
1285 exception=DestroyExceptionInfo(exception);
1286 registry=DestroySplayTree(registry);
1287 RelinquishDPCClient(authenticated == MagickFalse ? MagickTrue :
1289 return(HANDLER_RETURN_VALUE);
1292static size_t GetDPCPolicyLimit(
const char *name,
const size_t default_limit)
1295 policy_name[MagickPathExtent],
1301 limit=default_limit;
1302 (void) FormatLocaleString(policy_name,MagickPathExtent,
"cache:%s",name);
1303 policy_value=GetPolicyValue(policy_name);
1304 if (policy_value != (
char *) NULL)
1313 policy_limit=strtoul(policy_value,&q,10);
1314 if ((errno == 0) && (q != policy_value) && (policy_limit != 0))
1315 limit=(size_t) policy_limit;
1316 policy_value=DestroyString(policy_value);
1321static size_t GetMaxDPCClients(
void)
1323 return(GetDPCPolicyLimit(
"max-dpc-clients",DPCMaxClientWorkers));
1326static size_t GetMaxDPCUnauthenticatedClients(
void)
1330 unauthenticated_workers;
1332 client_workers=GetMaxDPCClients();
1333 unauthenticated_workers=GetDPCPolicyLimit(
"max-dpc-unauthenticated-clients",
1334 DPCMaxUnauthenticatedClientWorkers);
1335 return(MagickMin(unauthenticated_workers,client_workers));
1338static MagickBooleanType AcquireDPCClientWorker(
void)
1345 unauthenticated_worker_limit;
1348 max_dpc_clients=GetMaxDPCClients();
1349 unauthenticated_worker_limit=GetMaxDPCUnauthenticatedClients();
1351 if ((dpc_clients < max_dpc_clients) &&
1352 (dpc_unauthenticated_clients < unauthenticated_worker_limit))
1355 dpc_unauthenticated_clients++;
1358 UnlockSemaphoreInfo(dpc_semaphore);
1362MagickExport
void DistributePixelCacheServer(
const int port,
1363 ExceptionInfo *exception)
1366 service[MagickPathExtent];
1371#if defined(MAGICKCORE_THREAD_SUPPORT)
1377#elif defined(_MSC_VER)
1400 assert(exception != (ExceptionInfo *) NULL);
1401 assert(exception->signature == MagickCoreSignature);
1402 magick_unreferenced(exception);
1403 dpc_shared_secret=GetPolicyValue(
"cache:shared-secret");
1404 if (dpc_shared_secret == (
char *) NULL)
1405 ThrowFatalException(CacheFatalError,
"no shared secret");
1406#if defined(MAGICKCORE_HAVE_WINSOCK2)
1407 InitializeWinsock2(MagickFalse);
1409 (void) memset(&hint,0,
sizeof(hint));
1410 hint.ai_family=AF_INET;
1411 hint.ai_socktype=SOCK_STREAM;
1412 hint.ai_flags=AI_PASSIVE;
1413 FormatLocaleString(service,MagickPathExtent,
"%d",port);
1414 status=getaddrinfo(NULL,service,&hint,&result);
1416 ThrowFatalException(CacheFatalError,
"UnableToListen");
1417 server_socket=(SOCKET_TYPE) 0;
1418 for (p=result; p != NULL; p=p->ai_next)
1423 server_socket=(SOCKET_TYPE) socket(p->ai_family,p->ai_socktype,
1425 if (server_socket == -1)
1427 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(
char *) &one,
1428 (socklen_t)
sizeof(one));
1431 CLOSE_SOCKET(server_socket);
1434 SetSocketReceiveTimeout(server_socket,5.0);
1435 status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1438 CLOSE_SOCKET(server_socket);
1443 if (p == (
struct addrinfo *) NULL)
1444 ThrowFatalException(CacheFatalError,
"UnableToBind");
1445 freeaddrinfo(result);
1446 status=listen(server_socket,DPCPendingConnections);
1448 ThrowFatalException(CacheFatalError,
"UnableToListen");
1449#if defined(MAGICKCORE_THREAD_SUPPORT)
1450 pthread_attr_init(&attributes);
1451 pthread_attr_setdetachstate(&attributes,PTHREAD_CREATE_DETACHED);
1459 length = (socklen_t)
sizeof(address);
1461 client_socket_ptr=(SOCKET_TYPE *) AcquireMagickMemory(
sizeof(SOCKET_TYPE));
1462 if (client_socket_ptr == NULL)
1464 *client_socket_ptr=(SOCKET_TYPE) accept(server_socket,(
struct sockaddr *)
1466 if (*client_socket_ptr == -1)
1468 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1472 if (AcquireDPCClientWorker() == MagickFalse)
1474 CLOSE_SOCKET(*client_socket_ptr);
1475 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1479 SetSocketReceiveTimeout(*client_socket_ptr,5.0);
1482 CLOSE_SOCKET(*client_socket_ptr);
1483 RelinquishDPCClient(MagickTrue);
1484 client_socket_ptr=(SOCKET_TYPE *) RelinquishMagickMemory(
1488#if defined(MAGICKCORE_THREAD_SUPPORT)
1489 status=pthread_create(&thread_id,&attributes,DistributePixelCacheConnectionHandler,
1490 (
void *) client_socket_ptr);
1493 CLOSE_SOCKET(*client_socket_ptr);
1494 RelinquishDPCClient(MagickTrue);
1495 RelinquishMagickMemory(client_socket_ptr);
1498#elif defined(_MSC_VER)
1499 if (CreateThread(0,0,DistributePixelCacheConnectionHandler,(
void*) client_socket_ptr,
1500 0,&threadID) == (HANDLE) NULL)
1502 CLOSE_SOCKET(*client_socket_ptr);
1503 RelinquishDPCClient(MagickTrue);
1504 RelinquishMagickMemory(client_socket_ptr);
1528MagickPrivate
void DistributeCacheTerminus(
void)
1530#ifdef MAGICKCORE_HAVE_WINSOCK2
1532 ActivateSemaphoreInfo(&winsock_semaphore);
1533 LockSemaphoreInfo(winsock_semaphore);
1534 if (wsaData != (WSADATA *) NULL)
1537 wsaData=(WSADATA *) RelinquishMagickMemory((
void *) wsaData);
1539 UnlockSemaphoreInfo(winsock_semaphore);
1540 RelinquishSemaphoreInfo(&winsock_semaphore);
1542#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
1543 if (dpc_shared_secret != (
char *) NULL)
1544 dpc_shared_secret=DestroyString(dpc_shared_secret);
1546 RelinquishSemaphoreInfo(&dpc_semaphore);
1573MagickPrivate
int GetDistributeCacheFile(
const DistributeCacheInfo *server_info)
1575 assert(server_info != (DistributeCacheInfo *) NULL);
1576 assert(server_info->signature == MagickCoreSignature);
1577 return(server_info->file);
1604MagickPrivate
const char *GetDistributeCacheHostname(
1605 const DistributeCacheInfo *server_info)
1607 assert(server_info != (DistributeCacheInfo *) NULL);
1608 assert(server_info->signature == MagickCoreSignature);
1609 return(server_info->hostname);
1635MagickPrivate
int GetDistributeCachePort(
const DistributeCacheInfo *server_info)
1637 assert(server_info != (DistributeCacheInfo *) NULL);
1638 assert(server_info->signature == MagickCoreSignature);
1639 return(server_info->port);
1667MagickPrivate MagickBooleanType OpenDistributePixelCache(
1668 DistributeCacheInfo *server_info,Image *image)
1677 message[MagickPathExtent],
1683 assert(server_info != (DistributeCacheInfo *) NULL);
1684 assert(server_info->signature == MagickCoreSignature);
1685 assert(image != (Image *) NULL);
1686 assert(image->signature == MagickCoreSignature);
1692 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1693 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1694 (void) memcpy(p,&image->storage_class,
sizeof(image->storage_class));
1695 p+=(ptrdiff_t)
sizeof(image->storage_class);
1696 (void) memcpy(p,&image->colorspace,
sizeof(image->colorspace));
1697 p+=(ptrdiff_t)
sizeof(image->colorspace);
1698 (void) memcpy(p,&image->alpha_trait,
sizeof(image->alpha_trait));
1699 p+=(ptrdiff_t)
sizeof(image->alpha_trait);
1700 (void) memcpy(p,&image->channels,
sizeof(image->channels));
1701 p+=(ptrdiff_t)
sizeof(image->channels);
1702 (void) memcpy(p,&image->columns,
sizeof(image->columns));
1703 p+=(ptrdiff_t)
sizeof(image->columns);
1704 (void) memcpy(p,&image->rows,
sizeof(image->rows));
1705 p+=(ptrdiff_t)
sizeof(image->rows);
1706 (void) memcpy(p,&image->number_channels,
sizeof(image->number_channels));
1707 p+=(ptrdiff_t)
sizeof(image->number_channels);
1708 (void) memcpy(p,image->channel_map,MaxPixelChannels*
1709 sizeof(*image->channel_map));
1710 p+=(ptrdiff_t) MaxPixelChannels*
sizeof(*image->channel_map);
1711 (void) memcpy(p,&image->metacontent_extent,
sizeof(image->metacontent_extent));
1712 p+=(ptrdiff_t)
sizeof(image->metacontent_extent);
1713 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1714 if (count != (MagickOffsetType) (p-message))
1715 return(MagickFalse);
1717 count=dpc_receive(server_info->file,
sizeof(status),(
unsigned char *) &status);
1718 if (count != (MagickOffsetType)
sizeof(status))
1719 return(MagickFalse);
1756MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1757 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1758 const MagickSizeType length,
unsigned char *metacontent)
1764 message[MagickPathExtent],
1770 assert(server_info != (DistributeCacheInfo *) NULL);
1771 assert(server_info->signature == MagickCoreSignature);
1772 assert(region != (RectangleInfo *) NULL);
1773 assert(metacontent != (
unsigned char *) NULL);
1774 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1778 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1779 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1780 (void) memcpy(p,®ion->width,
sizeof(region->width));
1781 p+=(ptrdiff_t)
sizeof(region->width);
1782 (void) memcpy(p,®ion->height,
sizeof(region->height));
1783 p+=(ptrdiff_t)
sizeof(region->height);
1784 (void) memcpy(p,®ion->x,
sizeof(region->x));
1785 p+=(ptrdiff_t)
sizeof(region->x);
1786 (void) memcpy(p,®ion->y,
sizeof(region->y));
1787 p+=(ptrdiff_t)
sizeof(region->y);
1788 (void) memcpy(p,&length,
sizeof(length));
1789 p+=(ptrdiff_t)
sizeof(length);
1790 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1791 if (count != (MagickOffsetType) (p-message))
1793 return(dpc_receive(server_info->file,length,metacontent));
1829MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1830 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1831 const MagickSizeType length,
unsigned char *magick_restrict pixels)
1837 message[MagickPathExtent],
1843 assert(server_info != (DistributeCacheInfo *) NULL);
1844 assert(server_info->signature == MagickCoreSignature);
1845 assert(region != (RectangleInfo *) NULL);
1846 assert(pixels != (
unsigned char *) NULL);
1847 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1851 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1852 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1853 (void) memcpy(p,®ion->width,
sizeof(region->width));
1854 p+=(ptrdiff_t)
sizeof(region->width);
1855 (void) memcpy(p,®ion->height,
sizeof(region->height));
1856 p+=(ptrdiff_t)
sizeof(region->height);
1857 (void) memcpy(p,®ion->x,
sizeof(region->x));
1858 p+=(ptrdiff_t)
sizeof(region->x);
1859 (void) memcpy(p,®ion->y,
sizeof(region->y));
1860 p+=(ptrdiff_t)
sizeof(region->y);
1861 (void) memcpy(p,&length,
sizeof(length));
1862 p+=(ptrdiff_t)
sizeof(length);
1863 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1864 if (count != (MagickOffsetType) (p-message))
1866 return(dpc_receive(server_info->file,length,pixels));
1893MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1894 DistributeCacheInfo *server_info)
1903 message[MagickPathExtent],
1909 assert(server_info != (DistributeCacheInfo *) NULL);
1910 assert(server_info->signature == MagickCoreSignature);
1913 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1914 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1915 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1916 if (count != (MagickOffsetType) (p-message))
1917 return(MagickFalse);
1919 count=dpc_receive(server_info->file,
sizeof(status),(
unsigned char *) &status);
1920 if (count != (MagickOffsetType)
sizeof(status))
1921 return(MagickFalse);
1958MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1959 DistributeCacheInfo *server_info,
const RectangleInfo *region,
1960 const MagickSizeType length,
const unsigned char *metacontent)
1966 message[MagickPathExtent],
1972 assert(server_info != (DistributeCacheInfo *) NULL);
1973 assert(server_info->signature == MagickCoreSignature);
1974 assert(region != (RectangleInfo *) NULL);
1975 assert(metacontent != (
unsigned char *) NULL);
1976 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1980 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
1981 p+=(ptrdiff_t)
sizeof(server_info->session_key);
1982 (void) memcpy(p,®ion->width,
sizeof(region->width));
1983 p+=(ptrdiff_t)
sizeof(region->width);
1984 (void) memcpy(p,®ion->height,
sizeof(region->height));
1985 p+=(ptrdiff_t)
sizeof(region->height);
1986 (void) memcpy(p,®ion->x,
sizeof(region->x));
1987 p+=(ptrdiff_t)
sizeof(region->x);
1988 (void) memcpy(p,®ion->y,
sizeof(region->y));
1989 p+=(ptrdiff_t)
sizeof(region->y);
1990 (void) memcpy(p,&length,
sizeof(length));
1991 p+=(ptrdiff_t)
sizeof(length);
1992 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1993 if (count != (MagickOffsetType) (p-message))
1995 return(dpc_send(server_info->file,length,metacontent));
2032MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
2033 DistributeCacheInfo *server_info,
const RectangleInfo *region,
2034 const MagickSizeType length,
const unsigned char *magick_restrict pixels)
2040 message[MagickPathExtent],
2046 assert(server_info != (DistributeCacheInfo *) NULL);
2047 assert(server_info->signature == MagickCoreSignature);
2048 assert(region != (RectangleInfo *) NULL);
2049 assert(pixels != (
const unsigned char *) NULL);
2050 if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
2054 (void) memcpy(p,&server_info->session_key,
sizeof(server_info->session_key));
2055 p+=(ptrdiff_t)
sizeof(server_info->session_key);
2056 (void) memcpy(p,®ion->width,
sizeof(region->width));
2057 p+=(ptrdiff_t)
sizeof(region->width);
2058 (void) memcpy(p,®ion->height,
sizeof(region->height));
2059 p+=(ptrdiff_t)
sizeof(region->height);
2060 (void) memcpy(p,®ion->x,
sizeof(region->x));
2061 p+=(ptrdiff_t)
sizeof(region->x);
2062 (void) memcpy(p,®ion->y,
sizeof(region->y));
2063 p+=(ptrdiff_t)
sizeof(region->y);
2064 (void) memcpy(p,&length,
sizeof(length));
2065 p+=(ptrdiff_t)
sizeof(length);
2066 count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
2067 if (count != (MagickOffsetType) (p-message))
2069 return(dpc_send(server_info->file,length,pixels));