1 #include "gsocket.h"
2 #include <errno.h> // For errno
3
4 #ifdef _WIN32
5 static bool initialized = false;
6 #endif
7
GSocketErr(GStr message,bool inclSysMsg)8 void GSocketErr(GStr message, bool inclSysMsg) {
9 if (inclSysMsg) {
10 message.append(": ");
11 message.append(strerror(errno));
12 }
13 GError("%s\n",message.chars());
14 }
15
16 // Function to fill in address structure given an address and port
fillAddr(const GStr & address,unsigned short port,sockaddr_in & addr)17 static void fillAddr(const GStr &address, unsigned short port,
18 sockaddr_in &addr) {
19 memset(&addr, 0, sizeof(addr)); // Zero out address structure
20 addr.sin_family = AF_INET; // Internet address
21
22 hostent *host; // Resolve name
23 if ((host = gethostbyname(address.chars())) == NULL) {
24 // strerror() will not work for gethostbyname() and hstrerror()
25 // is supposedly obsolete
26 GSocketErr("Failed to resolve name (gethostbyname())");
27 }
28 addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
29
30 addr.sin_port = htons(port); // Assign port in network byte order
31 }
32
33 // GSocket Code
34
GSocket(int type,int protocol)35 GSocket::GSocket(int type, int protocol) {
36 #ifdef _WIN32
37 if (!initialized) {
38 WORD wVersionRequested;
39 WSADATA wsaData;
40
41 wVersionRequested = MAKEWORD(2, 0); // Request WinSock v2.0
42 if (WSAStartup(wVersionRequested, &wsaData) != 0) { // Load WinSock DLL
43 GSocketErr("Unable to load WinSock DLL");
44 }
45 initialized = true;
46 }
47 #endif
48
49 // Make a new socket
50 if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
51 GSocketErr("GSocket creation failed (socket())", true);
52 }
53 }
54
~GSocket()55 GSocket::~GSocket() {
56 #ifdef _WIN32
57 ::closesocket(sockDesc);
58 #else
59 ::close(sockDesc);
60 #endif
61 sockDesc = -1;
62 }
63
getLocalAddress()64 GStr GSocket::getLocalAddress() {
65 sockaddr_in addr;
66 unsigned int addr_len = sizeof(addr);
67
68 if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
69 GSocketErr("Fetch of local address failed (getsockname())", true);
70 }
71 return inet_ntoa(addr.sin_addr);
72 }
73
getLocalPort()74 unsigned short GSocket::getLocalPort() {
75 sockaddr_in addr;
76 unsigned int addr_len = sizeof(addr);
77
78 if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
79 GSocketErr("Fetch of local port failed (getsockname())", true);
80 }
81 return ntohs(addr.sin_port);
82 }
83
setLocalPort(unsigned short localPort)84 void GSocket::setLocalPort(unsigned short localPort) {
85 // Bind the socket to its port
86 sockaddr_in localAddr;
87 memset(&localAddr, 0, sizeof(localAddr));
88 localAddr.sin_family = AF_INET;
89 localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
90 localAddr.sin_port = htons(localPort);
91
92 if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
93 GSocketErr("Set of local port failed (bind())", true);
94 }
95 }
96
setLocalAddressAndPort(const GStr & localAddress,unsigned short localPort)97 void GSocket::setLocalAddressAndPort(const GStr &localAddress,
98 unsigned short localPort) {
99 // Get the address of the requested host
100 sockaddr_in localAddr;
101 fillAddr(localAddress, localPort, localAddr);
102
103 if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
104 GSocketErr("Set of local address and port failed (bind())", true);
105 }
106 }
107
cleanUp()108 void GSocket::cleanUp() {
109 #ifdef _WIN32
110 if (WSACleanup() != 0) {
111 GSocketErr("WSACleanup() failed");
112 }
113 #endif
114 }
115
resolveService(const GStr & service,const GStr & protocol)116 unsigned short GSocket::resolveService(const GStr &service,
117 const GStr &protocol) {
118 struct servent *serv; /* Structure containing service information */
119
120 if ((serv = getservbyname(service.chars(), protocol.chars())) == NULL)
121 return atoi(service.chars()); /* Service is port number */
122 else
123 return ntohs(serv->s_port); /* Found port (network byte order) by name */
124 }
125
126 // GCommSocket Code
setTimeout(int microsecs)127 void GCommSocket::setTimeout(int microsecs) {
128 #ifdef _WIN32
129 DWORD timeout = microsecs;
130 setsockopt(sockDesc, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
131 #else
132 struct timeval tv;
133 if (microsecs>1000) {
134 tv.tv_sec=microsecs / 1000;
135 tv.tv_usec=microsecs % 1000;
136 } else {
137 tv.tv_sec=0;
138 tv.tv_usec=microsecs;
139 }
140 setsockopt(sockDesc, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));
141 #endif
142 }
143
connect(const GStr & foreignAddress,unsigned short foreignPort)144 void GCommSocket::connect(const GStr &foreignAddress,
145 unsigned short foreignPort) {
146 // Get the address of the requested host
147 sockaddr_in destAddr;
148 fillAddr(foreignAddress, foreignPort, destAddr);
149
150 // Try to connect to the given port
151 if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
152 GSocketErr("Connect failed (connect())", true);
153 }
154 }
155
send(const void * buffer,int bufferLen)156 void GCommSocket::send(const void *buffer, int bufferLen) {
157 if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) {
158 GSocketErr("Send failed (send())", true);
159 }
160 }
161
recv(void * buffer,int bufferLen)162 int GCommSocket::recv(void *buffer, int bufferLen) {
163 int rtn;
164 if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
165 GSocketErr("Received failed (recv())", true);
166 }
167 return rtn;
168 }
169
recvline()170 GStr GCommSocket::recvline() {
171 GStr r;
172 char buf[1024];
173 char* p=NULL;
174 while (p==NULL) {
175 int rtn = ::recv(sockDesc, (raw_type *) buf, 1024, 0);
176 if (rtn<0) GSocketErr("Received failed (recv())", true);
177 if (rtn==0) return r;
178 p=(char*)memchr((void*)buf, '\n', rtn);
179 if (p) {
180 r.appendmem(buf, p-buf);
181 return r;
182 }
183 r.appendmem(buf, rtn);
184 }
185 return r;
186 }
187
188
getForeignAddress()189 GStr GCommSocket::getForeignAddress() {
190 sockaddr_in addr;
191 unsigned int addr_len = sizeof(addr);
192 if (getpeername(sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
193 //GSocketErr("Fetch of foreign address failed (getpeername())", true);
194 return "";
195 }
196 return inet_ntoa(addr.sin_addr);
197 }
198
199
200
201
getForeignPort()202 unsigned short GCommSocket::getForeignPort() {
203 sockaddr_in addr;
204 unsigned int addr_len = sizeof(addr);
205 if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
206 return 0;
207 }
208 return ntohs(addr.sin_port);
209 }
210
211 // GTCPServerSocket Code
212
accept()213 GTCPSocket *GTCPServerSocket::accept() {
214 int newConnSD;
215 if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
216 GSocketErr("Accept failed (accept())", true);
217 }
218
219 return new GTCPSocket(newConnSD);
220 }
221
setListen(int queueLen)222 void GTCPServerSocket::setListen(int queueLen) {
223 if (listen(sockDesc, queueLen) < 0)
224 GSocketErr("Set listening socket failed (listen())", true);
225 }
226
227 // GUDPSocket Code
228
setBroadcast()229 void GUDPSocket::setBroadcast() {
230 // If this fails, we'll hear about it when we try to send. This will allow
231 // system that cannot broadcast to continue if they don't plan to broadcast
232 int broadcastPermission = 1;
233 setsockopt(sockDesc, SOL_SOCKET, SO_BROADCAST,
234 (raw_type *) &broadcastPermission, sizeof(broadcastPermission));
235 }
236
disconnect()237 void GUDPSocket::disconnect() {
238 sockaddr_in nullAddr;
239 memset(&nullAddr, 0, sizeof(nullAddr));
240 nullAddr.sin_family = AF_UNSPEC;
241
242 // Try to disconnect
243 if (::connect(sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) {
244 #ifdef _WIN32
245 if (errno != WSAEAFNOSUPPORT) {
246 #else
247 if (errno != EAFNOSUPPORT) {
248 #endif
249 GSocketErr("Disconnect failed (connect())", true);
250 }
251 }
252 }
253
254 void GUDPSocket::sendTo(const void *buffer, int bufferLen,
255 const GStr &foreignAddress, unsigned short foreignPort) {
256 sockaddr_in destAddr;
257 fillAddr(foreignAddress, foreignPort, destAddr);
258 // Write out the whole buffer as a single message.
259 if (sendto(sockDesc, (raw_type *) buffer, bufferLen, 0,
260 (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) {
261 GSocketErr("Send failed (sendto())", true);
262 }
263 }
264
265 int GUDPSocket::recvFrom(void *buffer, int bufferLen, GStr &sourceAddress,
266 unsigned short &sourcePort) {
267 sockaddr_in clntAddr;
268 socklen_t addrLen = sizeof(clntAddr);
269 int rtn;
270 if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0,
271 (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
272 GSocketErr("Receive failed (recvfrom())", true);
273 }
274 sourceAddress = inet_ntoa(clntAddr.sin_addr);
275 sourcePort = ntohs(clntAddr.sin_port);
276
277 return rtn;
278 }
279
280 void GUDPSocket::setMulticastTTL(unsigned char multicastTTL) {
281 if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL,
282 (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) {
283 GSocketErr("Multicast TTL set failed (setsockopt())", true);
284 }
285 }
286
287 void GUDPSocket::joinGroup(const GStr &multicastGroup) {
288 struct ip_mreq multicastRequest;
289
290 multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.chars());
291 multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
292 if (setsockopt(sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,
293 (raw_type *) &multicastRequest,
294 sizeof(multicastRequest)) < 0) {
295 GSocketErr("Multicast group join failed (setsockopt())", true);
296 }
297 }
298
299 void GUDPSocket::leaveGroup(const GStr &multicastGroup) {
300 struct ip_mreq multicastRequest;
301
302 multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.chars());
303 multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
304 if (setsockopt(sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP,
305 (raw_type *) &multicastRequest,
306 sizeof(multicastRequest)) < 0) {
307 GSocketErr("Multicast group leave failed (setsockopt())", true);
308 }
309 }
310