xref: /haiku/src/servers/app/drawing/interface/remote/NetReceiver.cpp (revision 39d6c466d8217dcb3004074f29c27c60f0fa1ac1)
1 /*
2  * Copyright 2009, 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 	:
26 	fListener(listener),
27 	fTarget(target),
28 	fReceiverThread(-1),
29 	fStopThread(false),
30 	fEndpoint(NULL)
31 {
32 	fReceiverThread = spawn_thread(_NetworkReceiverEntry, "network receiver",
33 		B_NORMAL_PRIORITY, this);
34 	resume_thread(fReceiverThread);
35 }
36 
37 
38 NetReceiver::~NetReceiver()
39 {
40 	fStopThread = true;
41 
42 	if (fEndpoint != NULL)
43 		fEndpoint->Close();
44 
45 	//int32 result;
46 	//wait_for_thread(fReceiverThread, &result);
47 		// TODO: find out why closing the endpoint doesn't notify the waiter
48 
49 	kill_thread(fReceiverThread);
50 }
51 
52 
53 int32
54 NetReceiver::_NetworkReceiverEntry(void *data)
55 {
56 	return ((NetReceiver *)data)->_NetworkReceiver();
57 }
58 
59 
60 status_t
61 NetReceiver::_NetworkReceiver()
62 {
63 	static const uint16_t shutdown_message[] = { RP_CLOSE_CONNECTION, 0, 0 };
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 		fTarget->Write(shutdown_message, sizeof(shutdown_message));
69 		return result;
70 	}
71 
72 	while (!fStopThread) {
73 		fEndpoint = fListener->Accept(5000);
74 		if (fEndpoint == NULL) {
75 			fTarget->Write(shutdown_message, sizeof(shutdown_message));
76 			return B_ERROR;
77 		}
78 
79 		int32 errorCount = 0;
80 		TRACE("new endpoint connection: %p\n", fEndpoint);
81 		while (!fStopThread) {
82 			uint8 buffer[4096];
83 			int32 readSize = fEndpoint->Receive(buffer, sizeof(buffer));
84 			if (readSize < 0) {
85 				TRACE_ERROR("read failed, closing connection: %s\n",
86 					strerror(readSize));
87 				BNetEndpoint *endpoint = fEndpoint;
88 				fEndpoint = NULL;
89 				delete endpoint;
90 				fTarget->Write(shutdown_message, sizeof(shutdown_message));
91 				return readSize;
92 			}
93 
94 			if (readSize == 0) {
95 				TRACE("read 0 bytes, retrying\n");
96 				snooze(100 * 1000);
97 				errorCount++;
98 				if (errorCount == 5) {
99 					TRACE_ERROR("failed to read, assuming disconnect\n");
100 					break;
101 				}
102 
103 				continue;
104 			}
105 
106 			errorCount = 0;
107 			status_t result = fTarget->Write(buffer, readSize);
108 			if (result != B_OK) {
109 				TRACE_ERROR("writing to ring buffer failed: %s\n",
110 					strerror(result));
111 				fTarget->Write(shutdown_message, sizeof(shutdown_message));
112 				return result;
113 			}
114 		}
115 	}
116 
117 	return B_OK;
118 }
119