1 /* 2 * Copyright 2009, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include "NetReceiver.h" 10 #include "RemoteMessage.h" 11 12 #include "StreamingRingBuffer.h" 13 14 #include <NetEndpoint.h> 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 #define TRACE(x...) /*debug_printf("NetReceiver: " x)*/ 21 #define TRACE_ERROR(x...) debug_printf("NetReceiver: " x) 22 23 24 NetReceiver::NetReceiver(BNetEndpoint *listener, StreamingRingBuffer *target) 25 : 26 fListener(listener), 27 fTarget(target), 28 fReceiverThread(-1), 29 fStopThread(false), 30 fEndpoint(NULL) 31 { 32 fReceiverThread = spawn_thread(_NetworkReceiverEntry, "network receiver", 33 B_NORMAL_PRIORITY, this); 34 resume_thread(fReceiverThread); 35 } 36 37 38 NetReceiver::~NetReceiver() 39 { 40 fStopThread = true; 41 42 if (fEndpoint != NULL) 43 fEndpoint->Close(); 44 45 //int32 result; 46 //wait_for_thread(fReceiverThread, &result); 47 // TODO: find out why closing the endpoint doesn't notify the waiter 48 49 kill_thread(fReceiverThread); 50 } 51 52 53 int32 54 NetReceiver::_NetworkReceiverEntry(void *data) 55 { 56 return ((NetReceiver *)data)->_NetworkReceiver(); 57 } 58 59 60 status_t 61 NetReceiver::_NetworkReceiver() 62 { 63 static const uint16_t shutdown_message[] = { RP_CLOSE_CONNECTION, 0, 0 }; 64 65 status_t result = fListener->Listen(); 66 if (result != B_OK) { 67 TRACE_ERROR("failed to listen on port: %s\n", strerror(result)); 68 fTarget->Write(shutdown_message, sizeof(shutdown_message)); 69 return result; 70 } 71 72 while (!fStopThread) { 73 fEndpoint = fListener->Accept(5000); 74 if (fEndpoint == NULL) { 75 fTarget->Write(shutdown_message, sizeof(shutdown_message)); 76 return B_ERROR; 77 } 78 79 int32 errorCount = 0; 80 TRACE("new endpoint connection: %p\n", fEndpoint); 81 while (!fStopThread) { 82 uint8 buffer[4096]; 83 int32 readSize = fEndpoint->Receive(buffer, sizeof(buffer)); 84 if (readSize < 0) { 85 TRACE_ERROR("read failed, closing connection: %s\n", 86 strerror(readSize)); 87 BNetEndpoint *endpoint = fEndpoint; 88 fEndpoint = NULL; 89 delete endpoint; 90 fTarget->Write(shutdown_message, sizeof(shutdown_message)); 91 return readSize; 92 } 93 94 if (readSize == 0) { 95 TRACE("read 0 bytes, retrying\n"); 96 snooze(100 * 1000); 97 errorCount++; 98 if (errorCount == 5) { 99 TRACE_ERROR("failed to read, assuming disconnect\n"); 100 break; 101 } 102 103 continue; 104 } 105 106 errorCount = 0; 107 status_t result = fTarget->Write(buffer, readSize); 108 if (result != B_OK) { 109 TRACE_ERROR("writing to ring buffer failed: %s\n", 110 strerror(result)); 111 fTarget->Write(shutdown_message, sizeof(shutdown_message)); 112 return result; 113 } 114 } 115 } 116 117 return B_OK; 118 } 119