00001 #ifndef __NETSTREAM_H__
00002 #define __NETSTREAM_H__
00003
00004 #include <cstdio>
00005 #include <cstring>
00006
00007 #include <iostream>
00008 #include <iosfwd>
00009 #include <streambuf.h>
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <ctype.h>
00013 #include <unistd.h>
00014
00015 #include <string.h>
00016 #include <string>
00017
00018 #define INVALID_SOCKET (~0)
00019
00020 using namespace std;
00021
00022 template <class charT, class traits>
00023 class basic_netbuf : public streambuf {
00024 public:
00025
00026 typedef charT char_type;
00027 typedef typename traits::int_type int_type;
00028 typedef typename traits::pos_type pos_type;
00029 typedef typename traits::off_type off_type;
00030 typedef traits traits_type;
00031
00032 basic_netbuf();
00033 basic_netbuf(const IPaddr& addr);
00034 basic_netbuf(const IPaddr::ipnum_t& host, const IPaddr::ipport_t port);
00035 basic_netbuf(const IPaddr::const_ipname_t& host, const IPaddr::ipport_t port);
00036 basic_netbuf(size_t buf_in_size, size_t buf_out_size);
00037 virtual ~basic_netbuf();
00038
00039
00040
00041
00042 public:
00043 virtual bool open(const IPaddr& addr);
00044 virtual bool open(const IPaddr::const_ipname_t& str);
00045 virtual bool open(const IPaddr::ipnum_t& addr, const IPaddr::ipport_t& aPort);
00046 virtual bool open(const IPaddr::const_ipname_t& ahost, unsigned int aPort) { return open(IPaddr(ahost,aPort)); }
00047 virtual bool is_open() const { return (sock!=INVALID_SOCKET); }
00048 virtual void close();
00049
00050 virtual void setEcho(bool val = true) { is_echoing = val; }
00051 virtual bool getEcho() { return is_echoing; }
00052 protected:
00053 static void printBuffer(const char* buf, int buflen, const char* header);
00054 void Init() { Init(def_buf_in_size, def_buf_out_size); }
00055 void Init(size_t insize, size_t outsize);
00056
00057
00058
00059 public:
00060 virtual void in_sync();
00061 virtual void out_flush();
00062
00063 protected:
00064
00065 virtual streamsize showmanyc();
00066
00067 virtual int_type underflow();
00068 virtual int_type uflow();
00069
00070
00071
00072
00073
00074 virtual int_type overflow(int_type c = traits::eof());
00075
00076
00077
00078
00079
00080 virtual int sync();
00081
00082
00083
00084 protected:
00085 charT *buf_in, *buf_out;
00086 bool using_buf_in, using_buf_out;
00087 static const size_t def_buf_in_size;
00088 static const size_t def_buf_out_size;
00089 int sock;
00090 bool is_echoing;
00091 };
00092 template <class charT, class traits>
00093 const size_t basic_netbuf<charT,traits>::def_buf_in_size=1<<8;
00094 template <class charT, class traits>
00095 const size_t basic_netbuf<charT,traits>::def_buf_out_size=1<<12;
00096
00097
00098 template <class charT, class traits>
00099 class basic_iNetStream
00100 : public istream
00101 {
00102 public:
00103 typedef charT char_type;
00104 typedef typename traits::int_type int_type;
00105 typedef typename traits::pos_type pos_type;
00106 typedef typename traits::off_type off_type;
00107 typedef traits traits_type;
00108
00109 basic_iNetStream() : istream(&nb), nb() {}
00110 basic_iNetStream(const IPaddr::ipnum_t& host, const IPaddr::ipport_t port) : basic_iNetStream(&nb), nb(host,port) {}
00111 basic_iNetStream(const IPaddr::const_ipname_t& host, const IPaddr::ipport_t port) : basic_iNetStream(&nb), nb(host,port) {}
00112 basic_iNetStream(const IPaddr& addr) : istream(&nb), nb(addr) {}
00113 basic_iNetStream(size_t buf_in_size, size_t buf_out_size) : istream(&nb), nb(buf_in_size,buf_out_size) {}
00114
00115 inline basic_netbuf<charT, traits>* rdbuf() const { return const_cast<basic_netbuf<charT, traits>*>(&nb); }
00116
00117 inline bool open(const IPaddr& addr) { return nb.open(addr); }
00118 inline bool open(const IPaddr::const_ipname_t& str) { return nb.open(str); }
00119 inline bool open(const IPaddr::ipnum_t& addr, const IPaddr::ipport_t& aPort) { return nb.open(addr,aPort); }
00120 inline bool open(const IPaddr::const_ipname_t& ahost, unsigned int aPort) { return nb.open(ahost,aPort); }
00121 inline bool is_open() const { return nb.is_open(); }
00122
00123
00124
00125
00126
00127 inline void close() { return nb.close(); }
00128 inline void setEcho(bool val=true) { return nb.setEcho(val); }
00129 inline bool getEcho() { return nb.getEcho(); }
00130 private:
00131 basic_netbuf<charT, traits> nb;
00132 };
00133
00134
00135 template <class charT, class traits>
00136 class basic_oNetStream
00137 : public ostream
00138 {
00139 public:
00140 typedef charT char_type;
00141 typedef typename traits::int_type int_type;
00142 typedef typename traits::pos_type pos_type;
00143 typedef typename traits::off_type off_type;
00144 typedef traits traits_type;
00145
00146 basic_oNetStream() : ostream(&nb), nb() {}
00147 basic_oNetStream(const IPaddr::ipnum_t& host, const IPaddr::ipport_t port) : basic_oNetStream(&nb), nb(host,port) {}
00148 basic_oNetStream(const IPaddr::const_ipname_t& host, const IPaddr::ipport_t port) : basic_oNetStream(&nb), nb(host,port) {}
00149 basic_oNetStream(const IPaddr& addr) : basic_oNetStream(&nb), nb(addr) {}
00150 basic_oNetStream(size_t buf_in_size, size_t buf_out_size) : ostream(&nb), nb(buf_in_size,buf_out_size) {}
00151
00152 inline basic_netbuf<charT, traits>* rdbuf() const { return const_cast<basic_netbuf<charT, traits>*>(&nb); }
00153
00154 inline bool open(const IPaddr& addr) { return nb.open(addr); }
00155 inline bool open(const IPaddr::const_ipname_t& str) { return nb.open(str); }
00156 inline bool open(const IPaddr::ipnum_t& addr, const IPaddr::ipport_t& aPort) { return nb.open(addr,aPort); }
00157 inline bool open(const IPaddr::const_ipname_t& ahost, unsigned int aPort) { return nb.open(ahost,aPort); }
00158 inline bool is_open() const { return nb.is_open(); }
00159
00160
00161
00162
00163
00164 inline void close() { return nb.close(); }
00165 inline void setEcho(bool val=true) { return nb.setEcho(val); }
00166 inline bool getEcho() { return nb.getEcho(); }
00167 private:
00168 basic_netbuf<charT, traits> nb;
00169 };
00170
00171
00172 template <class charT, class traits>
00173 class basic_ioNetStream
00174 : public iostream
00175 {
00176 public:
00177 typedef charT char_type;
00178 typedef typename traits::int_type int_type;
00179 typedef typename traits::pos_type pos_type;
00180 typedef typename traits::off_type off_type;
00181 typedef traits traits_type;
00182
00183 basic_ioNetStream() : iostream(&nb), nb() {}
00184 basic_ioNetStream(const IPaddr& addr) : basic_ioNetStream(&nb), nb(addr) {}
00185 basic_ioNetStream(const IPaddr::ipnum_t& host, const IPaddr::ipport_t port) : basic_ioNetStream(&nb), nb(host,port) {}
00186 basic_ioNetStream(const IPaddr::const_ipname_t& host, const IPaddr::ipport_t port) : basic_ioNetStream(&nb), nb(host,port) {}
00187 basic_ioNetStream(size_t buf_in_size, size_t buf_out_size) : iostream(&nb), nb(buf_in_size,buf_out_size) {}
00188
00189 inline basic_netbuf<charT, traits>* rdbuf() const { return const_cast<basic_netbuf<charT, traits>*>(&nb); }
00190
00191 inline bool open(const IPaddr& addr) { return nb.open(addr); }
00192 inline bool open(const IPaddr::const_ipname_t& str) { return nb.open(str); }
00193 inline bool open(const IPaddr::ipnum_t& addr, const IPaddr::ipport_t& aPort) { return nb.open(addr,aPort); }
00194 inline bool open(const IPaddr::const_ipname_t& ahost, unsigned int aPort) { return nb.open(ahost,aPort); }
00195 inline bool is_open() { return nb.is_open(); }
00196
00197
00198
00199
00200
00201 inline void close() { nb.close(); }
00202 inline void setEcho(bool val=true) { return nb.setEcho(val); }
00203 inline bool getEcho() { return nb.getEcho(); }
00204 private:
00205 basic_netbuf<charT, traits> nb;
00206 };
00207
00208 template<class T>
00209 class char_traits {
00210 public:
00211 typedef T char_type;
00212 typedef int int_type;
00213 typedef T* pos_type;
00214 typedef unsigned int off_type;
00215 static void copy(pos_type dst, pos_type src, off_type size) {
00216 memcpy(dst,src,size);
00217 }
00218 static void move(pos_type dst, pos_type src, off_type size) {
00219 memmove(dst,src,size);
00220 }
00221 static int to_int_type(T c) { return c; }
00222 static int eof() { return EOF; }
00223 };
00224
00225 typedef basic_netbuf<char, char_traits<char> > netbuf;
00226 typedef basic_iNetStream<char, char_traits<char> > iNetStream;
00227 typedef basic_oNetStream<char, char_traits<char> > oNetStream;
00228 typedef basic_ioNetStream<char, char_traits<char> > ioNetStream;
00229
00230
00231
00232
00233 template <class charT, class traits>
00234 basic_netbuf<charT,traits>::basic_netbuf()
00235 : buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00236 sock(INVALID_SOCKET), is_echoing(false) {
00237 Init();
00238 }
00239 template <class charT, class traits>
00240 basic_netbuf<charT,traits>::basic_netbuf(const IPaddr& addr)
00241 : buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00242 sock(INVALID_SOCKET), is_echoing(false) {
00243 Init();
00244 open(addr);
00245 }
00246
00247 template <class charT, class traits>
00248 basic_netbuf<charT,traits>::basic_netbuf(const IPaddr::ipnum_t& host, const IPaddr::ipport_t port)
00249 : buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00250 sock(INVALID_SOCKET), is_echoing(false) {
00251 Init();
00252 open(host,port);
00253 }
00254
00255 template <class charT, class traits>
00256 basic_netbuf<charT,traits>::basic_netbuf(const IPaddr::const_ipname_t& host, const IPaddr::ipport_t port)
00257 : buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00258 sock(INVALID_SOCKET), is_echoing(false) {
00259 Init();
00260 open(host,port);
00261 }
00262
00263 template <class charT, class traits>
00264 basic_netbuf<charT,traits>::basic_netbuf(size_t buf_in_size, size_t buf_out_size)
00265 : buf_in(NULL), buf_out(NULL), using_buf_in(false), using_buf_out(false),
00266 sock(INVALID_SOCKET), is_echoing(false) {
00267 Init();
00268 }
00269
00270 template <class charT, class traits>
00271 basic_netbuf<charT,traits>::~basic_netbuf() {
00272 if(using_buf_in)
00273 delete [] buf_in;
00274 if(using_buf_out)
00275 delete [] buf_out;
00276 }
00277
00278 template<class charT, class traits>
00279 void
00280 basic_netbuf<charT,traits>::Init(size_t insize, size_t outsize) {
00281 buf_in = new charT[insize];
00282 buf_out = new charT[outsize];
00283 using_buf_in = using_buf_out = true;
00284 setg(buf_in,buf_in+insize,buf_in+insize);
00285 setp(buf_out,buf_out+outsize);
00286
00287
00288
00289 }
00290
00291 template <class charT, class traits>
00292 bool
00293 basic_netbuf<charT,traits>::open(const IPaddr& addr) {
00294 if(addr.get_num())
00295 return open(addr.get_num(),addr.get_port());
00296 return false;
00297 }
00298
00299 template <class charT, class traits>
00300 bool
00301 basic_netbuf<charT,traits>::open(const IPaddr::const_ipname_t& str) {
00302 const char*const colon = strrchr(str,':');
00303 if(colon==NULL)
00304 return false;
00305 char* tmp = new char[strlen(str)];
00306 char * d = tmp;
00307 for(const char * s=str; s!=colon; s++,d++)
00308 *d=*s;
00309 *d='\0';
00310 IPaddr::ipport_t port = atoi(colon+1);
00311 bool res = open(tmp,port);
00312 delete [] tmp;
00313 return res;
00314 }
00315
00316 template <class charT, class traits>
00317 bool
00318 basic_netbuf<charT,traits>::open(const IPaddr::ipnum_t& addr, const IPaddr::ipport_t& aPort) {
00319 struct sockaddr_in server;
00320
00321 memset((char *) &server, sizeof(server), 0);
00322 server.sin_family = AF_INET;
00323 server.sin_addr.s_addr = addr;
00324 server.sin_port = htons(aPort);
00325
00326
00327 sock = socket(AF_INET, SOCK_STREAM, 0);
00328 if(sock < 1) {
00329 cout << "NetClient error: socket failed to create stream socket" << endl;
00330 sock = INVALID_SOCKET;
00331 return false;
00332 }
00333
00334
00335 int err = connect(sock, (struct sockaddr *) &server, sizeof(server));
00336 if(err < 0) {
00337 cout << "NetClient error: connect failed to connect to requested address" << endl;
00338 sock = INVALID_SOCKET;
00339 return false;
00340 }
00341
00342 return true;
00343 }
00344
00345 template <class charT, class traits>
00346 void
00347 basic_netbuf<charT,traits>::close() {
00348 cout << "close called" << endl;
00349 if(!is_open())
00350 return;
00351 if(sock != INVALID_SOCKET) {
00352 cout << "closing" << endl;
00353 ::close(sock);
00354 cout << "closed" << endl;
00355 sock = INVALID_SOCKET;
00356 }
00357 }
00358
00359 template <class charT, class traits>
00360 void
00361 basic_netbuf<charT,traits>::printBuffer(const char *buf, int buflen, const char *header) {
00362 int line_begin = 1;
00363 for(int i = 0; i < buflen; i++) {
00364 if(buf[i] == '\n') {
00365 line_begin = 1;
00366 fputc('\n', stderr);
00367 } else {
00368 if(line_begin) fputs(header, stderr);
00369 line_begin = 0;
00370 fputc(buf[i], stderr);
00371 }
00372 }
00373 }
00374
00375 template <class charT, class traits>
00376 void
00377 basic_netbuf<charT,traits>::in_sync() {
00378 if(!is_open()) {
00379 cout << "NetClient error: must open connection before reading from it" << endl;
00380 return;
00381 }
00382 if(gptr()>egptr())
00383 gbump( egptr()-gptr() );
00384 unsigned long n = gptr()-eback()-1;
00385 charT * temp_buf = new char[n*sizeof(charT)];
00386 unsigned int used = read(sock, temp_buf, n*sizeof(charT));
00387 if(used<=0) {
00388 cout << "NetClient error: connection dropped" << endl;
00389 delete [] temp_buf;
00390 close();
00391 return;
00392 }
00393 if(is_echoing)
00394 printBuffer(temp_buf, used, "NetClient: recv: ");
00395
00396 used/=sizeof(charT);
00397 size_t remain = egptr()-eback()-used;
00398 traits::move(eback(),egptr()-remain,remain);
00399 traits::copy(egptr()-used,temp_buf,used);
00400 delete [] temp_buf;
00401 gbump( -used );
00402 }
00403
00404 template <class charT, class traits>
00405 void
00406 basic_netbuf<charT,traits>::out_flush() {
00407 if(!is_open()) {
00408 cout << "NetClient error: must open connection before writing to it" << endl;
00409 return;
00410 }
00411 size_t n = (pptr()-pbase())*sizeof(charT);
00412 if(n==0)
00413 return;
00414 size_t total = 0;
00415 while(total<n) {
00416 int sent = write(sock, pbase()+total, n-total);
00417 if(sent < 0) {
00418 cout << "NetClient error: send error" << endl;
00419 perror("send");
00420 close();
00421 return;
00422 }
00423 if(is_echoing)
00424 printBuffer(pbase()+total, sent, "NetClient: sent: ");
00425 total += sent;
00426 }
00427 total/=sizeof(charT);
00428 n/=sizeof(charT);
00429 if(total!=n)
00430 traits::move(pbase(),pbase()+total,n-total);
00431 pbump( -total );
00432 }
00433
00434
00435 template <class charT, class traits>
00436 inline streamsize
00437 basic_netbuf<charT, traits>::showmanyc() {
00438 return (gptr()<egptr())?(egptr()-gptr()):0;
00439 }
00440
00441 template <class charT, class traits>
00442 inline typename basic_netbuf<charT, traits>::int_type
00443 basic_netbuf<charT, traits>::underflow() {
00444 in_sync();
00445 if(gptr()<egptr())
00446 return traits::to_int_type(*gptr());
00447
00448
00449
00450 return traits::eof();
00451 }
00452
00453 template <class charT, class traits>
00454 inline typename basic_netbuf<charT, traits>::int_type
00455 basic_netbuf<charT, traits>::uflow() {
00456 in_sync();
00457 if(gptr()<egptr()) {
00458 int_type ans = traits::to_int_type(*gptr());
00459 gbump(1);
00460 return ans;
00461 }
00462
00463 return traits::eof();
00464 }
00465
00466 template <class charT, class traits>
00467 inline typename basic_netbuf<charT, traits>::int_type
00468 basic_netbuf<charT, traits>::overflow(int_type c) {
00469 out_flush();
00470 *pptr() = c;
00471 pbump(1);
00472 return is_open()?c:traits::eof();
00473 }
00474
00475 template <class charT, class traits>
00476 inline int
00477 basic_netbuf<charT, traits>::sync() {
00478 out_flush();
00479 in_sync();
00480 return is_open()?0:-1;
00481 }
00482
00483
00484 #endif