1 /* 2 * Copyright 2009, 2017, 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 NewConnectionCallback newConnectionCallback, void *newConnectionCookie) 26 : 27 fListener(listener), 28 fTarget(target), 29 fReceiverThread(-1), 30 fStopThread(false), 31 fNewConnectionCallback(newConnectionCallback), 32 fNewConnectionCookie(newConnectionCookie), 33 fEndpoint(newConnectionCallback == NULL ? listener : NULL) 34 { 35 fReceiverThread = spawn_thread(_NetworkReceiverEntry, "network receiver", 36 B_NORMAL_PRIORITY, this); 37 resume_thread(fReceiverThread); 38 } 39 40 41 NetReceiver::~NetReceiver() 42 { 43 fStopThread = true; 44 delete fEndpoint; 45 46 suspend_thread(fReceiverThread); 47 resume_thread(fReceiverThread); 48 } 49 50 51 int32 52 NetReceiver::_NetworkReceiverEntry(void *data) 53 { 54 NetReceiver *receiver = (NetReceiver *)data; 55 if (receiver->fNewConnectionCallback) 56 return receiver->_Listen(); 57 else 58 return receiver->_Transfer(); 59 } 60 61 62 status_t 63 NetReceiver::_Listen() 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 return result; 69 } 70 71 while (!fStopThread) { 72 if (fEndpoint != NULL) { 73 TRACE("closing previous connection\n"); 74 delete fEndpoint; 75 fEndpoint = NULL; 76 } 77 78 fEndpoint = fListener->Accept(5000); 79 if (fEndpoint == NULL) { 80 TRACE("got NULL endpoint from accept\n"); 81 continue; 82 } 83 84 TRACE("new endpoint connection: %p\n", fEndpoint); 85 86 if (fNewConnectionCallback != NULL 87 && fNewConnectionCallback(fNewConnectionCookie, *fEndpoint) != B_OK) 88 { 89 TRACE("connection callback rejected connection\n"); 90 continue; 91 } 92 93 _Transfer(); 94 } 95 96 return B_OK; 97 } 98 99 100 status_t 101 NetReceiver::_Transfer() 102 { 103 int32 errorCount = 0; 104 105 while (!fStopThread) { 106 uint8 buffer[4096]; 107 int32 readSize = fEndpoint->Receive(buffer, sizeof(buffer)); 108 if (readSize < 0) { 109 TRACE_ERROR("read failed, closing connection: %s\n", 110 strerror(readSize)); 111 return readSize; 112 } 113 114 if (readSize == 0) { 115 TRACE("read 0 bytes, retrying\n"); 116 snooze(100 * 1000); 117 errorCount++; 118 if (errorCount == 5) { 119 TRACE_ERROR("failed to read, assuming disconnect\n"); 120 return B_ERROR; 121 } 122 123 continue; 124 } 125 126 errorCount = 0; 127 status_t result = fTarget->Write(buffer, readSize); 128 if (result != B_OK) { 129 TRACE_ERROR("writing to ring buffer failed: %s\n", 130 strerror(result)); 131 return result; 132 } 133 } 134 135 return B_OK; 136 } 137