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
NetReceiver(BNetEndpoint * listener,StreamingRingBuffer * target,NewConnectionCallback newConnectionCallback,void * newConnectionCookie)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
~NetReceiver()41 NetReceiver::~NetReceiver()
42 {
43 fStopThread = true;
44 fEndpoint.Unset();
45
46 suspend_thread(fReceiverThread);
47 resume_thread(fReceiverThread);
48 }
49
50
51 int32
_NetworkReceiverEntry(void * data)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
_Listen()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 fEndpoint.SetTo(fListener->Accept(5000));
73 if (!fEndpoint.IsSet()) {
74 TRACE("got NULL endpoint from accept\n");
75 continue;
76 }
77
78 TRACE("new endpoint connection: %p\n", fEndpoint);
79
80 if (fNewConnectionCallback != NULL
81 && fNewConnectionCallback(
82 fNewConnectionCookie, *fEndpoint.Get()) != B_OK)
83 {
84 TRACE("connection callback rejected connection\n");
85 continue;
86 }
87
88 _Transfer();
89 }
90
91 return B_OK;
92 }
93
94
95 status_t
_Transfer()96 NetReceiver::_Transfer()
97 {
98 int32 errorCount = 0;
99
100 while (!fStopThread) {
101 uint8 buffer[4096];
102 int32 readSize = fEndpoint->Receive(buffer, sizeof(buffer));
103 if (readSize < 0) {
104 TRACE_ERROR("read failed, closing connection: %s\n",
105 strerror(readSize));
106 return readSize;
107 }
108
109 if (readSize == 0) {
110 TRACE("read 0 bytes, retrying\n");
111 snooze(100 * 1000);
112 errorCount++;
113 if (errorCount == 5) {
114 TRACE_ERROR("failed to read, assuming disconnect\n");
115 return B_ERROR;
116 }
117
118 continue;
119 }
120
121 errorCount = 0;
122 status_t result = fTarget->Write(buffer, readSize);
123 if (result != B_OK) {
124 TRACE_ERROR("writing to ring buffer failed: %s\n",
125 strerror(result));
126 return result;
127 }
128 }
129
130 return B_OK;
131 }
132