00001 #ifndef TCPIP_STACK_IMPLEMENTATION_FILE
00002 #define TCPIP_STACK_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "address.h"
00023 #include "imp_sockets.h"
00024 #include "machine_uid.h"
00025 #include "tcpip_definitions.h"
00026 #include "tcpip_stack.h"
00027
00028 #include <basis/function.h>
00029 #include <basis/portable.h>
00030 #include <basis/string_array.h>
00031
00032 #ifdef __UNIX__
00033 #include <arpa/inet.h>
00034 #include <errno.h>
00035 #include <memory.h>
00036 #include <netdb.h>
00037 #include <sys/ioctl.h>
00038 #include <sys/socket.h>
00039 #include <sys/time.h>
00040 #include <sys/types.h>
00041 #include <termios.h>
00042 #include <unistd.h>
00043 #endif
00044
00045
00046
00047
00048 #undef LOG
00049 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger(), to_print)
00050
00052
00053 #ifdef __WIN32__
00054 const WORD WINSOCK_VERSION_REQUIRED = 0x0101;
00055
00056 #endif
00057
00059
00060 tcpip_stack::tcpip_stack()
00061 : _healthy(initialize_tcpip())
00062 {}
00063
00064 tcpip_stack::~tcpip_stack()
00065 {
00066 deinitialize_tcpip();
00067 _healthy = false;
00068 }
00069
00070 bool tcpip_stack::initialize_tcpip()
00071 {
00072 #undef static_class_name
00073 #define static_class_name() "tcpip_stack"
00074 FUNCDEF("initialize_tcpip");
00075 #ifdef __WIN32__
00076
00077 WORD desired_winsock = WINSOCK_VERSION_REQUIRED;
00078 WSADATA startup_data;
00079 int error = WSAStartup(desired_winsock, &startup_data);
00080 if (error) {
00081 LOG(istring("startup error: ") + tcpip_error_name(portable::system_error()));
00082 return false;
00083 }
00084 #endif
00085 return true;
00086 #undef static_class_name
00087 }
00088
00089 void tcpip_stack::deinitialize_tcpip()
00090 {
00091 #ifdef __WIN32__
00092 WSACleanup();
00093 #endif
00094 }
00095
00096 istring tcpip_stack::hostname() const
00097 {
00098 FUNCDEF("hostname");
00099 char hostname[256];
00100 hostname[0] = '\0';
00101
00102 if (negative(gethostname(hostname, 255))) {
00103 LOG(istring(istring::SPRINTF, "gethostname error %s.",
00104 tcpip_error_name(portable::system_error()).s()));
00105 return hostname;
00106 }
00107 return hostname;
00108 }
00109
00110 istring tcpip_stack::tcpip_error_name(int error_value)
00111 {
00112 switch (error_value) {
00113
00114 case SOCK_EINTR: return "EINTR";
00115 case SOCK_EBADF: return "EBADF";
00116 case SOCK_EACCES: return "EACCES";
00117 case SOCK_EFAULT: return "EFAULT";
00118 case SOCK_EINVAL: return "EINVAL";
00119 case SOCK_EMFILE: return "EMFILE";
00120 case SOCK_EWOULDBLOCK: return "EWOULDBLOCK";
00121 case SOCK_EINPROGRESS: return "EINPROGRESS";
00122 case SOCK_EALREADY: return "EALREADY";
00123 case SOCK_ENOTSOCK: return "ENOTSOCK";
00124 case SOCK_EDESTADDRREQ: return "EDESTADDRREQ";
00125 case SOCK_EMSGSIZE: return "EMSGSIZE";
00126 case SOCK_EPROTOTYPE: return "EPROTOTYPE";
00127 case SOCK_ENOPROTOOPT: return "ENOPROTOOPT";
00128 case SOCK_EPROTONOSUPPORT: return "EPROTONOSUPPORT";
00129 case SOCK_ESOCKTNOSUPPORT: return "ESOCKTNOSUPPORT";
00130 case SOCK_EOPNOTSUPP: return "EOPNOTSUPP";
00131 case SOCK_EPFNOSUPPORT: return "EPFNOSUPPORT";
00132 case SOCK_EAFNOSUPPORT: return "EAFNOSUPPORT";
00133 case SOCK_EADDRINUSE: return "EADDRINUSE";
00134 case SOCK_EADDRNOTAVAIL: return "EADDRNOTAVAIL";
00135 case SOCK_ENETDOWN: return "ENETDOWN";
00136 case SOCK_ENETUNREACH: return "ENETUNREACH";
00137 case SOCK_ENETRESET: return "ENETRESET";
00138 case SOCK_ECONNABORTED: return "ECONNABORTED";
00139 case SOCK_ECONNRESET: return "ECONNRESET";
00140 case SOCK_ENOBUFS: return "ENOBUFS";
00141 case SOCK_EISCONN: return "EISCONN";
00142 case SOCK_ENOTCONN: return "ENOTCONN";
00143 case SOCK_ESHUTDOWN: return "ESHUTDOWN";
00144 case SOCK_ETOOMANYREFS: return "ETOOMANYREFS";
00145 case SOCK_ETIMEDOUT: return "ETIMEDOUT";
00146 case SOCK_ECONNREFUSED: return "ECONNREFUSED";
00147 case SOCK_ELOOP: return "ELOOP";
00148 case SOCK_ENAMETOOLONG: return "ENAMETOOLONG";
00149 case SOCK_EHOSTDOWN: return "EHOSTDOWN";
00150 case SOCK_EHOSTUNREACH: return "EHOSTUNREACH";
00151 case SOCK_ENOTEMPTY: return "ENOTEMPTY";
00152 case SOCK_EUSERS: return "EUSERS";
00153 case SOCK_EDQUOT: return "EDQUOT";
00154 case SOCK_ESTALE: return "ESTALE";
00155 case SOCK_EREMOTE: return "EREMOTE";
00156 #ifdef __WIN32__
00157 case SOCK_EPROCLIM: return "EPROCLIM";
00158 case SOCK_SYSNOTREADY: return "SYSNOTREADY";
00159 case SOCK_VERNOTSUPPORTED: return "VERNOTSUPPORTED";
00160 case SOCK_HOST_NOT_FOUND: return "HOST_NOT_FOUND";
00161 case SOCK_TRY_AGAIN: return "TRY_AGAIN";
00162 case SOCK_NO_RECOVERY: return "NO_RECOVERY";
00163 case SOCK_NO_DATA: return "NO_DATA";
00164 case SOCK_NOTINITIALISED: return "NOTINITIALISED";
00165 #endif
00166 }
00167
00168
00169 return portable::system_error_text(error_value);
00170 }
00171
00173
00174 bool tcpip_stack::enumerate_adapters(string_array &ip_addresses,
00175 bool add_local) const
00176 {
00177 FUNCDEF("enumerate_adapters");
00178 ip_addresses.reset();
00179
00180 if (add_local)
00181 ip_addresses += "127.0.0.1";
00183
00184
00186 istring this_host = hostname();
00187 #ifdef DEBUG_TCPIP_STACK
00188 LOG(istring("hostname is \"") + this_host + istring("\"."));
00189 #endif
00190 if (!this_host) {
00191 #ifdef DEBUG_TCPIP_STACK
00192 LOG("failed to get the hostname for this machine!");
00193 #endif
00194 return false;
00195 }
00196
00197 hostent *host_entry = gethostbyname(this_host.s());
00198 if (!host_entry) {
00199 #ifdef DEBUG_TCPIP_STACK
00200 LOG(istring("failed to get host entry for \"") + this_host + "\".");
00201 #endif
00202 return false;
00203 }
00204 for (int adapter_num = 0; ; adapter_num++) {
00205 in_addr *current_entry = (in_addr *)host_entry->h_addr_list[adapter_num];
00206 if (!current_entry) break;
00207 char *ip_address = inet_ntoa(*current_entry);
00208 #ifdef DEBUG_TCPIP_STACK
00209 LOG(istring("current is: ") + istring(ip_address));
00210 #endif
00211 ip_addresses += ip_address;
00212 }
00214
00215 #ifdef DEBUG_TCPIP_STACK
00216 LOG(istring("read addresses:") + log_base::platform_ending()
00217 + ip_addresses.text_form());
00218 #endif
00219
00220 return !!ip_addresses.length();
00221 }
00222
00223 bool tcpip_stack::enumerate_adapters(machine_uid_array &ip_addresses,
00224 bool add_local) const
00225 {
00226 ip_addresses.reset();
00227 string_array text_list;
00228 if (!enumerate_adapters(text_list, add_local))
00229 return false;
00230 for (int i = 0; i < text_list.length(); i++) {
00231 bool worked;
00232 internet_address addr_form = fill_and_resolve(text_list[i], 0, worked);
00233 if (worked) {
00234 hostname().stuff(addr_form.hostname, addr_form.MAXIMUM_HOSTNAME_LENGTH);
00235 ip_addresses += addr_form.convert();
00236 }
00237 }
00238 return !!ip_addresses.elements();
00239 }
00240
00241 sockaddr tcpip_stack::convert(const internet_address &make_from)
00242 {
00243 FUNCDEF("convert [to sockaddr]");
00244 sockaddr_in new_socket;
00245 memset(&new_socket, 0, sizeof(new_socket));
00246 new_socket.sin_family = AF_INET;
00247 byte_array ip(internet_address::ADDRESS_SIZE, make_from.ip_address);
00248 ip.stuff(internet_address::ADDRESS_SIZE, (byte *)&new_socket.sin_addr);
00249 new_socket.sin_port = htons(u_short(make_from.port));
00250
00251
00252 sockaddr to_return;
00253 memset(&to_return, 0, sizeof(to_return));
00254 memory_assign(&to_return, (sockaddr *)&new_socket, sizeof(new_socket));
00255
00256 return to_return;
00257 }
00258
00259 internet_address tcpip_stack::convert(const sockaddr &make_from_o)
00260 {
00261 const sockaddr_in *make_from = (const sockaddr_in *)&make_from_o;
00262 byte_array ip(internet_address::ADDRESS_SIZE, (byte *)&make_from->sin_addr);
00263 internet_address to_return;
00264 to_return.fill(ip, "", ntohs(make_from->sin_port));
00265 return to_return;
00266 }
00267
00268 byte_array tcpip_stack::full_resolve(const istring &hostname,
00269 istring &full_hostname) const
00270 {
00271 FUNCDEF("full_resolve");
00272 if (!hostname) return byte_array();
00273 full_hostname.reset();
00274
00275 if ( hostname.iequals("local") || hostname.iequals("localhost") ) {
00276 byte_array to_return = internet_address::localhost();
00277 full_hostname = "localhost";
00278 return to_return;
00279 } else if (hostname.iequals("inaddr_any")
00280 || hostname.iequals("any-address")) {
00281 byte_array to_return = internet_address::nil_address();
00282 full_hostname = "inaddr_any";
00283 return to_return;
00284 }
00285
00286
00287 hostent *machine = gethostbyname(hostname.observe());
00288 if (!machine) {
00289 LOG(istring(istring::SPRINTF, "gethostbyname error %s.",
00290 tcpip_error_name(portable::system_error()).s()));
00291 return byte_array();
00292 }
00293 full_hostname = istring(machine->h_name);
00294 return byte_array(machine->h_length, (byte *)machine->h_addr);
00295 }
00296
00297 bool tcpip_stack::resolve_any(const istring &hostname,
00298 internet_address &to_return) const
00299 {
00300 FUNCDEF("resolve_any");
00301 to_return = internet_address();
00302 if (!hostname) return false;
00303 istring full_host;
00304 byte_array ip = full_resolve(hostname, full_host);
00305 if (!ip.length()) return false;
00306
00307 full_host.stuff(to_return.hostname,
00308 internet_address::MAXIMUM_HOSTNAME_LENGTH);
00309
00310 ip.stuff(internet_address::ADDRESS_SIZE, (byte *)&to_return.ip_address);
00311 return true;
00312 }
00313
00314 istring tcpip_stack::dns_resolve(const istring &hostname) const
00315 {
00316 FUNCDEF("dns_resolve");
00317 if (!hostname) return "";
00318 if (hostname.iequals("local") || hostname.iequals("localhost")) {
00319 return "127.0.0.1";
00320 } else if (hostname.iequals("inaddr_any")
00321 || hostname.iequals("any-address")) {
00322 return "0.0.0.0";
00323 }
00324
00325
00326 hostent *machine = gethostbyname(hostname.observe());
00327 if (!machine) {
00328 return "";
00329 }
00330 byte_array ip(machine->h_length, (byte *)machine->h_addr);
00331
00332 istring to_return;
00333 for (int i = 0; i < ip.length(); i++) {
00334 to_return += istring(istring::SPRINTF, "%d", int(ip[i]));
00335 if (i != ip.length() - 1) to_return += ".";
00336 }
00337 return to_return;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 machine_uid tcpip_stack::this_host(int location_type) const
00362 {
00363 switch (location_type) {
00364 case machine_uid::TCPIP_LOCATION: {
00365 istring host = hostname();
00366 istring full_host;
00367 byte_array ip = full_resolve(host, full_host);
00368 if (!ip.length()) return machine_uid();
00369 return internet_machine_uid(full_host, ip);
00370 }
00371 case machine_uid::IPX_LOCATION: {
00373 return machine_uid();
00374 break;
00375 }
00376 case machine_uid::NETBIOS_LOCATION: {
00378 return machine_uid();
00379 break;
00380 }
00381 default:
00382
00383 return machine_uid();
00384 }
00385 }
00386
00387 internet_address tcpip_stack::fill_and_resolve(const istring &machine_in,
00388 int port, bool &worked) const
00389 {
00390 internet_address to_return;
00391 istring machine = machine_in;
00392 machine.to_lower();
00393 if (!machine) machine = "local";
00394 bool resolved = false;
00395 byte_array ip_addr;
00396 bool is_ip = false;
00397 if (machine.iequals("local") || machine.iequals("localhost")) {
00398
00399 machine = "localhost";
00400 ip_addr = internet_address::localhost();
00401 is_ip = true;
00402 resolved = true;
00403 } else if (machine.iequals("inaddr_any")
00404 || machine.iequals("any-address")) {
00405
00406 machine = "inaddr_any";
00407 ip_addr = internet_address::nil_address();
00408 is_ip = true;
00409 resolved = true;
00410 } else {
00411
00412 bool all_zeros;
00413 is_ip = internet_address::is_valid_internet_address(machine, ip_addr,
00414 all_zeros);
00415 }
00416 if (is_ip) {
00417
00418
00419
00420
00421 if (resolved) to_return.fill(ip_addr, machine, port);
00422 else to_return.fill(ip_addr, istring::empty_string(), port);
00423 resolved = true;
00424 } else {
00425
00426 istring full_host;
00427 ip_addr = full_resolve(machine, full_host);
00428 if (ip_addr.length()) {
00429 to_return.fill(ip_addr, machine, port);
00430 resolved = true;
00431 }
00432 }
00433 worked = resolved;
00434 return to_return;
00435 }
00436
00437
00438 #endif //TCPIP_STACK_IMPLEMENTATION_FILE
00439