00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 static const char* Copyright= "(C) Copyright Michigan State University 2002, All rights reserved";
00302
00303
00304
00305
00306
00311
00312 #include <config.h>
00313 #include "CSocket.h"
00314 #include <CApplicationSerializer.h>
00315
00316
00317
00318 #include <CTCPNoSuchHost.h>
00319 #include <CTCPNoSuchService.h>
00320 #include <CTCPBadSocketState.h>
00321 #include <CTCPConnectionFailed.h>
00322 #include <ErrnoException.h>
00323 #include <CTCPConnectionLost.h>
00324
00325
00326
00327 #include <stdio.h>
00328 #include <sys/types.h>
00329 #include <sys/socket.h>
00330 #include <sys/time.h>
00331 #include <netinet/in.h>
00332 #include <arpa/inet.h>
00333
00334
00335
00336 #include <vector>
00337
00338 #ifdef HAVE_STD_NAMESPACE
00339 using namespace std;
00340 #endif
00341
00342
00343
00344
00345 #ifndef TRUE
00346 #define TRUE 1
00347 #endif
00348 #ifndef FALSE
00349 #define FALSE 0
00350 #endif
00351
00352
00353
00354 map<CSocket::State, string> CSocket::m_StateNames;
00355
00371 CSocket::CSocket ()
00372 : m_Fd(-1),
00373 m_State(Disconnected)
00374
00375 {
00376 OpenSocket();
00377 }
00378
00384 CSocket::~CSocket ( )
00385 {
00386 if(m_State == Connected) {
00387 Shutdown();
00388 }
00389 if(m_Fd > 0) {
00390 close(m_Fd);
00391 }
00392 }
00393
00404 CSocket::CSocket ( int am_Fd, CSocket::State am_State ) :
00405 m_Fd(am_Fd),
00406 m_State(am_State)
00407
00408 {
00409 StockStateMap();
00410 }
00411
00412
00413
00448 void
00449 CSocket::Connect(const string& host, const string& service)
00450 {
00451
00452
00453 vector<CSocket::State> allowedStates;
00454 allowedStates.push_back(Disconnected);
00455
00456 if(m_State != Disconnected) throw CTCPBadSocketState(m_State, allowedStates,
00457 "CSocket::Connect");
00458
00459
00460
00461
00462 unsigned long int ipaddr;
00463 struct hostent* pEntry;
00464
00465 CApplicationSerializer::getInstance()->Lock();
00466 {
00467 ipaddr = inet_addr(host.c_str());
00468 if(ipaddr == INADDR_NONE) {
00469 pEntry = gethostbyname(host.c_str());
00470 if(pEntry) memcpy(&ipaddr, pEntry->h_addr, 4);
00471 }
00472 CApplicationSerializer::getInstance()->UnLock();
00473 if(!pEntry) throw CTCPNoSuchHost(host,
00474 "Null return from gethostbyname(3)");
00475 }
00476
00477
00478
00479
00480 unsigned short port = Service(service);
00481
00482
00483
00484
00485 Connect(ntohl(ipaddr), ntohs(port));
00486 }
00487
00500 void
00501 CSocket::Connect(unsigned long int IpAddress, unsigned short service)
00502
00503 {
00504
00505
00506 vector<CSocket::State> allowedStates;
00507 allowedStates.push_back(Disconnected);
00508
00509 if(m_State != Disconnected) throw CTCPBadSocketState(m_State, allowedStates,
00510 "CSocket::Connect");
00511
00512
00513
00514
00515 IpAddress = htonl(IpAddress);
00516 service = htons(service);
00517
00518
00519
00520 sockaddr_in Peer;
00521 Peer.sin_port = service;
00522 memcpy(&(Peer.sin_addr), &IpAddress, sizeof(unsigned long int));
00523 Peer.sin_family = AF_INET;
00524
00525
00526
00527 if(connect(m_Fd, (const sockaddr*)&Peer, sizeof(sockaddr_in)) < 0) {
00528 int sErrno = errno;
00529 string Ip, Svc;
00530 CApplicationSerializer::getInstance()->Lock();
00531 {
00532 char port[50];
00533 Ip = inet_ntoa(Peer.sin_addr);
00534 sprintf(port,"%d", ntohs(service));
00535 Svc = port;
00536
00537 }
00538 CApplicationSerializer::getInstance()->UnLock();
00539 errno = sErrno;
00540 throw CTCPConnectionFailed(Ip, Svc,
00541 "CSocket::Connect client connect(2) failed");
00542 }
00543
00544 m_State = Connected;
00545
00546
00547 }
00548
00567 void
00568 CSocket::Bind(const string& service)
00569 {
00570 vector<CSocket::State> allowedStates;
00571 allowedStates.push_back(Disconnected);
00572 if(m_State != Disconnected) throw CTCPBadSocketState(m_State, allowedStates,
00573 "CSocket::Bind");
00574
00575
00576
00577 int reuse=TRUE;
00578 if(setsockopt(m_Fd, SOL_SOCKET,
00579 SO_REUSEADDR, &reuse, sizeof(int)) < 0) {
00580 throw CErrnoException("CSocket::Bind - setsockopt92) for re-use failed");
00581 }
00582
00583
00584
00585 unsigned short port = Service(service);
00586
00587
00588
00589
00590 sockaddr_in Peer;
00591 Peer.sin_port = port;
00592 Peer.sin_family = AF_INET;
00593 Peer.sin_addr.s_addr = htonl(INADDR_ANY);
00594
00595 if(bind(m_Fd, (sockaddr*)&Peer, sizeof(sockaddr_in)) < 0) {
00596 throw CErrnoException("Error from bind(2) in CSocket::Bind()");
00597 }
00598 m_State = Bound;
00599
00600 }
00601
00623 void
00624 CSocket::Listen(unsigned int nBacklog)
00625 {
00626
00627
00628 if(m_State != Bound) {
00629 vector<CSocket::State> allowedStates;
00630 allowedStates.push_back(Bound);
00631 throw CTCPBadSocketState(m_State, allowedStates,
00632 "CSocket::Listen");
00633 }
00634 if(listen(m_Fd, nBacklog) < 0)
00635 throw CErrnoException("CSocket::Listen listen(2) failed");
00636
00637 m_State = Listening;
00638 }
00639
00672 CSocket*
00673 CSocket::Accept(string& client)
00674 {
00675
00676
00677 if(m_State != Listening) {
00678 vector<CSocket::State> allowedStates;
00679 allowedStates.push_back(Listening);
00680 throw CTCPBadSocketState(m_State, allowedStates,
00681 "CSocket::Accept");
00682 }
00683
00684
00685
00686
00687 struct sockaddr_in peerInfo;
00688 socklen_t addrlen(sizeof(sockaddr_in));
00689 int peerFd = accept(m_Fd, (sockaddr*)&peerInfo, &addrlen);
00690 if(peerFd < 0) {
00691 throw CErrnoException("CSocket::Accept accept(2) failed");
00692 }
00693
00694
00695
00696
00697
00698
00699 CSocket* pConnection = new CSocket(peerFd, Connected);
00700 client = AddressToHostString(peerInfo.sin_addr);
00701
00702 return pConnection;
00703 }
00704
00721 void
00722 CSocket::Shutdown()
00723 {
00724
00725
00726 if(m_State != Connected) {
00727 vector<CSocket::State> allowedStates;
00728 allowedStates.push_back(Connected);
00729 throw CTCPBadSocketState(m_State, allowedStates,
00730 "CSocket::Shutdown");
00731 }
00732
00733
00734 if(shutdown(m_Fd, SHUT_RDWR) < 0) {
00735 throw CErrnoException("CSocket::Shutdown failed in call to shutdown(2)");
00736 }
00737
00738 m_State = Disconnected;
00739 close(m_Fd);
00740 m_Fd = -1;
00741 OpenSocket();
00742 }
00743
00762 int
00763 CSocket::Read(void* pBuffer, size_t nBytes)
00764 {
00765
00766
00767 if(m_State != Connected) {
00768 vector<CSocket::State> allowedStates;
00769 allowedStates.push_back(Connected);
00770 throw CTCPBadSocketState(m_State, allowedStates,
00771 "CSocket::Read()");
00772 }
00773
00774
00775 int nB = read(m_Fd, pBuffer, nBytes);
00776
00777
00778
00779 if(nB == 0) {
00780 m_State = Disconnected;
00781 throw CTCPConnectionLost(this, "CSocket::Read: from read(2)");
00782 }
00783
00784
00785 if(nB < 0) {
00786 m_State = Disconnected;
00787 throw CErrnoException("CSocket::Read failed read(2)");
00788 }
00789
00790
00791 return nB;
00792 }
00793
00794
00823 int
00824 CSocket::Write(void* pBuffer, size_t nBytes)
00825 {
00826
00827
00828
00829
00830
00831
00832
00833 char* p((char* )pBuffer);
00834 int resid(nBytes);
00835 int nWritten(0);
00836
00837 while(resid) {
00838 int n = write(m_Fd, p, resid);
00839 if(n > 0) {
00840 resid -= n;
00841 nWritten += n;
00842 p += n;
00843 }
00844 else {
00845 if(nWritten > 0) {
00846 break;
00847 }
00848 if(errno == EPIPE) {
00849 m_State = Disconnected;
00850 throw CTCPConnectionLost(this,"CSocket::Write - first write of loop");
00851 }
00852 else {
00853 m_State = Disconnected;
00854 throw CErrnoException("CSocket::Write failed write(2)");
00855 }
00856 }
00857 }
00858 return nWritten;
00859
00860
00861 }
00862
00883 void
00884 CSocket::getPeer(unsigned short& port, string& peer)
00885 {
00886
00887
00888 if(m_State != Connected) {
00889 vector<CSocket::State> allowedStates;
00890 allowedStates.push_back(Connected);
00891 throw CTCPBadSocketState(m_State, allowedStates,
00892 "CSocket::GetPeer");
00893 }
00894
00895
00896 sockaddr_in PeerInfo;
00897 socklen_t addrsize(sizeof(sockaddr_in));
00898 if(getpeername(m_Fd, (sockaddr*)&PeerInfo, &addrsize) < 0) {
00899 throw CErrnoException("CSocket::getPeer failed call to getpeername(2)");
00900 }
00901
00902
00903
00904 port = ntohs(PeerInfo.sin_port);
00905 peer = AddressToHostString(PeerInfo.sin_addr);
00906
00907 }
00908
00929 void
00930 CSocket::OOBInline(bool State)
00931 {
00932 int state((int)State);
00933 if(setsockopt(m_Fd, SOL_SOCKET,
00934 SO_OOBINLINE, (void*)&state, sizeof(int)) < 0) {
00935 throw CErrnoException("CSocket::OOBInline setsockopt(2) failed");
00936 }
00937 }
00938
00954 bool
00955 CSocket::isOOBInline()
00956 {
00957 unsigned int state;
00958 socklen_t size(sizeof(int));
00959 if(getsockopt(m_Fd, SOL_SOCKET,
00960 SO_OOBINLINE, (void*)&state, &size) < 0) {
00961 throw CErrnoException("CSocket::OOBInline getsockopt(2) failed");
00962 }
00963 return state ? TRUE : FALSE;
00964 }
00965
00986 void
00987 CSocket::setRcvLowWaterMark(size_t nBytes)
00988 {
00989 if(setsockopt(m_Fd, SOL_SOCKET, SO_RCVLOWAT, (void*)&nBytes, sizeof(size_t)) < 0) {
00990 if (errno == ENOPROTOOPT) {
00991 return;
00992 }
00993 throw
00994 CErrnoException("CSocket::setRcvLowWaterMark() setsockopt(2) failed");
00995 }
00996 }
00997
00998
01010 size_t
01011 CSocket::getRcvLowWaterMark()
01012 {
01013 int nBytes;
01014 socklen_t addrlen(sizeof(int));
01015 if(getsockopt(m_Fd, SOL_SOCKET, SO_RCVLOWAT, &nBytes, &addrlen) < 0) {
01016 throw
01017 CErrnoException("CSocket::getRcvLowWaterMark() getsockopt(2) failed");
01018 }
01019 return (size_t)nBytes;
01020 }
01021
01039 void
01040 CSocket::setSndLowWaterMark(size_t nBytes)
01041 {
01042 if(setsockopt(m_Fd, SOL_SOCKET, SO_SNDLOWAT, &nBytes, sizeof(size_t)) < 0) {
01043 if (errno != ENOPROTOOPT) {
01044 CErrnoException("CSocket::setSndLowWaterMark() setsockopt(2) failed");
01045 }
01046 }
01047 }
01057 size_t
01058 CSocket::getSndLowWaterMark()
01059 {
01060 int nBytes;
01061 socklen_t adrlen(sizeof(int));
01062 if(getsockopt(m_Fd, SOL_SOCKET, SO_SNDLOWAT, &nBytes, &adrlen) < 0) {
01063 throw
01064 CErrnoException("CSocket::getRcvLowWaterMark() getsockopt(2) failed");
01065 }
01066 return (size_t)nBytes;
01067 }
01068
01080 void
01081 CSocket::setRcvTimeout(unsigned int nMs)
01082 {
01083
01084
01085
01086 timeval timeout;
01087 timeout.tv_sec = nMs / 1000;
01088 timeout.tv_usec = (nMs % 1000) * 1000;
01089
01090
01091
01092 if(setsockopt(m_Fd, SOL_SOCKET, SO_RCVTIMEO,
01093 &timeout, sizeof(timeval)) < 0) {
01094 if(errno != ENOPROTOOPT) {
01095 throw CErrnoException("CSocket::setRcvTimeout setsockopt(2) failed");
01096 }
01097 }
01098 }
01099
01111 unsigned int
01112 CSocket::getRcvTimeout()
01113 {
01114 timeval timeout;
01115 socklen_t adrlen(sizeof(timeval));
01116
01117
01118
01119 if(getsockopt(m_Fd, SOL_SOCKET, SO_RCVTIMEO,
01120 &timeout, &adrlen) < 0) {
01121 throw CErrnoException("CSocket::getRcvTimeout getsockopt(2) failed");
01122 }
01123
01124
01125 int nMs = timeout.tv_sec*1000; + timeout.tv_usec/1000000;
01126 return nMs;
01127 }
01128
01144 void
01145 CSocket::setSndTimeout(unsigned int nMs)
01146 {
01147
01148
01149 timeval timeout;
01150 timeout.tv_sec = nMs / 1000;
01151 timeout.tv_usec = (nMs % 1000) * 1000;
01152
01153
01154
01155 if(setsockopt(m_Fd, SOL_SOCKET, SO_SNDTIMEO,
01156 &timeout, sizeof(timeval)) < 0) {
01157 if(errno != ENOPROTOOPT) {
01158 throw CErrnoException("CSocket::setRcvTimeout setsockopt(2) failed");
01159 }
01160 }
01161 }
01162
01172 unsigned int
01173 CSocket::getSndTimeout()
01174 {
01175 timeval timeout;
01176 socklen_t adrlen(sizeof(timeval));
01177
01178
01179
01180 if(getsockopt(m_Fd, SOL_SOCKET, SO_SNDTIMEO,
01181 &timeout, &adrlen) < 0) {
01182 throw CErrnoException("CSocket::getRcvTimeout getsockopt(2) failed");
01183 }
01184
01185
01186 int nMs = timeout.tv_sec*1000; + timeout.tv_usec/1000000;
01187 return nMs;
01188 }
01189
01206 void
01207 CSocket::Debug(bool fState)
01208 {
01209 int state((int)fState);
01210 if(setsockopt(m_Fd, SOL_SOCKET, SO_DEBUG, &state, sizeof(int)) < 0) {
01211 throw CErrnoException("CSocket::Debug setsockopt(2) failed");
01212 }
01213
01214 }
01215
01227 bool
01228 CSocket::isDebug()
01229 {
01230 int fstate;
01231 socklen_t adrlen(sizeof(int));
01232 if(getsockopt(m_Fd, SOL_SOCKET, SO_DEBUG, &fstate, &adrlen) < 0) {
01233 throw CErrnoException("CSocket:Debug getsockopt(2) failed");
01234 }
01235 return fstate ? TRUE : FALSE;
01236 }
01237
01260 void
01261 CSocket::SetNotRoutable(bool fRoutable)
01262 {
01263 int state((int)fRoutable);
01264 if(setsockopt(m_Fd, SOL_SOCKET, SO_DONTROUTE, &state, sizeof(int)) < 0) {
01265 throw CErrnoException("CSocket::SetNotRoutable setsockopt(2) failed");
01266 }
01267
01268 }
01269
01285 bool
01286 CSocket::isNotRoutable()
01287 {
01288 int fState;
01289 socklen_t adrlen(sizeof(int));
01290 if(getsockopt(m_Fd, SOL_SOCKET, SO_DONTROUTE, &fState, &adrlen) < 0) {
01291 throw CErrnoException("CSocket::isNotRoutable getsockopt(2) failed");
01292 }
01293 return fState ? TRUE : FALSE;
01294 }
01295
01318 void
01319 CSocket::setSndBufSize(size_t nBufferSize)
01320 {
01321 unsigned int size((unsigned int)nBufferSize);
01322 if(setsockopt(m_Fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) {
01323 throw CErrnoException("CSocket::setSndBufSize setsockopt(2) failed");
01324 }
01325 }
01326
01339 size_t
01340 CSocket::getSndBufSize()
01341 {
01342 unsigned int size;
01343 socklen_t adrlen(sizeof(int));
01344 if(getsockopt(m_Fd, SOL_SOCKET, SO_SNDBUF, &size, &adrlen) < 0) {
01345 throw CErrnoException("CSocket::getSndBufSize getsockopt(2) failed");
01346 }
01347 return (size_t)size;
01348 }
01349
01364 void
01365 CSocket::setRcvBufSize(size_t nBytes)
01366 {
01367 unsigned int size = (unsigned int)nBytes;
01368
01369 if(setsockopt(m_Fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) {
01370 throw CErrnoException("CSocket::setRcvBufSize setsockopt(2) failed");
01371 }
01372 }
01373
01386 size_t
01387 CSocket::getRcvBufSize()
01388 {
01389 unsigned int size;
01390 socklen_t adrlen(sizeof(int));
01391 if(getsockopt(m_Fd, SOL_SOCKET, SO_RCVBUF, &size, &adrlen) < 0) {
01392 throw CErrnoException("CSocket::getSndBufSize getsockopt(2) failed");
01393 }
01394 return (size_t)size;
01395 }
01396
01418 void
01419 CSocket::setLinger(bool lOn, int nLingerSeconds)
01420 {
01421
01422
01423
01424
01425 linger lInfo;
01426 lInfo.l_onoff = lOn;
01427 if(lOn) lInfo.l_linger = nLingerSeconds;
01428
01429
01430
01431 if(setsockopt(m_Fd, SOL_SOCKET, SO_LINGER, &lInfo, sizeof(linger)) < 0) {
01432 throw CErrnoException("CSocket::setLinger setsockopt(2) failed");
01433 }
01434 }
01435
01452 void
01453 CSocket::getLinger(bool& isLingering, int& nLingerSeconds)
01454 {
01455 linger linfo;
01456 socklen_t addrlen(sizeof(linger));
01457 if(getsockopt(m_Fd, SOL_SOCKET, SO_LINGER, &linfo, &addrlen) < 0) {
01458 throw CErrnoException("CSocket::getLinger getsockopt(2) failed");
01459 }
01460
01461
01462
01463 isLingering = linfo.l_onoff;
01464 nLingerSeconds = linfo.l_linger;
01465 }
01477 unsigned short
01478 CSocket::Service(const string& rService)
01479 {
01480 unsigned short port;
01481 int nport;
01482
01483 if(sscanf(rService.c_str(), "%d", &nport) != 1) {
01484 struct servent* pEntry;
01485 CApplicationSerializer::getInstance()->Lock();
01486 {
01487 pEntry = getservbyname(rService.c_str(), "tcp");
01488 if(pEntry) port = pEntry->s_port;
01489 }
01490 CApplicationSerializer::getInstance()->UnLock();
01491 if(!pEntry) throw CTCPNoSuchService(rService,
01492 "Null return from getservbyname(3)");
01493 }
01494 else {
01495 port = nport;
01496 port = htons(port);
01497 }
01498 return port;
01499 }
01500
01514 string
01515 CSocket:: AddressToHostString(in_addr peer)
01516 {
01517 string result;
01518 CApplicationSerializer::getInstance()->Lock();
01519 {
01520 struct hostent* pEntry = gethostbyaddr((const char*)&peer,
01521 sizeof(in_addr), AF_INET);
01522 if(pEntry) {
01523 result = pEntry->h_name;
01524
01525 }
01526 else {
01527 result = inet_ntoa(peer);
01528 }
01529 }
01530 CApplicationSerializer::getInstance()->UnLock();
01531
01532 return result;
01533 }
01543 string
01544 CSocket::StateName(CSocket::State state)
01545 {
01546 StockStateMap();
01547 return m_StateNames[state];
01548 }
01555 void
01556 CSocket::StockStateMap()
01557 {
01558 if(!m_StateNames.empty()) {
01559 m_StateNames[Disconnected] = "Disconnected";
01560 m_StateNames[Bound] = "Bound";
01561 m_StateNames[Listening] = "Listening";
01562 m_StateNames[Connected] = "Connected";
01563 }
01564 }
01568 void
01569 CSocket::OpenSocket()
01570 {
01571 int protocol;
01572 struct protoent* pEntry;
01573 StockStateMap();
01574
01575 CApplicationSerializer::getInstance()->Lock();
01576 {
01577 struct protoent* pEntry = getprotobyname("TCP");
01578 if(pEntry) protocol = pEntry->p_proto;
01579 }
01580 CApplicationSerializer::getInstance()->UnLock();
01581
01582 if(!pEntry) throw
01583 CErrnoException("Getting TCP protocol num from getprotoent(3)");
01584
01585 m_Fd = socket(PF_INET, SOCK_STREAM, protocol);
01586 if(m_Fd == -1) throw
01587 CErrnoException("Creating socket with socket(2)");
01588
01589 }