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