]> granicus.if.org Git - imagemagick/commitdiff
(no commit message)
authorcristy <urban-warrior@git.imagemagick.org>
Tue, 15 Jan 2013 20:06:37 +0000 (20:06 +0000)
committercristy <urban-warrior@git.imagemagick.org>
Tue, 15 Jan 2013 20:06:37 +0000 (20:06 +0000)
MagickCore/cache-private.h
MagickCore/cache.c
MagickCore/distribute-cache-private.h
MagickCore/distribute-cache.c
MagickCore/thread-private.h
MagickWand/mogrify.c

index 698f3be9cdb458303c617f448f1234733570743a..a40a06b1daebab8cae5103bd6367498921383c17 100644 (file)
@@ -25,7 +25,6 @@ extern "C" {
 #include <time.h>
 #include "MagickCore/cache.h"
 #include "MagickCore/distribute-cache.h"
-#include "MagickCore/distribute-cache-private.h"
 #include "MagickCore/pixel.h"
 #include "MagickCore/random_.h"
 #include "MagickCore/thread-private.h"
@@ -103,7 +102,7 @@ typedef struct _CacheMethods
 } CacheMethods;
 
 typedef struct _NexusInfo
-   NexusInfo;
+  NexusInfo;
 
 typedef struct _CacheInfo
 {
@@ -176,7 +175,7 @@ typedef struct _CacheInfo
   RandomInfo
     *random_info;
 
-  DistributeCacheInfo
+  void
     *distribute_cache_info;
 
   MagickBooleanType
index c41e8b384192e4d0a77d2ac792710d1ced0344e9..6cd1e7979901d24642a88f6220150259e5d64e18 100644 (file)
@@ -48,6 +48,7 @@
 #include "MagickCore/color-private.h"
 #include "MagickCore/colorspace-private.h"
 #include "MagickCore/composite-private.h"
+#include "MagickCore/distribute-cache-private.h"
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
 #include "MagickCore/geometry.h"
@@ -139,11 +140,11 @@ static MagickBooleanType
   GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
     const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
   OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
-  ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
   ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
   SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
-  WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
-  WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
+  WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
+  WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
 
 static Quantum
   *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
@@ -1236,7 +1237,7 @@ static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
     }
     case DistributedCache:
     {
-      abort();
+      RelinquishDistributePixelCache(cache_info->distribute_cache_info);
       break;
     }
     default:
@@ -3844,8 +3845,36 @@ static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
       cache_info->distribute_cache_info=AcquireDistributeCacheInfo(exception);
       if (cache_info->distribute_cache_info != (DistributeCacheInfo *) NULL)
         {
-          cache_info->type=DistributedCache;
-          return(MagickTrue);
+          status=OpenDistributePixelCache(cache_info->distribute_cache_info,
+            image);
+          if (status != MagickFalse)
+            {
+              cache_info->type=DistributedCache;
+              if ((source_info.storage_class != UndefinedClass) &&
+                  (mode != ReadMode))
+                {
+                  status=ClonePixelCachePixels(cache_info,&source_info,
+                    exception);
+                  RelinquishPixelCachePixels(&source_info);
+                }
+              if (image->debug != MagickFalse)
+                {
+                  (void) FormatMagickSize(cache_info->length,MagickFalse,
+                    format);
+/*
+                  (void) FormatLocaleString(message,MaxTextExtent,
+                    "open %s (%d[%d], distribute, %.20gx%.20gx%.20g %s)",
+                    cache_info->distribute_cache_info->hostname,
+                    cache_info->distribute_cache_info->port,
+                    cache_info->distribute_cache_info->file,(double)
+                    cache_info->columns,(double) cache_info->rows,(double)
+                    cache_info->number_channels,format);
+*/
+                  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
+                    message);
+                }
+              return(MagickTrue);
+            }
         }
       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
         "CacheResourcesExhausted","`%s'",image->filename);
@@ -4443,6 +4472,7 @@ static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
     }
     case DistributedCache:
     {
+      puts("b");
       abort();
       break;
     }
@@ -4582,7 +4612,25 @@ static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
     }
     case DistributedCache:
     {
-      abort();
+      MagickBooleanType
+        status;
+
+      /*
+        Read pixels to distributed cache.
+      */
+      LockSemaphoreInfo(cache_info->file_semaphore);
+      status=ReadDistributePixelCache(cache_info->distribute_cache_info,
+        &nexus_info->region,nexus_info->pixels);
+      UnlockSemaphoreInfo(cache_info->file_semaphore);
+      if (status == MagickFalse)
+        {
+/*
+          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+            cache_info->distribute_cache_info->hostname);
+*/
+          return(MagickFalse);
+        }
+      break;
       break;
     }
     default:
@@ -4812,7 +4860,8 @@ static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
   if (cache_info->type == UndefinedCache)
     return((Quantum *) NULL);
   nexus_info->region=(*region);
-  if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
+  if ((cache_info->type != DiskCache) &&
+      (cache_info->type != DistributedCache) && (cache_info->type != PingCache))
     {
       ssize_t
         x,
@@ -5346,6 +5395,7 @@ static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
     }
     case DistributedCache:
     {
+      puts("e");
       abort();
       break;
     }
@@ -5486,7 +5536,24 @@ static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
     }
     case DistributedCache:
     {
-      abort();
+      MagickBooleanType
+        status;
+
+      /*
+        Write pixels to distributed cache.
+      */
+      LockSemaphoreInfo(cache_info->file_semaphore);
+      status=WriteDistributePixelCache(cache_info->distribute_cache_info,
+        &nexus_info->region,nexus_info->pixels);
+      UnlockSemaphoreInfo(cache_info->file_semaphore);
+      if (status == MagickFalse)
+        {
+/*
+          ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
+            cache_info->distribute_cache_info->hostname);
+*/
+          return(MagickFalse);
+        }
       break;
     }
     default:
index 83bfd50be495080475a22de6b14e59e5f1be9468..3ffe8db73084d2d2d2eb2209318c71a7ea5d72f4 100644 (file)
 extern "C" {
 #endif
 
+#include "MagickCore/geometry.h"
 #include "MagickCore/exception.h"
 
 typedef struct _DistributeCacheInfo
 {
-  size_t
-    session;
+  int
+    file;
+
+  MagickSizeType
+    session_key;
+
+  char
+    hostname[MaxTextExtent];
 
-#if defined(MAGICKCORE_HAVE_SOCKET)
   int
-    server;
-#endif
+    port;
 
   size_t
     signature;
@@ -42,4 +47,14 @@ extern MagickPrivate DistributeCacheInfo
   *AcquireDistributeCacheInfo(ExceptionInfo *),
   *DestroyDistributeCacheInfo(DistributeCacheInfo *);
 
+extern MagickPrivate MagickBooleanType
+  OpenDistributePixelCache(DistributeCacheInfo *,Image *),
+  ReadDistributePixelCache(DistributeCacheInfo *,const RectangleInfo *,
+    Quantum *),
+  WriteDistributePixelCache(DistributeCacheInfo *,const RectangleInfo *,
+    const Quantum *);
+
+extern MagickPrivate void
+  RelinquishDistributePixelCache(DistributeCacheInfo *);
+
 #endif
index ab29a032bcfe2de022e97b647043f8358c659a04..a26be2f048fb3a44ba2af200056ac14d1c2b132e 100644 (file)
@@ -41,7 +41,7 @@
 % 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.
+% 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/locale_.h"
 #include "MagickCore/memory_.h"
+#include "MagickCore/policy.h"
+#include "MagickCore/random_.h"
 #include "MagickCore/registry.h"
 #include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
 #if defined(MAGICKCORE_HAVE_SOCKET)
-#include <sys/socket.h>
+#include <netinet/in.h>
 #include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
 #endif
 \f
+/*
+  Define declarations.
+*/
+#define DPCHostname  "127.0.0.1"
+#define DPCPort  6668
+#define DPCSessionKeyLength  8
+\f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %                                                                             %
 %    o exception: return any errors or warnings in this structure.
 %
 */
+
+static MagickSizeType CRC64(const unsigned char *message,const size_t length)
+{
+  MagickSizeType
+    crc;
+
+  register ssize_t
+    i;
+
+  static MagickBooleanType
+    crc_initial = MagickFalse;
+
+  static MagickSizeType
+    crc_xor[256];
+
+  if (crc_initial == MagickFalse)
+    {
+      MagickSizeType
+        alpha;
+
+      for (i=0; i < 256; i++)
+      {
+        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;
+      }
+      crc_initial=MagickTrue;
+    }
+  crc=0;
+  for (i=0; i < (ssize_t) length; i++)
+    crc=crc_xor[(crc ^ message[i]) & 0xff] ^ (crc >> 8);
+  return(crc);
+}
+
+static int ConnectPixelCacheServer(const char *hostname,const int port,
+  MagickSizeType *session_key,ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_HAVE_SOCKET)
+  char
+    secret[MaxTextExtent];
+
+  const char
+    *shared_secret;
+
+  int
+    client_socket,
+    status;
+
+  ssize_t
+    count;
+
+  struct hostent
+    *host;
+
+  struct sockaddr_in
+    address;
+
+  unsigned char
+    session[MaxTextExtent];
+
+  /*
+    Connect to distributed pixel cache and get session key.
+  */
+  *session_key=0;
+  shared_secret=GetPolicyValue("shared-secret");
+  if (shared_secret == (const char *) NULL)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "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);
+  if (client_socket == -1)
+    {
+      (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));
+  if (status == -1)
+    {
+      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
+        "DistributedPixelCache","'%s'",hostname);
+      return(-1);
+    }
+  count=read(client_socket,secret,MaxTextExtent);
+  if (count != -1)
+    {
+      (void) memcpy(session+strlen(shared_secret),secret,(size_t) count);
+      *session_key=CRC64(session,strlen(shared_secret)+count);
+    }
+  if (*session_key == 0)
+    {
+      close(client_socket);
+      client_socket=(-1);
+    }
+  return(client_socket);
+#else
+  (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
+    "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
+  return(MagickFalse);
+#endif
+}
+
+static char *GetHostname(int *port,ExceptionInfo *exception)
+{
+  char
+    *host,
+    *hosts,
+    **hostlist;
+
+  int
+    argc;
+
+  register 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));
+    }
+  hosts=AcquireString(hostlist[(id++ % (argc-1))+1]);
+  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)
 {
-#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_HAVE_PTHREAD)
+  char
+    *hostname;
+
   DistributeCacheInfo
     *distribute_cache_info;
 
-  distribute_cache_info=(DistributeCacheInfo *) NULL;
+  MagickSizeType
+    session_key;
+
   distribute_cache_info=(DistributeCacheInfo *) AcquireMagickMemory(
     sizeof(*distribute_cache_info));
   if (distribute_cache_info == (DistributeCacheInfo *) NULL)
@@ -102,10 +300,21 @@ MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
   (void) ResetMagickMemory(distribute_cache_info,0,
     sizeof(*distribute_cache_info));
   distribute_cache_info->signature=MagickSignature;
+  /*
+    Contact pixel cache server.
+  */
+  distribute_cache_info->port=0;
+  hostname=GetHostname(&distribute_cache_info->port,exception);
+  session_key=0;
+  distribute_cache_info->file=ConnectPixelCacheServer(hostname,
+    distribute_cache_info->port,&session_key,exception);
+  distribute_cache_info->session_key=session_key;
+  (void) CopyMagickString(distribute_cache_info->hostname,hostname,
+    MaxTextExtent);
+  hostname=DestroyString(hostname);
+  if (distribute_cache_info->file == -1)
+    distribute_cache_info=DestroyDistributeCacheInfo(distribute_cache_info);
   return(distribute_cache_info);
-#else
-  return((DistributeCacheInfo *) NULL);
-#endif
 }
 \f
 /*
@@ -137,11 +346,9 @@ MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
 {
   assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
   assert(distribute_cache_info->signature == MagickSignature);
-#if defined(MAGICKCORE_HAVE_SOCKET)
-#endif
   distribute_cache_info->signature=(~MagickSignature);
-  distribute_cache_info=(DistributeCacheInfo *)
-    RelinquishMagickMemory(distribute_cache_info);
+  distribute_cache_info=(DistributeCacheInfo *) RelinquishMagickMemory(
+    distribute_cache_info);
   return(distribute_cache_info);
 }
 \f
@@ -150,18 +357,18 @@ MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
 %                                                                             %
 %                                                                             %
 %                                                                             %
-+   P i x e l C a c h e S e r v e r                                           %
++   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                       %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  PixelCacheServer() waits on the specified port for commands to create, read,
-%  update, or destroy a pixel cache.
+%  DistributePixelCacheServer() waits on the specified port for commands to
+%  create, read, update, or destroy a pixel cache.
 %
-%  The format of the PixelCacheServer() method is:
+%  The format of the DistributePixelCacheServer() method is:
 %
-%      void PixelCacheServer(const size_t port)
+%      void DistributePixelCacheServer(const size_t port)
 %
 %  A description of each parameter follows:
 %
@@ -170,89 +377,624 @@ MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport void PixelCacheServer(const size_t port,ExceptionInfo *exception)
+
+static MagickBooleanType CreateDistributeCache(int file,
+  const MagickSizeType session_key)
 {
-#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_HAVE_PTHREAD)
   char
-    message[MaxTextExtent],
-    service[MaxTextExtent];
+    key[MaxTextExtent];
 
-  int
-    file,
+  ExceptionInfo
+    *exception;
+
+  Image
+    *image;
+
+  MagickBooleanType
     status;
 
-  register struct addrinfo
+  ssize_t
+    count;
+
+  exception=AcquireExceptionInfo();
+  image=AcquireImage((ImageInfo *) NULL,exception);
+  count=read(file,&image->columns,sizeof(image->columns));
+  if (count != (ssize_t) sizeof(image->columns))
+    return(MagickFalse);
+  count=read(file,&image->rows,sizeof(image->rows));
+  if (count != (ssize_t) sizeof(image->rows))
+    return(MagickFalse);
+  count=read(file,&image->number_channels,sizeof(image->number_channels));
+  if (count != (ssize_t) sizeof(image->number_channels))
+    return(MagickFalse);
+  (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+  status=SetImageRegistry(ImageRegistryType,key,image,exception);
+  exception=DestroyExceptionInfo(exception);
+  image=DestroyImage(image);
+  return(status);
+}
+
+static MagickBooleanType DestroyDistributeCache(int file,
+  const MagickSizeType session_key)
+{
+  char
+    key[MaxTextExtent];
+
+  (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+  return(DeleteImageRegistry(key));
+}
+
+static MagickBooleanType ReadDistributeCache(int file,
+  const MagickSizeType session_key)
+{
+  char
+    key[MaxTextExtent];
+
+  CacheInfo
+    *cache_info;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *image;
+
+  RectangleInfo
+    region;
+
+  register const Quantum
     *p;
 
+  size_t
+    length;
+
   ssize_t
     count;
 
-  socklen_t
+  exception=AcquireExceptionInfo();
+  (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+  image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (image == (Image *) NULL)
+    return(MagickFalse);
+  cache_info=(CacheInfo *) image->cache;
+  count=read(file,&region.width,sizeof(region.width));
+  if (count != (ssize_t) sizeof(region.width))
+    return(MagickFalse);
+  count=read(file,&region.height,sizeof(region.height));
+  if (count != (ssize_t) sizeof(region.height))
+    return(MagickFalse);
+  count=read(file,&region.x,sizeof(region.x));
+  if (count != (ssize_t) sizeof(region.width))
+    return(MagickFalse);
+  count=read(file,&region.y,sizeof(region.y));
+  if (count != (ssize_t) sizeof(region.y))
+    return(MagickFalse);
+  length=(size_t) (region.width*cache_info->number_channels*sizeof(Quantum));
+  exception=AcquireExceptionInfo();
+  p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
+    exception);
+  exception=DestroyExceptionInfo(exception);
+  if (p != (const Quantum *) NULL)
+    return(MagickFalse);
+  count=write(file,p,length);
+  if (count != (ssize_t) length)
+    return(MagickFalse);
+  return(MagickTrue);
+}
+
+static MagickBooleanType WriteDistributeCache(int file,
+  const MagickSizeType session_key)
+{
+  char
+    key[MaxTextExtent];
+
+  CacheInfo
+    *cache_info;
+
+  ExceptionInfo
+    *exception;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+  RectangleInfo
+    region;
+
+  register Quantum
+    *p;
+
+  size_t
     length;
 
-  struct addrinfo
-    hints,
-    *result;
+  ssize_t
+    count;
 
-  struct sockaddr_storage
-    address;
+  exception=AcquireExceptionInfo();
+  (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+  image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (image == (Image *) NULL)
+    return(MagickFalse);
+  cache_info=(CacheInfo *) image->cache;
+  count=read(file,&region.width,sizeof(region.width));
+  if (count != (ssize_t) sizeof(region.width))
+    return(MagickFalse);
+  count=read(file,&region.height,sizeof(region.height));
+  if (count != (ssize_t) sizeof(region.height))
+    return(MagickFalse);
+  count=read(file,&region.x,sizeof(region.x));
+  if (count != (ssize_t) sizeof(region.width))
+    return(MagickFalse);
+  count=read(file,&region.y,sizeof(region.y));
+  if (count != (ssize_t) sizeof(region.y))
+    return(MagickFalse);
+  length=(size_t) (region.width*cache_info->number_channels*sizeof(Quantum));
+  p=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
+    exception);
+  exception=DestroyExceptionInfo(exception);
+  if (p != (Quantum *) NULL)
+    return(MagickFalse);
+  count=read(file,p,length);
+  if (count != (ssize_t) length)
+    return(MagickFalse);
+  status=SyncAuthenticPixels(image,exception);
+  return(status);
+}
 
-  (void) ResetMagickMemory(&hints,0,sizeof(hints));
-  hints.ai_family=AF_UNSPEC;    /* allow IPv4 or IPv6 */
-  hints.ai_socktype=SOCK_DGRAM; /* datagram socket */
-  hints.ai_flags=AI_PASSIVE;    /* for wildcard IP address */
-  hints.ai_protocol=0;          /* any protocol */
-  (void) FormatLocaleString(service,MaxTextExtent,"%.20g",(double) port);
-  status=getaddrinfo((const char *) NULL,service,&hints,&result);
-  if (status != 0)
-    {
-      (void) fprintf(stderr,"getaddrinfo: %s\n", gai_strerror(status));
-      exit(EXIT_FAILURE);
-    }
-  for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
+static void *DistributePixelCacheClient(void *socket)
+{
+  const char
+    *shared_secret;
+
+  int
+    client_socket,
+    status;
+
+  MagickSizeType
+    key,
+    session_key;
+
+  RandomInfo
+    *random_info;
+
+  ssize_t
+    count;
+
+  StringInfo
+    *secret;
+
+  unsigned char
+    command,
+    session[MaxTextExtent];
+
+  /*
+    Generate session key.
+  */
+  shared_secret=GetPolicyValue("shared-secret");
+  if (shared_secret == (const char *) NULL)
+    ThrowFatalException(CacheFatalError,"shared secret expected");
+  (void) CopyMagickString((char *) session,shared_secret,MaxTextExtent-
+    DPCSessionKeyLength);
+  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);
+  random_info=DestroyRandomInfo(random_info);
+  client_socket=(*(int *) socket);
+  count=write(client_socket,GetStringInfoDatum(secret),DPCSessionKeyLength);
+  secret=DestroyStringInfo(secret);
+  for ( ; ; )
   {
-    file=socket(p->ai_family, p->ai_socktype,p->ai_protocol);
-    if (file == -1)
-      continue;
-    if (bind(file,p->ai_addr,p->ai_addrlen) == 0)
+    count=read(client_socket,&command,1);
+    if (count <= 0)
       break;
-    (void) close(file);
-  }
-  if (p == NULL)
+    count=read(client_socket,&key,sizeof(key));
+    if ((count != (ssize_t) sizeof(key)) && (key != session_key))
+      break;
+    status=MagickFalse;
+    switch (command)
     {
-      (void) fprintf(stderr,"Could not bind\n");
-      exit(EXIT_FAILURE);
+      case 'c':
+      {
+        status=CreateDistributeCache(client_socket,session_key);
+        break;
+      }
+      case 'd':
+      {
+        status=DestroyDistributeCache(client_socket,session_key);
+        break;
+      }
+      case 'r':
+      {
+        status=ReadDistributeCache(client_socket,session_key);
+        break;
+      }
+      case 'w':
+      {
+        status=WriteDistributeCache(client_socket,session_key);
+        break;
+      }
+      default:
+        break;
     }
-  freeaddrinfo(result);
+    count=write(client_socket,&status,sizeof(status));
+    if (count != (ssize_t) sizeof(status))
+      break;
+  }
+  return((void *) NULL);
+}
+
+MagickExport void DistributePixelCacheServer(const size_t port,
+  ExceptionInfo *exception)
+{
+#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
+  int
+    server_socket,
+    status;
+
+  pthread_attr_t
+    attributes;
+
+  pthread_t
+    threads;
+
+  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));
+  if (status != 0)
+    ThrowFatalException(CacheFatalError,"UnableToBind");
+  status=listen(server_socket,32);
+  if (status != 0)
+    ThrowFatalException(CacheFatalError,"UnableToListen");
+  pthread_attr_init(&attributes);
   for ( ; ; )
   {
-    char
-      host[NI_MAXHOST],
-      service[NI_MAXSERV];
-
-    ssize_t
-      bytes;
-
-    length=(socklen_t) sizeof(struct sockaddr_storage);
-    count=recvfrom(file,message,MaxTextExtent,0,(struct sockaddr *) &address,
-      &length);
-    if (count == -1)
-      continue;
-    status=getnameinfo((struct sockaddr *) &address,length,host,NI_MAXHOST,
-      service,NI_MAXSERV,NI_NUMERICSERV);
-    if (status == 0)
-      (void) printf("received %ld bytes from %s:%s\n",(long) count,host,
-        service);
-    else
-      (void) fprintf(stderr,"getnameinfo: %s\n", gai_strerror(status));
-    bytes=sendto(file,message,(size_t) count,0,(struct sockaddr *) &address,
-      length);
-    if (bytes != count)
-      (void) fprintf(stderr,"error sending response\n");
+    int
+      client_socket;
+
+    socklen_t
+      length;
+
+    length=(socklen_t) sizeof(address);
+    client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
+    if (client_socket == -1)
+      ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
+    status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
+      (void *) &client_socket);
+    if (status == -1)
+      ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
   }
+  (void) close(server_socket);
 #else
-  (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
-    "DelegateLibrarySupportNotBuiltIn","'%s' (socket)",
-    "distributed pixel cache");
+  ThrowFatalException(MissingDelegateError,"distributed pixel cache");
 #endif
 }
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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 *distribute_cache_info,Image *image)
+%
+%  A description of each parameter follows:
+%
+%    o distribute_cache_info: the distributed cache info.
+%
+%    o image: the image.
+%
+*/
+MagickPrivate MagickBooleanType OpenDistributePixelCache(
+  DistributeCacheInfo *distribute_cache_info,Image *image)
+{
+  int
+    file;
+
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    session_key;
+
+  ssize_t
+    count;
+
+  assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+  assert(distribute_cache_info->signature == MagickSignature);
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickSignature);
+  file=distribute_cache_info->file;
+  session_key=distribute_cache_info->session_key;
+  count=write(file,"c",1);
+  if (count != 1)
+    return(MagickFalse);
+  count=write(file,&session_key,sizeof(session_key));
+  if (count != (ssize_t) sizeof(session_key))
+    return(MagickFalse);
+  count=write(file,&image->columns,sizeof(image->columns));
+  if (count != (ssize_t) sizeof(image->columns))
+    return(MagickFalse);
+  count=write(file,&image->rows,sizeof(image->rows));
+  if (count != (ssize_t) sizeof(image->rows))
+    return(MagickFalse);
+  count=write(file,&image->number_channels,sizeof(image->number_channels));
+  if (count != (ssize_t) sizeof(image->number_channels))
+    return(MagickFalse);
+  count=read(file,&status,sizeof(status));
+  if (count != (ssize_t) sizeof(status))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   R e a d D i s t r i b u t e P i x e l C a c h e                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  ReadDistributePixelCache() reads pixels from the specified region of the
+%  distributed pixel cache.
+%
+%  The format of the ReadDistributePixelCache method is:
+%
+%      MagickBooleanType *ReadDistributePixelCache(
+%        DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+%        Quantum *pixels)
+%
+%  A description of each parameter follows:
+%
+%    o distribute_cache_info: the distributed cache info.
+%
+%    o image: the image.
+%
+%    o region: read the pixels from this region of the image.
+%
+%    o pixels: read these pixels from the pixel cache.
+%
+*/
+MagickPrivate MagickBooleanType ReadDistributePixelCache(
+  DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+  Quantum *pixels)
+{
+  CacheInfo
+    *cache_info;
+
+  char
+    key[MaxTextExtent];
+
+  ExceptionInfo
+    *exception;
+
+  int
+    file;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    session_key;
+
+  size_t
+    length;
+
+  ssize_t
+    count;
+
+  assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+  assert(distribute_cache_info->signature == MagickSignature);
+  assert(region != (RectangleInfo *) NULL);
+  assert(pixels != (Quantum *) NULL);
+  exception=AcquireExceptionInfo();
+  (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+  image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (image == (Image *) NULL)
+    return(MagickFalse);
+  cache_info=(CacheInfo *) image->cache;
+  file=distribute_cache_info->file;
+  session_key=distribute_cache_info->session_key;
+  count=write(file,"r",1);
+  if (count != 1)
+    return(MagickFalse);
+  count=write(file,&session_key,sizeof(session_key));
+  if (count != (ssize_t) sizeof(session_key))
+    return(MagickFalse);
+  count=write(file,&region->width,sizeof(region->width));
+  if (count != (ssize_t) sizeof(region->width))
+    return(MagickFalse);
+  count=write(file,&region->height,sizeof(region->height));
+  if (count != (ssize_t) sizeof(region->height))
+    return(MagickFalse);
+  count=write(file,&region->x,sizeof(region->x));
+  if (count != (ssize_t) sizeof(region->x))
+    return(MagickFalse);
+  count=write(file,&region->y,sizeof(region->x));
+  if (count != (ssize_t) sizeof(region->y))
+    return(MagickFalse);
+  length=(size_t) (region->width*cache_info->number_channels*sizeof(Quantum));
+  count=read(file,(unsigned char *) pixels,length);
+  if (count != (ssize_t) length)
+    return(MagickFalse);
+  count=read(file,&status,sizeof(status));
+  if (count != (ssize_t) sizeof(status))
+    return(MagickFalse);
+  return(MagickTrue);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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:
+%
+%      void RelinquishDistributePixelCache(
+%        DistributeCacheInfo *distribute_cache_info)
+%
+%  A description of each parameter follows:
+%
+%    o distribute_cache_info: the distributed cache info.
+%
+*/
+MagickPrivate void RelinquishDistributePixelCache(
+  DistributeCacheInfo *distribute_cache_info)
+{
+  int
+    file;
+
+  MagickSizeType
+    session_key;
+
+  assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+  assert(distribute_cache_info->signature == MagickSignature);
+  file=distribute_cache_info->file;
+  session_key=distribute_cache_info->session_key;
+  (void) write(file,"c",1);
+  (void) write(file,&session_key,sizeof(session_key));
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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                         %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  WriteDistributePixelCache() writes image pixels to the specified region of
+%  the distributed pixel cache.
+
+%
+%  The format of the WriteDistributePixelCache method is:
+%
+%      MagickBooleanType *WriteDistributePixelCache(
+%        DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+%        const Quantum *pixels)
+%
+%  A description of each parameter follows:
+%
+%    o distribute_cache_info: the distributed cache info.
+%
+%    o image: the image.
+%
+%    o region: write the pixels to this region of the image.
+%
+%    o pixels: write these pixels to the pixel cache.
+%
+*/
+MagickPrivate MagickBooleanType WriteDistributePixelCache(
+  DistributeCacheInfo *distribute_cache_info,const RectangleInfo *region,
+  const Quantum *pixels)
+{
+  CacheInfo
+    *cache_info;
+
+  char
+    key[MaxTextExtent];
+
+  ExceptionInfo
+    *exception;
+
+  int
+    file;
+
+  Image
+    *image;
+
+  MagickBooleanType
+    status;
+
+  MagickSizeType
+    session_key;
+
+  size_t
+    length;
+
+  ssize_t
+    count;
+
+  assert(distribute_cache_info != (DistributeCacheInfo *) NULL);
+  assert(distribute_cache_info->signature == MagickSignature);
+  assert(region != (RectangleInfo *) NULL);
+  assert(pixels != (Quantum *) NULL);
+  exception=AcquireExceptionInfo();
+  (void) FormatLocaleString(key,MaxTextExtent,"%.20g",(double) session_key);
+  image=(Image *) GetImageRegistry(ImageRegistryType,key,exception);
+  exception=DestroyExceptionInfo(exception);
+  if (image == (Image *) NULL)
+    return(MagickFalse);
+  cache_info=(CacheInfo *) image->cache;
+  file=distribute_cache_info->file;
+  session_key=distribute_cache_info->session_key;
+  count=write(file,"u",1);
+  if (count != 1)
+    return(MagickFalse);
+  count=write(file,&session_key,sizeof(session_key));
+  if (count != (ssize_t) sizeof(session_key))
+    return(MagickFalse);
+  count=write(file,&region->width,sizeof(region->width));
+  if (count != (ssize_t) sizeof(region->width))
+    return(MagickFalse);
+  count=write(file,&region->height,sizeof(region->height));
+  if (count != (ssize_t) sizeof(region->height))
+    return(MagickFalse);
+  count=write(file,&region->x,sizeof(region->x));
+  if (count != (ssize_t) sizeof(region->x))
+    return(MagickFalse);
+  count=write(file,&region->y,sizeof(region->x));
+  if (count != (ssize_t) sizeof(region->y))
+    return(MagickFalse);
+  length=(size_t) (region->width*cache_info->number_channels*sizeof(Quantum));
+  count=write(file,(unsigned char *) pixels,length);
+  if (count != (ssize_t) length)
+    return(MagickFalse);
+  count=read(file,&status,sizeof(status));
+  if (count != (ssize_t) sizeof(status))
+    return(MagickFalse);
+  return(MagickTrue);
+}
index 4b1234d3419a92f064b0a7db9ed5b4a0c4e83ab0..69cc5a98c9893a639f57db6bfba5860a80d98ce0 100644 (file)
@@ -33,7 +33,7 @@ extern "C" {
   num_threads((expression) == 0 ? 1 : \
     ((chunk) > (16*GetMagickResourceLimit(ThreadResource))) && \
      (GetImagePixelCacheType(source) != DiskCache) && \
-    (GetImagePixelCacheType(destination) != DiskCache) ? \
+     (GetImagePixelCacheType(destination) != DiskCache) ? \
       GetMagickResourceLimit(ThreadResource) : \
       GetMagickResourceLimit(ThreadResource) < 2 ? 1 : 2)
 
index 3c9fbf3cd38baaffcfd3fb67c4d22f3dcb427d7b..da8323980c24c33bb06a5d396e967253f1cb71c4 100644 (file)
@@ -154,7 +154,7 @@ WandExport MagickBooleanType MagickCommandGenesis(ImageInfo *image_info,
       (void) SetLogEventMask(argv[++i]);
     if (LocaleCompare("-distribute-cache",option) == 0)
       {
-        PixelCacheServer(StringToUnsignedLong(argv[++i]),exception);
+        DistributePixelCacheServer(StringToUnsignedLong(argv[++i]),exception);
         exit(0);
       }
     if (LocaleCompare("-duration",option) == 0)