Winsock needs to be initialized.
[dftpd.git] / Data.cpp
blob8d85d1458705360cd82ac5bcb9e19b4e6b619896
1 #ifdef _WIN32
2 #include <winsock.h>
3 typedef int socklen_t;
4 #else
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <sys/select.h>
10 #endif
12 #include <unistd.h>
13 #include <string.h>
14 #include <errno.h>
15 #include "Data.hpp"
16 #include "Session.hpp"
17 #include "Exceptions.hpp"
18 #include "DataBufferFile.hpp"
19 #include "DataBufferListing.hpp"
21 #ifdef SYMBIAN
23 #include "DataBufferFileSymbian.hpp"
25 Data::Data( const SessionWPtr& session, RFile* file, Mode mode )
26 : m_sock( 0 )
27 , m_mode( mode )
28 , m_session( session )
29 , m_buf( new char[BufSize] )
31 if( mode == M_UPLOAD )
33 m_data.reset( new DataBufferFileSymbian( file, BufSize ) );
35 else
37 m_data.reset( new DataBufferFileSymbian( file, BufSize ) );
40 #endif
42 Data::Data( const SessionWPtr& session, FILE* file, Mode mode )
43 : m_sock( 0 )
44 , m_mode( mode )
45 , m_session( session )
46 , m_buf( new char[BufSize] )
48 if( mode == M_UPLOAD )
50 m_data.reset( new DataBufferFile( file, BufSize ) );
52 else
54 m_data.reset( new DataBufferFile( file, BufSize ) );
58 Data::Data( const SessionWPtr& session, const std::list<std::string>& list )
59 : m_sock( 0 )
60 , m_mode( M_UPLOAD )
61 , m_session( session )
62 , m_buf( new char[BufSize] )
63 , m_data( new DataBufferListing( list ) )
67 Data::~Data()
69 delete[] m_buf;
71 if( m_sock != 0 )
73 close( m_sock );
77 bool Data::Connect( const std::string& addr, int port )
79 if( ( m_sock = socket( PF_INET, SOCK_STREAM, 0 ) ) == -1 )
81 throw SessionErrorException;
84 sockaddr_in sa;
86 sa.sin_family = AF_INET;
87 sa.sin_port = htons( port );
88 sa.sin_addr.s_addr = inet_addr( addr.c_str() );
89 memset( sa.sin_zero, 0, sizeof( sa.sin_zero ) );
91 return connect( m_sock, (sockaddr*)&sa, sizeof( sockaddr ) ) != -1;
94 bool Data::Accept( int sock )
96 sockaddr_in addr;
97 socklen_t size = sizeof( addr );
99 int incoming = accept( sock, (sockaddr*)&addr, &size );
101 if( incoming == -1 )
103 return false;
106 m_sock = incoming;
108 return true;
111 void Data::Tick()
113 if( m_mode == M_UPLOAD )
115 Send();
117 else
119 Receive();
123 void Data::Send()
125 int len = m_data->Read( m_buf, BufSize );
127 if( len == 0 )
129 m_session.lock()->DataConnectionFinished();
131 else
133 int pos = 0;
134 char *ptr = m_buf;
136 while( pos != len && CanSend() )
138 int size = send( m_sock, ptr, len - pos, 0 );
140 if( size == -1 )
142 throw SessionErrorException;
144 else if( size == 0 )
146 m_session.lock()->DataConnectionError();
147 return;
150 pos += size;
151 ptr += size;
154 if( pos != len )
156 m_data->Store( ptr, len - pos );
161 void Data::Receive()
163 int total = 0;
165 while( total < BufSize && CanReceive() )
167 int size = recv( m_sock, m_buf, BufSize - total, 0 );
168 if( size == -1 )
170 throw SessionErrorException;
172 else if( size == 0 )
174 m_session.lock()->DataConnectionFinished();
175 return;
177 else
179 int writeSize = m_data->Write( m_buf, size );
181 if( writeSize != size )
183 m_session.lock()->OutOfSpace();
184 return;
188 total += size;
192 bool Data::CanSend()
194 fd_set fd;
195 FD_ZERO( &fd );
196 FD_SET( m_sock, &fd );
197 timeval tv;
198 tv.tv_sec = 0;
199 tv.tv_usec = 0;
200 select( m_sock + 1, NULL, &fd, NULL, &tv );
202 return FD_ISSET( m_sock, &fd );
205 bool Data::CanReceive()
207 fd_set fd;
208 FD_ZERO( &fd );
209 FD_SET( m_sock, &fd );
210 timeval tv;
211 tv.tv_sec = 0;
212 tv.tv_usec = 0;
213 select( m_sock + 1, &fd, NULL, NULL, &tv );
215 return FD_ISSET( m_sock, &fd );