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