distribute-cache.c revision 8155c1010f07e0f6a2598524957844fc45af15e6
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% John Cristy % 22% January 2013 % 23% % 24% % 25% Copyright 1999-2013 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% http://www.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/list.h" 64#include "MagickCore/locale_.h" 65#include "MagickCore/memory_.h" 66#include "MagickCore/nt-base-private.h" 67#include "MagickCore/pixel.h" 68#include "MagickCore/policy.h" 69#include "MagickCore/random_.h" 70#include "MagickCore/registry.h" 71#include "MagickCore/splay-tree.h" 72#include "MagickCore/string_.h" 73#include "MagickCore/string-private.h" 74#include "MagickCore/version.h" 75#include "MagickCore/version-private.h" 76#if defined(MAGICKCORE_HAVE_SOCKET) 77#include <netinet/in.h> 78#include <netdb.h> 79#include <sys/socket.h> 80#include <arpa/inet.h> 81#endif 82 83/* 84 Define declarations. 85*/ 86#define DPCHostname "127.0.0.1" 87#define DPCPendingConnections 10 88#define DPCPort 6668 89#define DPCSessionKeyLength 8 90#ifndef MSG_NOSIGNAL 91# define MSG_NOSIGNAL 0 92#endif 93 94/* 95%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 96% % 97% % 98% % 99+ 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 % 100% % 101% % 102% % 103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 104% 105% AcquireDistributeCacheInfo() allocates the DistributeCacheInfo structure. 106% 107% The format of the AcquireDistributeCacheInfo method is: 108% 109% DistributeCacheInfo *AcquireDistributeCacheInfo(ExceptionInfo *exception) 110% 111% A description of each parameter follows: 112% 113% o exception: return any errors or warnings in this structure. 114% 115*/ 116 117static inline MagickSizeType MagickMin(const MagickSizeType x, 118 const MagickSizeType y) 119{ 120 if (x < y) 121 return(x); 122 return(y); 123} 124 125static inline MagickOffsetType dpc_read(int file,const MagickSizeType length, 126 unsigned char *restrict message) 127{ 128 register MagickOffsetType 129 i; 130 131 ssize_t 132 count; 133 134 count=0; 135 for (i=0; i < (MagickOffsetType) length; i+=count) 136 { 137 count=recv(file,message+i,(size_t) MagickMin(length-i,(MagickSizeType) 138 SSIZE_MAX),0); 139 if (count <= 0) 140 { 141 count=0; 142 if (errno != EINTR) 143 break; 144 } 145 } 146 return(i); 147} 148 149static int ConnectPixelCacheServer(const char *hostname,const int port, 150 size_t *session_key,ExceptionInfo *exception) 151{ 152#if defined(MAGICKCORE_HAVE_SOCKET) 153 char 154 service[MaxTextExtent]; 155 156 const char 157 *shared_secret; 158 159 int 160 client_socket, 161 status; 162 163 ssize_t 164 count; 165 166 struct addrinfo 167 hint, 168 *result; 169 170 unsigned char 171 secret[MaxTextExtent]; 172 173 /* 174 Connect to distributed pixel cache and get session key. 175 */ 176 *session_key=0; 177 shared_secret=GetPolicyValue("shared-secret"); 178 if (shared_secret == (const char *) NULL) 179 { 180 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 181 "DistributedPixelCache","'%s'","shared secret expected"); 182 return(-1); 183 } 184 (void) ResetMagickMemory(&hint,0,sizeof(hint)); 185 hint.ai_family=AF_INET; 186 hint.ai_socktype=SOCK_STREAM; 187 hint.ai_flags=AI_PASSIVE; 188 (void) FormatLocaleString(service,MaxTextExtent,"%d",port); 189 status=getaddrinfo(hostname,service,&hint,&result); 190 if (status != 0) 191 { 192 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 193 "DistributedPixelCache","'%s'",hostname); 194 return(-1); 195 } 196 client_socket=socket(result->ai_family,result->ai_socktype, 197 result->ai_protocol); 198 if (client_socket == -1) 199 { 200 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 201 "DistributedPixelCache","'%s'",hostname); 202 return(-1); 203 } 204 status=connect(client_socket,result->ai_addr,result->ai_addrlen); 205 if (status == -1) 206 { 207 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 208 "DistributedPixelCache","'%s'",hostname); 209 return(-1); 210 } 211 count=recv(client_socket,secret,MaxTextExtent,0); 212 if (count != -1) 213 { 214 StringInfo 215 *nonce; 216 217 nonce=AcquireStringInfo(count); 218 (void) memcpy(GetStringInfoDatum(nonce),secret,(size_t) count); 219 *session_key=GetMagickSignature(nonce); 220 nonce=DestroyStringInfo(nonce); 221 } 222 if (*session_key == 0) 223 { 224 close(client_socket); 225 client_socket=(-1); 226 } 227 return(client_socket); 228#else 229 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 230 "DelegateLibrarySupportNotBuiltIn","distributed pixel cache"); 231 return(MagickFalse); 232#endif 233} 234 235static char *GetHostname(int *port,ExceptionInfo *exception) 236{ 237 char 238 *host, 239 *hosts, 240 **hostlist; 241 242 int 243 argc; 244 245 register ssize_t 246 i; 247 248 static size_t 249 id = 0; 250 251 /* 252 Parse host list (e.g. 192.168.100.1:6668,192.168.100.2:6668). 253 */ 254 hosts=(char *) GetImageRegistry(StringRegistryType,"cache:hosts", 255 exception); 256 if (hosts == (char *) NULL) 257 { 258 *port=DPCPort; 259 return(AcquireString(DPCHostname)); 260 } 261 (void) SubstituteString(&hosts,","," "); 262 hostlist=StringToArgv(hosts,&argc); 263 hosts=DestroyString(hosts); 264 if (hostlist == (char **) NULL) 265 { 266 *port=DPCPort; 267 return(AcquireString(DPCHostname)); 268 } 269 hosts=AcquireString(hostlist[(id++ % (argc-1))+1]); 270 for (i=0; i < (ssize_t) argc; i++) 271 hostlist[i]=DestroyString(hostlist[i]); 272 hostlist=(char **) RelinquishMagickMemory(hostlist); 273 (void) SubstituteString(&hosts,":"," "); 274 hostlist=StringToArgv(hosts,&argc); 275 if (hostlist == (char **) NULL) 276 { 277 *port=DPCPort; 278 return(AcquireString(DPCHostname)); 279 } 280 host=AcquireString(hostlist[1]); 281 if (hostlist[2] == (char *) NULL) 282 *port=DPCPort; 283 else 284 *port=StringToLong(hostlist[2]); 285 for (i=0; i < (ssize_t) argc; i++) 286 hostlist[i]=DestroyString(hostlist[i]); 287 hostlist=(char **) RelinquishMagickMemory(hostlist); 288 return(host); 289} 290 291MagickPrivate DistributeCacheInfo *AcquireDistributeCacheInfo( 292 ExceptionInfo *exception) 293{ 294 char 295 *hostname; 296 297 DistributeCacheInfo 298 *server_info; 299 300 size_t 301 session_key; 302 303 /* 304 Connect to the distributed pixel cache server. 305 */ 306 server_info=(DistributeCacheInfo *) AcquireMagickMemory(sizeof(*server_info)); 307 if (server_info == (DistributeCacheInfo *) NULL) 308 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 309 (void) ResetMagickMemory(server_info,0,sizeof(*server_info)); 310 server_info->signature=MagickSignature; 311 server_info->port=0; 312 hostname=GetHostname(&server_info->port,exception); 313 session_key=0; 314 server_info->file=ConnectPixelCacheServer(hostname,server_info->port, 315 &session_key,exception); 316 server_info->session_key=session_key; 317 (void) CopyMagickString(server_info->hostname,hostname,MaxTextExtent); 318 hostname=DestroyString(hostname); 319 if (server_info->file == -1) 320 server_info=DestroyDistributeCacheInfo(server_info); 321 return(server_info); 322} 323 324/* 325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 326% % 327% % 328% % 329+ 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 % 330% % 331% % 332% % 333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 334% 335% DestroyDistributeCacheInfo() deallocates memory associated with an 336% DistributeCacheInfo structure. 337% 338% The format of the DestroyDistributeCacheInfo method is: 339% 340% DistributeCacheInfo *DestroyDistributeCacheInfo( 341% DistributeCacheInfo *server_info) 342% 343% A description of each parameter follows: 344% 345% o server_info: the distributed cache info. 346% 347*/ 348MagickPrivate DistributeCacheInfo *DestroyDistributeCacheInfo( 349 DistributeCacheInfo *server_info) 350{ 351 assert(server_info != (DistributeCacheInfo *) NULL); 352 assert(server_info->signature == MagickSignature); 353 if (server_info->file > 0) 354 (void) close(server_info->file); 355 server_info->signature=(~MagickSignature); 356 server_info=(DistributeCacheInfo *) RelinquishMagickMemory(server_info); 357 return(server_info); 358} 359 360/* 361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 362% % 363% % 364% % 365+ 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 % 366% % 367% % 368% % 369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 370% 371% DistributePixelCacheServer() waits on the specified port for commands to 372% create, read, update, or destroy a pixel cache. 373% 374% The format of the DistributePixelCacheServer() method is: 375% 376% void DistributePixelCacheServer(const int port) 377% 378% A description of each parameter follows: 379% 380% o port: connect the distributed pixel cache at this port. 381% 382% o exception: return any errors or warnings in this structure. 383% 384*/ 385 386static MagickBooleanType DestroyDistributeCache(SplayTreeInfo *registry, 387 int file,const size_t session_key) 388{ 389 /* 390 Destroy distributed pixel cache. 391 */ 392 return(DeleteNodeFromSplayTree(registry,(const void *) session_key)); 393} 394 395static inline MagickOffsetType dpc_send(int file,const MagickSizeType length, 396 const unsigned char *restrict message) 397{ 398 MagickOffsetType 399 count; 400 401 register MagickOffsetType 402 i; 403 404 /* 405 Ensure a complete message is sent. 406 */ 407 count=0; 408 for (i=0; i < (MagickOffsetType) length; i+=count) 409 { 410 count=(MagickOffsetType) send(file,message+i,(size_t) MagickMin(length-i, 411 (MagickSizeType) SSIZE_MAX),MSG_NOSIGNAL); 412 if (count <= 0) 413 { 414 count=0; 415 if (errno != EINTR) 416 break; 417 } 418 } 419 return(i); 420} 421 422static MagickBooleanType OpenDistributeCache(SplayTreeInfo *registry, 423 int file,const size_t session_key,ExceptionInfo *exception) 424{ 425 Image 426 *image; 427 428 MagickBooleanType 429 status; 430 431 MagickOffsetType 432 count; 433 434 MagickSizeType 435 length; 436 437 register unsigned char 438 *p; 439 440 unsigned char 441 message[MaxTextExtent]; 442 443 /* 444 Open distributed pixel cache. 445 */ 446 image=AcquireImage((ImageInfo *) NULL,exception); 447 if (image == (Image *) NULL) 448 return(MagickFalse); 449 length=sizeof(image->storage_class)+sizeof(image->colorspace)+ 450 sizeof(image->alpha_trait)+sizeof(image->mask)+sizeof(image->columns)+ 451 sizeof(image->rows)+sizeof(image->number_channels)+MaxPixelChannels* 452 sizeof(*image->channel_map)+sizeof(image->metacontent_extent); 453 count=dpc_read(file,length,message); 454 if (count != (MagickOffsetType) length) 455 return(MagickFalse); 456 /* 457 Deserialize the image attributes. 458 */ 459 p=message; 460 (void) memcpy(&image->storage_class,p,sizeof(image->storage_class)); 461 p+=sizeof(image->storage_class); 462 (void) memcpy(&image->colorspace,p,sizeof(image->colorspace)); 463 p+=sizeof(image->colorspace); 464 (void) memcpy(&image->alpha_trait,p,sizeof(image->alpha_trait)); 465 p+=sizeof(image->alpha_trait); 466 (void) memcpy(&image->mask,p,sizeof(image->mask)); 467 p+=sizeof(image->mask); 468 (void) memcpy(&image->columns,p,sizeof(image->columns)); 469 p+=sizeof(image->columns); 470 (void) memcpy(&image->rows,p,sizeof(image->rows)); 471 p+=sizeof(image->rows); 472 (void) memcpy(&image->number_channels,p,sizeof(image->number_channels)); 473 p+=sizeof(image->number_channels); 474 (void) memcpy(image->channel_map,p,MaxPixelChannels* 475 sizeof(*image->channel_map)); 476 p+=MaxPixelChannels*sizeof(*image->channel_map); 477 (void) memcpy(&image->metacontent_extent,p,sizeof(image->metacontent_extent)); 478 p+=sizeof(image->metacontent_extent); 479 if (SyncImagePixelCache(image,exception) == MagickFalse) 480 return(MagickFalse); 481 status=AddValueToSplayTree(registry,(const void *) session_key,image); 482 return(status); 483} 484 485static MagickBooleanType ReadDistributeCacheMetacontent(SplayTreeInfo *registry, 486 int file,const size_t session_key,ExceptionInfo *exception) 487{ 488 const unsigned char 489 *metacontent; 490 491 Image 492 *image; 493 494 MagickOffsetType 495 count; 496 497 MagickSizeType 498 length; 499 500 RectangleInfo 501 region; 502 503 register const Quantum 504 *p; 505 506 register unsigned char 507 *q; 508 509 unsigned char 510 message[MaxTextExtent]; 511 512 /* 513 Read distributed pixel cache metacontent. 514 */ 515 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key); 516 if (image == (Image *) NULL) 517 return(MagickFalse); 518 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+ 519 sizeof(region.y)+sizeof(length); 520 count=dpc_read(file,length,message); 521 if (count != (MagickOffsetType) length) 522 return(MagickFalse); 523 q=message; 524 (void) memcpy(®ion.width,q,sizeof(region.width)); 525 q+=sizeof(region.width); 526 (void) memcpy(®ion.height,q,sizeof(region.height)); 527 q+=sizeof(region.height); 528 (void) memcpy(®ion.x,q,sizeof(region.x)); 529 q+=sizeof(region.x); 530 (void) memcpy(®ion.y,q,sizeof(region.y)); 531 q+=sizeof(region.y); 532 (void) memcpy(&length,q,sizeof(length)); 533 q+=sizeof(length); 534 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height, 535 exception); 536 if (p == (const Quantum *) NULL) 537 return(MagickFalse); 538 metacontent=GetVirtualMetacontent(image); 539 count=dpc_send(file,length,metacontent); 540 if (count != (MagickOffsetType) length) 541 return(MagickFalse); 542 return(MagickTrue); 543} 544 545static MagickBooleanType ReadDistributeCachePixels(SplayTreeInfo *registry, 546 int file,const size_t session_key,ExceptionInfo *exception) 547{ 548 Image 549 *image; 550 551 MagickOffsetType 552 count; 553 554 MagickSizeType 555 length; 556 557 RectangleInfo 558 region; 559 560 register const Quantum 561 *p; 562 563 register unsigned char 564 *q; 565 566 unsigned char 567 message[MaxTextExtent]; 568 569 /* 570 Read distributed pixel cache pixels. 571 */ 572 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key); 573 if (image == (Image *) NULL) 574 return(MagickFalse); 575 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+ 576 sizeof(region.y)+sizeof(length); 577 count=dpc_read(file,length,message); 578 if (count != (MagickOffsetType) length) 579 return(MagickFalse); 580 q=message; 581 (void) memcpy(®ion.width,q,sizeof(region.width)); 582 q+=sizeof(region.width); 583 (void) memcpy(®ion.height,q,sizeof(region.height)); 584 q+=sizeof(region.height); 585 (void) memcpy(®ion.x,q,sizeof(region.x)); 586 q+=sizeof(region.x); 587 (void) memcpy(®ion.y,q,sizeof(region.y)); 588 q+=sizeof(region.y); 589 (void) memcpy(&length,q,sizeof(length)); 590 q+=sizeof(length); 591 p=GetVirtualPixels(image,region.x,region.y,region.width,region.height, 592 exception); 593 if (p == (const Quantum *) NULL) 594 return(MagickFalse); 595 count=dpc_send(file,length,(unsigned char *) p); 596 if (count != (MagickOffsetType) length) 597 return(MagickFalse); 598 return(MagickTrue); 599} 600 601static void *RelinquishImageRegistry(void *image) 602{ 603 return((void *) DestroyImageList((Image *) image)); 604} 605 606static MagickBooleanType WriteDistributeCacheMetacontent( 607 SplayTreeInfo *registry,int file,const size_t session_key, 608 ExceptionInfo *exception) 609{ 610 Image 611 *image; 612 613 MagickOffsetType 614 count; 615 616 MagickSizeType 617 length; 618 619 RectangleInfo 620 region; 621 622 register Quantum 623 *q; 624 625 register unsigned char 626 *p; 627 628 unsigned char 629 message[MaxTextExtent], 630 *metacontent; 631 632 /* 633 Write distributed pixel cache metacontent. 634 */ 635 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key); 636 if (image == (Image *) NULL) 637 return(MagickFalse); 638 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+ 639 sizeof(region.y)+sizeof(length); 640 count=dpc_read(file,length,message); 641 if (count != (MagickOffsetType) length) 642 return(MagickFalse); 643 p=message; 644 (void) memcpy(®ion.width,p,sizeof(region.width)); 645 p+=sizeof(region.width); 646 (void) memcpy(®ion.height,p,sizeof(region.height)); 647 p+=sizeof(region.height); 648 (void) memcpy(®ion.x,p,sizeof(region.x)); 649 p+=sizeof(region.x); 650 (void) memcpy(®ion.y,p,sizeof(region.y)); 651 p+=sizeof(region.y); 652 (void) memcpy(&length,p,sizeof(length)); 653 p+=sizeof(length); 654 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height, 655 exception); 656 if (q == (Quantum *) NULL) 657 return(MagickFalse); 658 metacontent=GetAuthenticMetacontent(image); 659 count=dpc_read(file,length,metacontent); 660 if (count != (MagickOffsetType) length) 661 return(MagickFalse); 662 return(SyncAuthenticPixels(image,exception)); 663} 664 665static MagickBooleanType WriteDistributeCachePixels(SplayTreeInfo *registry, 666 int file,const size_t session_key,ExceptionInfo *exception) 667{ 668 Image 669 *image; 670 671 MagickOffsetType 672 count; 673 674 MagickSizeType 675 length; 676 677 RectangleInfo 678 region; 679 680 register Quantum 681 *q; 682 683 register unsigned char 684 *p; 685 686 unsigned char 687 message[MaxTextExtent]; 688 689 /* 690 Write distributed pixel cache pixels. 691 */ 692 image=(Image *) GetValueFromSplayTree(registry,(const void *) session_key); 693 if (image == (Image *) NULL) 694 return(MagickFalse); 695 length=sizeof(region.width)+sizeof(region.height)+sizeof(region.x)+ 696 sizeof(region.y)+sizeof(length); 697 count=dpc_read(file,length,message); 698 if (count != (MagickOffsetType) length) 699 return(MagickFalse); 700 p=message; 701 (void) memcpy(®ion.width,p,sizeof(region.width)); 702 p+=sizeof(region.width); 703 (void) memcpy(®ion.height,p,sizeof(region.height)); 704 p+=sizeof(region.height); 705 (void) memcpy(®ion.x,p,sizeof(region.x)); 706 p+=sizeof(region.x); 707 (void) memcpy(®ion.y,p,sizeof(region.y)); 708 p+=sizeof(region.y); 709 (void) memcpy(&length,p,sizeof(length)); 710 p+=sizeof(length); 711 q=GetAuthenticPixels(image,region.x,region.y,region.width,region.height, 712 exception); 713 if (q == (Quantum *) NULL) 714 return(MagickFalse); 715 count=dpc_read(file,length,(unsigned char *) q); 716 if (count != (MagickOffsetType) length) 717 return(MagickFalse); 718 return(SyncAuthenticPixels(image,exception)); 719} 720 721static void *DistributePixelCacheClient(void *socket) 722{ 723 const char 724 *shared_secret; 725 726 ExceptionInfo 727 *exception; 728 729 int 730 client_socket; 731 732 MagickBooleanType 733 status; 734 735 MagickOffsetType 736 count; 737 738 register unsigned char 739 *p; 740 741 RandomInfo 742 *random_info; 743 744 size_t 745 key, 746 session_key; 747 748 SplayTreeInfo 749 *registry; 750 751 StringInfo 752 *secret; 753 754 unsigned char 755 command, 756 session[2*MaxTextExtent]; 757 758 /* 759 Distributed pixel cache client. 760 */ 761 shared_secret=GetPolicyValue("shared-secret"); 762 if (shared_secret == (const char *) NULL) 763 ThrowFatalException(CacheFatalError,"shared secret expected"); 764 p=session; 765 (void) CopyMagickString((char *) p,shared_secret,MaxTextExtent); 766 p+=strlen(shared_secret); 767 random_info=AcquireRandomInfo(); 768 secret=GetRandomKey(random_info,DPCSessionKeyLength); 769 (void) memcpy(p,GetStringInfoDatum(secret),DPCSessionKeyLength); 770 session_key=GetMagickSignature(secret); 771 random_info=DestroyRandomInfo(random_info); 772 exception=AcquireExceptionInfo(); 773 registry=NewSplayTree((int (*)(const void *,const void *)) NULL, 774 (void *(*)(void *)) NULL,RelinquishImageRegistry); 775 client_socket=(*(int *) socket); 776 count=dpc_send(client_socket,DPCSessionKeyLength,GetStringInfoDatum(secret)); 777 secret=DestroyStringInfo(secret); 778 for ( ; ; ) 779 { 780 count=dpc_read(client_socket,1,(unsigned char *) &command); 781 if (count <= 0) 782 break; 783 count=dpc_read(client_socket,sizeof(key),(unsigned char *) &key); 784 if ((count != (MagickOffsetType) sizeof(key)) || (key != session_key)) 785 break; 786 status=MagickFalse; 787 switch (command) 788 { 789 case 'o': 790 { 791 status=OpenDistributeCache(registry,client_socket,session_key, 792 exception); 793 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status); 794 break; 795 } 796 case 'r': 797 { 798 status=ReadDistributeCachePixels(registry,client_socket,session_key, 799 exception); 800 break; 801 } 802 case 'R': 803 { 804 status=ReadDistributeCacheMetacontent(registry,client_socket, 805 session_key,exception); 806 break; 807 } 808 case 'w': 809 { 810 status=WriteDistributeCachePixels(registry,client_socket,session_key, 811 exception); 812 break; 813 } 814 case 'W': 815 { 816 status=WriteDistributeCacheMetacontent(registry,client_socket, 817 session_key,exception); 818 break; 819 } 820 case 'd': 821 { 822 status=DestroyDistributeCache(registry,client_socket,session_key); 823 break; 824 } 825 default: 826 break; 827 } 828 if (status == MagickFalse) 829 break; 830 if (command == 'd') 831 break; 832 } 833 count=dpc_send(client_socket,sizeof(status),(unsigned char *) &status); 834 (void) close(client_socket); 835 exception=DestroyExceptionInfo(exception); 836 registry=DestroySplayTree(registry); 837 return((void *) NULL); 838} 839 840MagickExport void DistributePixelCacheServer(const int port, 841 ExceptionInfo *exception) 842{ 843#if defined(MAGICKCORE_HAVE_SOCKET) && defined(MAGICKCORE_THREAD_SUPPORT) 844 char 845 service[MaxTextExtent]; 846 847 int 848 server_socket, 849 status; 850 851 pthread_attr_t 852 attributes; 853 854 pthread_t 855 threads; 856 857 register struct addrinfo 858 *p; 859 860 struct addrinfo 861 hint, 862 *result; 863 864 struct sockaddr_in 865 address; 866 867 /* 868 Launch distributed pixel cache server. 869 */ 870 (void) ResetMagickMemory(&hint,0,sizeof(hint)); 871 hint.ai_family=AF_INET; 872 hint.ai_socktype=SOCK_STREAM; 873 hint.ai_flags=AI_PASSIVE; 874 (void) FormatLocaleString(service,MaxTextExtent,"%d",port); 875 status=getaddrinfo((const char *) NULL,service,&hint,&result); 876 if (status != 0) 877 ThrowFatalException(CacheFatalError,"UnableToListen"); 878 server_socket=0; 879 for (p=result; p != (struct addrinfo *) NULL; p=p->ai_next) 880 { 881 int 882 one; 883 884 server_socket=socket(p->ai_family,p->ai_socktype,p->ai_protocol); 885 if (server_socket == -1) 886 continue; 887 one=1; 888 status=setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t) 889 sizeof(one)); 890 if (status == -1) 891 continue; 892 status=bind(server_socket,p->ai_addr,p->ai_addrlen); 893 if (status == -1) 894 { 895 (void) close(status); 896 continue; 897 } 898 break; 899 } 900 if (p == (struct addrinfo *) NULL) 901 ThrowFatalException(CacheFatalError,"UnableToBind"); 902 freeaddrinfo(result); 903 status=listen(server_socket,DPCPendingConnections); 904 if (status != 0) 905 ThrowFatalException(CacheFatalError,"UnableToListen"); 906 pthread_attr_init(&attributes); 907 for ( ; ; ) 908 { 909 int 910 client_socket; 911 912 socklen_t 913 length; 914 915 length=(socklen_t) sizeof(address); 916 client_socket=accept(server_socket,(struct sockaddr *) &address,&length); 917 if (client_socket == -1) 918 ThrowFatalException(CacheFatalError,"UnableToEstablishConnection"); 919 status=pthread_create(&threads,&attributes,DistributePixelCacheClient, 920 (void *) &client_socket); 921 if (status == -1) 922 ThrowFatalException(CacheFatalError,"UnableToCreateClientThread"); 923 } 924 (void) close(server_socket); 925#else 926 ThrowFatalException(MissingDelegateError,"distributed pixel cache"); 927#endif 928} 929 930/* 931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 932% % 933% % 934% % 935+ G e t D i s t r i b u t e C a c h e F i l e % 936% % 937% % 938% % 939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 940% 941% GetDistributeCacheFile() returns the file associated with this 942% DistributeCacheInfo structure. 943% 944% The format of the GetDistributeCacheFile method is: 945% 946% int GetDistributeCacheFile(const DistributeCacheInfo *server_info) 947% 948% A description of each parameter follows: 949% 950% o server_info: the distributed cache info. 951% 952*/ 953MagickPrivate int GetDistributeCacheFile(const DistributeCacheInfo *server_info) 954{ 955 assert(server_info != (DistributeCacheInfo *) NULL); 956 assert(server_info->signature == MagickSignature); 957 return(server_info->file); 958} 959 960/* 961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 962% % 963% % 964% % 965+ 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 % 966% % 967% % 968% % 969%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 970% 971% GetDistributeCacheHostname() returns the hostname associated with this 972% DistributeCacheInfo structure. 973% 974% The format of the GetDistributeCacheHostname method is: 975% 976% const char *GetDistributeCacheHostname( 977% const DistributeCacheInfo *server_info) 978% 979% A description of each parameter follows: 980% 981% o server_info: the distributed cache info. 982% 983*/ 984MagickPrivate const char *GetDistributeCacheHostname( 985 const DistributeCacheInfo *server_info) 986{ 987 assert(server_info != (DistributeCacheInfo *) NULL); 988 assert(server_info->signature == MagickSignature); 989 return(server_info->hostname); 990} 991 992/* 993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 994% % 995% % 996% % 997+ G e t D i s t r i b u t e C a c h e P o r t % 998% % 999% % 1000% % 1001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1002% 1003% GetDistributeCachePort() returns the port associated with this 1004% DistributeCacheInfo structure. 1005% 1006% The format of the GetDistributeCachePort method is: 1007% 1008% int GetDistributeCachePort(const DistributeCacheInfo *server_info) 1009% 1010% A description of each parameter follows: 1011% 1012% o server_info: the distributed cache info. 1013% 1014*/ 1015MagickPrivate int GetDistributeCachePort(const DistributeCacheInfo *server_info) 1016{ 1017 assert(server_info != (DistributeCacheInfo *) NULL); 1018 assert(server_info->signature == MagickSignature); 1019 return(server_info->port); 1020} 1021 1022/* 1023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1024% % 1025% % 1026% % 1027+ O p e n D i s t r i b u t e P i x e l C a c h e % 1028% % 1029% % 1030% % 1031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1032% 1033% OpenDistributePixelCache() opens a pixel cache on a remote server. 1034% 1035% The format of the OpenDistributePixelCache method is: 1036% 1037% MagickBooleanType *OpenDistributePixelCache( 1038% DistributeCacheInfo *server_info,Image *image) 1039% 1040% A description of each parameter follows: 1041% 1042% o server_info: the distributed cache info. 1043% 1044% o image: the image. 1045% 1046*/ 1047MagickPrivate MagickBooleanType OpenDistributePixelCache( 1048 DistributeCacheInfo *server_info,Image *image) 1049{ 1050 MagickBooleanType 1051 status; 1052 1053 MagickOffsetType 1054 count; 1055 1056 register unsigned char 1057 *p; 1058 1059 unsigned char 1060 message[MaxTextExtent]; 1061 1062 /* 1063 Open distributed pixel cache. 1064 */ 1065 assert(server_info != (DistributeCacheInfo *) NULL); 1066 assert(server_info->signature == MagickSignature); 1067 assert(image != (Image *) NULL); 1068 assert(image->signature == MagickSignature); 1069 p=message; 1070 *p++='o'; /* open */ 1071 /* 1072 Serialize image attributes (see ValidatePixelCacheMorphology()). 1073 */ 1074 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key)); 1075 p+=sizeof(server_info->session_key); 1076 (void) memcpy(p,&image->storage_class,sizeof(image->storage_class)); 1077 p+=sizeof(image->storage_class); 1078 (void) memcpy(p,&image->colorspace,sizeof(image->colorspace)); 1079 p+=sizeof(image->colorspace); 1080 (void) memcpy(p,&image->alpha_trait,sizeof(image->alpha_trait)); 1081 p+=sizeof(image->alpha_trait); 1082 (void) memcpy(p,&image->mask,sizeof(image->mask)); 1083 p+=sizeof(image->mask); 1084 (void) memcpy(p,&image->columns,sizeof(image->columns)); 1085 p+=sizeof(image->columns); 1086 (void) memcpy(p,&image->rows,sizeof(image->rows)); 1087 p+=sizeof(image->rows); 1088 (void) memcpy(p,&image->number_channels,sizeof(image->number_channels)); 1089 p+=sizeof(image->number_channels); 1090 (void) memcpy(p,image->channel_map,MaxPixelChannels* 1091 sizeof(*image->channel_map)); 1092 p+=MaxPixelChannels*sizeof(*image->channel_map); 1093 (void) memcpy(p,&image->metacontent_extent,sizeof(image->metacontent_extent)); 1094 p+=sizeof(image->metacontent_extent); 1095 count=dpc_send(server_info->file,p-message,message); 1096 if (count != (MagickOffsetType) (p-message)) 1097 return(MagickFalse); 1098 status=MagickFalse; 1099 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status); 1100 if (count != (MagickOffsetType) sizeof(status)) 1101 return(MagickFalse); 1102 return(status); 1103} 1104 1105/* 1106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1107% % 1108% % 1109% % 1110+ 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 % 1111% % 1112% % 1113% % 1114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1115% 1116% ReadDistributePixelCacheMetacontents() reads metacontent from the specified 1117% region of the distributed pixel cache. 1118% 1119% The format of the ReadDistributePixelCacheMetacontents method is: 1120% 1121% MagickOffsetType ReadDistributePixelCacheMetacontents( 1122% DistributeCacheInfo *server_info,const RectangleInfo *region, 1123% const MagickSizeType length,unsigned char *metacontent) 1124% 1125% A description of each parameter follows: 1126% 1127% o server_info: the distributed cache info. 1128% 1129% o image: the image. 1130% 1131% o region: read the metacontent from this region of the image. 1132% 1133% o length: the length in bytes of the metacontent. 1134% 1135% o metacontent: read these metacontent from the pixel cache. 1136% 1137*/ 1138MagickPrivate MagickOffsetType ReadDistributePixelCacheMetacontent( 1139 DistributeCacheInfo *server_info,const RectangleInfo *region, 1140 const MagickSizeType length,unsigned char *metacontent) 1141{ 1142 MagickOffsetType 1143 count; 1144 1145 register unsigned char 1146 *p; 1147 1148 unsigned char 1149 message[MaxTextExtent]; 1150 1151 /* 1152 Read distributed pixel cache metacontent. 1153 */ 1154 assert(server_info != (DistributeCacheInfo *) NULL); 1155 assert(server_info->signature == MagickSignature); 1156 assert(region != (RectangleInfo *) NULL); 1157 assert(metacontent != (unsigned char *) NULL); 1158 if (length > (MagickSizeType) SSIZE_MAX) 1159 return(-1); 1160 p=message; 1161 *p++='R'; 1162 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key)); 1163 p+=sizeof(server_info->session_key); 1164 (void) memcpy(p,®ion->width,sizeof(region->width)); 1165 p+=sizeof(region->width); 1166 (void) memcpy(p,®ion->height,sizeof(region->height)); 1167 p+=sizeof(region->height); 1168 (void) memcpy(p,®ion->x,sizeof(region->x)); 1169 p+=sizeof(region->x); 1170 (void) memcpy(p,®ion->y,sizeof(region->y)); 1171 p+=sizeof(region->y); 1172 (void) memcpy(p,&length,sizeof(length)); 1173 p+=sizeof(length); 1174 count=dpc_send(server_info->file,p-message,message); 1175 if (count != (MagickOffsetType) (p-message)) 1176 return(-1); 1177 return(dpc_read(server_info->file,length,metacontent)); 1178} 1179 1180/* 1181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1182% % 1183% % 1184% % 1185+ 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 % 1186% % 1187% % 1188% % 1189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1190% 1191% ReadDistributePixelCachePixels() reads pixels from the specified region of 1192% the distributed pixel cache. 1193% 1194% The format of the ReadDistributePixelCachePixels method is: 1195% 1196% MagickOffsetType ReadDistributePixelCachePixels( 1197% DistributeCacheInfo *server_info,const RectangleInfo *region, 1198% const MagickSizeType length,unsigned char *pixels) 1199% 1200% A description of each parameter follows: 1201% 1202% o server_info: the distributed cache info. 1203% 1204% o image: the image. 1205% 1206% o region: read the pixels from this region of the image. 1207% 1208% o length: the length in bytes of the pixels. 1209% 1210% o pixels: read these pixels from the pixel cache. 1211% 1212*/ 1213MagickPrivate MagickOffsetType ReadDistributePixelCachePixels( 1214 DistributeCacheInfo *server_info,const RectangleInfo *region, 1215 const MagickSizeType length,unsigned char *pixels) 1216{ 1217 MagickOffsetType 1218 count; 1219 1220 register unsigned char 1221 *p; 1222 1223 unsigned char 1224 message[MaxTextExtent]; 1225 1226 /* 1227 Read distributed pixel cache pixels. 1228 */ 1229 assert(server_info != (DistributeCacheInfo *) NULL); 1230 assert(server_info->signature == MagickSignature); 1231 assert(region != (RectangleInfo *) NULL); 1232 assert(pixels != (unsigned char *) NULL); 1233 if (length > (MagickSizeType) SSIZE_MAX) 1234 return(-1); 1235 p=message; 1236 *p++='r'; 1237 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key)); 1238 p+=sizeof(server_info->session_key); 1239 (void) memcpy(p,®ion->width,sizeof(region->width)); 1240 p+=sizeof(region->width); 1241 (void) memcpy(p,®ion->height,sizeof(region->height)); 1242 p+=sizeof(region->height); 1243 (void) memcpy(p,®ion->x,sizeof(region->x)); 1244 p+=sizeof(region->x); 1245 (void) memcpy(p,®ion->y,sizeof(region->y)); 1246 p+=sizeof(region->y); 1247 (void) memcpy(p,&length,sizeof(length)); 1248 p+=sizeof(length); 1249 count=dpc_send(server_info->file,p-message,message); 1250 if (count != (MagickOffsetType) (p-message)) 1251 return(-1); 1252 return(dpc_read(server_info->file,length,pixels)); 1253} 1254 1255/* 1256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1257% % 1258% % 1259% % 1260+ 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 % 1261% % 1262% % 1263% % 1264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1265% 1266% RelinquishDistributePixelCache() frees resources acquired with 1267% OpenDistributePixelCache(). 1268% 1269% The format of the RelinquishDistributePixelCache method is: 1270% 1271% MagickBooleanType RelinquishDistributePixelCache( 1272% DistributeCacheInfo *server_info) 1273% 1274% A description of each parameter follows: 1275% 1276% o server_info: the distributed cache info. 1277% 1278*/ 1279MagickPrivate MagickBooleanType RelinquishDistributePixelCache( 1280 DistributeCacheInfo *server_info) 1281{ 1282 MagickBooleanType 1283 status; 1284 1285 MagickOffsetType 1286 count; 1287 1288 register unsigned char 1289 *p; 1290 1291 unsigned char 1292 message[MaxTextExtent]; 1293 1294 /* 1295 Delete distributed pixel cache. 1296 */ 1297 assert(server_info != (DistributeCacheInfo *) NULL); 1298 assert(server_info->signature == MagickSignature); 1299 p=message; 1300 *p++='d'; 1301 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key)); 1302 p+=sizeof(server_info->session_key); 1303 count=dpc_send(server_info->file,p-message,message); 1304 if (count != (MagickOffsetType) (p-message)) 1305 return(MagickFalse); 1306 count=dpc_read(server_info->file,sizeof(status),(unsigned char *) &status); 1307 if (count != (MagickOffsetType) sizeof(status)) 1308 return(MagickFalse); 1309 return(status); 1310} 1311 1312/* 1313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1314% % 1315% % 1316% % 1317+ 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 % 1318% % 1319% % 1320% % 1321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1322% 1323% WriteDistributePixelCacheMetacontents() writes image metacontent to the 1324% specified region of the distributed pixel cache. 1325% 1326% The format of the WriteDistributePixelCacheMetacontents method is: 1327% 1328% MagickOffsetType WriteDistributePixelCacheMetacontents( 1329% DistributeCacheInfo *server_info,const RectangleInfo *region, 1330% const MagickSizeType length,const unsigned char *metacontent) 1331% 1332% A description of each parameter follows: 1333% 1334% o server_info: the distributed cache info. 1335% 1336% o image: the image. 1337% 1338% o region: write the metacontent to this region of the image. 1339% 1340% o length: the length in bytes of the metacontent. 1341% 1342% o metacontent: write these metacontent to the pixel cache. 1343% 1344*/ 1345MagickPrivate MagickOffsetType WriteDistributePixelCacheMetacontent( 1346 DistributeCacheInfo *server_info,const RectangleInfo *region, 1347 const MagickSizeType length,const unsigned char *metacontent) 1348{ 1349 MagickOffsetType 1350 count; 1351 1352 register unsigned char 1353 *p; 1354 1355 unsigned char 1356 message[MaxTextExtent]; 1357 1358 /* 1359 Write distributed pixel cache metacontent. 1360 */ 1361 assert(server_info != (DistributeCacheInfo *) NULL); 1362 assert(server_info->signature == MagickSignature); 1363 assert(region != (RectangleInfo *) NULL); 1364 assert(metacontent != (unsigned char *) NULL); 1365 if (length > (MagickSizeType) SSIZE_MAX) 1366 return(-1); 1367 p=message; 1368 *p++='W'; 1369 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key)); 1370 p+=sizeof(server_info->session_key); 1371 (void) memcpy(p,®ion->width,sizeof(region->width)); 1372 p+=sizeof(region->width); 1373 (void) memcpy(p,®ion->height,sizeof(region->height)); 1374 p+=sizeof(region->height); 1375 (void) memcpy(p,®ion->x,sizeof(region->x)); 1376 p+=sizeof(region->x); 1377 (void) memcpy(p,®ion->y,sizeof(region->y)); 1378 p+=sizeof(region->y); 1379 (void) memcpy(p,&length,sizeof(length)); 1380 p+=sizeof(length); 1381 count=dpc_send(server_info->file,p-message,message); 1382 if (count != (MagickOffsetType) (p-message)) 1383 return(-1); 1384 return(dpc_send(server_info->file,length,metacontent)); 1385} 1386 1387/* 1388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1389% % 1390% % 1391% % 1392+ 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 % 1393% % 1394% % 1395% % 1396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1397% 1398% WriteDistributePixelCachePixels() writes image pixels to the specified 1399% region of the distributed pixel cache. 1400% 1401% The format of the WriteDistributePixelCachePixels method is: 1402% 1403% MagickBooleanType WriteDistributePixelCachePixels( 1404% DistributeCacheInfo *server_info,const RectangleInfo *region, 1405% const MagickSizeType length,const unsigned char *pixels) 1406% 1407% A description of each parameter follows: 1408% 1409% o server_info: the distributed cache info. 1410% 1411% o image: the image. 1412% 1413% o region: write the pixels to this region of the image. 1414% 1415% o length: the length in bytes of the pixels. 1416% 1417% o pixels: write these pixels to the pixel cache. 1418% 1419*/ 1420MagickPrivate MagickOffsetType WriteDistributePixelCachePixels( 1421 DistributeCacheInfo *server_info,const RectangleInfo *region, 1422 const MagickSizeType length,const unsigned char *pixels) 1423{ 1424 MagickOffsetType 1425 count; 1426 1427 register unsigned char 1428 *p; 1429 1430 unsigned char 1431 message[MaxTextExtent]; 1432 1433 /* 1434 Write distributed pixel cache pixels. 1435 */ 1436 assert(server_info != (DistributeCacheInfo *) NULL); 1437 assert(server_info->signature == MagickSignature); 1438 assert(region != (RectangleInfo *) NULL); 1439 assert(pixels != (const unsigned char *) NULL); 1440 if (length > (MagickSizeType) SSIZE_MAX) 1441 return(-1); 1442 p=message; 1443 *p++='w'; 1444 (void) memcpy(p,&server_info->session_key,sizeof(server_info->session_key)); 1445 p+=sizeof(server_info->session_key); 1446 (void) memcpy(p,®ion->width,sizeof(region->width)); 1447 p+=sizeof(region->width); 1448 (void) memcpy(p,®ion->height,sizeof(region->height)); 1449 p+=sizeof(region->height); 1450 (void) memcpy(p,®ion->x,sizeof(region->x)); 1451 p+=sizeof(region->x); 1452 (void) memcpy(p,®ion->y,sizeof(region->y)); 1453 p+=sizeof(region->y); 1454 (void) memcpy(p,&length,sizeof(length)); 1455 p+=sizeof(length); 1456 count=dpc_send(server_info->file,p-message,message); 1457 if (count != (MagickOffsetType) (p-message)) 1458 return(-1); 1459 return(dpc_send(server_info->file,length,pixels)); 1460} 1461