xref: /haiku/src/kits/network/libnetapi/NetEndpoint.cpp (revision 7120e97489acbf17d86d3f33e3b2e68974fd4b23)
1 /******************************************************************************
2 /
3 /	File:			NetEndpoint.cpp
4 /
5 /   Description:    The Network API.
6 /
7 /	Copyright 2002, OpenBeOS Project, All Rights Reserved.
8 /
9 ******************************************************************************/
10 
11 #include <string.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <netdb.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <NetEndpoint.h>
20 
21 BNetEndpoint::BNetEndpoint(int protocol)
22 	:	fStatus(B_OK),
23 		fSocket(0),
24 		fTimeout(B_INFINITE_TIMEOUT),
25 		fLocalAddr(),
26 		fRemoteAddr()
27 {
28 	if ((fSocket = socket(AF_INET, protocol, 0)) < 0)
29 		fStatus = B_ERROR;
30 }
31 
32 BNetEndpoint::BNetEndpoint(int handle, bigtime_t timeout)
33 	:   fStatus(B_OK),
34 		fSocket(0),
35 		fTimeout(timeout),
36 		fLocalAddr(),
37 		fRemoteAddr()
38 {
39 	if ((fSocket = dup(handle)) < 0)
40 		fStatus = B_ERROR;
41 }
42 
43 BNetEndpoint::BNetEndpoint(const BNetEndpoint & endpoint)
44 	:	fStatus(endpoint.fStatus),
45 		fSocket(endpoint.fSocket),
46 		fTimeout(endpoint.fTimeout),
47 		fLocalAddr(endpoint.fLocalAddr),
48 		fRemoteAddr(endpoint.fRemoteAddr)
49 {
50 }
51 
52 BNetEndpoint::~BNetEndpoint()
53 {
54 	Close();
55 }
56 
57 BNetEndpoint::BNetEndpoint(BMessage *archive)
58 	:	fStatus(B_OK),
59 		fSocket(0),
60 		fTimeout(B_INFINITE_TIMEOUT),
61 		fLocalAddr(),
62 		fRemoteAddr()
63 {
64 	// TODO
65 	fStatus = B_ERROR;
66 }
67 
68 status_t BNetEndpoint::Archive(BMessage *into, bool deep = true) const
69 {
70 	// TODO
71 	return B_ERROR;
72 }
73 
74 BArchivable *BNetEndpointInstantiate(BMessage *archive)
75 {
76 	// TODO
77 	return NULL;
78 }
79 
80 status_t BNetEndpoint::InitCheck() const
81 {
82 	return fStatus;
83 }
84 
85 int BNetEndpoint::Socket() const
86 {
87 	return fSocket;
88 }
89 
90 const BNetAddress & BNetEndpoint::LocalAddr() const
91 {
92 	return fLocalAddr;
93 }
94 
95 const BNetAddress & BNetEndpoint::RemoteAddr() const
96 {
97 	return fRemoteAddr;
98 }
99 
100 status_t BNetEndpoint::SetProtocol(int protocol)
101 {
102 	Close();
103 	if ((fSocket = ::socket(AF_INET, protocol, 0)) < 0)
104 		return B_ERROR;
105 	return B_OK;
106 }
107 
108 status_t BNetEndpoint::SetOption(int32 option, int32 level,
109 							 	 const void * data, unsigned int length)
110 {
111 	if (setsockopt(fSocket, level, option, data, length) < 0)
112 		return B_ERROR;
113 	return B_OK;
114 }
115 
116 status_t BNetEndpoint::SetNonBlocking(bool enable)
117 {
118 	int flags = fcntl(fSocket, F_GETFL);
119 	if (enable)
120 		flags |= O_NONBLOCK;
121 	else
122 		flags &= ~O_NONBLOCK;
123 	if (fcntl(fSocket, F_SETFL, flags) < 0)
124 		return B_ERROR;
125 	return B_OK;
126 }
127 
128 status_t BNetEndpoint::SetReuseAddr(bool enable)
129 {
130 	return SetOption(SO_REUSEADDR, SOL_SOCKET, &enable, sizeof(enable));
131 }
132 
133 void BNetEndpoint::SetTimeout(bigtime_t timeout)
134 {
135 	fTimeout = timeout;
136 }
137 
138 status_t BNetEndpoint::Bind(const BNetAddress & address)
139 {
140 	sockaddr_in addr;
141 	if (address.GetAddr(addr) == B_OK) {
142 		if (bind(fSocket, (sockaddr *) &addr, sizeof(addr)) >= 0) {
143 			sockaddr_in name;
144 			int length = sizeof(name);
145 
146 			if (getsockname(fSocket, (sockaddr *) &name, &length) >= 0)
147 				fLocalAddr.SetTo(name);
148 
149 			return B_OK;
150 		}
151 	}
152 	return B_ERROR;
153 }
154 
155 status_t BNetEndpoint::Bind(int port)
156 {
157 	char hostname[256];
158 
159 	if (gethostname(hostname, sizeof(hostname)) >= 0)
160 		return BNetEndpoint::Bind(BNetAddress(hostname, port));
161 	return B_ERROR;
162 }
163 
164 void BNetEndpoint::Close()
165 {
166 	close(fSocket);
167 	fSocket = 0;
168 }
169 
170 status_t BNetEndpoint::Connect(const BNetAddress & address)
171 {
172 	sockaddr_in addr;
173 	if (address.GetAddr(addr) == B_OK) {
174 		if (connect(fSocket, (sockaddr *) &addr, sizeof(addr)) >= 0) {
175 			sockaddr_in name;
176 			int length = sizeof(name);
177 
178 			if (getpeername(fSocket, (sockaddr *) &name, &length) >= 0)
179 				fRemoteAddr.SetTo(name);
180 			return B_OK;
181 		}
182 	}
183 	return B_ERROR;
184 }
185 
186 status_t BNetEndpoint::Connect(const char * hostname, int port)
187 {
188 	BNetAddress address(hostname, port);
189 
190 	return BNetEndpoint::Connect(address);
191 }
192 
193 status_t BNetEndpoint::Listen(int backlog)
194 {
195 	if (listen(fSocket, backlog) < 0)
196 		return B_ERROR;
197 	return B_OK;
198 }
199 
200 BNetEndpoint *BNetEndpoint::Accept(int32 timeout)
201 {
202 	if (IsDataPending(timeout < 0 ? B_INFINITE_TIMEOUT : 1000LL * timeout)) {
203 		sockaddr_in name;
204 		int length = sizeof(name);
205 
206 		int handle = accept(fSocket, (sockaddr *) &name, &length);
207 		if (handle >= 0) {
208 			BNetEndpoint * endpoint = new BNetEndpoint(handle, fTimeout);
209 			if (endpoint != NULL) {
210 				endpoint->fRemoteAddr.SetTo(name);
211 				if (getsockname(handle, (sockaddr *) &name, &length) >= 0)
212 					endpoint->fLocalAddr.SetTo(name);
213 			}
214 			return endpoint;
215 		}
216 	}
217 	return NULL;
218 }
219 
220 bool BNetEndpoint::IsDataPending(bigtime_t timeout)
221 {
222 	fd_set fds;
223 	struct timeval tv;
224 
225 	FD_ZERO(&fds);
226 	FD_SET(fSocket, &fds);
227 
228 	tv.tv_sec = timeout / 1000000;
229 	tv.tv_usec = (timeout % 1000000);
230 
231 	return (select(fSocket + 1, &fds, NULL, NULL, &tv) > 0);
232 }
233 
234 int32 BNetEndpoint::Receive(void * buffer, size_t length, int flags)
235 {
236 	if (IsDataPending(fTimeout))
237 		return recv(fSocket, buffer, length, flags);
238 	return -1;
239 }
240 
241 int32 BNetEndpoint::Receive(BNetBuffer & buffer, size_t length, int flags)
242 {
243 	BNetBuffer chunk(length);
244 	length = Receive(chunk.Data(), chunk.Size(), flags);
245 	buffer.AppendData(chunk.Data(), length);
246 	return length;
247 }
248 
249 int32 BNetEndpoint::ReceiveFrom(void * buffer, size_t length,
250 							    const BNetAddress & address, int flags)
251 {
252 	sockaddr_in addr;
253 	int addrlen = sizeof(addr);
254 	if (address.GetAddr(addr) == B_OK && IsDataPending(fTimeout))
255 		return recvfrom(fSocket, buffer, length, flags,
256 						(sockaddr *) &addr, &addrlen);
257 	return -1;
258 }
259 
260 int32 BNetEndpoint::ReceiveFrom(BNetBuffer & buffer,
261 							    const BNetAddress & address, int flags)
262 {
263 	return ReceiveFrom(buffer.Data(), buffer.Size(), address, flags);
264 }
265 
266 int32 BNetEndpoint::Send(const void * buffer, size_t length, int flags)
267 {
268 	return send(fSocket, (const char *) buffer, length, flags);
269 }
270 
271 int32 BNetEndpoint::Send(const BNetBuffer & buffer, int flags)
272 {
273 	return Send(buffer.Data(), buffer.Size(), flags);
274 }
275 
276 int32 BNetEndpoint::SendTo(const void * buffer, size_t length,
277 						   const BNetAddress & address, int flags)
278 {
279 	sockaddr_in addr;
280 	address.GetAddr(addr);
281 	return sendto(fSocket, buffer, length, flags,
282 				  (sockaddr *) &addr, sizeof(addr));
283 }
284 
285 int32 BNetEndpoint::SendTo(const BNetBuffer & buffer,
286 						   const BNetAddress & address, int flags)
287 {
288 	return SendTo(buffer.Data(), buffer.Size(), address, flags);
289 }
290