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