xref: /haiku/src/servers/app/drawing/interface/remote/NetReceiver.cpp (revision 410ed2fbba58819ac21e27d3676739728416761d)
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 	fEndpoint.Unset();
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 		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
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