Adapted to recent changes of %build_linklib.
[AROS-Contrib.git] / FryingPan / framework / Generic / NetSocket.cpp
blob8c591e626fa36191639d1389bb34297ca9c9359e
1 /*
2 * Amiga Generic Set - set of libraries and includes to ease sw development for all Amiga platforms
3 * Copyright (C) 2001-2011 Tomasz Wiszkowski Tomasz.Wiszkowski at gmail.com.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "LibrarySpool.h"
21 #include "NetSocket.h"
22 #include "Synchronizer.h"
23 #include <libclass/bsdsocket.h>
24 #include <libdata/bsdsocket/netdb.h>
25 #include <libdata/bsdsocket/in.h>
26 #include <libdata/bsdsocket/ioctl.h>
27 #include <libdata/bsdsocket/socketbasetags.h>
28 #include <libclass/exec.h>
29 #include "LibrarySpool.h"
30 #include <LibC/LibC.h>
31 #include <libclass/dos.h>
33 using namespace GenNS;
35 struct timeval
37 uint32 seconds;
38 uint32 micro;
41 int32 NetSocket::stTrue = 1;
42 int32 NetSocket::stFalse = 0;
44 NetSocket::NetSocket(NetSocket::SocketID *socket, bool isserv)
46 FConstruct(socket, isserv);
49 void NetSocket::FConstruct(NetSocket::SocketID *socket, bool server)
51 lThreadSignal=0;
53 addr_local = new sockaddr_in;
54 addr_remote = new sockaddr_in;
56 bsock = BSDSocketIFace::GetInstance(0);
57 bConnected = -1;
58 lSocket = -1;
60 bServer = server;
61 nSignal = -1;
63 if (bsock != 0)
65 int32 temp;
67 temp = Exec->AllocSignal(-1);
68 lSignal = 1<<temp;
69 SetSignals(lSignal);
70 nSignal = temp;
71 lSocket = (socket) ? bsock->ObtainSocket(socket->id, socket->domain, socket->type, socket->proto) : -1;
72 bConnected = (lSocket >= 0) ? true : false;
73 if (lSocket)
75 FSetupSocket();
80 NetSocket::~NetSocket()
82 SetSignals(0);
83 FDisconnect();
84 bsock->FreeInstance();
85 delete addr_local;
86 delete addr_remote;
89 bool NetSocket::FResolve(char* AHost, int APort, sockaddr_in *AAddr)
91 if (AHost)
93 hostent *pHost = bsock->gethostbyname(AHost);
95 if (0 != pHost)
97 Exec->CopyMem(pHost->h_addr_list[0], &AAddr->sin_addr, sizeof(AAddr->sin_addr));
99 else
101 AAddr->sin_addr.s_addr = bsock->inet_addr(AHost);
102 if (AAddr->sin_addr.s_addr == 0xffffffff)
103 return false;
106 else
108 AAddr->sin_addr.s_addr = INADDR_ANY;
111 AAddr->sin_family = AF_INET;
112 AAddr->sin_port = W2BE(APort);
113 return true;
116 bool NetSocket::FSetupSocket()
118 uint32 lSockEvMask = FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE | FD_ERROR;
119 uint32 bs = 32768;
121 if (lSocket == -1)
122 return false;
124 bsock->setsockopt(lSocket, SOL_SOCKET, SO_EVENTMASK, &lSockEvMask, sizeof(unsigned long));
125 if (error < 0)
127 //request("", "Unable to set socket options", "Ok", 0);
128 FDisconnect();
129 return false;
132 error = bsock->setsockopt(lSocket, SOL_SOCKET, SO_KEEPALIVE, &stTrue, sizeof(stTrue));
133 if (error < 0)
135 //request("", "Unable to set socket options", "Ok", 0);
136 FDisconnect();
137 return false;
140 error = bsock->setsockopt(lSocket, SOL_SOCKET, SO_SNDBUF, &bs, sizeof(bs));
141 if (error < 0)
143 //request("", "Unable to set socket options", "Ok", 0);
144 FDisconnect();
145 return false;
148 error = bsock->setsockopt(lSocket, SOL_SOCKET, SO_RCVBUF, &bs, sizeof(bs));
149 if (error < 0)
151 //request("", "Unable to set socket options", "Ok", 0);
152 FDisconnect();
153 return false;
155 bsock->IoctlSocket(lSocket, FIONBIO, (char*)&stFalse);
156 // bsock->IoctlSocket(lSocket, FIOASYNC, (char*)&stTrue);
158 return true;
161 bool NetSocket::FConnect(char* AHost, int16 APort, SocketType stype)
163 sockaddr_in addr;
165 FDisconnect();
167 error = 0;
168 lSocket = bsock->socket(AF_INET, FTypeToInet(stype), 0);
170 if (!FSetupSocket())
171 return false;
173 if (!FResolve(AHost, APort, &addr))
175 request("", "Unable to resolve host name", "Ok", 0);
176 FDisconnect();
177 return false;
180 error = bsock->connect(lSocket, (sockaddr*)&addr, sizeof(addr));
181 if (error < 0)
183 request("", "Unable to connect", "Ok", 0);
184 FDisconnect();
185 return false;
188 bServer = false;
189 bConnected = true;
191 FGetAddresses();
193 return true;
196 void NetSocket::FGetAddresses()
198 if (!bConnected)
199 return;
200 if (bsock == 0)
201 return;
203 int32 i;
205 i = sizeof(addr_local);
206 bsock->getsocketname(lSocket, (sockaddr*)addr_local, &i);
207 i = sizeof(addr_local);
208 bsock->getpeername(lSocket, (sockaddr*)addr_remote, &i);
212 void NetSocket::FDisconnect()
214 if (lSocket != -1)
216 if (bServer)
217 bsock->shutdown(lSocket, 2);
218 bsock->CloseSocket(lSocket);
220 lSocket = -1;
221 bConnected = false;
222 bServer = false;
223 return;
226 bool NetSocket::FBind(int16 APort, SocketType stype)
228 sockaddr_in addr;
229 uint32 lSockEvMask = FD_CONNECT | FD_ACCEPT | FD_READ | FD_CLOSE | FD_ERROR;
230 int32 pTrue = 1;
232 FDisconnect();
234 lSocket = bsock->socket(AF_INET, FTypeToInet(stype), 0);
235 bsock->setsockopt(lSocket, SOL_SOCKET, SO_EVENTMASK, &lSockEvMask, sizeof(unsigned long));
236 bsock->setsockopt(lSocket, SOL_SOCKET, SO_KEEPALIVE, &stTrue, sizeof(stTrue));
237 bsock->IoctlSocket(lSocket, FIONBIO, (char*)&pTrue);
238 bsock->IoctlSocket(lSocket, FIOASYNC, (char*)&pTrue);
240 if (!FResolve(0, APort, &addr))
242 FDisconnect();
243 return false;
246 error = bsock->bind(lSocket, (sockaddr*)&addr, sizeof(addr));
247 if (error < 0)
249 FDisconnect();
250 return false;
253 error = bsock->listen(lSocket, 5);
254 if (error < 0)
256 FDisconnect();
257 return false;
260 bServer = true;
261 bConnected = true;
262 FGetAddresses();
263 return true;
266 int32 NetSocket::FTypeToInet(SocketType stype)
268 switch (stype)
270 case Skt_TCP:
271 return SOCK_STREAM;
272 break;
273 case Skt_UDP:
274 return SOCK_DGRAM;
275 break;
276 default:
277 return SOCK_STREAM;
281 bool NetSocket::FTryAccept(NetSocket::SocketID *s)
283 sockaddr saddr;
284 int32 laddr = sizeof(sockaddr);
286 /* FIXME: very very very basic stuff. need to allow other types too? not sure - dgram is connectionless.
288 s->id = bsock->ReleaseSocket(bsock->accept(lSocket, &saddr, &laddr), 65536 + Utility->GetUniqueID());
289 s->domain = AF_INET;
290 s->type = SOCK_STREAM;
291 s->proto = 0;
293 return (s->id != -1);
296 int32 NetSocket::ReadBuffer(void* buffer, int32 maxlen)
298 return FReadBuffer(buffer, maxlen);
301 int32 NetSocket::WriteBuffer(void* buffer, int32 maxlen)
303 return FWriteBuffer(buffer, maxlen);
306 int32 NetSocket::FReadBuffer(void* buff, int32 len)
308 if (len == 0)
309 return 0;
311 int32 bytes;
316 bytes = WaitStatus(~0, 0);
317 if (bytes & SEv_Disconnected)
318 return -1;
319 } while (0 == (bytes & SEv_DataReady));
322 //bsock->IoctlSocket(lSocket, FIONREAD, &bytes);
327 bytes = bsock->recv(lSocket, buff, len, MSG_WAITALL);
329 if (Errno() != 11) // EAGAIN
330 break;
331 DOS->Delay(1);
332 } while (true);
334 if (bytes <= 0)
336 FDisconnect();
337 return bytes;
339 return bytes;
342 int32 NetSocket::Errno()
344 return bsock->Errno();
347 int32 NetSocket::FWriteBuffer(void* buff, int32 len)
349 int32 bs;
350 int32 sent = 0;
352 while (len > 0)
356 bs = WaitStatus(~0, 0, SEv_WriteReady | SEv_Disconnected);
357 if (bs & SEv_Disconnected)
358 return -1;
359 } while (0 == (bs & SEv_WriteReady));
365 bs = bsock->send(lSocket, &((char*)buff)[sent], len < 32768 ? len : 32768, 0);
367 if (Errno() != 11) // EAGAIN
368 break;
369 DOS->Delay(1);
370 } while (true);
372 if (bs > 0)
373 len -= bs, sent += bs;
376 return sent;
379 bool NetSocket::Listen(int APort, SocketType stype)
381 return FBind(APort, stype);
384 bool NetSocket::Connect(char* AHost, int APort, SocketType stype)
386 return FConnect(AHost, APort, stype);
389 void NetSocket::Disconnect()
391 FDisconnect();
394 bool NetSocket::Accept(NetSocket::SocketID* sid)
396 return FTryAccept(sid);
399 void NetSocket::SetSignals(uint32 signal)
401 if (nSignal)
403 Exec->FreeSignal(nSignal);
404 nSignal = -1;
406 lSignal = signal;
407 bsock->SocketBaseTagList((TagItem*)ARRAY(SBTC_SIGEVENTMASK, lSignal, 0));
408 bsock->SetSocketSignals(0, lSignal, 0);
411 uint32 NetSocket::GetSignals()
413 return lSignal;
416 int32 NetSocket::GetDataAvail()
418 int32 bytes = 0;
419 int32 error;
420 error = bsock->IoctlSocket(lSocket, FIONREAD, &bytes);
421 if (error < 0)
423 request("Info", "Disconnected? (get data avail)", "Ok", 0);
425 return bytes;
428 uint32 NetSocket::FGetStatus(uint32 millis, uint32 sigs, uint16 events)
430 fd_set rx, wx, ex;
431 int32 sock;
432 timeval tv =
434 millis/1000,
435 (millis % 1000) * 1000
438 if (!bConnected)
439 return SEv_Disconnected; // unmaskable...
441 memset(&rx, 0, sizeof(rx));
442 memset(&wx, 0, sizeof(rx));
443 if (events & (SEv_DataReady | SEv_IncomingCall))
444 FD_SET(lSocket, &rx);
445 if (events & (SEv_WriteReady))
446 FD_SET(lSocket, &wx);
447 // oob
448 Exec->CopyMem(&rx, &ex, sizeof(rx));
450 if ((sock = bsock->WaitSelect(lSocket + 1, &rx, &wx, &ex, &tv, &sigs)) < 0)
452 return SEv_Disconnected;
455 //request("Info", "%ld %lx %lx %lx", "Ok", ARRAY(sock, rx.fds_bits[0], wx.fds_bits[0], ex.fds_bits[0]));
457 sock = 0;
458 if (sigs != 0)
459 sock |= SEv_OtherEvent;
461 if (FD_ISSET(lSocket, &rx))
463 if (!bServer)
465 sock |= SEv_DataReady;
467 else
468 sock |= SEv_IncomingCall;
471 if (FD_ISSET(lSocket, &wx))
472 sock |= SEv_WriteReady;
474 Exec->SetSignal(sigs, sigs);
476 return sock;
479 uint32 NetSocket::GetStatus()
481 return FGetStatus(0, 0, SEv_AllEvents);
484 uint32 NetSocket::WaitStatus(uint32 millis, uint32 sigs, uint16 events)
486 return FGetStatus(millis, sigs, events);
489 uint32 NetSocket::GetLocalIP()
491 if (!bConnected)
492 return 0;
493 return addr_local->sin_addr.s_addr;
496 uint16 NetSocket::GetLocalPort()
498 if (!bConnected)
499 return 0;
500 return addr_local->sin_port;
503 uint32 NetSocket::GetRemoteIP()
505 if (!bConnected)
506 return 0;
507 return addr_remote->sin_addr.s_addr;
510 uint16 NetSocket::GetRemotePort()
512 if (!bConnected)
513 return 0;
514 return addr_remote->sin_port;