Coverage Report

Created: 2025-08-12 07:37

/src/imagemagick/MagickCore/distribute-cache.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%    DDDD    IIIII   SSSSS  TTTTT  RRRR   IIIII  BBBB   U   U  TTTTT  EEEEE   %
6
%    D   D     I     SS       T    R   R    I    B   B  U   U    T    E       %
7
%    D   D     I      SSS     T    RRRR     I    BBBB   U   U    T    EEE     %
8
%    D   D     I        SS    T    R R      I    B   B  U   U    T    E       %
9
%    DDDDA   IIIII   SSSSS    T    R  R   IIIII  BBBB    UUU     T    EEEEE   %
10
%                                                                             %
11
%                      CCCC   AAA    CCCC  H   H  EEEEE                       %
12
%                     C      A   A  C      H   H  E                           %
13
%                     C      AAAAA  C      HHHHH  EEE                         %
14
%                     C      A   A  C      H   H  E                           %
15
%                      CCCC  A   A   CCCC  H   H  EEEEE                       %
16
%                                                                             %
17
%                                                                             %
18
%                 MagickCore Distributed Pixel Cache Methods                  %
19
%                                                                             %
20
%                              Software Design                                %
21
%                                   Cristy                                    %
22
%                                January 2013                                 %
23
%                                                                             %
24
%                                                                             %
25
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
26
%  dedicated to making software imaging solutions freely available.           %
27
%                                                                             %
28
%  You may not use this file except in compliance with the License.  You may  %
29
%  obtain a copy of the License at                                            %
30
%                                                                             %
31
%    https://imagemagick.org/script/license.php                               %
32
%                                                                             %
33
%  Unless required by applicable law or agreed to in writing, software        %
34
%  distributed under the License is distributed on an "AS IS" BASIS,          %
35
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
36
%  See the License for the specific language governing permissions and        %
37
%  limitations under the License.                                             %
38
%                                                                             %
39
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40
%
41
% A distributed pixel cache is an extension of the traditional pixel cache
42
% available on a single host.  The distributed pixel cache may span multiple
43
% servers so that it can grow in size and transactional capacity to support
44
% very large images.  Start up the pixel cache server on one or more machines.
45
% When you read or operate on an image and the local pixel cache resources are
46
% exhausted, ImageMagick contacts one or more of these remote pixel servers to
47
% store or retrieve pixels.
48
%
49
*/
50

51
/*
52
  Include declarations.
53
*/
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
#undef MAGICKCORE_HAVE_DISTRIBUTE_CACHE
79
#define SOCKET_TYPE int
80
#if defined(MAGICKCORE_DPC_SUPPORT)
81
#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT)
82
#include <netinet/in.h>
83
#include <netdb.h>
84
#include <sys/socket.h>
85
#include <arpa/inet.h>
86
0
#define CLOSE_SOCKET(socket) (void) close_utf8(socket)
87
#define HANDLER_RETURN_TYPE void *
88
0
#define HANDLER_RETURN_VALUE (void *) NULL
89
0
#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
#undef SOCKET_TYPE
97
#define SOCKET_TYPE SOCKET
98
#define LENGTH_TYPE int
99
#define MAGICKCORE_HAVE_DISTRIBUTE_CACHE 1
100
#define MAGICKCORE_HAVE_WINSOCK2 1
101
#endif
102
#endif
103

104
/*
105
  Define declarations.
106
*/
107
0
#define DPCHostname  "127.0.0.1"
108
0
#define DPCPendingConnections  10
109
0
#define DPCPort  6668
110
#define DPCSessionKeyLength  8
111
#ifndef MSG_NOSIGNAL
112
#  define MSG_NOSIGNAL 0
113
#endif
114

115
/*
116
  Static declarations.
117
*/
118
#ifdef MAGICKCORE_HAVE_WINSOCK2
119
static SemaphoreInfo
120
  *winsock2_semaphore = (SemaphoreInfo *) NULL;
121
122
static WSADATA
123
  *wsaData = (WSADATA*) NULL;
124
#endif
125

126
/*
127
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128
%                                                                             %
129
%                                                                             %
130
%                                                                             %
131
+   A c q u i r e D i s t r i b u t e C a c h e I n f o                       %
132
%                                                                             %
133
%                                                                             %
134
%                                                                             %
135
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136
%
137
%  AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure.
138
%
139
%  The format of the AcquireDistributeCacheInfo method is:
140
%
141
%      DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception)
142
%
143
%  A description of each parameter follows:
144
%
145
%    o exception: return any errors or warnings in this structure.
146
%
147
*/
148
149
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
150
static inline MagickOffsetType dpc_read(SOCKET_TYPE magick_unused(file),
151
  const MagickSizeType magick_unused(length),
152
  unsigned char *magick_restrict magick_unused(message))
153
{
154
  magick_unreferenced(file);
155
  magick_unreferenced(length);
156
  magick_unreferenced(message);
157
  return(-1);
158
}
159
#else
160
static inline MagickOffsetType dpc_read(SOCKET_TYPE file,const MagickSizeType length,
161
  unsigned char *magick_restrict message)
162
0
{
163
0
  MagickOffsetType
164
0
    i;
165
166
0
  ssize_t
167
0
    count;
168
169
0
  count=0;
170
0
  for (i=0; i < (MagickOffsetType) length; i+=count)
171
0
  {
172
0
    count=recv(file,(char *) message+i,(LENGTH_TYPE) MagickMin(length-
173
0
      (MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),0);
174
0
    if (count <= 0)
175
0
      {
176
0
        count=0;
177
0
        if (errno != EINTR)
178
0
          break;
179
0
      }
180
0
  }
181
0
  return(i);
182
0
}
183
#endif
184
185
#if defined(MAGICKCORE_HAVE_WINSOCK2)
186
static void InitializeWinsock2(MagickBooleanType use_lock)
187
{
188
  if (use_lock != MagickFalse)
189
    {
190
      if (winsock2_semaphore == (SemaphoreInfo *) NULL)
191
        ActivateSemaphoreInfo(&winsock2_semaphore);
192
      LockSemaphoreInfo(winsock2_semaphore);
193
    }
194
  if (wsaData == (WSADATA *) NULL)
195
    {
196
      wsaData=(WSADATA *) AcquireMagickMemory(sizeof(WSADATA));
197
      if (WSAStartup(MAKEWORD(2,2),wsaData) != 0)
198
        ThrowFatalException(CacheFatalError,"WSAStartup failed");
199
    }
200
  if (use_lock != MagickFalse)
201
    UnlockSemaphoreInfo(winsock2_semaphore);
202
}
203
#endif
204
205
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
206
static int ConnectPixelCacheServer(const char *magick_unused(hostname),
207
  const int magick_unused(port),size_t *magick_unused(session_key),
208
  ExceptionInfo *exception)
209
{
210
  magick_unreferenced(hostname);
211
  magick_unreferenced(port);
212
  magick_unreferenced(session_key);
213
  (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
214
    "DelegateLibrarySupportNotBuiltIn","distributed pixel cache");
215
  return(MagickFalse);
216
}
217
#else
218
static int ConnectPixelCacheServer(const char *hostname,const int port,
219
  size_t *session_key,ExceptionInfo *exception)
220
0
{
221
0
  char
222
0
    service[MagickPathExtent],
223
0
    *shared_secret;
224
225
0
  int
226
0
    status;
227
228
0
  SOCKET_TYPE
229
0
    client_socket;
230
231
0
  StringInfo
232
0
    *nonce;
233
234
0
  ssize_t
235
0
    count;
236
237
0
  struct addrinfo
238
0
    hint,
239
0
    *result;
240
241
  /*
242
    Connect to distributed pixel cache and get session key.
243
  */
244
0
  *session_key=0;
245
#if defined(MAGICKCORE_HAVE_WINSOCK2)
246
  InitializeWinsock2(MagickTrue);
247
#endif
248
0
  (void) memset(&hint,0,sizeof(hint));
249
0
  hint.ai_family=AF_INET;
250
0
  hint.ai_socktype=SOCK_STREAM;
251
0
  hint.ai_flags=AI_PASSIVE;
252
0
  (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
253
0
  status=getaddrinfo(hostname,service,&hint,&result);
254
0
  if (status != 0)
255
0
    {
256
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
257
0
        "DistributedPixelCache","'%s': %s",hostname,GetExceptionMessage(errno));
258
0
      return(-1);
259
0
    }
260
0
  client_socket=socket(result->ai_family,result->ai_socktype,
261
0
    result->ai_protocol);
262
0
  if (client_socket == -1)
263
0
    {
264
0
      freeaddrinfo(result);
265
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
266
0
        "DistributedPixelCache","'%s': %s",hostname,GetExceptionMessage(errno));
267
0
      return(-1);
268
0
    }
269
0
  status=connect(client_socket,result->ai_addr,(socklen_t) result->ai_addrlen);
270
0
  freeaddrinfo(result);
271
0
  if (status == -1)
272
0
    {
273
0
      CLOSE_SOCKET(client_socket);
274
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
275
0
        "DistributedPixelCache","'%s': %s",hostname,GetExceptionMessage(errno));
276
0
      return(-1);
277
0
    }
278
0
  count=recv(client_socket,(char *) session_key,sizeof(*session_key),0);
279
0
  if (count == -1)
280
0
    {
281
0
      CLOSE_SOCKET(client_socket);
282
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
283
0
        "DistributedPixelCache","'%s': %s",hostname,GetExceptionMessage(errno));
284
0
      return(-1);
285
0
    }
286
  /*
287
    Authenticate client session key to server session key.
288
  */
289
0
  shared_secret=GetPolicyValue("cache:shared-secret");
290
0
  if (shared_secret == (char *) NULL)
291
0
    {
292
0
      CLOSE_SOCKET(client_socket);
293
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
294
0
        "DistributedPixelCache","'%s': shared secret required",hostname);
295
0
      return(-1);
296
0
    }
297
0
  nonce=StringToStringInfo(shared_secret);
298
0
  if ((size_t) GetMagickSignature(nonce) != *session_key)
299
0
    {
300
0
      CLOSE_SOCKET(client_socket);
301
0
      (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
302
0
        "DistributedPixelCache","'%s' authentication failed",hostname);
303
0
      return(-1);
304
0
    }
305
0
  shared_secret=DestroyString(shared_secret);
306
0
  nonce=DestroyStringInfo(nonce);
307
0
  return((int) client_socket);
308
0
}
309
#endif
310
311
static char *GetHostname(int *port,ExceptionInfo *exception)
312
0
{
313
0
  char
314
0
    *host,
315
0
    *hosts,
316
0
    **hostlist;
317
318
0
  int
319
0
    argc;
320
321
0
  ssize_t
322
0
    i;
323
324
0
  static size_t
325
0
    id = 0;
326
327
  /*
328
    Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668).
329
  */
330
0
  hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts",exception);
331
0
  if (hosts == (char *) NULL)
332
0
    {
333
0
      *port=DPCPort;
334
0
      return(AcquireString(DPCHostname));
335
0
    }
336
0
  (void) SubstituteString(&hosts,","," ");
337
0
  hostlist=StringToArgv(hosts,&argc);
338
0
  hosts=DestroyString(hosts);
339
0
  if (hostlist == (char **) NULL)
340
0
    {
341
0
      *port=DPCPort;
342
0
      return(AcquireString(DPCHostname));
343
0
    }
344
0
  hosts=AcquireString(hostlist[(id++ % ((size_t) argc-1))+1]);
345
0
  for (i=0; i < (ssize_t) argc; i++)
346
0
    hostlist[i]=DestroyString(hostlist[i]);
347
0
  hostlist=(char **) RelinquishMagickMemory(hostlist);
348
0
  (void) SubstituteString(&hosts,":"," ");
349
0
  hostlist=StringToArgv(hosts,&argc);
350
0
  if (hostlist == (char **) NULL)
351
0
    {
352
0
      *port=DPCPort;
353
0
      return(AcquireString(DPCHostname));
354
0
    }
355
0
  host=AcquireString(hostlist[1]);
356
0
  if (hostlist[2] == (char *) NULL)
357
0
    *port=DPCPort;
358
0
  else
359
0
    *port=StringToLong(hostlist[2]);
360
0
  for (i=0; i < (ssize_t) argc; i++)
361
0
    hostlist[i]=DestroyString(hostlist[i]);
362
0
  hostlist=(char **) RelinquishMagickMemory(hostlist);
363
0
  return(host);
364
0
}
365
366
MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo(
367
  ExceptionInfo *exception)
368
0
{
369
0
  char
370
0
    *hostname;
371
372
0
  DistributeCacheInfo
373
0
    *server_info;
374
375
0
  size_t
376
0
    session_key;
377
378
  /*
379
    Connect to the distributed pixel cache server.
380
  */
381
0
  server_info=(DistributeCacheInfo *) AcquireCriticalMemory(
382
0
    sizeof(*server_info));
383
0
  (void) memset(server_info,0,sizeof(*server_info));
384
0
  server_info->signature=MagickCoreSignature;
385
0
  server_info->port=0;
386
0
  hostname=GetHostname(&server_info->port,exception);
387
0
  session_key=0;
388
0
  server_info->file=ConnectPixelCacheServer(hostname,server_info->port,
389
0
    &session_key,exception);
390
0
  if (server_info->file == -1)
391
0
    server_info=DestroyDistributeCacheInfo(server_info);
392
0
  else
393
0
    {
394
0
      server_info->session_key=session_key;
395
0
      (void) CopyMagickString(server_info->hostname,hostname,MagickPathExtent);
396
0
      server_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
397
0
        MagickFalse;
398
0
    }
399
0
  hostname=DestroyString(hostname);
400
0
  return(server_info);
401
0
}
402

403
/*
404
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
405
%                                                                             %
406
%                                                                             %
407
%                                                                             %
408
+   D e s t r o y D i s t r i b u t e C a c h e I n f o                       %
409
%                                                                             %
410
%                                                                             %
411
%                                                                             %
412
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413
%
414
%  DestroyDistributeCacheInfo() deallocates memory associated with an
415
%  DistributeCacheInfo structure.
416
%
417
%  The format of the DestroyDistributeCacheInfo method is:
418
%
419
%      DistributeCacheInfo *DestroyDistributeCacheInfo(
420
%        DistributeCacheInfo *server_info)
421
%
422
%  A description of each parameter follows:
423
%
424
%    o server_info: the distributed cache info.
425
%
426
*/
427
MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo(
428
  DistributeCacheInfo *server_info)
429
0
{
430
0
  assert(server_info != (DistributeCacheInfo *) NULL);
431
0
  assert(server_info->signature == MagickCoreSignature);
432
0
#if defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
433
0
  if (server_info->file > 0)
434
0
    CLOSE_SOCKET(server_info->file);
435
0
#endif
436
0
  server_info->signature=(~MagickCoreSignature);
437
0
  server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info);
438
0
  return(server_info);
439
0
}
440

441
/*
442
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443
%                                                                             %
444
%                                                                             %
445
%                                                                             %
446
+   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                       %
447
%                                                                             %
448
%                                                                             %
449
%                                                                             %
450
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451
%
452
%  DistributePixelCacheServer() waits on the specified port for commands to
453
%  create, read, update, or destroy a pixel cache.
454
%
455
%  The format of the DistributePixelCacheServer() method is:
456
%
457
%      void DistributePixelCacheServer(const int port)
458
%
459
%  A description of each parameter follows:
460
%
461
%    o port: connect the distributed pixel cache at this port.
462
%
463
%    o exception: return any errors or warnings in this structure.
464
%
465
*/
466
467
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
468
static inline MagickOffsetType dpc_send(SOCKET_TYPE magick_unused(file),
469
  const MagickSizeType magick_unused(length),
470
  const void *magick_restrict magick_unused(message))
471
{
472
  magick_unreferenced(file);
473
  magick_unreferenced(length);
474
  magick_unreferenced(message);
475
  return(-1);
476
}
477
#else
478
static inline MagickOffsetType dpc_send(SOCKET_TYPE file,const MagickSizeType length,
479
  const void *magick_restrict message)
480
0
{
481
0
  MagickOffsetType
482
0
    i;
483
484
0
  ssize_t
485
0
    count;
486
487
  /*
488
    Ensure a complete message is sent.
489
  */
490
0
  count=0;
491
0
  for (i=0; i < (MagickOffsetType) length; i+=count)
492
0
  {
493
0
    count=(ssize_t) send(file,(char *) message+i,(LENGTH_TYPE)
494
0
      MagickMin(length-(MagickSizeType) i,(MagickSizeType) MagickMaxBufferExtent),
495
0
      MSG_NOSIGNAL);
496
0
    if (count <= 0)
497
0
      {
498
0
        count=0;
499
0
        if (errno != EINTR)
500
0
          break;
501
0
      }
502
0
  }
503
0
  return(i);
504
0
}
505
#endif
506
507
#if !defined(MAGICKCORE_HAVE_DISTRIBUTE_CACHE)
508
MagickExport void DistributePixelCacheServer(const int magick_unused(port),
509
  ExceptionInfo *magick_unused(exception))
510
{
511
  magick_unreferenced(port);
512
  magick_unreferenced(exception);
513
  ThrowFatalException(MissingDelegateError,"DelegateLibrarySupportNotBuiltIn");
514
}
515
#else
516
static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry,
517
  const size_t session_key)
518
0
{
519
0
  MagickAddressType
520
0
    key = (MagickAddressType) session_key;
521
522
  /*
523
    Destroy distributed pixel cache.
524
  */
525
0
  return(DeleteNodeFromSplayTree(registry,(const void *) key));
526
0
}
527
528
static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry,
529
  SOCKET_TYPE file,const size_t session_key,ExceptionInfo *exception)
530
0
{
531
0
  Image
532
0
    *image;
533
534
0
  MagickAddressType
535
0
    key = (MagickAddressType) session_key;
536
537
0
  MagickBooleanType
538
0
    status;
539
540
0
  MagickOffsetType
541
0
    count;
542
543
0
  MagickSizeType
544
0
    length;
545
546
0
  unsigned char
547
0
    message[MagickPathExtent],
548
0
    *p;
549
550
  /*
551
    Open distributed pixel cache.
552
  */
553
0
  image=AcquireImage((ImageInfo *) NULL,exception);
554
0
  if (image == (Image *) NULL)
555
0
    return(MagickFalse);
556
0
  length=sizeof(image->storage_class)+sizeof(image->colorspace)+
557
0
    sizeof(image->alpha_trait)+sizeof(image->channels)+sizeof(image->columns)+
558
0
    sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels*
559
0
    sizeof(*image->channel_map)+sizeof(image->metacontent_extent);
560
0
  count=dpc_read(file,length,message);
561
0
  if (count != (MagickOffsetType) length)
562
0
    return(MagickFalse);
563
  /*
564
    Deserialize the image attributes.
565
  */
566
0
  p=message;
567
0
  (void) memcpy(&image->storage_class,p,sizeof(image->storage_class));
568
0
  p+=(ptrdiff_t) sizeof(image->storage_class);
569
0
  (void) memcpy(&image->colorspace,p,sizeof(image->colorspace));
570
0
  p+=(ptrdiff_t) sizeof(image->colorspace);
571
0
  (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait));
572
0
  p+=(ptrdiff_t) sizeof(image->alpha_trait);
573
0
  (void) memcpy(&image->channels,p,sizeof(image->channels));
574
0
  p+=(ptrdiff_t) sizeof(image->channels);
575
0
  (void) memcpy(&image->columns,p,sizeof(image->columns));
576
0
  p+=(ptrdiff_t) sizeof(image->columns);
577
0
  (void) memcpy(&image->rows,p,sizeof(image->rows));
578
0
  p+=(ptrdiff_t) sizeof(image->rows);
579
0
  (void) memcpy(&image->number_channels,p,sizeof(image->number_channels));
580
0
  p+=(ptrdiff_t) sizeof(image->number_channels);
581
0
  (void) memcpy(image->channel_map,p,MaxPixelChannels*
582
0
    sizeof(*image->channel_map));
583
0
  p+=(ptrdiff_t) MaxPixelChannels*sizeof(*image->channel_map);
584
0
  (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent));
585
0
  p+=(ptrdiff_t) sizeof(image->metacontent_extent);
586
0
  if (SyncImagePixelCache(image,exception) == MagickFalse)
587
0
    return(MagickFalse);
588
0
  status=AddValueToSplayTree(registry,(const void *) key,image);
589
0
  return(status);
590
0
}
591
592
static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry,
593
  SOCKET_TYPE file,const size_t session_key,ExceptionInfo *exception)
594
0
{
595
0
  const Quantum
596
0
    *p;
597
598
0
  const unsigned char
599
0
    *metacontent;
600
601
0
  Image
602
0
    *image;
603
604
0
  MagickAddressType
605
0
    key = (MagickAddressType) session_key;
606
607
0
  MagickOffsetType
608
0
    count;
609
610
0
  MagickSizeType
611
0
    length;
612
613
0
  RectangleInfo
614
0
    region;
615
616
0
  unsigned char
617
0
    message[MagickPathExtent],
618
0
    *q;
619
620
  /*
621
    Read distributed pixel cache metacontent.
622
  */
623
0
  image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
624
0
  if (image == (Image *) NULL)
625
0
    return(MagickFalse);
626
0
  length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
627
0
    sizeof(region.y)+sizeof(length);
628
0
  count=dpc_read(file,length,message);
629
0
  if (count != (MagickOffsetType) length)
630
0
    return(MagickFalse);
631
0
  q=message;
632
0
  (void) memcpy(&region.width,q,sizeof(region.width));
633
0
  q+=(ptrdiff_t) sizeof(region.width);
634
0
  (void) memcpy(&region.height,q,sizeof(region.height));
635
0
  q+=(ptrdiff_t) sizeof(region.height);
636
0
  (void) memcpy(&region.x,q,sizeof(region.x));
637
0
  q+=(ptrdiff_t) sizeof(region.x);
638
0
  (void) memcpy(&region.y,q,sizeof(region.y));
639
0
  q+=(ptrdiff_t) sizeof(region.y);
640
0
  (void) memcpy(&length,q,sizeof(length));
641
0
  q+=(ptrdiff_t) sizeof(length);
642
0
  p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
643
0
    exception);
644
0
  if (p == (const Quantum *) NULL)
645
0
    return(MagickFalse);
646
0
  metacontent=(const unsigned char *) GetVirtualMetacontent(image);
647
0
  count=dpc_send(file,length,metacontent);
648
0
  if (count != (MagickOffsetType) length)
649
0
    return(MagickFalse);
650
0
  return(MagickTrue);
651
0
}
652
653
static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry,
654
  SOCKET_TYPE file,const size_t session_key,ExceptionInfo *exception)
655
0
{
656
0
  const Quantum
657
0
    *p;
658
659
0
  Image
660
0
    *image;
661
662
0
  MagickAddressType
663
0
    key = (MagickAddressType) session_key;
664
665
0
  MagickOffsetType
666
0
    count;
667
668
0
  MagickSizeType
669
0
    length;
670
671
0
  RectangleInfo
672
0
    region;
673
674
0
  unsigned char
675
0
    message[MagickPathExtent],
676
0
    *q;
677
678
  /*
679
    Read distributed pixel cache pixels.
680
  */
681
0
  image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
682
0
  if (image == (Image *) NULL)
683
0
    return(MagickFalse);
684
0
  length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
685
0
    sizeof(region.y)+sizeof(length);
686
0
  count=dpc_read(file,length,message);
687
0
  if (count != (MagickOffsetType) length)
688
0
    return(MagickFalse);
689
0
  q=message;
690
0
  (void) memcpy(&region.width,q,sizeof(region.width));
691
0
  q+=(ptrdiff_t) sizeof(region.width);
692
0
  (void) memcpy(&region.height,q,sizeof(region.height));
693
0
  q+=(ptrdiff_t) sizeof(region.height);
694
0
  (void) memcpy(&region.x,q,sizeof(region.x));
695
0
  q+=(ptrdiff_t) sizeof(region.x);
696
0
  (void) memcpy(&region.y,q,sizeof(region.y));
697
0
  q+=(ptrdiff_t) sizeof(region.y);
698
0
  (void) memcpy(&length,q,sizeof(length));
699
0
  q+=(ptrdiff_t) sizeof(length);
700
0
  p=GetVirtualPixels(image,region.x,region.y,region.width,region.height,
701
0
    exception);
702
0
  if (p == (const Quantum *) NULL)
703
0
    return(MagickFalse);
704
0
  count=dpc_send(file,length,p);
705
0
  if (count != (MagickOffsetType) length)
706
0
    return(MagickFalse);
707
0
  return(MagickTrue);
708
0
}
709
710
static void *RelinquishImageRegistry(void *image)
711
0
{
712
0
  return((void *) DestroyImageList((Image *) image));
713
0
}
714
715
static MagickBooleanType WriteDistributeCacheMetacontent(
716
  SplayTreeInfo *registry,SOCKET_TYPE file,const size_t session_key,
717
  ExceptionInfo *exception)
718
0
{
719
0
  Image
720
0
    *image;
721
722
0
  MagickAddressType
723
0
    key = (MagickAddressType) session_key;
724
725
0
  MagickOffsetType
726
0
    count;
727
728
0
  MagickSizeType
729
0
    length;
730
731
0
  Quantum
732
0
    *q;
733
734
0
  RectangleInfo
735
0
    region;
736
737
0
  unsigned char
738
0
    message[MagickPathExtent],
739
0
    *metacontent,
740
0
    *p;
741
742
  /*
743
    Write distributed pixel cache metacontent.
744
  */
745
0
  key=session_key;
746
0
  image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
747
0
  if (image == (Image *) NULL)
748
0
    return(MagickFalse);
749
0
  length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
750
0
    sizeof(region.y)+sizeof(length);
751
0
  count=dpc_read(file,length,message);
752
0
  if (count != (MagickOffsetType) length)
753
0
    return(MagickFalse);
754
0
  p=message;
755
0
  (void) memcpy(&region.width,p,sizeof(region.width));
756
0
  p+=(ptrdiff_t) sizeof(region.width);
757
0
  (void) memcpy(&region.height,p,sizeof(region.height));
758
0
  p+=(ptrdiff_t) sizeof(region.height);
759
0
  (void) memcpy(&region.x,p,sizeof(region.x));
760
0
  p+=(ptrdiff_t) sizeof(region.x);
761
0
  (void) memcpy(&region.y,p,sizeof(region.y));
762
0
  p+=(ptrdiff_t) sizeof(region.y);
763
0
  (void) memcpy(&length,p,sizeof(length));
764
0
  p+=(ptrdiff_t) sizeof(length);
765
0
  q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
766
0
    exception);
767
0
  if (q == (Quantum *) NULL)
768
0
    return(MagickFalse);
769
0
  metacontent=(unsigned char *) GetAuthenticMetacontent(image);
770
0
  count=dpc_read(file,length,metacontent);
771
0
  if (count != (MagickOffsetType) length)
772
0
    return(MagickFalse);
773
0
  return(SyncAuthenticPixels(image,exception));
774
0
}
775
776
static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry,
777
  SOCKET_TYPE file,const size_t session_key,ExceptionInfo *exception)
778
0
{
779
0
  Image
780
0
    *image;
781
782
0
  MagickAddressType
783
0
    key = (MagickAddressType) session_key;
784
785
0
  MagickOffsetType
786
0
    count;
787
788
0
  MagickSizeType
789
0
    length;
790
791
0
  Quantum
792
0
    *q;
793
794
0
  RectangleInfo
795
0
    region;
796
797
0
  unsigned char
798
0
    message[MagickPathExtent],
799
0
    *p;
800
801
  /*
802
    Write distributed pixel cache pixels.
803
  */
804
0
  image=(Image *) GetValueFromSplayTree(registry,(const void *) key);
805
0
  if (image == (Image *) NULL)
806
0
    return(MagickFalse);
807
0
  length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+
808
0
    sizeof(region.y)+sizeof(length);
809
0
  count=dpc_read(file,length,message);
810
0
  if (count != (MagickOffsetType) length)
811
0
    return(MagickFalse);
812
0
  p=message;
813
0
  (void) memcpy(&region.width,p,sizeof(region.width));
814
0
  p+=(ptrdiff_t) sizeof(region.width);
815
0
  (void) memcpy(&region.height,p,sizeof(region.height));
816
0
  p+=(ptrdiff_t) sizeof(region.height);
817
0
  (void) memcpy(&region.x,p,sizeof(region.x));
818
0
  p+=(ptrdiff_t) sizeof(region.x);
819
0
  (void) memcpy(&region.y,p,sizeof(region.y));
820
0
  p+=(ptrdiff_t) sizeof(region.y);
821
0
  (void) memcpy(&length,p,sizeof(length));
822
0
  p+=(ptrdiff_t) sizeof(length);
823
0
  q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height,
824
0
    exception);
825
0
  if (q == (Quantum *) NULL)
826
0
    return(MagickFalse);
827
0
  count=dpc_read(file,length,(unsigned char *) q);
828
0
  if (count != (MagickOffsetType) length)
829
0
    return(MagickFalse);
830
0
  return(SyncAuthenticPixels(image,exception));
831
0
}
832
833
static HANDLER_RETURN_TYPE DistributePixelCacheClient(void *socket)
834
0
{
835
0
  char
836
0
    *shared_secret;
837
838
0
  ExceptionInfo
839
0
    *exception;
840
841
0
  MagickBooleanType
842
0
    status = MagickFalse;
843
844
0
  MagickOffsetType
845
0
    count;
846
847
0
  size_t
848
0
    key,
849
0
    session_key;
850
851
0
  SOCKET_TYPE
852
0
    client_socket;
853
854
0
  SplayTreeInfo
855
0
    *registry;
856
857
0
  StringInfo
858
0
    *nonce;
859
860
0
  unsigned char
861
0
    command;
862
863
  /*
864
    Generate session key.
865
  */
866
0
  shared_secret=GetPolicyValue("cache:shared-secret");
867
0
  if (shared_secret == (char *) NULL)
868
0
    ThrowFatalException(CacheFatalError,"shared secret required");
869
0
  nonce=StringToStringInfo(shared_secret);
870
0
  shared_secret=DestroyString(shared_secret);
871
0
  session_key=GetMagickSignature(nonce);
872
0
  nonce=DestroyStringInfo(nonce);
873
0
  exception=AcquireExceptionInfo();
874
  /*
875
    Process client commands.
876
  */
877
0
  registry=NewSplayTree((int (*)(const void *,const void *)) NULL,
878
0
    (void *(*)(void *)) NULL,RelinquishImageRegistry);
879
0
  client_socket=(*(SOCKET_TYPE *) socket);
880
0
  count=dpc_send(client_socket,sizeof(session_key),&session_key);
881
0
  for (status=MagickFalse; ; )
882
0
  {
883
0
    count=dpc_read(client_socket,1,(unsigned char *) &command);
884
0
    if (count <= 0)
885
0
      break;
886
0
    count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key);
887
0
    if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key))
888
0
      break;
889
0
    switch (command)
890
0
    {
891
0
      case 'o':
892
0
      {
893
0
        status=OpenDistributeCache(registry,client_socket,session_key,
894
0
          exception);
895
0
        count=dpc_send(client_socket,sizeof(status),&status);
896
0
        break;
897
0
      }
898
0
      case 'r':
899
0
      {
900
0
        status=ReadDistributeCachePixels(registry,client_socket,session_key,
901
0
          exception);
902
0
        break;
903
0
      }
904
0
      case 'R':
905
0
      {
906
0
        status=ReadDistributeCacheMetacontent(registry,client_socket,
907
0
          session_key,exception);
908
0
        break;
909
0
      }
910
0
      case 'w':
911
0
      {
912
0
        status=WriteDistributeCachePixels(registry,client_socket,session_key,
913
0
          exception);
914
0
        break;
915
0
      }
916
0
      case 'W':
917
0
      {
918
0
        status=WriteDistributeCacheMetacontent(registry,client_socket,
919
0
          session_key,exception);
920
0
        break;
921
0
      }
922
0
      case 'd':
923
0
      {
924
0
        status=DestroyDistributeCache(registry,session_key);
925
0
        break;
926
0
      }
927
0
      default:
928
0
        break;
929
0
    }
930
0
    if (status == MagickFalse)
931
0
      break;
932
0
    if (command == 'd')
933
0
      break;
934
0
  }
935
0
  count=dpc_send(client_socket,sizeof(status),&status);
936
0
  CLOSE_SOCKET(client_socket);
937
0
  exception=DestroyExceptionInfo(exception);
938
0
  registry=DestroySplayTree(registry);
939
0
  return(HANDLER_RETURN_VALUE);
940
0
}
941
942
MagickExport void DistributePixelCacheServer(const int port,
943
  ExceptionInfo *exception)
944
0
{
945
0
  char
946
0
    service[MagickPathExtent];
947
948
0
  int
949
0
    status;
950
951
0
#if defined(MAGICKCORE_THREAD_SUPPORT)
952
0
  pthread_attr_t
953
0
    attributes;
954
955
0
  pthread_t
956
0
    threads;
957
#elif defined(_MSC_VER)
958
  DWORD
959
    threadID;
960
#else
961
  Not implemented!
962
#endif
963
964
0
  struct addrinfo
965
0
    *p;
966
967
0
  SOCKET_TYPE
968
0
    server_socket;
969
970
0
  struct addrinfo
971
0
    hint,
972
0
    *result;
973
974
0
  struct sockaddr_in
975
0
    address;
976
977
  /*
978
    Launch distributed pixel cache server.
979
  */
980
0
  assert(exception != (ExceptionInfo *) NULL);
981
0
  assert(exception->signature == MagickCoreSignature);
982
0
  magick_unreferenced(exception);
983
#if defined(MAGICKCORE_HAVE_WINSOCK2)
984
  InitializeWinsock2(MagickFalse);
985
#endif
986
0
  (void) memset(&hint,0,sizeof(hint));
987
0
  hint.ai_family=AF_INET;
988
0
  hint.ai_socktype=SOCK_STREAM;
989
0
  hint.ai_flags=AI_PASSIVE;
990
0
  (void) FormatLocaleString(service,MagickPathExtent,"%d",port);
991
0
  status=getaddrinfo((const char *) NULL,service,&hint,&result);
992
0
  if (status != 0)
993
0
    ThrowFatalException(CacheFatalError,"UnableToListen");
994
0
  server_socket=(SOCKET_TYPE) 0;
995
0
  for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next)
996
0
  {
997
0
    int
998
0
      one;
999
1000
0
    server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol);
1001
0
    if (server_socket == -1)
1002
0
      continue;
1003
0
    one=1;
1004
0
    status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(char *) &one,
1005
0
      (socklen_t) sizeof(one));
1006
0
    if (status == -1)
1007
0
      {
1008
0
        CLOSE_SOCKET(server_socket);
1009
0
        continue;
1010
0
      }
1011
0
    status=bind(server_socket,p->ai_addr,(socklen_t) p->ai_addrlen);
1012
0
    if (status == -1)
1013
0
      {
1014
0
        CLOSE_SOCKET(server_socket);
1015
0
        continue;
1016
0
      }
1017
0
    break;
1018
0
  }
1019
0
  if (p == (struct addrinfo *) NULL)
1020
0
    ThrowFatalException(CacheFatalError,"UnableToBind");
1021
0
  freeaddrinfo(result);
1022
0
  status=listen(server_socket,DPCPendingConnections);
1023
0
  if (status != 0)
1024
0
    ThrowFatalException(CacheFatalError,"UnableToListen");
1025
0
#if defined(MAGICKCORE_THREAD_SUPPORT)
1026
0
  pthread_attr_init(&attributes);
1027
0
#endif
1028
0
  for ( ; ; )
1029
0
  {
1030
0
    SOCKET_TYPE
1031
0
      client_socket;
1032
1033
0
    socklen_t
1034
0
      length;
1035
1036
0
    length=(socklen_t) sizeof(address);
1037
0
    client_socket=accept(server_socket,(struct sockaddr *) &address,&length);
1038
0
    if (client_socket == -1)
1039
0
      ThrowFatalException(CacheFatalError,"UnableToEstablishConnection");
1040
0
#if defined(MAGICKCORE_THREAD_SUPPORT)
1041
0
    status=pthread_create(&threads,&attributes,DistributePixelCacheClient,
1042
0
      (void *) &client_socket);
1043
0
    if (status == -1)
1044
0
      ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
1045
#elif defined(_MSC_VER)
1046
    if (CreateThread(0,0,DistributePixelCacheClient,(void*) &client_socket,0,&threadID) == (HANDLE) NULL)
1047
      ThrowFatalException(CacheFatalError,"UnableToCreateClientThread");
1048
#else
1049
    Not implemented!
1050
#endif
1051
0
  }
1052
0
}
1053
#endif
1054

1055
/*
1056
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057
%                                                                             %
1058
%                                                                             %
1059
%                                                                             %
1060
+  D i s t r i b u t e C a c h e T e r m i n u s                              %
1061
%                                                                             %
1062
%                                                                             %
1063
%                                                                             %
1064
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1065
%
1066
%  DistributeCacheTerminus() destroys the Distributed Cache.
1067
%
1068
*/
1069
MagickPrivate void DistributeCacheTerminus(void)
1070
0
{
1071
#ifdef MAGICKCORE_HAVE_WINSOCK2
1072
  if (winsock2_semaphore == (SemaphoreInfo *) NULL)
1073
    ActivateSemaphoreInfo(&winsock2_semaphore);
1074
  LockSemaphoreInfo(winsock2_semaphore);
1075
  if (wsaData != (WSADATA *) NULL)
1076
    {
1077
      WSACleanup();
1078
      wsaData=(WSADATA *) RelinquishMagickMemory((void *) wsaData);
1079
    }
1080
  UnlockSemaphoreInfo(winsock2_semaphore);
1081
  RelinquishSemaphoreInfo(&winsock2_semaphore);
1082
#endif
1083
0
}
1084
1085
/*
1086
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087
%                                                                             %
1088
%                                                                             %
1089
%                                                                             %
1090
+   G e t D i s t r i b u t e C a c h e F i l e                               %
1091
%                                                                             %
1092
%                                                                             %
1093
%                                                                             %
1094
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1095
%
1096
%  GetDistributeCacheFile() returns the file associated with this
1097
%  DistributeCacheInfo structure.
1098
%
1099
%  The format of the GetDistributeCacheFile method is:
1100
%
1101
%      int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1102
%
1103
%  A description of each parameter follows:
1104
%
1105
%    o server_info: the distributed cache info.
1106
%
1107
*/
1108
MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info)
1109
0
{
1110
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1111
0
  assert(server_info->signature == MagickCoreSignature);
1112
0
  return(server_info->file);
1113
0
}
1114

1115
/*
1116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117
%                                                                             %
1118
%                                                                             %
1119
%                                                                             %
1120
+   G e t D i s t r i b u t e C a c h e H o s t n a m e                       %
1121
%                                                                             %
1122
%                                                                             %
1123
%                                                                             %
1124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125
%
1126
%  GetDistributeCacheHostname() returns the hostname associated with this
1127
%  DistributeCacheInfo structure.
1128
%
1129
%  The format of the GetDistributeCacheHostname method is:
1130
%
1131
%      const char *GetDistributeCacheHostname(
1132
%        const DistributeCacheInfo *server_info)
1133
%
1134
%  A description of each parameter follows:
1135
%
1136
%    o server_info: the distributed cache info.
1137
%
1138
*/
1139
MagickPrivate const char *GetDistributeCacheHostname(
1140
  const DistributeCacheInfo *server_info)
1141
0
{
1142
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1143
0
  assert(server_info->signature == MagickCoreSignature);
1144
0
  return(server_info->hostname);
1145
0
}
1146

1147
/*
1148
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149
%                                                                             %
1150
%                                                                             %
1151
%                                                                             %
1152
+   G e t D i s t r i b u t e C a c h e P o r t                               %
1153
%                                                                             %
1154
%                                                                             %
1155
%                                                                             %
1156
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1157
%
1158
%  GetDistributeCachePort() returns the port associated with this
1159
%  DistributeCacheInfo structure.
1160
%
1161
%  The format of the GetDistributeCachePort method is:
1162
%
1163
%      int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1164
%
1165
%  A description of each parameter follows:
1166
%
1167
%    o server_info: the distributed cache info.
1168
%
1169
*/
1170
MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info)
1171
0
{
1172
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1173
0
  assert(server_info->signature == MagickCoreSignature);
1174
0
  return(server_info->port);
1175
0
}
1176

1177
/*
1178
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179
%                                                                             %
1180
%                                                                             %
1181
%                                                                             %
1182
+   O p e n D i s t r i b u t e P i x e l C a c h e                           %
1183
%                                                                             %
1184
%                                                                             %
1185
%                                                                             %
1186
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1187
%
1188
%  OpenDistributePixelCache() opens a pixel cache on a remote server.
1189
%
1190
%  The format of the OpenDistributePixelCache method is:
1191
%
1192
%      MagickBooleanType *OpenDistributePixelCache(
1193
%        DistributeCacheInfo *server_info,Image *image)
1194
%
1195
%  A description of each parameter follows:
1196
%
1197
%    o server_info: the distributed cache info.
1198
%
1199
%    o image: the image.
1200
%
1201
*/
1202
MagickPrivate MagickBooleanType OpenDistributePixelCache(
1203
  DistributeCacheInfo *server_info,Image *image)
1204
0
{
1205
0
  MagickBooleanType
1206
0
    status;
1207
1208
0
  MagickOffsetType
1209
0
    count;
1210
1211
0
  unsigned char
1212
0
    message[MagickPathExtent],
1213
0
    *p;
1214
1215
  /*
1216
    Open distributed pixel cache.
1217
  */
1218
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1219
0
  assert(server_info->signature == MagickCoreSignature);
1220
0
  assert(image != (Image *) NULL);
1221
0
  assert(image->signature == MagickCoreSignature);
1222
0
  p=message;
1223
0
  *p++='o';  /* open */
1224
  /*
1225
    Serialize image attributes (see ValidatePixelCacheMorphology()).
1226
  */
1227
0
  (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1228
0
  p+=(ptrdiff_t) sizeof(server_info->session_key);
1229
0
  (void) memcpy(p,&image->storage_class,sizeof(image->storage_class));
1230
0
  p+=(ptrdiff_t) sizeof(image->storage_class);
1231
0
  (void) memcpy(p,&image->colorspace,sizeof(image->colorspace));
1232
0
  p+=(ptrdiff_t) sizeof(image->colorspace);
1233
0
  (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait));
1234
0
  p+=(ptrdiff_t) sizeof(image->alpha_trait);
1235
0
  (void) memcpy(p,&image->channels,sizeof(image->channels));
1236
0
  p+=(ptrdiff_t) sizeof(image->channels);
1237
0
  (void) memcpy(p,&image->columns,sizeof(image->columns));
1238
0
  p+=(ptrdiff_t) sizeof(image->columns);
1239
0
  (void) memcpy(p,&image->rows,sizeof(image->rows));
1240
0
  p+=(ptrdiff_t) sizeof(image->rows);
1241
0
  (void) memcpy(p,&image->number_channels,sizeof(image->number_channels));
1242
0
  p+=(ptrdiff_t) sizeof(image->number_channels);
1243
0
  (void) memcpy(p,image->channel_map,MaxPixelChannels*
1244
0
    sizeof(*image->channel_map));
1245
0
  p+=(ptrdiff_t) MaxPixelChannels*sizeof(*image->channel_map);
1246
0
  (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent));
1247
0
  p+=(ptrdiff_t) sizeof(image->metacontent_extent);
1248
0
  count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1249
0
  if (count != (MagickOffsetType) (p-message))
1250
0
    return(MagickFalse);
1251
0
  status=MagickFalse;
1252
0
  count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1253
0
  if (count != (MagickOffsetType) sizeof(status))
1254
0
    return(MagickFalse);
1255
0
  return(status);
1256
0
}
1257

1258
/*
1259
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1260
%                                                                             %
1261
%                                                                             %
1262
%                                                                             %
1263
+   R e a d D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t     %
1264
%                                                                             %
1265
%                                                                             %
1266
%                                                                             %
1267
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268
%
1269
%  ReadDistributePixelCacheMetacontents() reads metacontent from the specified
1270
%  region of the distributed pixel cache.
1271
%
1272
%  The format of the ReadDistributePixelCacheMetacontents method is:
1273
%
1274
%      MagickOffsetType ReadDistributePixelCacheMetacontents(
1275
%        DistributeCacheInfo *server_info,const RectangleInfo *region,
1276
%        const MagickSizeType length,unsigned char *metacontent)
1277
%
1278
%  A description of each parameter follows:
1279
%
1280
%    o server_info: the distributed cache info.
1281
%
1282
%    o image: the image.
1283
%
1284
%    o region: read the metacontent from this region of the image.
1285
%
1286
%    o length: the length in bytes of the metacontent.
1287
%
1288
%    o metacontent: read these metacontent from the pixel cache.
1289
%
1290
*/
1291
MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent(
1292
  DistributeCacheInfo *server_info,const RectangleInfo *region,
1293
  const MagickSizeType length,unsigned char *metacontent)
1294
0
{
1295
0
  MagickOffsetType
1296
0
    count;
1297
1298
0
  unsigned char
1299
0
    message[MagickPathExtent],
1300
0
    *p;
1301
1302
  /*
1303
    Read distributed pixel cache metacontent.
1304
  */
1305
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1306
0
  assert(server_info->signature == MagickCoreSignature);
1307
0
  assert(region != (RectangleInfo *) NULL);
1308
0
  assert(metacontent != (unsigned char *) NULL);
1309
0
  if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1310
0
    return(-1);
1311
0
  p=message;
1312
0
  *p++='R';
1313
0
  (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1314
0
  p+=(ptrdiff_t) sizeof(server_info->session_key);
1315
0
  (void) memcpy(p,&region->width,sizeof(region->width));
1316
0
  p+=(ptrdiff_t) sizeof(region->width);
1317
0
  (void) memcpy(p,&region->height,sizeof(region->height));
1318
0
  p+=(ptrdiff_t) sizeof(region->height);
1319
0
  (void) memcpy(p,&region->x,sizeof(region->x));
1320
0
  p+=(ptrdiff_t) sizeof(region->x);
1321
0
  (void) memcpy(p,&region->y,sizeof(region->y));
1322
0
  p+=(ptrdiff_t) sizeof(region->y);
1323
0
  (void) memcpy(p,&length,sizeof(length));
1324
0
  p+=(ptrdiff_t) sizeof(length);
1325
0
  count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1326
0
  if (count != (MagickOffsetType) (p-message))
1327
0
    return(-1);
1328
0
  return(dpc_read(server_info->file,length,metacontent));
1329
0
}
1330

1331
/*
1332
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333
%                                                                             %
1334
%                                                                             %
1335
%                                                                             %
1336
+   R e a d D i s t r i b u t e P i x e l C a c h e P i x e l s               %
1337
%                                                                             %
1338
%                                                                             %
1339
%                                                                             %
1340
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341
%
1342
%  ReadDistributePixelCachePixels() reads pixels from the specified region of
1343
%  the distributed pixel cache.
1344
%
1345
%  The format of the ReadDistributePixelCachePixels method is:
1346
%
1347
%      MagickOffsetType ReadDistributePixelCachePixels(
1348
%        DistributeCacheInfo *server_info,const RectangleInfo *region,
1349
%        const MagickSizeType length,unsigned char *magick_restrict pixels)
1350
%
1351
%  A description of each parameter follows:
1352
%
1353
%    o server_info: the distributed cache info.
1354
%
1355
%    o image: the image.
1356
%
1357
%    o region: read the pixels from this region of the image.
1358
%
1359
%    o length: the length in bytes of the pixels.
1360
%
1361
%    o pixels: read these pixels from the pixel cache.
1362
%
1363
*/
1364
MagickPrivate MagickOffsetType ReadDistributePixelCachePixels(
1365
  DistributeCacheInfo *server_info,const RectangleInfo *region,
1366
  const MagickSizeType length,unsigned char *magick_restrict pixels)
1367
0
{
1368
0
  MagickOffsetType
1369
0
    count;
1370
1371
0
  unsigned char
1372
0
    message[MagickPathExtent],
1373
0
    *p;
1374
1375
  /*
1376
    Read distributed pixel cache pixels.
1377
  */
1378
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1379
0
  assert(server_info->signature == MagickCoreSignature);
1380
0
  assert(region != (RectangleInfo *) NULL);
1381
0
  assert(pixels != (unsigned char *) NULL);
1382
0
  if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1383
0
    return(-1);
1384
0
  p=message;
1385
0
  *p++='r';
1386
0
  (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1387
0
  p+=(ptrdiff_t) sizeof(server_info->session_key);
1388
0
  (void) memcpy(p,&region->width,sizeof(region->width));
1389
0
  p+=(ptrdiff_t) sizeof(region->width);
1390
0
  (void) memcpy(p,&region->height,sizeof(region->height));
1391
0
  p+=(ptrdiff_t) sizeof(region->height);
1392
0
  (void) memcpy(p,&region->x,sizeof(region->x));
1393
0
  p+=(ptrdiff_t) sizeof(region->x);
1394
0
  (void) memcpy(p,&region->y,sizeof(region->y));
1395
0
  p+=(ptrdiff_t) sizeof(region->y);
1396
0
  (void) memcpy(p,&length,sizeof(length));
1397
0
  p+=(ptrdiff_t) sizeof(length);
1398
0
  count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1399
0
  if (count != (MagickOffsetType) (p-message))
1400
0
    return(-1);
1401
0
  return(dpc_read(server_info->file,length,pixels));
1402
0
}
1403

1404
/*
1405
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406
%                                                                             %
1407
%                                                                             %
1408
%                                                                             %
1409
+   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               %
1410
%                                                                             %
1411
%                                                                             %
1412
%                                                                             %
1413
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414
%
1415
%  RelinquishDistributePixelCache() frees resources acquired with
1416
%  OpenDistributePixelCache().
1417
%
1418
%  The format of the RelinquishDistributePixelCache method is:
1419
%
1420
%      MagickBooleanType RelinquishDistributePixelCache(
1421
%        DistributeCacheInfo *server_info)
1422
%
1423
%  A description of each parameter follows:
1424
%
1425
%    o server_info: the distributed cache info.
1426
%
1427
*/
1428
MagickPrivate MagickBooleanType RelinquishDistributePixelCache(
1429
  DistributeCacheInfo *server_info)
1430
0
{
1431
0
  MagickBooleanType
1432
0
    status;
1433
1434
0
  MagickOffsetType
1435
0
    count;
1436
1437
0
  unsigned char
1438
0
    message[MagickPathExtent],
1439
0
    *p;
1440
1441
  /*
1442
    Delete distributed pixel cache.
1443
  */
1444
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1445
0
  assert(server_info->signature == MagickCoreSignature);
1446
0
  p=message;
1447
0
  *p++='d';
1448
0
  (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1449
0
  p+=(ptrdiff_t) sizeof(server_info->session_key);
1450
0
  count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1451
0
  if (count != (MagickOffsetType) (p-message))
1452
0
    return(MagickFalse);
1453
0
  status=MagickFalse;
1454
0
  count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status);
1455
0
  if (count != (MagickOffsetType) sizeof(status))
1456
0
    return(MagickFalse);
1457
0
  return(status);
1458
0
}
1459

1460
/*
1461
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462
%                                                                             %
1463
%                                                                             %
1464
%                                                                             %
1465
+   W r i t e D i s t r i b u t e P i x e l C a c h e M e t a c o n t e n t   %
1466
%                                                                             %
1467
%                                                                             %
1468
%                                                                             %
1469
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1470
%
1471
%  WriteDistributePixelCacheMetacontents() writes image metacontent to the
1472
%  specified region of the distributed pixel cache.
1473
%
1474
%  The format of the WriteDistributePixelCacheMetacontents method is:
1475
%
1476
%      MagickOffsetType WriteDistributePixelCacheMetacontents(
1477
%        DistributeCacheInfo *server_info,const RectangleInfo *region,
1478
%        const MagickSizeType length,const unsigned char *metacontent)
1479
%
1480
%  A description of each parameter follows:
1481
%
1482
%    o server_info: the distributed cache info.
1483
%
1484
%    o image: the image.
1485
%
1486
%    o region: write the metacontent to this region of the image.
1487
%
1488
%    o length: the length in bytes of the metacontent.
1489
%
1490
%    o metacontent: write these metacontent to the pixel cache.
1491
%
1492
*/
1493
MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent(
1494
  DistributeCacheInfo *server_info,const RectangleInfo *region,
1495
  const MagickSizeType length,const unsigned char *metacontent)
1496
0
{
1497
0
  MagickOffsetType
1498
0
    count;
1499
1500
0
  unsigned char
1501
0
    message[MagickPathExtent],
1502
0
    *p;
1503
1504
  /*
1505
    Write distributed pixel cache metacontent.
1506
  */
1507
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1508
0
  assert(server_info->signature == MagickCoreSignature);
1509
0
  assert(region != (RectangleInfo *) NULL);
1510
0
  assert(metacontent != (unsigned char *) NULL);
1511
0
  if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1512
0
    return(-1);
1513
0
  p=message;
1514
0
  *p++='W';
1515
0
  (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1516
0
  p+=(ptrdiff_t) sizeof(server_info->session_key);
1517
0
  (void) memcpy(p,&region->width,sizeof(region->width));
1518
0
  p+=(ptrdiff_t) sizeof(region->width);
1519
0
  (void) memcpy(p,&region->height,sizeof(region->height));
1520
0
  p+=(ptrdiff_t) sizeof(region->height);
1521
0
  (void) memcpy(p,&region->x,sizeof(region->x));
1522
0
  p+=(ptrdiff_t) sizeof(region->x);
1523
0
  (void) memcpy(p,&region->y,sizeof(region->y));
1524
0
  p+=(ptrdiff_t) sizeof(region->y);
1525
0
  (void) memcpy(p,&length,sizeof(length));
1526
0
  p+=(ptrdiff_t) sizeof(length);
1527
0
  count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1528
0
  if (count != (MagickOffsetType) (p-message))
1529
0
    return(-1);
1530
0
  return(dpc_send(server_info->file,length,metacontent));
1531
0
}
1532

1533
/*
1534
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535
%                                                                             %
1536
%                                                                             %
1537
%                                                                             %
1538
+   W r i t e D i s t r i b u t e P i x e l C a c h e P i x e l s             %
1539
%                                                                             %
1540
%                                                                             %
1541
%                                                                             %
1542
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543
%
1544
%  WriteDistributePixelCachePixels() writes image pixels to the specified
1545
%  region of the distributed pixel cache.
1546
%
1547
%  The format of the WriteDistributePixelCachePixels method is:
1548
%
1549
%      MagickBooleanType WriteDistributePixelCachePixels(
1550
%        DistributeCacheInfo *server_info,const RectangleInfo *region,
1551
%        const MagickSizeType length,
1552
%        const unsigned char *magick_restrict pixels)
1553
%
1554
%  A description of each parameter follows:
1555
%
1556
%    o server_info: the distributed cache info.
1557
%
1558
%    o image: the image.
1559
%
1560
%    o region: write the pixels to this region of the image.
1561
%
1562
%    o length: the length in bytes of the pixels.
1563
%
1564
%    o pixels: write these pixels to the pixel cache.
1565
%
1566
*/
1567
MagickPrivate MagickOffsetType WriteDistributePixelCachePixels(
1568
  DistributeCacheInfo *server_info,const RectangleInfo *region,
1569
  const MagickSizeType length,const unsigned char *magick_restrict pixels)
1570
0
{
1571
0
  MagickOffsetType
1572
0
    count;
1573
1574
0
  unsigned char
1575
0
    message[MagickPathExtent],
1576
0
    *p;
1577
1578
  /*
1579
    Write distributed pixel cache pixels.
1580
  */
1581
0
  assert(server_info != (DistributeCacheInfo *) NULL);
1582
0
  assert(server_info->signature == MagickCoreSignature);
1583
0
  assert(region != (RectangleInfo *) NULL);
1584
0
  assert(pixels != (const unsigned char *) NULL);
1585
0
  if (length > (MagickSizeType) MAGICK_SSIZE_MAX)
1586
0
    return(-1);
1587
0
  p=message;
1588
0
  *p++='w';
1589
0
  (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key));
1590
0
  p+=(ptrdiff_t) sizeof(server_info->session_key);
1591
0
  (void) memcpy(p,&region->width,sizeof(region->width));
1592
0
  p+=(ptrdiff_t) sizeof(region->width);
1593
0
  (void) memcpy(p,&region->height,sizeof(region->height));
1594
0
  p+=(ptrdiff_t) sizeof(region->height);
1595
0
  (void) memcpy(p,&region->x,sizeof(region->x));
1596
0
  p+=(ptrdiff_t) sizeof(region->x);
1597
0
  (void) memcpy(p,&region->y,sizeof(region->y));
1598
0
  p+=(ptrdiff_t) sizeof(region->y);
1599
0
  (void) memcpy(p,&length,sizeof(length));
1600
0
  p+=(ptrdiff_t) sizeof(length);
1601
0
  count=dpc_send(server_info->file,(MagickSizeType) (p-message),message);
1602
0
  if (count != (MagickOffsetType) (p-message))
1603
0
    return(-1);
1604
0
  return(dpc_send(server_info->file,length,pixels));
1605
0
}