00001 #ifndef RAW_SOCKET_IMPLEMENTATION_FILE
00002 #define RAW_SOCKET_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "imp_sockets.h"
00019 #include "raw_socket.h"
00020 #include "tcpip_definitions.h"
00021 #include "tcpip_stack.h"
00022
00023 #include <basis/function.h>
00024 #include <basis/portable.h>
00025 #include <loggers/console_logger.h>
00026
00027 #ifdef __UNIX__
00028 #include <arpa/inet.h>
00029 #include <errno.h>
00030 #include <netinet/tcp.h>
00031 #include <sys/ioctl.h>
00032 #include <sys/socket.h>
00033 #include <unistd.h>
00034 #define OPTYPE (void *)
00035 #endif
00036 #ifdef __WIN32__
00037 #define OPTYPE (char *)
00038 #endif
00039
00040
00041
00042
00043 #undef LOG
00044 #define LOG(to_print) CLASS_EMERGENCY_LOG(console_logger(), to_print)
00045
00046 const int MULTIPLE_DISCONNECT_CHECKS = 28;
00047
00048
00049
00050
00051 class fd_set_wrapper : public fd_set {};
00052
00054
00055 const u_int NON_BLOCKING = FIONBIO;
00056 const u_int IOCTL_READ = FIONREAD;
00057
00058 #ifdef __WIN32__
00059
00060 int PASCAL FAR __WSAFDIsSet(SOCKET fd, fd_set FAR *the_set)
00061 {
00062 int i = the_set->fd_count;
00063 while (i--)
00064 if (the_set->fd_array[i] == fd)
00065 return true;
00066 return false;
00067 }
00068 #endif
00069
00071
00072 raw_socket::raw_socket()
00073 : _stack(new tcpip_stack())
00074 {}
00075
00076 raw_socket::~raw_socket()
00077 {
00078 WHACK(_stack);
00079 }
00080
00081 int raw_socket::close(u_int &socket)
00082 {
00083 int to_return = 0;
00084 #ifdef __WIN32__
00085 to_return = closesocket(socket);
00086 #endif
00087 #ifdef __UNIX__
00088 to_return = ::close(socket);
00089 #endif
00090 socket = 0;
00091 return to_return;
00092 }
00093
00094
00095 inline void combine(istring &existing, const istring &addition)
00096 {
00097 if (addition.t()) {
00098 if (existing.t()) existing += " | ";
00099 existing += addition;
00100 }
00101 }
00102
00103 istring raw_socket::interest_name(int interest)
00104 {
00105 istring to_return;
00106 if (interest & SI_CONNECTED) combine(to_return, "CONNECTED");
00107 if (interest & SI_DISCONNECTED) combine(to_return, "DISCONNECTED");
00108 if (interest & SI_WRITABLE) combine(to_return, "WRITABLE");
00109 if (interest & SI_READABLE) combine(to_return, "READABLE");
00110 if (interest & SI_ERRONEOUS) combine(to_return, "ERRONEOUS");
00111 if (!interest) combine(to_return, "NORMAL");
00112 return to_return;
00113 }
00114
00115 int raw_socket::ioctl(u_int socket, int request, void *argp) const
00116 {
00117 #ifdef __UNIX__
00118 return ::ioctl(socket, request, argp);
00119 #endif
00120 #ifdef __WIN32__
00121 return ioctlsocket(socket, request, (u_long *)argp);
00122 #endif
00123 }
00124
00125 bool raw_socket::set_non_blocking(u_int socket, bool non_blocking)
00126 {
00127 FUNCDEF("set_non_blocking");
00128 int arg = int(non_blocking);
00129 if (negative(ioctl(socket, FIONBIO, &arg))) {
00130 LOG(isprintf("Could not set FIONBIO option on raw_socket %u.", socket));
00131 return false;
00132 }
00133 return true;
00134 }
00135
00136 bool raw_socket::set_nagle_algorithm(u_int socket, bool use_nagle)
00137 {
00138 FUNCDEF("set_nagle_algorithm");
00139 int arg = int(!use_nagle);
00140 if (negative(setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, OPTYPE &arg,
00141 sizeof(arg)))) {
00142 LOG(isprintf("Could not change nagle coalescing mode on %u.", socket));
00143 return false;
00144 }
00145 return true;
00146 }
00147
00148 bool raw_socket::set_broadcast(u_int socket, bool broadcasting)
00149 {
00150 FUNCDEF("set_broadcast");
00151 int arg = int(broadcasting);
00152 if (negative(setsockopt(socket, SOL_SOCKET, SO_BROADCAST, OPTYPE &arg,
00153 sizeof(arg)))) {
00154 LOG(isprintf("Could not change broadcast mode on %u.", socket));
00155 return false;
00156 }
00157 return true;
00158 }
00159
00160 bool raw_socket::set_reuse_address(u_int socket, bool reuse)
00161 {
00162 FUNCDEF("set_reuse_address");
00163 int arg = int(reuse);
00164 if (negative(setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, OPTYPE &arg,
00165 sizeof(arg)))) {
00166 LOG(isprintf("Could not set reuse address mode on %u.", socket));
00167 return false;
00168 }
00169 return true;
00170 }
00171
00172 bool raw_socket::set_keep_alive(u_int socket, bool keep_alive)
00173 {
00174 FUNCDEF("set_keep_alive");
00175 int arg = int(keep_alive);
00176 if (negative(setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, OPTYPE &arg,
00177 sizeof(arg)))) {
00178 LOG(isprintf("Could not set keep alive mode on %u.", socket));
00179 return false;
00180 }
00181 return true;
00182 }
00183
00184 int raw_socket::select(u_int socket, int mode, int timeout) const
00185 {
00186 FUNCDEF("select [single]");
00187 if (!socket) return SI_ERRONEOUS;
00188 fd_set_wrapper read_list, write_list, exceps;
00189 int ret = inner_select(socket, mode, timeout, read_list, write_list, exceps);
00190 if (!ret) return 0;
00191 if (ret == SI_ERRONEOUS) return SI_ERRONEOUS;
00192
00193 return analyze_select_result(socket, mode, read_list, write_list, exceps);
00194 }
00195
00196 int raw_socket::inner_select(u_int socket, int mode, int timeout,
00197 fd_set_wrapper &read_list, fd_set_wrapper &write_list,
00198 fd_set_wrapper &exceptions) const
00199 {
00200 FUNCDEF("inner_select");
00201
00202
00203 FD_ZERO(&read_list); FD_SET(socket, &read_list);
00204 FD_ZERO(&write_list); FD_SET(socket, &write_list);
00205 FD_ZERO(&exceptions); FD_SET(socket, &exceptions);
00206
00207 timeval time_out = portable::fill_timeval_ms(timeout);
00208
00209
00210
00211 int ret = ::select(socket + 1,
00212 (mode & SELECTING_JUST_WRITE)? NIL : &read_list,
00213 (mode & SELECTING_JUST_READ)? NIL : &write_list,
00214 &exceptions, &time_out);
00215 int error = portable::system_error();
00216
00217 if (!ret) return 0;
00218
00219 if (ret == SOCKET_ERROR) {
00220 switch (error) {
00221
00222 case SOCK_EFAULT:
00223 case SOCK_ENETDOWN:
00224 case SOCK_EINVAL:
00225 case SOCK_EINTR:
00226 #ifdef __WIN32__
00227 case SOCK_NOTINITIALISED:
00228 #endif
00229 case SOCK_ENOTSOCK:
00230 break;
00231
00232
00233 case SOCK_EINPROGRESS:
00234 case 0:
00235 default:
00236 #ifdef DEBUG_RAW_SOCKET
00237 LOG("got to weird case, in progress or zero.");
00238 #endif
00239 return 0;
00240 }
00241 #ifdef DEBUG_RAW_SOCKET
00242 LOG(isprintf("socket %u had error %d in select: %s.",
00243 socket, error, _stack->tcpip_error_name(error).s()));
00244 #endif
00245 return SI_ERRONEOUS;
00246 }
00247
00248
00249 return SI_BASELINE;
00250 }
00251
00252 int raw_socket::test_readability(u_int socket) const
00253 {
00254 FUNCDEF("test_readability");
00255 u_int len;
00256 if (negative(ioctl(socket, IOCTL_READ, &len))) {
00257 LOG(istring(istring::SPRINTF, "socket %u had ioctl error: %s.",
00258 socket, _stack->tcpip_error_name(portable::system_error()).s()));
00259 return SI_ERRONEOUS;
00260 } else {
00261 if (positive(len)) return SI_READABLE;
00262 else return SI_DISCONNECTED;
00263 }
00264 }
00265
00266 int raw_socket::analyze_select_result(u_int socket, int mode,
00267 fd_set_wrapper &read_list, fd_set_wrapper &write_list,
00268 fd_set_wrapper &exceptions) const
00269 {
00270 FUNCDEF("analyze_select_result");
00271 int to_return = 0;
00272
00273
00274 if (FD_ISSET(socket, &exceptions)) {
00275 #ifdef DEBUG_RAW_SOCKET
00276 LOG(istring(istring::SPRINTF, "exception seen for socket %u!", socket));
00277 #endif
00278 }
00279
00280
00281 if ( ! (mode & SELECTING_JUST_WRITE) && FD_ISSET(socket, &read_list)) {
00282
00283
00284
00285 int readable = test_readability(socket);
00286 if (readable == SI_ERRONEOUS)
00287 to_return |= SI_ERRONEOUS;
00288 else if (readable == SI_READABLE)
00289 to_return |= SI_READABLE;
00290 else if (readable == SI_DISCONNECTED) {
00291
00292
00293
00294 bool really_disconnected = true;
00295 for (int i = 0; i < MULTIPLE_DISCONNECT_CHECKS; i++) {
00296 fd_set_wrapper read_list, write_list, exceps;
00297 int temp_ret = inner_select(socket, SELECTING_JUST_READ, 0, read_list,
00298 write_list, exceps);
00299
00300 if (!temp_ret) {
00301
00302
00303
00304 really_disconnected = false;
00305 break;
00306 }
00307 if (temp_ret == SI_ERRONEOUS) {
00308
00309
00310 really_disconnected = true;
00311 break;
00312 }
00313
00314 if (!FD_ISSET(socket, &read_list)) {
00315
00316
00317 really_disconnected = false;
00318 break;
00319 }
00320
00321
00322
00323 readable = test_readability(socket);
00324 if (readable != SI_DISCONNECTED) {
00325
00326 really_disconnected = false;
00327 break;
00328 }
00329 }
00330 if (really_disconnected) {
00331 #ifdef DEBUG_RAW_SOCKET
00332 LOG(isprintf("connection closed on socket %u.", socket));
00333 #endif
00334 to_return |= SI_DISCONNECTED;
00335 }
00336 }
00337 }
00338
00339
00340 if (! (mode & SELECTING_JUST_READ) && FD_ISSET(socket, &write_list)) {
00341 to_return |= SI_WRITABLE;
00342 }
00343
00344 return to_return;
00345 }
00346
00347 int raw_socket::select(int_array &read_sox, int_array &write_sox,
00348 int timeout) const
00349 {
00350 FUNCDEF("select [multiple]");
00351 if (!read_sox.length() && !write_sox.length())
00352 return 0;
00353
00354 int to_return = 0;
00355
00356
00357
00358 fd_set_wrapper read_list; FD_ZERO(&read_list);
00359 fd_set_wrapper write_list; FD_ZERO(&write_list);
00360 fd_set_wrapper exceptions; FD_ZERO(&exceptions);
00361
00362 u_int highest = 0;
00363 int i = 0;
00364 for (i = 0; i < read_sox.length(); i++) {
00365 u_int sock = (u_int)read_sox[i];
00366 if (sock > highest) highest = sock;
00367 FD_SET(sock, &read_list);
00368 }
00369 for (i = 0; i < write_sox.length(); i++) {
00370 u_int sock = (u_int)write_sox[i];
00371 if (sock > highest) highest = sock;
00372 FD_SET(sock, &write_list);
00373 }
00374
00375 timeval time_out = portable::fill_timeval_ms(timeout);
00376
00377
00378
00379 int ret = ::select(highest + 1,
00380 (read_sox.length())? &read_list : NIL,
00381 (write_sox.length())? &write_list : NIL,
00382 &exceptions, &time_out);
00383 int error = portable::system_error();
00384
00385 if (ret == SOCKET_ERROR) {
00386 switch (error) {
00387
00388 case SOCK_EFAULT:
00389 case SOCK_ENETDOWN:
00390 case SOCK_EINVAL:
00391 case SOCK_EINTR:
00392 #ifdef __WIN32__
00393 case SOCK_NOTINITIALISED:
00394 #endif
00395 case SOCK_ENOTSOCK:
00396 break;
00397
00398
00399 case SOCK_EINPROGRESS:
00400 case 0:
00401 default:
00402 #ifdef DEBUG_RAW_SOCKET
00403 LOG("got to weird case, in progress or zero.");
00404 #endif
00405
00406
00407
00408 return 0;
00409 }
00410 #ifdef DEBUG_RAW_SOCKET
00411 LOG(isprintf("sockets had error %d in select: %s.",
00412 error, _stack->tcpip_error_name(error).s()));
00413 #endif
00414
00415
00416
00417 return SI_ERRONEOUS;
00418 } else if (!ret) {
00419
00420 read_sox.reset();
00421 write_sox.reset();
00422 return 0;
00423 }
00424
00425
00426
00427 for (int k = 0; k < read_sox.length(); k++) {
00428 u_int socket = read_sox[k];
00429 int interim = analyze_select_result(socket, SELECTING_JUST_READ, read_list,
00430 write_list, exceptions);
00431 if (!interim) {
00432
00433 read_sox.zap(k, k);
00434 k--;
00435 continue;
00436 }
00437 to_return |= interim;
00438 }
00439 for (int p = 0; p < write_sox.length(); p++) {
00440 u_int socket = write_sox[p];
00441 int interim = analyze_select_result(socket, SELECTING_JUST_WRITE, read_list,
00442 write_list, exceptions);
00443 if (!interim) {
00444
00445 write_sox.zap(p, p);
00446 p--;
00447 continue;
00448 }
00449 to_return |= interim;
00450 }
00451
00452 return to_return;
00453 }
00454
00455
00456
00457 #endif //RAW_SOCKET_IMPLEMENTATION_FILE
00458