xref: /haiku/src/servers/app/drawing/interface/remote/NetReceiver.cpp (revision 5ac9b506412b11afb993bb52d161efe7666958a5)
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