1// PortChannel.cpp
2
3#include <new>
4#include <string.h>
5
6#include "PortChannel.h"
7#include "Utils.h"
8
9static const int32 kMaxPortMessageSize = 102400;	// 100 KB
10static const int32 kDefaultBufferSize	= 10240;	// 10 KB
11
12// constructor
13PortChannel::PortChannel()
14	: Channel(),
15	  fSendPort(-1),
16	  fReceivePort(-1),
17	  fBuffer(new(std::nothrow) uint8[kDefaultBufferSize]),
18	  fBufferSize(kDefaultBufferSize),
19	  fBufferOffset(0),
20	  fBufferContentSize(0)
21{
22	fSendPort = create_port(10, "port connection send port");
23	fReceivePort = create_port(10, "port connection receive port");
24}
25
26// constructor
27PortChannel::PortChannel(const Info* info, bool inverse)
28	: Channel(),
29	  fSendPort(inverse ? info->receivePort : info->sendPort),
30	  fReceivePort(inverse ? info->sendPort : info->receivePort),
31	  fBuffer(new(std::nothrow) uint8[kDefaultBufferSize]),
32	  fBufferSize(kDefaultBufferSize),
33	  fBufferOffset(0),
34	  fBufferContentSize(0)
35{
36}
37
38// constructor
39PortChannel::PortChannel(port_id sendPort, port_id receivePort)
40	: Channel(),
41	  fSendPort(sendPort),
42	  fReceivePort(receivePort),
43	  fBuffer(new(std::nothrow) uint8[kDefaultBufferSize]),
44	  fBufferSize(kDefaultBufferSize),
45	  fBufferOffset(0),
46	  fBufferContentSize(0)
47{
48}
49
50// destructor
51PortChannel::~PortChannel()
52{
53	delete[] fBuffer;
54}
55
56// InitCheck
57status_t
58PortChannel::InitCheck() const
59{
60	if (fSendPort < 0)
61		return fSendPort;
62	if (fReceivePort < 0)
63		return fReceivePort;
64	if (!fBuffer)
65		return B_NO_MEMORY;
66	return B_OK;
67}
68
69// GetInfo
70void
71PortChannel::GetInfo(Info* info) const
72{
73	if (info) {
74		info->sendPort = fSendPort;
75		info->receivePort = fReceivePort;
76	}
77}
78
79// Close
80void
81PortChannel::Close()
82{
83	if (fSendPort >= 0) {
84		delete_port(fSendPort);
85		fSendPort = -1;
86	}
87	if (fReceivePort >= 0) {
88		delete_port(fReceivePort);
89		fReceivePort = -1;
90	}
91}
92
93// Send
94status_t
95PortChannel::Send(const void* _buffer, int32 size)
96{
97	if (size == 0)
98		return B_OK;
99	if (!_buffer || size < 0)
100		return B_BAD_VALUE;
101	const uint8* buffer = static_cast<const uint8*>(_buffer);
102	while (size > 0) {
103		int32 sendSize = min(size, fBufferSize);
104		status_t error = write_port(fSendPort, 0, buffer, size);
105		if (error != B_OK)
106			return error;
107		size -= sendSize;
108		buffer += sendSize;
109	}
110	return B_OK;
111}
112
113// Receive
114status_t
115PortChannel::Receive(void* _buffer, int32 size)
116{
117	if (size == 0)
118		return B_OK;
119	if (!_buffer || size < 0)
120		return B_BAD_VALUE;
121	uint8* buffer = static_cast<uint8*>(_buffer);
122	while (size > 0) {
123		if (fBufferContentSize > 0) {
124			// there's something in our buffer: just read from there
125			int32 bytesRead = min(size, fBufferContentSize);
126			memcpy(buffer, fBuffer + fBufferOffset, bytesRead);
127			fBufferOffset += bytesRead;
128			fBufferContentSize -= bytesRead;
129			size -= bytesRead;
130			buffer += bytesRead;
131		} else {
132			// nothing left in the buffer: we read from the port
133			if (size > fBufferSize) {
134				// we shall read more than what would fit into our buffer, so
135				// we can directly read into the user buffer
136				ssize_t bytesRead = read_port(fReceivePort, 0, buffer, size);
137				if (bytesRead < 0)
138					return bytesRead;
139				size -= bytesRead;
140				buffer += bytesRead;
141			} else {
142				// we read into our buffer
143				ssize_t bytesRead = read_port(fReceivePort, 0, fBuffer,
144					fBufferSize);
145				if (bytesRead < 0)
146					return bytesRead;
147				fBufferOffset = 0;
148				fBufferContentSize = bytesRead;
149			}
150		}
151	}
152	return B_OK;
153}
154
155