1 /* 2 * Copyright 2001-2007, 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 165 ssize_t bufferSize; 166 do { 167 bufferSize = port_buffer_size_etc(fReceivePort, 168 timeout == B_INFINITE_TIMEOUT ? B_RELATIVE_TIMEOUT : 0, 169 timeout); 170 } while (bufferSize == B_INTERRUPTED); 171 172 STRACE(("info: LinkReceiver got port_buffer_size() = %ld.\n", bufferSize)); 173 174 if (bufferSize < 0) 175 return (status_t)bufferSize; 176 177 // make sure our receive buffer is large enough 178 if (bufferSize > fRecvBufferSize) { 179 if (bufferSize <= (ssize_t)kInitialBufferSize) 180 bufferSize = (ssize_t)kInitialBufferSize; 181 else 182 bufferSize = (bufferSize + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 183 184 if (bufferSize > (ssize_t)kMaxBufferSize) 185 return B_ERROR; // we can't continue 186 187 STRACE(("info: LinkReceiver setting receive buffersize to %ld.\n", bufferSize)); 188 char *buffer = (char *)malloc(bufferSize); 189 if (buffer == NULL) 190 return B_NO_MEMORY; 191 192 free(fRecvBuffer); 193 fRecvBuffer = buffer; 194 fRecvBufferSize = bufferSize; 195 } 196 } 197 198 return B_OK; 199 } 200 201 202 status_t 203 LinkReceiver::ReadFromPort(bigtime_t timeout) 204 { 205 // we are here so it means we finished reading the buffer contents 206 ResetBuffer(); 207 208 status_t err = AdjustReplyBuffer(timeout); 209 if (err < B_OK) 210 return err; 211 212 int32 code; 213 ssize_t bytesRead; 214 215 STRACE(("info: LinkReceiver reading port %ld.\n", fReceivePort)); 216 while (true) { 217 if (timeout != B_INFINITE_TIMEOUT) { 218 do { 219 bytesRead = read_port_etc(fReceivePort, &code, fRecvBuffer, 220 fRecvBufferSize, B_TIMEOUT, timeout); 221 } while (bytesRead == B_INTERRUPTED); 222 } else { 223 do { 224 bytesRead = read_port(fReceivePort, &code, fRecvBuffer, 225 fRecvBufferSize); 226 } while (bytesRead == B_INTERRUPTED); 227 } 228 229 STRACE(("info: LinkReceiver read %ld bytes.\n", bytesRead)); 230 if (bytesRead < B_OK) 231 return bytesRead; 232 233 // we just ignore incorrect messages, and don't bother our caller 234 235 if (code != kLinkCode) { 236 STRACE(("wrong port message %lx received.\n", code)); 237 continue; 238 } 239 240 // port read seems to be valid 241 break; 242 } 243 244 fDataSize = bytesRead; 245 return B_OK; 246 } 247 248 249 status_t 250 LinkReceiver::Read(void *data, ssize_t size) 251 { 252 // STRACE(("info: LinkReceiver Read()ing %ld bytes...\n", size)); 253 if (fReadError < B_OK) 254 return fReadError; 255 256 if (data == NULL || size < 1) { 257 fReadError = B_BAD_VALUE; 258 return B_BAD_VALUE; 259 } 260 261 if (fDataSize == 0 || fReplySize == 0) 262 return B_NO_INIT; // need to call GetNextReply() first 263 264 if (fRecvPosition + size > fRecvStart + fReplySize) { 265 // reading past the end of current message 266 fReadError = B_BAD_VALUE; 267 return B_BAD_VALUE; 268 } 269 270 memcpy(data, fRecvBuffer + fRecvPosition, size); 271 fRecvPosition += size; 272 return fReadError; 273 } 274 275 276 status_t 277 LinkReceiver::ReadString(char** _string, size_t* _length) 278 { 279 int32 length = 0; 280 status_t status; 281 282 status = Read<int32>(&length); 283 if (status < B_OK) 284 return status; 285 286 char *string; 287 288 if (length < 0) { 289 status = B_ERROR; 290 goto err; 291 } 292 293 string = (char *)malloc(length + 1); 294 if (string == NULL) { 295 status = B_NO_MEMORY; 296 goto err; 297 } 298 299 if (length > 0) { 300 status = Read(string, length); 301 if (status < B_OK) { 302 free(string); 303 return status; 304 } 305 } 306 307 // make sure the string is null terminated 308 string[length] = '\0'; 309 310 if (_length) 311 *_length = length; 312 *_string = string; 313 314 return B_OK; 315 316 err: 317 fRecvPosition -= sizeof(int32); 318 // rewind the transaction 319 return status; 320 } 321 322 323 status_t 324 LinkReceiver::ReadString(BString &string, size_t* _length) 325 { 326 int32 length = 0; 327 status_t status; 328 329 status = Read<int32>(&length); 330 if (status < B_OK) 331 return status; 332 333 if (length < 0) { 334 status = B_ERROR; 335 goto err; 336 } 337 338 if (length > 0) { 339 char* buffer = string.LockBuffer(length + 1); 340 if (buffer == NULL) { 341 status = B_NO_MEMORY; 342 goto err; 343 } 344 345 status = Read(buffer, length); 346 if (status < B_OK) { 347 string.UnlockBuffer(); 348 goto err; 349 } 350 351 // make sure the string is null terminated 352 buffer[length] = '\0'; 353 string.UnlockBuffer(length); 354 } else 355 string = ""; 356 357 if (_length) 358 *_length = length; 359 360 return B_OK; 361 362 err: 363 fRecvPosition -= sizeof(int32); 364 // rewind the transaction 365 return status; 366 } 367 368 369 status_t 370 LinkReceiver::ReadString(char *buffer, size_t bufferLength) 371 { 372 int32 length = 0; 373 status_t status; 374 375 status = Read<int32>(&length); 376 if (status < B_OK) 377 return status; 378 379 if (length >= (int32)bufferLength) { 380 status = B_BUFFER_OVERFLOW; 381 goto err; 382 } 383 384 if (length < 0) { 385 status = B_ERROR; 386 goto err; 387 } 388 389 if (length > 0) { 390 status = Read(buffer, length); 391 if (status < B_OK) 392 goto err; 393 } 394 395 // make sure the string is null terminated 396 buffer[length] = '\0'; 397 return B_OK; 398 399 err: 400 fRecvPosition -= sizeof(int32); 401 // rewind the transaction 402 return status; 403 } 404 405 status_t 406 LinkReceiver::ReadRegion(BRegion* region) 407 { 408 status_t status = Read(®ion->fCount, sizeof(int32)); 409 if (status >= B_OK) 410 status = Read(®ion->fBounds, sizeof(clipping_rect)); 411 if (status >= B_OK) { 412 if (!region->_SetSize(region->fCount)) 413 status = B_NO_MEMORY; 414 else { 415 status = Read(region->fData, 416 region->fCount * sizeof(clipping_rect)); 417 } 418 if (status < B_OK) 419 region->MakeEmpty(); 420 } 421 return status; 422 } 423 424 425 } // namespace BPrivate 426 427 428