aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/archive.h47
-rw-r--r--src/exceptions.cpp1
-rw-r--r--src/exceptions.h2
-rw-r--r--src/socket.cpp232
-rw-r--r--src/socket.h23
-rw-r--r--src/stream.h10
6 files changed, 312 insertions, 3 deletions
diff --git a/src/archive.h b/src/archive.h
index 9ac3303..2f782d3 100644
--- a/src/archive.h
+++ b/src/archive.h
@@ -9,6 +9,53 @@
9 9
10namespace Bu 10namespace Bu
11{ 11{
12 /**
13 * Provides a framework for serialization of objects and primitives. The
14 * archive will handle any basic primitive, a few special types, like char *
15 * strings, as well as STL classes and anything that inherits from the
16 * Archival class. Each Archive operates on a Stream, so you can send the
17 * data using an Archive almost anywhere.
18 *
19 * In order to use an Archive to store something to a file, try something
20 * like:
21 *@code
22 * File sOut("output", "wb"); // This is a stream subclass
23 * Archive ar( sOut, Archive::save );
24 * ar << myClass;
25 @endcode
26 * In this example myClass is any class that inherits from Archival. When
27 * the storage operator is called, the Archival::archive() function in the
28 * myClass object is called with a reference to the Archive. This can be
29 * handled in one of two ways:
30 *@code
31 * void MyClass::archive( Archive &ar )
32 * {
33 * ar && sName && nAge && sJob;
34 * }
35 @endcode
36 * Here we don't worry about weather we're loading or saving by using the
37 * smart && operator. This allows us to write very consistent, very simple
38 * archive functions that really do a lot of work. If we wanted to do
39 * something different in the case of loading or saving we would do:
40 *@code
41 * void MyClass::archive( Archive &ar )
42 * {
43 * if( ar.isLoading() )
44 * {
45 * ar >> sName >> nAge >> sJob;
46 * } else
47 * {
48 * ar << sName << nAge << sJob;
49 * }
50 * }
51 @endcode
52 * Archive currently does not provide facility to make fully portable
53 * archives. For example, it will not convert between endianness for you,
54 * nor will it take into account differences between primitive sizes on
55 * different platforms. This, at the moment, is up to the user to ensure.
56 * One way of dealing with the latter problem is to make sure and use
57 * explicit primitive types from the stdint.h header, i.e. int32_t.
58 */
12 class Archive 59 class Archive
13 { 60 {
14 private: 61 private:
diff --git a/src/exceptions.cpp b/src/exceptions.cpp
index 37f09a4..a512105 100644
--- a/src/exceptions.cpp
+++ b/src/exceptions.cpp
@@ -7,4 +7,5 @@ namespace Bu
7 subExceptionDef( FileException ) 7 subExceptionDef( FileException )
8 subExceptionDef( ConnectionException ) 8 subExceptionDef( ConnectionException )
9 subExceptionDef( PluginException ) 9 subExceptionDef( PluginException )
10 subExceptionDef( UnsupportedException )
10} 11}
diff --git a/src/exceptions.h b/src/exceptions.h
index b28d292..3efa19f 100644
--- a/src/exceptions.h
+++ b/src/exceptions.h
@@ -10,6 +10,7 @@ namespace Bu
10 subExceptionDecl( FileException ) 10 subExceptionDecl( FileException )
11 subExceptionDecl( ConnectionException ) 11 subExceptionDecl( ConnectionException )
12 subExceptionDecl( PluginException ) 12 subExceptionDecl( PluginException )
13 subExceptionDecl( UnsupportedException )
13 14
14 enum eFileException 15 enum eFileException
15 { 16 {
@@ -19,6 +20,7 @@ namespace Bu
19 enum eConnectionException 20 enum eConnectionException
20 { 21 {
21 excodeReadError, 22 excodeReadError,
23 excodeWriteError,
22 excodeBadReadError, 24 excodeBadReadError,
23 excodeConnectionClosed, 25 excodeConnectionClosed,
24 excodeSocketTimeout 26 excodeSocketTimeout
diff --git a/src/socket.cpp b/src/socket.cpp
index c5c592b..e206bb5 100644
--- a/src/socket.cpp
+++ b/src/socket.cpp
@@ -1,10 +1,240 @@
1#include <string.h>
2#include <stdio.h>
3#include <errno.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <sys/time.h>
9#include <netinet/in.h>
10#include <netdb.h>
11#include <arpa/inet.h>
12#include <errno.h>
13#include <fcntl.h>
1#include "socket.h" 14#include "socket.h"
15#include "exceptions.h"
2 16
3Bu::Socket::Socket() 17#define RBS (1024*2)
18
19Bu::Socket::Socket( int nSocket ) :
20 nSocket( nSocket ),
21 bActive( true )
4{ 22{
5} 23}
6 24
25Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout )
26{
27 struct sockaddr_in xServerName;
28 bActive = false;
29
30 /* Create the socket. */
31 nSocket = socket( PF_INET, SOCK_STREAM, 0 );
32
33 if( nSocket < 0 )
34 {
35 throw ExceptionBase("Couldn't create socket.\n");
36 }
37
38 // These lines set the socket to non-blocking, a good thing?
39 int flags;
40 flags = fcntl(nSocket, F_GETFL, 0);
41 flags |= O_NONBLOCK;
42 if (fcntl(nSocket, F_SETFL, flags) < 0)
43 {
44 throw ExceptionBase("Couldn't set socket options.\n");
45 }
46
47 /* Connect to the server. */
48 //printf("Resolving hostname (%s)...\n", sAddr );
49 {
50 struct hostent *hostinfo;
51
52 xServerName.sin_family = AF_INET;
53 xServerName.sin_port = htons( nPort );
54 hostinfo = gethostbyname( sAddr.getStr() );
55 if (hostinfo == NULL)
56 {
57 throw ExceptionBase("Couldn't resolve hostname.\n");
58 }
59 xServerName.sin_addr = *(struct in_addr *) hostinfo->h_addr;
60 }
61
62 //printf("Making actual connection...");
63 //fflush( stdout );
64 connect(
65 nSocket,
66 (struct sockaddr *)&xServerName,
67 sizeof(xServerName)
68 );
69 //printf("Connected.\n");
70
71 bActive = true;
72
73 if( nTimeout > 0 )
74 {
75 fd_set rfds, wfds, efds;
76 int retval;
77
78 FD_ZERO(&rfds);
79 FD_SET(nSocket, &rfds);
80 FD_ZERO(&wfds);
81 FD_SET(nSocket, &wfds);
82 FD_ZERO(&efds);
83 FD_SET(nSocket, &efds);
84
85 struct timeval tv;
86 tv.tv_sec = nTimeout;
87 tv.tv_usec = 0;
88
89 retval = select( nSocket+1, &rfds, &wfds, &efds, &tv );
90
91 if( retval == 0 )
92 {
93 close();
94 throw ExceptionBase("Connection timeout.\n");
95 }
96
97 }
98}
99
7Bu::Socket::~Socket() 100Bu::Socket::~Socket()
8{ 101{
9} 102}
10 103
104void Bu::Socket::close()
105{
106 if( bActive )
107 {
108 fsync( nSocket );
109 ::close( nSocket );
110 }
111 bActive = false;
112 //xInputBuf.clearData();
113 //xOutputBuf.clearData();
114 //if( pProtocol != NULL )
115 //{
116 // delete pProtocol;
117 // pProtocol = NULL;
118 //}
119}
120
121void Bu::Socket::read()
122{
123 char buffer[RBS];
124 int nbytes;
125 int nTotalRead=0;
126
127 for(;;)
128 {
129 //memset( buffer, 0, RBS );
130
131 nbytes = ::read( nSocket, buffer, RBS );
132 if( nbytes < 0 && errno != 0 && errno != EAGAIN )
133 {
134 //printf("errno: %d, %s\n", errno, strerror( errno ) );
135 /* Read error. */
136 //perror("readInput");
137 throw ConnectionException(
138 excodeReadError,
139 "Read error: %s",
140 strerror( errno )
141 );
142 }
143 else
144 {
145 if( nbytes <= 0 )
146 break;
147 nTotalRead += nbytes;
148 sReadBuf.append( buffer, nbytes );
149 /* Data read. */
150 if( nbytes < RBS )
151 {
152 break;
153 }
154
155 /* New test, if data is divisible by RBS bytes on some libs the
156 * read could block, this keeps it from happening.
157 */
158 {
159 fd_set rfds;
160 FD_ZERO(&rfds);
161 FD_SET(nSocket, &rfds);
162 struct timeval tv = { 0, 0 };
163 int retval = select( nSocket+1, &rfds, NULL, NULL, &tv );
164 if( retval == -1 )
165 throw ConnectionException(
166 excodeBadReadError,
167 "Bad Read error"
168 );
169 if( !FD_ISSET( nSocket, &rfds ) )
170 break;
171 }
172 }
173 }
174
175 /*
176 if( pProtocol != NULL && nTotalRead > 0 )
177 {
178 pProtocol->onNewData();
179 }*/
180}
181
182size_t Bu::Socket::read( void *pBuf, size_t nBytes )
183{
184 read();
185
186
187
188 return sReadBuf.getSize();
189}
190
191size_t Bu::Socket::write( const void *pBuf, size_t nBytes )
192{
193 int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) );
194 if( nWrote < 0 )
195 {
196 throw ConnectionException( excodeWriteError, strerror(errno) );
197 }
198 return nWrote;
199}
200
201long Bu::Socket::tell()
202{
203 throw UnsupportedException();
204}
205
206void Bu::Socket::seek( long offset )
207{
208 throw UnsupportedException();
209}
210
211void Bu::Socket::setPos( long pos )
212{
213 throw UnsupportedException();
214}
215
216void Bu::Socket::setPosEnd( long pos )
217{
218 throw UnsupportedException();
219}
220
221bool Bu::Socket::isEOS()
222{
223 return !bActive;
224}
225
226bool Bu::Socket::canRead()
227{
228 return true;
229}
230
231bool Bu::Socket::canWrite()
232{
233 return true;
234}
235
236bool Bu::Socket::canSeek()
237{
238 return false;
239}
240
diff --git a/src/socket.h b/src/socket.h
index 8ccde71..3d0125d 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -4,6 +4,7 @@
4#include <stdint.h> 4#include <stdint.h>
5 5
6#include "stream.h" 6#include "stream.h"
7#include "fstring.h"
7 8
8namespace Bu 9namespace Bu
9{ 10{
@@ -13,11 +14,29 @@ namespace Bu
13 class Socket : public Stream 14 class Socket : public Stream
14 { 15 {
15 public: 16 public:
16 Socket(); 17 Socket( int nSocket );
18 Socket( const FString &sAddr, int nPort, int nTimeout=30 );
17 virtual ~Socket(); 19 virtual ~Socket();
20
21 virtual void close();
22 virtual void read();
23 virtual size_t read( void *pBuf, size_t nBytes );
24 virtual size_t write( const void *pBuf, size_t nBytes );
18 25
19 private: 26 virtual long tell();
27 virtual void seek( long offset );
28 virtual void setPos( long pos );
29 virtual void setPosEnd( long pos );
30 virtual bool isEOS();
31
32 virtual bool canRead();
33 virtual bool canWrite();
34 virtual bool canSeek();
20 35
36 private:
37 int nSocket;
38 bool bActive;
39 FString sReadBuf;
21 }; 40 };
22} 41}
23 42
diff --git a/src/stream.h b/src/stream.h
index ae94234..e640959 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -6,6 +6,16 @@
6 6
7namespace Bu 7namespace Bu
8{ 8{
9 /**
10 * The basis for a completely general data transport mechanism. Anything
11 * that inherits from this should provide at least the basic read and/or
12 * write functions, and very probably the close function. Any functions
13 * that aren't supported should throw an exception if called.
14 *
15 * The constructor of a child class should pretty much universally be used
16 * to open the stream. I can't think of anything that should require an
17 * exception.
18 */
9 class Stream 19 class Stream
10 { 20 {
11 public: 21 public: