]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/distribute-cache.c
The 8bim profile will be updated when the iptc profile is changed.
[imagemagick] / MagickCore / distribute-cache.c
index 1c930ae8587eef2195b2f4fec8bbcc019886ef16..36a0ac44454da74327cb7b265b2ab43964a462ab 100644 (file)
 %                 MagickCore Distributed Pixel Cache Methods                  %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                January 2013                                 %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 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  %
 #include "MagickCore/exception-private.h"
 #include "MagickCore/geometry.h"
 #include "MagickCore/image.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"
-#if defined(MAGICKCORE_HAVE_SOCKET)
+#include "MagickCore/version.h"
+#include "MagickCore/version-private.h"
+#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
 #include <netinet/in.h>
 #include <netdb.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
+#else
+#undef send
+#undef recv
+#define send(file,buffer,length,flags)  0
+#define recv(file,buffer,length,flags)  0
 #endif
 \f
 /*
   Define declarations.
 */
 #define DPCHostname  "127.0.0.1"
+#define DPCPendingConnections  10
 #define DPCPort  6668
 #define DPCSessionKeyLength  8
+#ifndef MSG_NOSIGNAL
+#  define MSG_NOSIGNAL 0
+#endif
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 */
 
-static MagickSizeType CRC64(const unsigned char *message,const size_t length)
+static inline MagickSizeType MagickMin(const MagickSizeType x,
+  const MagickSizeType y)
 {
-  MagickSizeType
-    crc;
+  if (x < y)
+    return(x);
+  return(y);
+}
 
-  register ssize_t
+static inline MagickOffsetType dpc_read(int file,const MagickSizeType length,
+  unsigned char *restrict message)
+{
+  register MagickOffsetType
     i;
 
-  static MagickBooleanType
-    crc_initial = MagickFalse;
-
-  static MagickSizeType
-    crc_xor[256];
+  ssize_t
+    count;
 
-  if (crc_initial == MagickFalse)
-    {
-      MagickSizeType
-        alpha;
+#if !defined(MAGICKCORE_HAVE_SOCKET) || !defined(MAGICKCORE_THREAD_SUPPORT)
+  magick_unreferenced(file);
+  magick_unreferenced(message);
+#endif
 
-      for (i=0; i < 256; i++)
+  count=0;
+  for (i=0; i < (MagickOffsetType) length; i+=count)
+  {
+    count=recv(file,message+i,(size_t) MagickMin(length-i,(MagickSizeType)
+      SSIZE_MAX),0);
+    if (count <= 0)
       {
-        register ssize_t
-          j;
-
-        alpha=(MagickSizeType) i;
-        for (j=0; j < 8; j++)
-        {
-          if ((alpha & 0x01) == 0)
-            alpha>>=1;
-          else
-            alpha=(MagickSizeType) ((alpha >> 1) ^
-              MagickULLConstant(0xd800000000000000));
-        }
-        crc_xor[i]=alpha;
+        count=0;
+        if (errno != EINTR)
+          break;
       }
-      crc_initial=MagickTrue;
-    }
-  crc=0;
-  for (i=0; i < (ssize_t) length; i++)
-    crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
-  return(crc);
+  }
+  return(i);
 }
 
 static int ConnectPixelCacheServer(const char *hostname,const int port,
-  MagickSizeType *session_key,ExceptionInfo *exception)
+  size_t *session_key,ExceptionInfo *exception)
 {
-#if defined(MAGICKCORE_HAVE_SOCKET)
+#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
   char
-    secret[MaxTextExtent];
+    service[MaxTextExtent];
 
   const char
     *shared_secret;
@@ -165,14 +173,12 @@ static int ConnectPixelCacheServer(const char *hostname,const int port,
   ssize_t
     count;
 
-  struct hostent
-    *host;
-
-  struct sockaddr_in
-    address;
+  struct addrinfo
+    hint,
+    *result;
 
   unsigned char
-    session[MaxTextExtent];
+    secret[MaxTextExtent];
 
   /*
     Connect to distributed pixel cache and get session key.
@@ -185,22 +191,28 @@ static int ConnectPixelCacheServer(const char *hostname,const int port,
         "DistributedPixelCache","'%s'","shared secret expected");
       return(-1);
     }
-  (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
-    DPCSessionKeyLength);
-  host=gethostbyname(hostname);
-  client_socket=socket(AF_INET,SOCK_STREAM,0);
+  (void) ResetMagickMemory(&hint,0,sizeof(hint));
+  hint.ai_family=AF_INET;
+  hint.ai_socktype=SOCK_STREAM;
+  hint.ai_flags=AI_PASSIVE;
+  (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
+  status=getaddrinfo(hostname,service,&hint,&result);
+  if (status != 0)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "DistributedPixelCache","'%s'",hostname);
+      return(-1);
+    }
+  client_socket=socket(result->ai_family,result->ai_socktype,
+    result->ai_protocol);
   if (client_socket == -1)
     {
+      (void) close(client_socket);
       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
         "DistributedPixelCache","'%s'",hostname);
       return(-1);
     }
-  (void) ResetMagickMemory(&address,0,sizeof(address));
-  address.sin_family=AF_INET;
-  address.sin_port=htons((uint16_t) port);
-  address.sin_addr=(*((struct in_addr *) host->h_addr));
-  status=connect(client_socket,(struct sockaddr *) &address,(socklen_t)
-    sizeof(struct sockaddr));
+  status=connect(client_socket,result->ai_addr,result->ai_addrlen);
   if (status == -1)
     {
       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
@@ -210,8 +222,13 @@ static int ConnectPixelCacheServer(const char *hostname,const int port,
   count=recv(client_socket,secret,MaxTextExtent,0);
   if (count != -1)
     {
-      (void) memcpy(session+strlen(shared_secret),secret,(size_t) count);
-      *session_key=CRC64(session,strlen(shared_secret)+count);
+      StringInfo
+        *nonce;
+
+      nonce=AcquireStringInfo(count);
+      (void) memcpy(GetStringInfoDatum(nonce),secret,(size_t) count);
+      *session_key=GetMagickSignature(nonce);
+      nonce=DestroyStringInfo(nonce);
     }
   if (*session_key == 0)
     {
@@ -245,8 +262,7 @@ static char *GetHostname(int *port,ExceptionInfo *exception)
   /*
     Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
   */
-  hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",
-    exception);
+  hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",exception);
   if (hosts == (char *) NULL)
     {
       *port=DPCPort;
@@ -291,17 +307,17 @@ MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
   DistributeCacheInfo
     *server_info;
 
-  MagickSizeType
+  size_t
     session_key;
 
+  /*
+    Connect to the distributed pixel cache server.
+  */
   server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info));
   if (server_info == (DistributeCacheInfo *) NULL)
     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
   (void) ResetMagickMemory(server_info,0,sizeof(*server_info));
   server_info->signature=MagickSignature;
-  /*
-    Contact pixel cache server.
-  */
   server_info->port=0;
   hostname=GetHostname(&server_info->port,exception);
   session_key=0;
@@ -312,6 +328,7 @@ MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
   hostname=DestroyString(hostname);
   if (server_info->file == -1)
     server_info=DestroyDistributeCacheInfo(server_info);
+  server_info->debug=IsEventLogging();
   return(server_info);
 }
 \f
@@ -367,7 +384,7 @@ MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
 %
 %  The format of the DistributePixelCacheServer() method is:
 %
-%      void DistributePixelCacheServer(const size_t port)
+%      void DistributePixelCacheServer(const int port)
 %
 %  A description of each parameter follows:
 %
@@ -378,13 +395,49 @@ MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
 */
 
 static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
-  int file,const MagickSizeType session_key)
+  int magick_unused(file),const size_t session_key)
 {
+  /*
+    Destroy distributed pixel cache.
+  */
+  magick_unreferenced(file);
   return(DeleteNodeFromSplayTree(registry,(const void *) session_key));
 }
 
-static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
-  int file,const MagickSizeType session_key,ExceptionInfo *exception)
+static inline MagickOffsetType dpc_send(int file,const MagickSizeType length,
+  const unsigned char *restrict message)
+{
+  MagickOffsetType
+    count;
+
+  register MagickOffsetType
+    i;
+
+#if !defined(MAGICKCORE_HAVE_SOCKET) || !defined(MAGICKCORE_THREAD_SUPPORT)
+  magick_unreferenced(file);
+  magick_unreferenced(message);
+#endif
+
+  /*
+    Ensure a complete message is sent.
+  */
+  count=0;
+  for (i=0; i < (MagickOffsetType) length; i+=count)
+  {
+    count=(MagickOffsetType) send(file,message+i,(size_t) MagickMin(length-i,
+      (MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL);
+    if (count <= 0)
+      {
+        count=0;
+        if (errno != EINTR)
+          break;
+      }
+  }
+  return(i);
+}
+
+static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,int file,
+  const size_t session_key,ExceptionInfo *exception)
 {
   Image
     *image;
@@ -392,39 +445,65 @@ static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
   MagickBooleanType
     status;
 
-  register unsigned char
-    *p;
+  MagickOffsetType
+    count;
 
-  size_t
+  MagickSizeType
     length;
 
-  ssize_t
-    count;
+  register unsigned char
+    *p;
 
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Open distributed pixel cache.
+  */
   image=AcquireImage((ImageInfo *) NULL,exception);
   if (image == (Image *) NULL)
     return(MagickFalse);
-  length=sizeof(image->columns)+sizeof(image->rows)+
-    sizeof(image->number_channels);
-  count=recv(file,buffer,length,0);
-  if (count != (ssize_t) length)
+  length=sizeof(image->storage_class)+sizeof(image->colorspace)+
+    sizeof(image->alpha_trait)+sizeof(image->read_mask)+
+    sizeof(image->write_mask)+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)
     return(MagickFalse);
-  p=buffer;
+  /*
+    Deserialize the image attributes.
+  */
+  p=message;
+  (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
+  p+=sizeof(image->storage_class);
+  (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
+  p+=sizeof(image->colorspace);
+  (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
+  p+=sizeof(image->alpha_trait);
+  (void) memcpy(&image->read_mask,p,sizeof(image->read_mask));
+  p+=sizeof(image->read_mask);
+  (void) memcpy(&image->write_mask,p,sizeof(image->write_mask));
+  p+=sizeof(image->write_mask);
   (void) memcpy(&image->columns,p,sizeof(image->columns));
   p+=sizeof(image->columns);
   (void) memcpy(&image->rows,p,sizeof(image->rows));
   p+=sizeof(image->rows);
   (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
   p+=sizeof(image->number_channels);
+  (void) memcpy(image->channel_map,p,MaxPixelChannels*
+    sizeof(*image->channel_map));
+  p+=MaxPixelChannels*sizeof(*image->channel_map);
+  (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
+  p+=sizeof(image->metacontent_extent);
+  if (SyncImagePixelCache(image,exception) == MagickFalse)
+    return(MagickFalse);
   status=AddValueToSplayTree(registry,(const void *) session_key,image);
   return(status);
 }
 
 static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
-  int file,const MagickSizeType session_key,ExceptionInfo *exception)
+  int file,const size_t session_key,ExceptionInfo *exception)
 {
   const unsigned char
     *metacontent;
@@ -432,6 +511,12 @@ static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
   Image
     *image;
 
+  MagickOffsetType
+    count;
+
+  MagickSizeType
+    length;
+
   RectangleInfo
     region;
 
@@ -441,51 +526,54 @@ static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
   register unsigned char
     *q;
 
-  size_t
-    length;
-
-  ssize_t
-    count;
-
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Read distributed pixel cache metacontent.
+  */
   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
   if (image == (Image *) NULL)
     return(MagickFalse);
   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
     sizeof(region.y)+sizeof(length);
-  count=recv(file,buffer,length,0);
-  if (count != (ssize_t) length)
+  count=dpc_read(file,length,message);
+  if (count != (MagickOffsetType) length)
     return(MagickFalse);
-  q=buffer;
+  q=message;
   (void) memcpy(&region.width,q,sizeof(region.width));
   q+=sizeof(region.width);
   (void) memcpy(&region.height,q,sizeof(region.height));
-  q+=sizeof(region.width);
+  q+=sizeof(region.height);
   (void) memcpy(&region.x,q,sizeof(region.x));
-  q+=sizeof(region.width);
+  q+=sizeof(region.x);
   (void) memcpy(&region.y,q,sizeof(region.y));
-  q+=sizeof(region.width);
+  q+=sizeof(region.y);
   (void) memcpy(&length,q,sizeof(length));
   q+=sizeof(length);
   p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
     exception);
   if (p == (const Quantum *) NULL)
     return(MagickFalse);
-  metacontent=GetVirtualMetacontent(image);
-  count=send(file,metacontent,length,0);
-  if (count != (ssize_t) length)
+  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,
-  int file,const MagickSizeType session_key,ExceptionInfo *exception)
+  int file,const size_t session_key,ExceptionInfo *exception)
 {
   Image
     *image;
 
+  MagickOffsetType
+    count;
+
+  MagickSizeType
+    length;
+
   RectangleInfo
     region;
 
@@ -495,53 +583,58 @@ static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
   register unsigned char
     *q;
 
-  size_t
-    length;
-
-  ssize_t
-    count;
-
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Read distributed pixel cache pixels.
+  */
   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
   if (image == (Image *) NULL)
     return(MagickFalse);
   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
     sizeof(region.y)+sizeof(length);
-  count=recv(file,buffer,length,0);
-  if (count != (ssize_t) length)
+  count=dpc_read(file,length,message);
+  if (count != (MagickOffsetType) length)
     return(MagickFalse);
-  q=buffer;
+  q=message;
   (void) memcpy(&region.width,q,sizeof(region.width));
   q+=sizeof(region.width);
   (void) memcpy(&region.height,q,sizeof(region.height));
-  q+=sizeof(region.width);
+  q+=sizeof(region.height);
   (void) memcpy(&region.x,q,sizeof(region.x));
-  q+=sizeof(region.width);
+  q+=sizeof(region.x);
   (void) memcpy(&region.y,q,sizeof(region.y));
-  q+=sizeof(region.width);
+  q+=sizeof(region.y);
   (void) memcpy(&length,q,sizeof(length));
   q+=sizeof(length);
   p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
     exception);
   if (p == (const Quantum *) NULL)
     return(MagickFalse);
-  count=send(file,p,length,0);
-  if (count != (ssize_t) length)
+  count=dpc_send(file,length,(unsigned char *) p);
+  if (count != (MagickOffsetType) length)
     return(MagickFalse);
   return(MagickTrue);
 }
 
+static void *RelinquishImageRegistry(void *image)
+{
+  return((void *) DestroyImageList((Image *) image));
+}
+
 static MagickBooleanType WriteDistributeCacheMetacontent(
-  SplayTreeInfo *registry,int file,const MagickSizeType session_key,
+  SplayTreeInfo *registry,int file,const size_t session_key,
   ExceptionInfo *exception)
 {
   Image
     *image;
 
-  MagickBooleanType
-    status;
+  MagickOffsetType
+    count;
+
+  MagickSizeType
+    length;
 
   RectangleInfo
     region;
@@ -552,55 +645,54 @@ static MagickBooleanType WriteDistributeCacheMetacontent(
   register unsigned char
     *p;
 
-  size_t
-    length;
-
-  ssize_t
-    count;
-
   unsigned char
-    buffer[MaxTextExtent],
+    message[MaxTextExtent],
     *metacontent;
 
+  /*
+    Write distributed pixel cache metacontent.
+  */
   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
   if (image == (Image *) NULL)
     return(MagickFalse);
   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
     sizeof(region.y)+sizeof(length);
-  count=recv(file,buffer,length,0);
-  if (count != (ssize_t) length)
+  count=dpc_read(file,length,message);
+  if (count != (MagickOffsetType) length)
     return(MagickFalse);
-  p=buffer;
+  p=message;
   (void) memcpy(&region.width,p,sizeof(region.width));
   p+=sizeof(region.width);
   (void) memcpy(&region.height,p,sizeof(region.height));
-  p+=sizeof(region.width);
+  p+=sizeof(region.height);
   (void) memcpy(&region.x,p,sizeof(region.x));
-  p+=sizeof(region.width);
+  p+=sizeof(region.x);
   (void) memcpy(&region.y,p,sizeof(region.y));
-  p+=sizeof(region.width);
+  p+=sizeof(region.y);
   (void) memcpy(&length,p,sizeof(length));
   p+=sizeof(length);
   q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
     exception);
   if (q == (Quantum *) NULL)
     return(MagickFalse);
-  metacontent=GetAuthenticMetacontent(image);
-  count=recv(file,metacontent,length,0);
-  if (count != (ssize_t) length)
+  metacontent=(unsigned char *) GetAuthenticMetacontent(image);
+  count=dpc_read(file,length,metacontent);
+  if (count != (MagickOffsetType) length)
     return(MagickFalse);
-  status=SyncAuthenticPixels(image,exception);
-  return(status);
+  return(SyncAuthenticPixels(image,exception));
 }
 
 static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
-  int file,const MagickSizeType session_key,ExceptionInfo *exception)
+  int file,const size_t session_key,ExceptionInfo *exception)
 {
   Image
     *image;
 
-  MagickBooleanType
-    status;
+  MagickOffsetType
+    count;
+
+  MagickSizeType
+    length;
 
   RectangleInfo
     region;
@@ -611,43 +703,39 @@ static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
   register unsigned char
     *p;
 
-  size_t
-    length;
-
-  ssize_t
-    count;
-
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Write distributed pixel cache pixels.
+  */
   image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key);
   if (image == (Image *) NULL)
     return(MagickFalse);
   length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
     sizeof(region.y)+sizeof(length);
-  count=recv(file,buffer,length,0);
-  if (count != (ssize_t) length)
+  count=dpc_read(file,length,message);
+  if (count != (MagickOffsetType) length)
     return(MagickFalse);
-  p=buffer;
+  p=message;
   (void) memcpy(&region.width,p,sizeof(region.width));
   p+=sizeof(region.width);
   (void) memcpy(&region.height,p,sizeof(region.height));
-  p+=sizeof(region.width);
+  p+=sizeof(region.height);
   (void) memcpy(&region.x,p,sizeof(region.x));
-  p+=sizeof(region.width);
+  p+=sizeof(region.x);
   (void) memcpy(&region.y,p,sizeof(region.y));
-  p+=sizeof(region.width);
+  p+=sizeof(region.y);
   (void) memcpy(&length,p,sizeof(length));
   p+=sizeof(length);
   q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
     exception);
   if (q == (Quantum *) NULL)
     return(MagickFalse);
-  count=recv(file,q,length,0);
-  if (count != (ssize_t) length)
+  count=dpc_read(file,length,(unsigned char *) q);
+  if (count != (MagickOffsetType) length)
     return(MagickFalse);
-  status=SyncAuthenticPixels(image,exception);
-  return(status);
+  return(SyncAuthenticPixels(image,exception));
 }
 
 static void *DistributePixelCacheClient(void *socket)
@@ -664,53 +752,56 @@ static void *DistributePixelCacheClient(void *socket)
   MagickBooleanType
     status;
 
-  MagickSizeType
-    key,
-    session_key;
+  MagickOffsetType
+    count;
+
+  register unsigned char
+    *p;
 
   RandomInfo
     *random_info;
 
+  size_t
+    key,
+    session_key;
+
   SplayTreeInfo
     *registry;
 
-  ssize_t
-    count;
-
   StringInfo
     *secret;
 
   unsigned char
     command,
-    session[MaxTextExtent];
+    session[2*MaxTextExtent];
 
   /*
-    Generate session key.
+    Distributed pixel cache client.
   */
   shared_secret=GetPolicyValue("shared-secret");
   if (shared_secret == (const char *) NULL)
     ThrowFatalException(CacheFatalError,"shared secret expected");
-  (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
-    DPCSessionKeyLength);
+  p=session;
+  (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent);
+  p+=strlen(shared_secret);
   random_info=AcquireRandomInfo();
   secret=GetRandomKey(random_info,DPCSessionKeyLength);
-  (void) memcpy(session+strlen(shared_secret),GetStringInfoDatum(secret),
-    DPCSessionKeyLength);
-  session_key=CRC64(session,strlen(shared_secret)+DPCSessionKeyLength);
+  (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength);
+  session_key=GetMagickSignature(secret);
   random_info=DestroyRandomInfo(random_info);
   exception=AcquireExceptionInfo();
   registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
-    (void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
+    (void *(*)(void *)) NULL,RelinquishImageRegistry);
   client_socket=(*(int *) socket);
-  count=send(client_socket,GetStringInfoDatum(secret),DPCSessionKeyLength,0);
+  count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret));
   secret=DestroyStringInfo(secret);
   for ( ; ; )
   {
-    count=recv(client_socket,&command,1,0);
+    count=dpc_read(client_socket,1,(unsigned char *) &command);
     if (count <= 0)
       break;
-    count=recv(client_socket,&key,sizeof(key),0);
-    if ((count != (ssize_t) sizeof(key)) && (key != session_key))
+    count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
+    if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
       break;
     status=MagickFalse;
     switch (command)
@@ -719,6 +810,7 @@ static void *DistributePixelCacheClient(void *socket)
       {
         status=OpenDistributeCache(registry,client_socket,session_key,
           exception);
+        count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
         break;
       }
       case 'r':
@@ -753,22 +845,25 @@ static void *DistributePixelCacheClient(void *socket)
       default:
         break;
     }
-    count=send(client_socket,&status,sizeof(status),0);
-    if (count != (ssize_t) sizeof(status))
+    if (status == MagickFalse)
       break;
     if (command == 'd')
       break;
   }
+  count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status);
   (void) close(client_socket);
   exception=DestroyExceptionInfo(exception);
   registry=DestroySplayTree(registry);
   return((void *) NULL);
 }
 
-MagickExport void DistributePixelCacheServer(const size_t port,
+MagickExport void DistributePixelCacheServer(const int port,
   ExceptionInfo *exception)
 {
 #if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
+  char
+    service[MaxTextExtent];
+
   int
     server_socket,
     status;
@@ -779,21 +874,58 @@ MagickExport void DistributePixelCacheServer(const size_t port,
   pthread_t
     threads;
 
+  register struct addrinfo
+    *p;
+
+  struct addrinfo
+    hint,
+    *result;
+
   struct sockaddr_in
     address;
 
   /*
     Launch distributed pixel cache server.
   */
-  server_socket=socket(AF_INET,SOCK_STREAM,0);
-  address.sin_family=AF_INET;
-  address.sin_port=htons(port);
-  address.sin_addr.s_addr=htonl(INADDR_ANY);
-  status=bind(server_socket,(struct sockaddr *) &address,(socklen_t)
-    sizeof(address));
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  (void) ResetMagickMemory(&hint,0,sizeof(hint));
+  hint.ai_family=AF_INET;
+  hint.ai_socktype=SOCK_STREAM;
+  hint.ai_flags=AI_PASSIVE;
+  (void) FormatLocaleString(service,MaxTextExtent,"%d",port);
+  status=getaddrinfo((const char *) NULL,service,&hint,&result);
   if (status != 0)
+    ThrowFatalException(CacheFatalError,"UnableToListen");
+  server_socket=0;
+  for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
+  {
+    int
+      one;
+
+    server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
+    if (server_socket == -1)
+      continue;
+    one=1;
+    status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
+      sizeof(one));
+    if (status == -1)
+      {
+        (void) close(server_socket);
+        continue;
+      }
+    status=bind(server_socket,p->ai_addr,p->ai_addrlen);
+    if (status == -1)
+      {
+        (void) close(server_socket);
+        continue;
+      }
+    break;
+  }
+  if (p == (struct addrinfo *) NULL)
     ThrowFatalException(CacheFatalError,"UnableToBind");
-  status=listen(server_socket,5);
+  freeaddrinfo(result);
+  status=listen(server_socket,DPCPendingConnections);
   if (status != 0)
     ThrowFatalException(CacheFatalError,"UnableToListen");
   pthread_attr_init(&attributes);
@@ -943,36 +1075,58 @@ MagickPrivate MagickBooleanType OpenDistributePixelCache(
   MagickBooleanType
     status;
 
+  MagickOffsetType
+    count;
+
   register unsigned char
     *p;
 
-  ssize_t
-    count;
-
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Open distributed pixel cache.
+  */
   assert(server_info != (DistributeCacheInfo *) NULL);
   assert(server_info->signature == MagickSignature);
   assert(image != (Image *) NULL);
   assert(image->signature == MagickSignature);
-  p=buffer;
+  p=message;
   *p++='o';  /* open */
+  /*
+    Serialize image attributes (see ValidatePixelCacheMorphology()).
+  */
   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   p+=sizeof(server_info->session_key);
+  (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
+  p+=sizeof(image->storage_class);
+  (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
+  p+=sizeof(image->colorspace);
+  (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
+  p+=sizeof(image->alpha_trait);
+  (void) memcpy(p,&image->read_mask,sizeof(image->read_mask));
+  p+=sizeof(image->read_mask);
+  (void) memcpy(p,&image->write_mask,sizeof(image->write_mask));
+  p+=sizeof(image->write_mask);
   (void) memcpy(p,&image->columns,sizeof(image->columns));
   p+=sizeof(image->columns);
   (void) memcpy(p,&image->rows,sizeof(image->rows));
   p+=sizeof(image->rows);
   (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
   p+=sizeof(image->number_channels);
-  count=send(server_info->file,buffer,p-buffer,0);
-  if (count != (ssize_t) (p-buffer))
+  (void) memcpy(p,image->channel_map,MaxPixelChannels*
+    sizeof(*image->channel_map));
+  p+=MaxPixelChannels*sizeof(*image->channel_map);
+  (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
+  p+=sizeof(image->metacontent_extent);
+  count=dpc_send(server_info->file,p-message,message);
+  if (count != (MagickOffsetType) (p-message))
     return(MagickFalse);
-  count=recv(server_info->file,&status,sizeof(status),0);
-  if (count != (ssize_t) sizeof(status))
+  status=MagickFalse;
+  count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
+  if (count != (MagickOffsetType) sizeof(status))
     return(MagickFalse);
-  return(MagickTrue);
+  return(status);
 }
 \f
 /*
@@ -1012,9 +1166,6 @@ MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
   DistributeCacheInfo *server_info,const RectangleInfo *region,
   const MagickSizeType length,unsigned char *metacontent)
 {
-  MagickBooleanType
-    status;
-
   MagickOffsetType
     count;
 
@@ -1022,16 +1173,19 @@ MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
     *p;
 
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Read distributed pixel cache metacontent.
+  */
   assert(server_info != (DistributeCacheInfo *) NULL);
   assert(server_info->signature == MagickSignature);
   assert(region != (RectangleInfo *) NULL);
   assert(metacontent != (unsigned char *) NULL);
-  if (length != (size_t) length)
+  if (length > (MagickSizeType) SSIZE_MAX)
     return(-1);
-  p=buffer;
-  *p++='R';  /* read */
+  p=message;
+  *p++='R';
   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   p+=sizeof(server_info->session_key);
   (void) memcpy(p,&region->width,sizeof(region->width));
@@ -1044,17 +1198,10 @@ MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
   p+=sizeof(region->y);
   (void) memcpy(p,&length,sizeof(length));
   p+=sizeof(length);
-  count=(MagickOffsetType) send(server_info->file,buffer,p-buffer,0);
-  if (count != (MagickOffsetType) (p-buffer))
+  count=dpc_send(server_info->file,p-message,message);
+  if (count != (MagickOffsetType) (p-message))
     return(-1);
-  count=(MagickOffsetType) recv(server_info->file,(unsigned char *) metacontent,
-    (size_t) length,0);
-  if (count != (MagickOffsetType) length)
-    return(count);
-  count=(MagickOffsetType) recv(server_info->file,&status,sizeof(status),0);
-  if (count != (MagickOffsetType) sizeof(status))
-    return(-1);
-  return((MagickOffsetType) length);
+  return(dpc_read(server_info->file,length,metacontent));
 }
 \f
 /*
@@ -1075,7 +1222,7 @@ MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
 %
 %      MagickOffsetType ReadDistributePixelCachePixels(
 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
-%        const MagickSizeType length,unsigned char *pixels)
+%        const MagickSizeType length,unsigned char *restrict pixels)
 %
 %  A description of each parameter follows:
 %
@@ -1092,11 +1239,8 @@ MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
 */
 MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
   DistributeCacheInfo *server_info,const RectangleInfo *region,
-  const MagickSizeType length,unsigned char *pixels)
+  const MagickSizeType length,unsigned char *restrict pixels)
 {
-  MagickBooleanType
-    status;
-
   MagickOffsetType
     count;
 
@@ -1104,16 +1248,19 @@ MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
     *p;
 
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Read distributed pixel cache pixels.
+  */
   assert(server_info != (DistributeCacheInfo *) NULL);
   assert(server_info->signature == MagickSignature);
   assert(region != (RectangleInfo *) NULL);
   assert(pixels != (unsigned char *) NULL);
-  if (length != (size_t) length)
+  if (length > (MagickSizeType) SSIZE_MAX)
     return(-1);
-  p=buffer;
-  *p++='r';  /* read */
+  p=message;
+  *p++='r';
   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   p+=sizeof(server_info->session_key);
   (void) memcpy(p,&region->width,sizeof(region->width));
@@ -1126,17 +1273,10 @@ MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
   p+=sizeof(region->y);
   (void) memcpy(p,&length,sizeof(length));
   p+=sizeof(length);
-  count=(MagickOffsetType) send(server_info->file,buffer,p-buffer,0);
-  if (count != (MagickOffsetType) (p-buffer))
-    return(-1);
-  count=(MagickOffsetType) recv(server_info->file,(unsigned char *) pixels,
-    (size_t) length,0);
-  if (count != (MagickOffsetType) length)
-    return(count);
-  count=recv(server_info->file,&status,sizeof(status),0);
-  if (count != (MagickOffsetType) sizeof(status))
+  count=dpc_send(server_info->file,p-message,message);
+  if (count != (MagickOffsetType) (p-message))
     return(-1);
-  return((MagickOffsetType) length);
+  return(dpc_read(server_info->file,length,pixels));
 }
 \f
 /*
@@ -1166,25 +1306,34 @@ MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
 MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
   DistributeCacheInfo *server_info)
 {
-  register unsigned char
-    *p;
+  MagickBooleanType
+    status;
 
-  ssize_t
+  MagickOffsetType
     count;
 
+  register unsigned char
+    *p;
+
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Delete distributed pixel cache.
+  */
   assert(server_info != (DistributeCacheInfo *) NULL);
   assert(server_info->signature == MagickSignature);
-  p=buffer;
-  *p++='d';  /* delete */
+  p=message;
+  *p++='d';
   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   p+=sizeof(server_info->session_key);
-  count=send(server_info->file,buffer,p-buffer,0);
-  if (count != (ssize_t) (p-buffer))
+  count=dpc_send(server_info->file,p-message,message);
+  if (count != (MagickOffsetType) (p-message))
     return(MagickFalse);
-  return(MagickTrue);
+  count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
+  if (count != (MagickOffsetType) sizeof(status))
+    return(MagickFalse);
+  return(status);
 }
 \f
 /*
@@ -1224,9 +1373,6 @@ MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
   DistributeCacheInfo *server_info,const RectangleInfo *region,
   const MagickSizeType length,const unsigned char *metacontent)
 {
-  MagickBooleanType
-    status;
-
   MagickOffsetType
     count;
 
@@ -1234,16 +1380,19 @@ MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
     *p;
 
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Write distributed pixel cache metacontent.
+  */
   assert(server_info != (DistributeCacheInfo *) NULL);
   assert(server_info->signature == MagickSignature);
   assert(region != (RectangleInfo *) NULL);
   assert(metacontent != (unsigned char *) NULL);
-  if (length != (size_t) length)
+  if (length > (MagickSizeType) SSIZE_MAX)
     return(-1);
-  p=buffer;
-  *p++='W';  /* write */
+  p=message;
+  *p++='W';
   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   p+=sizeof(server_info->session_key);
   (void) memcpy(p,&region->width,sizeof(region->width));
@@ -1256,17 +1405,10 @@ MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
   p+=sizeof(region->y);
   (void) memcpy(p,&length,sizeof(length));
   p+=sizeof(length);
-  count=(MagickOffsetType) send(server_info->file,buffer,p-buffer,0);
-  if (count != (MagickOffsetType) (p-buffer))
-    return(-1);
-  count=(MagickOffsetType) send(server_info->file,(unsigned char *) metacontent,
-    (size_t) length,0);
-  if (count != (ssize_t) length)
-    return(count);
-  count=recv(server_info->file,&status,sizeof(status),0);
-  if (count != (ssize_t) sizeof(status))
+  count=dpc_send(server_info->file,p-message,message);
+  if (count != (MagickOffsetType) (p-message))
     return(-1);
-  return((MagickOffsetType) length);
+  return(dpc_send(server_info->file,length,metacontent));
 }
 \f
 /*
@@ -1287,7 +1429,7 @@ MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
 %
 %      MagickBooleanType WriteDistributePixelCachePixels(
 %        DistributeCacheInfo *server_info,const RectangleInfo *region,
-%        const MagickSizeType length,const unsigned char *pixels)
+%        const MagickSizeType length,const unsigned char *restrict pixels)
 %
 %  A description of each parameter follows:
 %
@@ -1304,11 +1446,8 @@ MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
 */
 MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
   DistributeCacheInfo *server_info,const RectangleInfo *region,
-  const MagickSizeType length,const unsigned char *pixels)
+  const MagickSizeType length,const unsigned char *restrict pixels)
 {
-  MagickBooleanType
-    status;
-
   MagickOffsetType
     count;
 
@@ -1316,16 +1455,19 @@ MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
     *p;
 
   unsigned char
-    buffer[MaxTextExtent];
+    message[MaxTextExtent];
 
+  /*
+    Write distributed pixel cache pixels.
+  */
   assert(server_info != (DistributeCacheInfo *) NULL);
   assert(server_info->signature == MagickSignature);
   assert(region != (RectangleInfo *) NULL);
   assert(pixels != (const unsigned char *) NULL);
-  if (length != (size_t) length)
+  if (length > (MagickSizeType) SSIZE_MAX)
     return(-1);
-  p=buffer;
-  *p++='w';  /* write */
+  p=message;
+  *p++='w';
   (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
   p+=sizeof(server_info->session_key);
   (void) memcpy(p,&region->width,sizeof(region->width));
@@ -1338,15 +1480,8 @@ MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
   p+=sizeof(region->y);
   (void) memcpy(p,&length,sizeof(length));
   p+=sizeof(length);
-  count=(MagickOffsetType) send(server_info->file,buffer,p-buffer,0);
-  if (count != (MagickOffsetType) (p-buffer))
-    return(-1);
-  count=(MagickOffsetType) send(server_info->file,(unsigned char *) pixels,
-    (size_t) length,0);
-  if (count != (MagickOffsetType) length)
-    return(count);
-  count=recv(server_info->file,&status,sizeof(status),0);
-  if (count != (ssize_t) sizeof(status))
+  count=dpc_send(server_info->file,p-message,message);
+  if (count != (MagickOffsetType) (p-message))
     return(-1);
-  return((MagickOffsetType) length);
+  return(dpc_send(server_info->file,length,pixels));
 }