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