00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "socket.h"
00015 #include "configreader.h"
00016 #include "inspstring.h"
00017 #include "socketengine.h"
00018 #include "inspircd.h"
00019
00020 using irc::sockets::OpenTCPSocket;
00021 using irc::sockets::NonBlocking;
00022
00023 bool InspSocket::Readable()
00024 {
00025 return ((this->state != I_CONNECTING) && (this->WaitingForWriteEvent == false));
00026 }
00027
00028 InspSocket::InspSocket(InspIRCd* SI)
00029 {
00030 this->Timeout = NULL;
00031 this->state = I_DISCONNECTED;
00032 this->fd = -1;
00033 this->WaitingForWriteEvent = false;
00034 this->Instance = SI;
00035 this->IsIOHooked = false;
00036 }
00037
00038 InspSocket::InspSocket(InspIRCd* SI, int newfd, const char* ip)
00039 {
00040 this->Timeout = NULL;
00041 this->fd = newfd;
00042 this->state = I_CONNECTED;
00043 strlcpy(this->IP,ip,MAXBUF);
00044 this->WaitingForWriteEvent = false;
00045 this->Instance = SI;
00046 this->IsIOHooked = false;
00047 if (this->fd > -1)
00048 this->Instance->SE->AddFd(this);
00049 }
00050
00051 InspSocket::InspSocket(InspIRCd* SI, const std::string &ipaddr, int aport, bool listening, unsigned long maxtime, const std::string &connectbindip)
00052 {
00053 this->cbindip = connectbindip;
00054 this->fd = -1;
00055 this->Instance = SI;
00056 strlcpy(host,ipaddr.c_str(),MAXBUF);
00057 this->WaitingForWriteEvent = false;
00058 this->IsIOHooked = false;
00059 this->Timeout = NULL;
00060 if (listening)
00061 {
00062 if ((this->fd = OpenTCPSocket(host)) == ERROR)
00063 {
00064 this->fd = -1;
00065 this->state = I_ERROR;
00066 this->OnError(I_ERR_SOCKET);
00067 return;
00068 }
00069 else
00070 {
00071 if (!SI->BindSocket(this->fd,aport,(char*)ipaddr.c_str()))
00072 {
00073 this->Close();
00074 this->fd = -1;
00075 this->state = I_ERROR;
00076 this->OnError(I_ERR_BIND);
00077 this->ClosePending = true;
00078 return;
00079 }
00080 else
00081 {
00082 this->state = I_LISTENING;
00083 this->port = aport;
00084 if (this->fd > -1)
00085 {
00086 if (!this->Instance->SE->AddFd(this))
00087 {
00088 this->Close();
00089 this->state = I_ERROR;
00090 this->OnError(I_ERR_NOMOREFDS);
00091 }
00092 }
00093 return;
00094 }
00095 }
00096 }
00097 else
00098 {
00099 strlcpy(this->host,ipaddr.c_str(),MAXBUF);
00100 this->port = aport;
00101
00102 bool ipvalid = true;
00103 #ifdef IPV6
00104 if (strchr(host,':'))
00105 {
00106 in6_addr n;
00107 if (inet_pton(AF_INET6, host, &n) < 1)
00108 ipvalid = false;
00109 }
00110 else
00111 #endif
00112 {
00113 in_addr n;
00114 if (inet_aton(host,&n) < 1)
00115 ipvalid = false;
00116 }
00117 if (!ipvalid)
00118 {
00119 this->Instance->Log(DEBUG,"BUG: Hostname passed to InspSocket, rather than an IP address!");
00120 this->OnError(I_ERR_CONNECT);
00121 this->Close();
00122 this->fd = -1;
00123 this->state = I_ERROR;
00124 return;
00125 }
00126 else
00127 {
00128 strlcpy(this->IP,host,MAXBUF);
00129 timeout_val = maxtime;
00130 if (!this->DoConnect())
00131 {
00132 this->OnError(I_ERR_CONNECT);
00133 this->Close();
00134 this->fd = -1;
00135 this->state = I_ERROR;
00136 return;
00137 }
00138 }
00139 }
00140 }
00141
00142 void InspSocket::WantWrite()
00143 {
00144 this->Instance->SE->WantWrite(this);
00145 this->WaitingForWriteEvent = true;
00146 }
00147
00148 void InspSocket::SetQueues(int nfd)
00149 {
00150
00151 int sendbuf = 32768;
00152 int recvbuf = 32768;
00153 if(setsockopt(nfd,SOL_SOCKET,SO_SNDBUF,(const char *)&sendbuf,sizeof(sendbuf)) || setsockopt(nfd,SOL_SOCKET,SO_RCVBUF,(const char *)&recvbuf,sizeof(sendbuf)))
00154 {
00155
00156
00157 }
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 bool InspSocket::BindAddr(const std::string &ip)
00169 {
00170 ConfigReader Conf(this->Instance);
00171 socklen_t size = sizeof(sockaddr_in);
00172 #ifdef IPV6
00173 bool v6 = false;
00174
00175 if ((ip.empty()) || (ip.find(':') != std::string::npos))
00176 v6 = true;
00177 #endif
00178 int j = 0;
00179 while (j < Conf.Enumerate("bind") || (!ip.empty()))
00180 {
00181 std::string IP = ip.empty() ? Conf.ReadValue("bind","address",j) : ip;
00182 if (!ip.empty() || Conf.ReadValue("bind","type",j) == "servers")
00183 {
00184 if (!ip.empty() || ((IP != "*") && (IP != "127.0.0.1") && (!IP.empty()) && (IP != "::1")))
00185 {
00186
00187 sockaddr* s = new sockaddr[2];
00188 #ifdef IPV6
00189 if (v6)
00190 {
00191 in6_addr n;
00192 if (inet_pton(AF_INET6, IP.c_str(), &n) > 0)
00193 {
00194 memcpy(&((sockaddr_in6*)s)->sin6_addr, &n, sizeof(sockaddr_in6));
00195 ((sockaddr_in6*)s)->sin6_port = 0;
00196 ((sockaddr_in6*)s)->sin6_family = AF_INET6;
00197 size = sizeof(sockaddr_in6);
00198 }
00199 else
00200 {
00201 delete[] s;
00202 j++;
00203 continue;
00204 }
00205 }
00206 else
00207 #endif
00208 {
00209 in_addr n;
00210 if (inet_aton(IP.c_str(), &n) > 0)
00211 {
00212 ((sockaddr_in*)s)->sin_addr = n;
00213 ((sockaddr_in*)s)->sin_port = 0;
00214 ((sockaddr_in*)s)->sin_family = AF_INET;
00215 }
00216 else
00217 {
00218 delete[] s;
00219 j++;
00220 continue;
00221 }
00222 }
00223
00224 if (bind(this->fd, s, size) < 0)
00225 {
00226 this->state = I_ERROR;
00227 this->OnError(I_ERR_BIND);
00228 this->fd = -1;
00229 delete[] s;
00230 return false;
00231 }
00232
00233 delete[] s;
00234 return true;
00235 }
00236 }
00237 j++;
00238 }
00239 return true;
00240 }
00241
00242 bool InspSocket::DoConnect()
00243 {
00244
00245 sockaddr* addr = new sockaddr[2];
00246 socklen_t size = sizeof(sockaddr_in);
00247 #ifdef IPV6
00248 bool v6 = false;
00249 if ((!*this->host) || strchr(this->host, ':'))
00250 v6 = true;
00251
00252 if (v6)
00253 {
00254 this->fd = socket(AF_INET6, SOCK_STREAM, 0);
00255 if ((this->fd > -1) && ((strstr(this->IP,"::ffff:") != (char*)&this->IP) && (strstr(this->IP,"::FFFF:") != (char*)&this->IP)))
00256 {
00257 if (!this->BindAddr(this->cbindip))
00258 {
00259 delete[] addr;
00260 return false;
00261 }
00262 }
00263 }
00264 else
00265 #endif
00266 {
00267 this->fd = socket(AF_INET, SOCK_STREAM, 0);
00268 if (this->fd > -1)
00269 {
00270 if (!this->BindAddr(this->cbindip))
00271 {
00272 delete[] addr;
00273 return false;
00274 }
00275 }
00276 }
00277
00278 if (this->fd == -1)
00279 {
00280 this->state = I_ERROR;
00281 this->OnError(I_ERR_SOCKET);
00282 delete[] addr;
00283 return false;
00284 }
00285
00286 #ifdef IPV6
00287 if (v6)
00288 {
00289 in6_addr addy;
00290 if (inet_pton(AF_INET6, this->host, &addy) > 0)
00291 {
00292 ((sockaddr_in6*)addr)->sin6_family = AF_INET6;
00293 memcpy(&((sockaddr_in6*)addr)->sin6_addr, &addy, sizeof(addy));
00294 ((sockaddr_in6*)addr)->sin6_port = htons(this->port);
00295 size = sizeof(sockaddr_in6);
00296 }
00297 }
00298 else
00299 #endif
00300 {
00301 in_addr addy;
00302 if (inet_aton(this->host, &addy) > 0)
00303 {
00304 ((sockaddr_in*)addr)->sin_family = AF_INET;
00305 ((sockaddr_in*)addr)->sin_addr = addy;
00306 ((sockaddr_in*)addr)->sin_port = htons(this->port);
00307 }
00308 }
00309 #ifndef WIN32
00310 int flags = fcntl(this->fd, F_GETFL, 0);
00311 fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
00312 #else
00313 unsigned long flags = 0;
00314 ioctlsocket(this->fd, FIONBIO, &flags);
00315 #endif
00316 if (connect(this->fd, (sockaddr*)addr, size) == -1)
00317 {
00318 if (errno != EINPROGRESS)
00319 {
00320 this->OnError(I_ERR_CONNECT);
00321 this->Close();
00322 this->state = I_ERROR;
00323 delete[] addr;
00324 return false;
00325 }
00326
00327 this->Timeout = new SocketTimeout(this->GetFd(), this->Instance, this, timeout_val, this->Instance->Time());
00328 this->Instance->Timers->AddTimer(this->Timeout);
00329 }
00330 #ifdef WIN32
00331
00332 flags = 0;
00333 ioctlsocket(this->fd, FIONBIO, &flags);
00334 #endif
00335 this->state = I_CONNECTING;
00336 delete[] addr;
00337 if (this->fd > -1)
00338 {
00339 if (!this->Instance->SE->AddFd(this))
00340 {
00341 this->OnError(I_ERR_NOMOREFDS);
00342 this->Close();
00343 this->state = I_ERROR;
00344 return false;
00345 }
00346 this->SetQueues(this->fd);
00347 }
00348 return true;
00349 }
00350
00351
00352 void InspSocket::Close()
00353 {
00354
00355
00356
00357
00358 int save = errno;
00359 if (this->fd > -1)
00360 {
00361 if (this->IsIOHooked && Instance->Config->GetIOHook(this))
00362 {
00363 try
00364 {
00365 if (this->state != I_LISTENING)
00366 Instance->Config->GetIOHook(this)->OnRawSocketClose(this->fd);
00367 }
00368 catch (CoreException& modexcept)
00369 {
00370 Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00371 }
00372 }
00373 shutdown(this->fd,2);
00374 if (close(this->fd) != -1)
00375 this->OnClose();
00376
00377 if (Instance->SocketCull.find(this) == Instance->SocketCull.end())
00378 Instance->SocketCull[this] = this;
00379 }
00380 errno = save;
00381 }
00382
00383 std::string InspSocket::GetIP()
00384 {
00385 return this->IP;
00386 }
00387
00388 char* InspSocket::Read()
00389 {
00390 #ifdef WINDOWS
00391 if ((fd < 0) || (m_internalFd > MAX_DESCRIPTORS))
00392 #else
00393 if ((fd < 0) || (fd > MAX_DESCRIPTORS))
00394 #endif
00395 return NULL;
00396
00397 int n = 0;
00398
00399 if (this->IsIOHooked)
00400 {
00401 int result2 = 0;
00402 int MOD_RESULT = 0;
00403 try
00404 {
00405 MOD_RESULT = Instance->Config->GetIOHook(this)->OnRawSocketRead(this->fd,this->ibuf,sizeof(this->ibuf) - 1,result2);
00406 }
00407 catch (CoreException& modexcept)
00408 {
00409 Instance->Log(DEFAULT,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00410 }
00411 if (MOD_RESULT < 0)
00412 {
00413 n = -1;
00414 errno = EAGAIN;
00415 }
00416 else
00417 {
00418 n = result2;
00419 }
00420 }
00421 else
00422 {
00423 n = recv(this->fd,this->ibuf,sizeof(this->ibuf) - 1,0);
00424 }
00425
00426
00427
00428
00429
00430
00431
00432 if (n > 0)
00433 {
00434 ibuf[n] = 0;
00435 return ibuf;
00436 }
00437 else
00438 {
00439 int err = errno;
00440 if (err == EAGAIN)
00441 return "";
00442 else
00443 return NULL;
00444 }
00445 }
00446
00447 void InspSocket::MarkAsClosed()
00448 {
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 void InspSocket::Write(const std::string &data)
00464 {
00465
00466
00467 outbuffer.push_back(data);
00468 this->Instance->SE->WantWrite(this);
00469 }
00470
00471 bool InspSocket::FlushWriteBuffer()
00472 {
00473 errno = 0;
00474 if ((this->fd > -1) && (this->state == I_CONNECTED))
00475 {
00476 if (this->IsIOHooked)
00477 {
00478 while (outbuffer.size() && (errno != EAGAIN))
00479 {
00480 try
00481 {
00482
00483
00484
00485 Instance->Config->GetIOHook(this)->OnRawSocketWrite(this->fd, outbuffer[0].c_str(), outbuffer[0].length());
00486 outbuffer.pop_front();
00487 }
00488 catch (CoreException& modexcept)
00489 {
00490 Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00491 return true;
00492 }
00493 }
00494 }
00495 else
00496 {
00497
00498
00499
00500 while (outbuffer.size() && (errno != EAGAIN))
00501 {
00502
00503 #ifndef WIN32
00504 int result = write(this->fd,outbuffer[0].c_str(),outbuffer[0].length());
00505 #else
00506 int result = send(this->fd,outbuffer[0].c_str(),outbuffer[0].length(), 0);
00507 #endif
00508 if (result > 0)
00509 {
00510 if ((unsigned int)result >= outbuffer[0].length())
00511 {
00512
00513
00514
00515
00516
00517 outbuffer.pop_front();
00518 }
00519 else
00520 {
00521 std::string temp = outbuffer[0].substr(result);
00522 outbuffer[0] = temp;
00523
00524
00525
00526
00527
00528 errno = EAGAIN;
00529 }
00530 }
00531 else if (result == 0)
00532 {
00533 this->Instance->SE->DelFd(this);
00534 this->Close();
00535 return true;
00536 }
00537 else if ((result == -1) && (errno != EAGAIN))
00538 {
00539 this->OnError(I_ERR_WRITE);
00540 this->state = I_ERROR;
00541 this->Instance->SE->DelFd(this);
00542 this->Close();
00543 return true;
00544 }
00545 }
00546 }
00547 }
00548
00549 if ((errno == EAGAIN) && (fd > -1))
00550 {
00551 this->Instance->SE->WantWrite(this);
00552 }
00553
00554 return (fd < 0);
00555 }
00556
00557 void SocketTimeout::Tick(time_t now)
00558 {
00559 if (ServerInstance->SE->GetRef(this->sfd) != this->sock)
00560 return;
00561
00562 if (this->sock->state == I_CONNECTING)
00563 {
00564
00565
00566
00567
00568 this->sock->OnTimeout();
00569 this->sock->OnError(I_ERR_TIMEOUT);
00570 this->sock->timeout = true;
00571
00572
00573
00574
00575
00576 this->sock->state = I_ERROR;
00577
00578 if (ServerInstance->SocketCull.find(this->sock) == ServerInstance->SocketCull.end())
00579 ServerInstance->SocketCull[this->sock] = this->sock;
00580 }
00581
00582 this->sock->Timeout = NULL;
00583 }
00584
00585 bool InspSocket::Poll()
00586 {
00587 #ifdef WINDOWS
00588 if(Instance->SE->GetRef(this->fd) != this)
00589 return false;
00590 int incoming = -1;
00591 #else
00592 if (this->Instance->SE->GetRef(this->fd) != this)
00593 return false;
00594
00595 int incoming = -1;
00596
00597 if ((fd < 0) || (fd > MAX_DESCRIPTORS))
00598 return false;
00599 #endif
00600 switch (this->state)
00601 {
00602 case I_CONNECTING:
00603
00604
00605
00606 #ifndef WINDOWS
00607 if (this->fd > -1)
00608 {
00609 this->Instance->SE->DelFd(this);
00610 this->SetState(I_CONNECTED);
00611 if (!this->Instance->SE->AddFd(this))
00612 return false;
00613 }
00614 #else
00615 this->SetState(I_CONNECTED);
00616 #endif
00617 Instance->Log(DEBUG,"Inspsocket I_CONNECTING state");
00618 if (Instance->Config->GetIOHook(this))
00619 {
00620 Instance->Log(DEBUG,"Hook for raw connect");
00621 try
00622 {
00623 Instance->Config->GetIOHook(this)->OnRawSocketConnect(this->fd);
00624 }
00625 catch (CoreException& modexcept)
00626 {
00627 Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00628 }
00629 }
00630 return this->OnConnected();
00631 break;
00632 case I_LISTENING:
00633 {
00634
00635 sockaddr* client = new sockaddr[2];
00636 length = sizeof (sockaddr_in);
00637 std::string recvip;
00638 #ifdef IPV6
00639 if ((!*this->host) || strchr(this->host, ':'))
00640 length = sizeof(sockaddr_in6);
00641 #endif
00642 incoming = _accept (this->fd, client, &length);
00643 #ifdef IPV6
00644 if ((!*this->host) || strchr(this->host, ':'))
00645 {
00646 char buf[1024];
00647 recvip = inet_ntop(AF_INET6, &((sockaddr_in6*)client)->sin6_addr, buf, sizeof(buf));
00648 }
00649 else
00650 #endif
00651 recvip = inet_ntoa(((sockaddr_in*)client)->sin_addr);
00652 this->OnIncomingConnection(incoming, (char*)recvip.c_str());
00653
00654 NonBlocking(incoming);
00655
00656 if (this->IsIOHooked)
00657 {
00658 try
00659 {
00660 Instance->Config->GetIOHook(this)->OnRawSocketAccept(incoming, recvip.c_str(), this->port);
00661 }
00662 catch (CoreException& modexcept)
00663 {
00664 Instance->Log(DEBUG,"%s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason());
00665 }
00666 }
00667
00668 this->SetQueues(incoming);
00669
00670 delete[] client;
00671 return true;
00672 }
00673 break;
00674 case I_CONNECTED:
00675
00676 return this->OnDataReady();
00677 break;
00678 default:
00679 break;
00680 }
00681 return true;
00682 }
00683
00684 void InspSocket::SetState(InspSocketState s)
00685 {
00686 this->state = s;
00687 }
00688
00689 InspSocketState InspSocket::GetState()
00690 {
00691 return this->state;
00692 }
00693
00694 int InspSocket::GetFd()
00695 {
00696 return this->fd;
00697 }
00698
00699 bool InspSocket::OnConnected() { return true; }
00700 void InspSocket::OnError(InspSocketError e) { return; }
00701 int InspSocket::OnDisconnect() { return 0; }
00702 int InspSocket::OnIncomingConnection(int newfd, char* ip) { return 0; }
00703 bool InspSocket::OnDataReady() { return true; }
00704 bool InspSocket::OnWriteReady() { return true; }
00705 void InspSocket::OnTimeout() { return; }
00706 void InspSocket::OnClose() { return; }
00707
00708 InspSocket::~InspSocket()
00709 {
00710 this->Close();
00711 if (Timeout)
00712 {
00713 Instance->Timers->DelTimer(Timeout);
00714 Timeout = NULL;
00715 }
00716 }
00717
00718 void InspSocket::HandleEvent(EventType et, int errornum)
00719 {
00720 switch (et)
00721 {
00722 case EVENT_ERROR:
00723 switch (errornum)
00724 {
00725 case ETIMEDOUT:
00726 this->OnError(I_ERR_TIMEOUT);
00727 break;
00728 case ECONNREFUSED:
00729 case 0:
00730 this->OnError(this->state == I_CONNECTING ? I_ERR_CONNECT : I_ERR_WRITE);
00731 break;
00732 case EADDRINUSE:
00733 this->OnError(I_ERR_BIND);
00734 break;
00735 case EPIPE:
00736 case EIO:
00737 this->OnError(I_ERR_WRITE);
00738 break;
00739 }
00740 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00741 this->Instance->SocketCull[this] = this;
00742 return;
00743 break;
00744 case EVENT_READ:
00745 if (!this->Poll())
00746 {
00747 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00748 this->Instance->SocketCull[this] = this;
00749 return;
00750 }
00751 break;
00752 case EVENT_WRITE:
00753 if (this->WaitingForWriteEvent)
00754 {
00755 this->WaitingForWriteEvent = false;
00756 if (!this->OnWriteReady())
00757 {
00758 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00759 this->Instance->SocketCull[this] = this;
00760 return;
00761 }
00762 }
00763 if (this->state == I_CONNECTING)
00764 {
00765
00766
00767
00768
00769
00770
00771 this->HandleEvent(EVENT_READ);
00772 return;
00773 }
00774 else
00775 {
00776 if (this->FlushWriteBuffer())
00777 {
00778 if (this->Instance->SocketCull.find(this) == this->Instance->SocketCull.end())
00779 this->Instance->SocketCull[this] = this;
00780 return;
00781 }
00782 }
00783 break;
00784 }
00785 }
00786