xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/private/Port.cpp (revision b30304acc8c37e678a1bf66976d15bdab103f931)
1 // Port.cpp
2 
3 #include <new>
4 
5 #include "AreaSupport.h"
6 #include "Compatibility.h"
7 #include "Port.h"
8 
9 using std::nothrow;
10 
11 // minimal and maximal port size
12 static const int32 kMinPortSize = 1024;			// 1 kB
13 static const int32 kMaxPortSize = 64 * 1024;	// 64 kB
14 
15 // constructor
16 Port::Port(int32 size)
17 	: fBuffer(NULL),
18 	  fCapacity(0),
19 	  fMessageSize(0),
20 	  fInitStatus(B_NO_INIT),
21 	  fOwner(true)
22 {
23 	// adjust size to be within the sane bounds
24 	if (size < kMinPortSize)
25 		size = kMinPortSize;
26 	else if (size > kMaxPortSize)
27 		size = kMaxPortSize;
28 	// allocate the buffer
29 	fBuffer = new(nothrow) uint8[size];
30 	if (!fBuffer) {
31 		fInitStatus = B_NO_MEMORY;
32 		return;
33 	}
34 	// create the owner port
35 	fInfo.owner_port = create_port(1, "port owner port");
36 	if (fInfo.owner_port < 0) {
37 		fInitStatus = fInfo.owner_port;
38 		return;
39 	}
40 	// create the client port
41 	fInfo.client_port = create_port(1, "port client port");
42 	if (fInfo.client_port < 0) {
43 		fInitStatus = fInfo.client_port;
44 		return;
45 	}
46 	fInfo.size = size;
47 	fCapacity = size;
48 	fInitStatus = B_OK;
49 }
50 
51 // constructor
52 Port::Port(const Info* info)
53 	: fBuffer(NULL),
54 	  fCapacity(0),
55 	  fMessageSize(0),
56 	  fInitStatus(B_NO_INIT),
57 	  fOwner(false)
58 {
59 	// check parameters
60 	if (!info || info->owner_port < 0 || info->client_port < 0
61 		|| info->size < kMinPortSize || info->size > kMaxPortSize) {
62 		return;
63 	}
64 	// allocate the buffer
65 	fBuffer = new(nothrow) uint8[info->size];
66 	if (!fBuffer) {
67 		fInitStatus = B_NO_MEMORY;
68 		return;
69 	}
70 	// init the info
71 	fInfo.owner_port = info->owner_port;
72 	fInfo.client_port = info->client_port;
73 	fInfo.size = info->size;
74 	// init the other members
75 	fCapacity = info->size;
76 	fInitStatus = B_OK;
77 }
78 
79 // destructor
80 Port::~Port()
81 {
82 	Close();
83 	delete[] fBuffer;
84 }
85 
86 // Close
87 void
88 Port::Close()
89 {
90 	if (fInitStatus != B_OK)
91 		return;
92 	fInitStatus = B_NO_INIT;
93 	// delete the ports only if we are the owner
94 	if (fOwner) {
95 		if (fInfo.owner_port >= 0)
96 			delete_port(fInfo.owner_port);
97 		if (fInfo.client_port >= 0)
98 			delete_port(fInfo.client_port);
99 	}
100 	fInfo.owner_port = -1;
101 	fInfo.client_port = -1;
102 }
103 
104 // InitCheck
105 status_t
106 Port::InitCheck() const
107 {
108 	return fInitStatus;
109 }
110 
111 // GetInfo
112 const Port::Info*
113 Port::GetInfo() const
114 {
115 	return &fInfo;
116 }
117 
118 // GetBuffer
119 void*
120 Port::GetBuffer() const
121 {
122 	return fBuffer;
123 }
124 
125 // GetCapacity
126 int32
127 Port::GetCapacity() const
128 {
129 	return fCapacity;
130 }
131 
132 // GetMessage
133 void*
134 Port::GetMessage() const
135 {
136 	return (fInitStatus == B_OK && fMessageSize > 0 ? fBuffer : NULL);
137 }
138 
139 // GetMessageSize
140 int32
141 Port::GetMessageSize() const
142 {
143 	return (fInitStatus == B_OK ? fMessageSize : 0);
144 }
145 
146 // Send
147 status_t
148 Port::Send(int32 size)
149 {
150 	if (fInitStatus != B_OK)
151 		return fInitStatus;
152 	if (size <= 0 || size > fCapacity)
153 		return B_BAD_VALUE;
154 	fMessageSize = 0;
155 	port_id port = (fOwner ? fInfo.client_port : fInfo.owner_port);
156 	status_t error;
157 	do {
158 		error = write_port(port, 0, fBuffer, size);
159 	} while (error == B_INTERRUPTED);
160 	return (fInitStatus = error);
161 }
162 
163 // SendAndReceive
164 status_t
165 Port::SendAndReceive(int32 size)
166 {
167 	status_t error = Send(size);
168 	if (error != B_OK)
169 		return error;
170 	return Receive();
171 }
172 
173 // Receive
174 status_t
175 Port::Receive(bigtime_t timeout)
176 {
177 	if (fInitStatus != B_OK)
178 		return fInitStatus;
179 	port_id port = (fOwner ? fInfo.owner_port : fInfo.client_port);
180 	status_t error = B_OK;
181 	do {
182 		int32 code;
183 		ssize_t bytesRead;
184 		if (timeout >= 0) {
185 			bytesRead = read_port_etc(port, &code, fBuffer, fCapacity,
186 				B_RELATIVE_TIMEOUT, timeout);
187 		} else
188 			bytesRead = read_port(port, &code, fBuffer, fCapacity);
189 		if (bytesRead < 0)
190 			error = bytesRead;
191 		else
192 			fMessageSize = bytesRead;
193 	} while (error == B_INTERRUPTED);
194 	if (error == B_TIMED_OUT || error == B_WOULD_BLOCK) {
195 		return error;
196 	}
197 	if (error != B_OK)
198 		return (fInitStatus = error);
199 	if (fMessageSize <= 0 || fMessageSize > fCapacity) {
200 		fMessageSize = 0;
201 		return B_BAD_DATA;
202 	}
203 	return B_OK;
204 }
205 
206