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
24NetReceiver::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
41NetReceiver::~NetReceiver()
42{
43	fStopThread = true;
44	fEndpoint.Unset();
45
46	suspend_thread(fReceiverThread);
47	resume_thread(fReceiverThread);
48}
49
50
51int32
52NetReceiver::_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
62status_t
63NetReceiver::_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
95status_t
96NetReceiver::_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