1 /*
2  *
3  *  C++ Portable Types Library (PTypes)
4  *  Version 2.1.1  Released 27-Jun-2007
5  *
6  *  Copyright (C) 2001-2007 Hovik Melikyan
7  *
8  *  http://www.melikyan.com/ptypes/
9  *
10  */
11 
12 #ifdef WIN32
13 #  include <winsock2.h>
14 #else
15 #  include <sys/time.h>
16 #  include <sys/types.h>
17 #  include <sys/socket.h>
18 #  include <netinet/in.h>
19 #  include <arpa/inet.h>
20 #  include <netdb.h>
21 #  include <unistd.h>
22 #  include <time.h>
23 #endif
24 
25 
26 #include "pinet.h"
27 
28 
29 PTYPES_BEGIN
30 
31 
32 //
33 // ipmessage: IPv4 UDP message class
34 //
35 
36 
ipmessage()37 ipmessage::ipmessage()
38     : unknown(), ippeerinfo(ipnone, nullstring, 0), handle(invhandle)  {}
39 
40 
ipmessage(ipaddress iip,int iport)41 ipmessage::ipmessage(ipaddress iip, int iport)
42     : unknown(), ippeerinfo(iip, nullstring, iport), handle(invhandle)  {}
43 
44 
ipmessage(const char * ihost,int iport)45 ipmessage::ipmessage(const char* ihost, int iport)
46     : unknown(), ippeerinfo(ipnone, ihost, iport), handle(invhandle)  {}
47 
48 
ipmessage(const string & ihost,int iport)49 ipmessage::ipmessage(const string& ihost, int iport)
50     : unknown(), ippeerinfo(ipnone, ihost, iport), handle(invhandle)  {}
51 
52 
~ipmessage()53 ipmessage::~ipmessage()
54 {
55     close();
56 }
57 
58 
set_ip(ipaddress iip)59 void ipmessage::set_ip(ipaddress iip)
60 {
61     ip = iip;
62     PTYPES_NAMESPACE::clear(host);
63 }
64 
65 
set_host(const string & ihost)66 void ipmessage::set_host(const string& ihost)
67 {
68     host = ihost;
69     ip = 0;
70 }
71 
72 
set_host(const char * ihost)73 void ipmessage::set_host(const char* ihost)
74 {
75     host = ihost;
76     ip = 0;
77 }
78 
79 
set_port(int iport)80 void ipmessage::set_port(int iport)
81 {
82     port = iport;
83 }
84 
85 
get_myip()86 ipaddress ipmessage::get_myip()
87 {
88     ippeerinfo p;
89     if (!psockname(handle, p))
90         error(usockerrno(), "Couldn't get my IP");
91     return p.get_ip();
92 }
93 
94 
get_myport()95 int ipmessage::get_myport()
96 {
97     ippeerinfo p;
98     if (!psockname(handle, p))
99         error(usockerrno(), "Couldn't get my port number");
100     return p.get_port();
101 }
102 
103 
close()104 void ipmessage::close()
105 {
106     if (handle != invhandle)
107         ::closesocket(pexchange(&handle, invhandle));
108 }
109 
110 
open()111 void ipmessage::open()
112 {
113     close();
114     if ((handle = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0)
115         error(usockerrno(), "Couldn't create socket");
116     // allow broadcasts
117     int one = 1;
118     if (::setsockopt(handle, SOL_SOCKET, SO_BROADCAST, (sockval_t)&one, sizeof(one)) != 0)
119         error(usockerrno(), "Couldn't enable broadcasts");
120     sockopt(handle);
121 }
122 
123 
sockopt(int)124 void ipmessage::sockopt(int)
125 {
126 }
127 
128 
waitfor(int timeout)129 bool ipmessage::waitfor(int timeout)
130 {
131     return psockwait(handle, timeout);
132 }
133 
134 
send(const char * buf,int count)135 void ipmessage::send(const char* buf, int count)
136 {
137     if (handle == invhandle)
138         open();
139 
140     sockaddr_in sa;
141     memset(&sa, 0, sizeof(sa));
142     sa.sin_family = AF_INET;
143     sa.sin_port = htons(ushort(get_port()));
144     sa.sin_addr.s_addr = get_ip();
145     if (sendto(handle, buf, count, 0, (sockaddr*)&sa, sizeof(sa)) < 0)
146         error(usockerrno(), "Couldn't write");
147 }
148 
149 
receive(char * buf,int count,ipaddress & src)150 int ipmessage::receive(char* buf, int count, ipaddress& src)
151 {
152     if (handle == invhandle)
153         error(EINVAL, "Couldn't read");  // must send() first
154 
155     sockaddr_in sa;
156     psocklen fromlen = sizeof(sa);
157     int result = ::recvfrom(handle, buf, count, 0, (sockaddr*)&sa, &fromlen);
158     if (result < 0)
159         error(usockerrno(), "Couldn't read");
160     src = sa.sin_addr.s_addr;
161     return result;
162 }
163 
164 
receive(char * buf,int count)165 int ipmessage::receive(char* buf, int count)
166 {
167     ipaddress src;
168     return receive(buf, count, src);
169 }
170 
171 
receive(int max,ipaddress & src)172 string ipmessage::receive(int max, ipaddress& src)
173 {
174     string result;
175     setlength(result, max);
176     int numread = receive(pchar(pconst(result)), max, src);
177     setlength(result, numread);
178     return result;
179 }
180 
181 
receive(int max)182 string ipmessage::receive(int max)
183 {
184     ipaddress src;
185     return receive(max, src);
186 }
187 
188 
189 #ifdef _MSC_VER
190 // disable "unreachable code" warning for throw (known compiler bug)
191 #  pragma warning (disable: 4702)
192 #endif
193 
error(int code,const char * msg)194 void ipmessage::error(int code, const char* msg)
195 {
196     string s = usockerrmsg(code);
197     if (isempty(s))
198         s = msg;
199     throw new estream(nil, code, s + " [" + ippeerinfo::asstring(true) + ']');
200 }
201 
202 
203 PTYPES_END
204