1 /* 2 * Copyright 2001-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Pahtz <pahtz@yahoo.com.au> 7 * Axel Dörfler 8 * Stephan Aßmus <superstippi@gmx.de> 9 */ 10 11 /** Class for low-overhead port-based messaging */ 12 13 #include <LinkReceiver.h> 14 15 #include <stdlib.h> 16 #include <string.h> 17 #include <new> 18 19 #include <ServerProtocol.h> 20 #include <String.h> 21 #include <Region.h> 22 23 #include "link_message.h" 24 25 26 //#define DEBUG_BPORTLINK 27 #ifdef DEBUG_BPORTLINK 28 # include <stdio.h> 29 # define STRACE(x) printf x 30 #else 31 # define STRACE(x) ; 32 #endif 33 34 namespace BPrivate { 35 36 LinkReceiver::LinkReceiver(port_id port) 37 : 38 fReceivePort(port), fRecvBuffer(NULL), fRecvPosition(0), fRecvStart(0), 39 fRecvBufferSize(0), fDataSize(0), 40 fReplySize(0), fReadError(B_OK) 41 { 42 } 43 44 45 LinkReceiver::~LinkReceiver() 46 { 47 free(fRecvBuffer); 48 } 49 50 51 void 52 LinkReceiver::SetPort(port_id port) 53 { 54 fReceivePort = port; 55 } 56 57 58 status_t 59 LinkReceiver::GetNextMessage(int32 &code, bigtime_t timeout) 60 { 61 int32 remaining; 62 63 fReadError = B_OK; 64 65 remaining = fDataSize - (fRecvStart + fReplySize); 66 STRACE(("info: LinkReceiver GetNextReply() reports %ld bytes remaining in buffer.\n", remaining)); 67 68 // find the position of the next message header in the buffer 69 message_header *header; 70 if (remaining <= 0) { 71 status_t err = ReadFromPort(timeout); 72 if (err < B_OK) 73 return err; 74 remaining = fDataSize; 75 header = (message_header *)fRecvBuffer; 76 } else { 77 fRecvStart += fReplySize; // start of the next message 78 fRecvPosition = fRecvStart; 79 header = (message_header *)(fRecvBuffer + fRecvStart); 80 } 81 82 // check we have a well-formed message 83 if (remaining < (int32)sizeof(message_header)) { 84 // we don't have enough data for a complete header 85 STRACE(("error info: LinkReceiver remaining %ld bytes is less than header size.\n", remaining)); 86 ResetBuffer(); 87 return B_ERROR; 88 } 89 90 fReplySize = header->size; 91 if (fReplySize > remaining || fReplySize < (int32)sizeof(message_header)) { 92 STRACE(("error info: LinkReceiver message size of %ld bytes smaller than header size.\n", fReplySize)); 93 ResetBuffer(); 94 return B_ERROR; 95 } 96 97 code = header->code; 98 fRecvPosition += sizeof(message_header); 99 100 STRACE(("info: LinkReceiver got header %ld [%ld %ld %ld] from port %ld.\n", 101 header->code, fReplySize, header->code, header->flags, fReceivePort)); 102 103 return B_OK; 104 } 105 106 107 bool 108 LinkReceiver::HasMessages() const 109 { 110 return fDataSize - (fRecvStart + fReplySize) > 0 111 || port_count(fReceivePort) > 0; 112 } 113 114 115 bool 116 LinkReceiver::NeedsReply() const 117 { 118 if (fReplySize == 0) 119 return false; 120 121 message_header *header = (message_header *)(fRecvBuffer + fRecvStart); 122 return (header->flags & kNeedsReply) != 0; 123 } 124 125 126 int32 127 LinkReceiver::Code() const 128 { 129 if (fReplySize == 0) 130 return B_ERROR; 131 132 message_header *header = (message_header *)(fRecvBuffer + fRecvStart); 133 return header->code; 134 } 135 136 137 void 138 LinkReceiver::ResetBuffer() 139 { 140 fRecvPosition = 0; 141 fRecvStart = 0; 142 fDataSize = 0; 143 fReplySize = 0; 144 } 145 146 147 status_t 148 LinkReceiver::AdjustReplyBuffer(bigtime_t timeout) 149 { 150 // Here we take advantage of the compiler's dead-code elimination 151 if (kInitialBufferSize == kMaxBufferSize) { 152 // fixed buffer size 153 154 if (fRecvBuffer != NULL) 155 return B_OK; 156 157 fRecvBuffer = (char *)malloc(kInitialBufferSize); 158 if (fRecvBuffer == NULL) 159 return B_NO_MEMORY; 160 161 fRecvBufferSize = kInitialBufferSize; 162 } else { 163 STRACE(("info: LinkReceiver getting port_buffer_size().\n")); 164 ssize_t bufferSize; 165 if (timeout == B_INFINITE_TIMEOUT) 166 bufferSize = port_buffer_size(fReceivePort); 167 else 168 bufferSize = port_buffer_size_etc(fReceivePort, B_TIMEOUT, timeout); 169 STRACE(("info: LinkReceiver got port_buffer_size() = %ld.\n", bufferSize)); 170 171 if (bufferSize < 0) 172 return (status_t)bufferSize; 173 174 // make sure our receive buffer is large enough 175 if (bufferSize > fRecvBufferSize) { 176 if (bufferSize <= (ssize_t)kInitialBufferSize) 177 bufferSize = (ssize_t)kInitialBufferSize; 178 else 179 bufferSize = (bufferSize + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 180 181 if (bufferSize > (ssize_t)kMaxBufferSize) 182 return B_ERROR; // we can't continue 183 184 STRACE(("info: LinkReceiver setting receive buffersize to %ld.\n", bufferSize)); 185 char *buffer = (char *)malloc(bufferSize); 186 if (buffer == NULL) 187 return B_NO_MEMORY; 188 189 free(fRecvBuffer); 190 fRecvBuffer = buffer; 191 fRecvBufferSize = bufferSize; 192 } 193 } 194 195 return B_OK; 196 } 197 198 199 status_t 200 LinkReceiver::ReadFromPort(bigtime_t timeout) 201 { 202 // we are here so it means we finished reading the buffer contents 203 ResetBuffer(); 204 205 status_t err = AdjustReplyBuffer(timeout); 206 if (err < B_OK) 207 return err; 208 209 int32 code; 210 ssize_t bytesRead; 211 212 STRACE(("info: LinkReceiver reading port %ld.\n", fReceivePort)); 213 while (true) { 214 if (timeout != B_INFINITE_TIMEOUT) { 215 do { 216 bytesRead = read_port_etc(fReceivePort, &code, fRecvBuffer, 217 fRecvBufferSize, B_TIMEOUT, timeout); 218 } while (bytesRead == B_INTERRUPTED); 219 } else { 220 do { 221 bytesRead = read_port(fReceivePort, &code, fRecvBuffer, 222 fRecvBufferSize); 223 } while (bytesRead == B_INTERRUPTED); 224 } 225 226 STRACE(("info: LinkReceiver read %ld bytes.\n", bytesRead)); 227 if (bytesRead < B_OK) 228 return bytesRead; 229 230 // we just ignore incorrect messages, and don't bother our caller 231 232 if (code != kLinkCode) { 233 STRACE(("wrong port message %lx received.\n", code)); 234 continue; 235 } 236 237 // port read seems to be valid 238 break; 239 } 240 241 fDataSize = bytesRead; 242 return B_OK; 243 } 244 245 246 status_t 247 LinkReceiver::Read(void *data, ssize_t size) 248 { 249 // STRACE(("info: LinkReceiver Read()ing %ld bytes...\n", size)); 250 if (fReadError < B_OK) 251 return fReadError; 252 253 if (data == NULL || size < 1) { 254 fReadError = B_BAD_VALUE; 255 return B_BAD_VALUE; 256 } 257 258 if (fDataSize == 0 || fReplySize == 0) 259 return B_NO_INIT; // need to call GetNextReply() first 260 261 if (fRecvPosition + size > fRecvStart + fReplySize) { 262 // reading past the end of current message 263 fReadError = B_BAD_VALUE; 264 return B_BAD_VALUE; 265 } 266 267 memcpy(data, fRecvBuffer + fRecvPosition, size); 268 fRecvPosition += size; 269 return fReadError; 270 } 271 272 273 status_t 274 LinkReceiver::ReadString(char** _string, size_t* _length) 275 { 276 int32 length = 0; 277 status_t status; 278 279 status = Read<int32>(&length); 280 if (status < B_OK) 281 return status; 282 283 char *string; 284 285 if (length < 0) { 286 status = B_ERROR; 287 goto err; 288 } 289 290 string = (char *)malloc(length + 1); 291 if (string == NULL) { 292 status = B_NO_MEMORY; 293 goto err; 294 } 295 296 if (length > 0) { 297 status = Read(string, length); 298 if (status < B_OK) { 299 free(string); 300 return status; 301 } 302 } 303 304 // make sure the string is null terminated 305 string[length] = '\0'; 306 307 if (_length) 308 *_length = length; 309 *_string = string; 310 311 return B_OK; 312 313 err: 314 fRecvPosition -= sizeof(int32); 315 // rewind the transaction 316 return status; 317 } 318 319 320 status_t 321 LinkReceiver::ReadString(BString &string, size_t* _length) 322 { 323 int32 length = 0; 324 status_t status; 325 326 status = Read<int32>(&length); 327 if (status < B_OK) 328 return status; 329 330 if (length < 0) { 331 status = B_ERROR; 332 goto err; 333 } 334 335 if (length > 0) { 336 char* buffer = string.LockBuffer(length + 1); 337 if (buffer == NULL) { 338 status = B_NO_MEMORY; 339 goto err; 340 } 341 342 status = Read(buffer, length); 343 if (status < B_OK) { 344 string.UnlockBuffer(); 345 goto err; 346 } 347 348 // make sure the string is null terminated 349 buffer[length] = '\0'; 350 string.UnlockBuffer(length); 351 } else 352 string = ""; 353 354 if (_length) 355 *_length = length; 356 357 return B_OK; 358 359 err: 360 fRecvPosition -= sizeof(int32); 361 // rewind the transaction 362 return status; 363 } 364 365 366 status_t 367 LinkReceiver::ReadString(char *buffer, size_t bufferLength) 368 { 369 int32 length = 0; 370 status_t status; 371 372 status = Read<int32>(&length); 373 if (status < B_OK) 374 return status; 375 376 if (length >= (int32)bufferLength) { 377 status = B_BUFFER_OVERFLOW; 378 goto err; 379 } 380 381 if (length < 0) { 382 status = B_ERROR; 383 goto err; 384 } 385 386 if (length > 0) { 387 status = Read(buffer, length); 388 if (status < B_OK) 389 goto err; 390 } 391 392 // make sure the string is null terminated 393 buffer[length] = '\0'; 394 return B_OK; 395 396 err: 397 fRecvPosition -= sizeof(int32); 398 // rewind the transaction 399 return status; 400 } 401 402 status_t 403 LinkReceiver::ReadRegion(BRegion* region) 404 { 405 status_t status = Read(®ion->count, sizeof(int32)); 406 if (status >= B_OK) 407 status = Read(®ion->bound, sizeof(clipping_rect)); 408 if (status >= B_OK) { 409 region->set_size(region->count); 410 status = Read(region->data, region->count * sizeof(clipping_rect)); 411 if (status < B_OK) 412 region->MakeEmpty(); 413 } 414 return status; 415 } 416 417 418 } // namespace BPrivate 419 420 421