1#ifndef CRYPTOPP_SOCKETFT_H
2#define CRYPTOPP_SOCKETFT_H
3
4#include "config.h"
5
6#ifdef SOCKETS_AVAILABLE
7
8#include "network.h"
9#include "queue.h"
10
11#ifdef USE_WINDOWS_STYLE_SOCKETS
12#	if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
13#		error Winsock 1 is not supported by this library. Please include this file or winsock2.h before windows.h.
14#	endif
15#include <winsock2.h>
16#include "winpipes.h"
17#else
18#include <sys/time.h>
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <unistd.h>
22#endif
23
24NAMESPACE_BEGIN(CryptoPP)
25
26#ifdef USE_WINDOWS_STYLE_SOCKETS
27typedef ::SOCKET socket_t;
28#else
29typedef int socket_t;
30const socket_t INVALID_SOCKET = -1;
31// cygwin 1.1.4 doesn't have SHUT_RD
32const int SD_RECEIVE = 0;
33const int SD_SEND = 1;
34const int SD_BOTH = 2;
35const int SOCKET_ERROR = -1;
36#endif
37
38#ifndef socklen_t
39typedef TYPE_OF_SOCKLEN_T socklen_t;	// see config.h
40#endif
41
42//! wrapper for Windows or Berkeley Sockets
43class Socket
44{
45public:
46	//! exception thrown by Socket class
47	class Err : public OS_Error
48	{
49	public:
50		Err(socket_t s, const std::string& operation, int error);
51		socket_t GetSocket() const {return m_s;}
52
53	private:
54		socket_t m_s;
55	};
56
57	Socket(socket_t s = INVALID_SOCKET, bool own=false) : m_s(s), m_own(own) {}
58	Socket(const Socket &s) : m_s(s.m_s), m_own(false) {}
59	virtual ~Socket();
60
61	bool GetOwnership() const {return m_own;}
62	void SetOwnership(bool own) {m_own = own;}
63
64	operator socket_t() {return m_s;}
65	socket_t GetSocket() const {return m_s;}
66	void AttachSocket(socket_t s, bool own=false);
67	socket_t DetachSocket();
68	void CloseSocket();
69
70	void Create(int nType = SOCK_STREAM);
71	void Bind(unsigned int port, const char *addr=NULL);
72	void Bind(const sockaddr* psa, socklen_t saLen);
73	void Listen(int backlog=5);
74	// the next three functions return false if the socket is in nonblocking mode
75	// and the operation cannot be completed immediately
76	bool Connect(const char *addr, unsigned int port);
77	bool Connect(const sockaddr* psa, socklen_t saLen);
78	bool Accept(Socket& s, sockaddr *psa=NULL, socklen_t *psaLen=NULL);
79	void GetSockName(sockaddr *psa, socklen_t *psaLen);
80	void GetPeerName(sockaddr *psa, socklen_t *psaLen);
81	unsigned int Send(const byte* buf, size_t bufLen, int flags=0);
82	unsigned int Receive(byte* buf, size_t bufLen, int flags=0);
83	void ShutDown(int how = SD_SEND);
84
85	void IOCtl(long cmd, unsigned long *argp);
86	bool SendReady(const timeval *timeout);
87	bool ReceiveReady(const timeval *timeout);
88
89	virtual void HandleError(const char *operation) const;
90	void CheckAndHandleError_int(const char *operation, int result) const
91		{if (result == SOCKET_ERROR) HandleError(operation);}
92	void CheckAndHandleError(const char *operation, socket_t result) const
93		{if (result == SOCKET_ERROR) HandleError(operation);}
94#ifdef USE_WINDOWS_STYLE_SOCKETS
95	void CheckAndHandleError(const char *operation, BOOL result) const
96		{assert(result==TRUE || result==FALSE); if (!result) HandleError(operation);}
97	void CheckAndHandleError(const char *operation, bool result) const
98		{if (!result) HandleError(operation);}
99#endif
100
101	//! look up the port number given its name, returns 0 if not found
102	static unsigned int PortNameToNumber(const char *name, const char *protocol="tcp");
103	//! start Windows Sockets 2
104	static void StartSockets();
105	//! calls WSACleanup for Windows Sockets
106	static void ShutdownSockets();
107	//! returns errno or WSAGetLastError
108	static int GetLastError();
109	//! sets errno or calls WSASetLastError
110	static void SetLastError(int errorCode);
111
112protected:
113	virtual void SocketChanged() {}
114
115	socket_t m_s;
116	bool m_own;
117};
118
119class SocketsInitializer
120{
121public:
122	SocketsInitializer() {Socket::StartSockets();}
123	~SocketsInitializer() {try {Socket::ShutdownSockets();} catch (...) {}}
124};
125
126class SocketReceiver : public NetworkReceiver
127{
128public:
129	SocketReceiver(Socket &s);
130
131#ifdef USE_BERKELEY_STYLE_SOCKETS
132	bool MustWaitToReceive() {return true;}
133#else
134	~SocketReceiver();
135	bool MustWaitForResult() {return true;}
136#endif
137	bool Receive(byte* buf, size_t bufLen);
138	unsigned int GetReceiveResult();
139	bool EofReceived() const {return m_eofReceived;}
140
141	unsigned int GetMaxWaitObjectCount() const {return 1;}
142	void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
143
144private:
145	Socket &m_s;
146	bool m_eofReceived;
147
148#ifdef USE_WINDOWS_STYLE_SOCKETS
149	WindowsHandle m_event;
150	OVERLAPPED m_overlapped;
151	bool m_resultPending;
152	DWORD m_lastResult;
153#else
154	unsigned int m_lastResult;
155#endif
156};
157
158class SocketSender : public NetworkSender
159{
160public:
161	SocketSender(Socket &s);
162
163#ifdef USE_BERKELEY_STYLE_SOCKETS
164	bool MustWaitToSend() {return true;}
165#else
166	~SocketSender();
167	bool MustWaitForResult() {return true;}
168	bool MustWaitForEof() { return true; }
169	bool EofSent();
170#endif
171	void Send(const byte* buf, size_t bufLen);
172	unsigned int GetSendResult();
173	void SendEof();
174
175	unsigned int GetMaxWaitObjectCount() const {return 1;}
176	void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack);
177
178private:
179	Socket &m_s;
180#ifdef USE_WINDOWS_STYLE_SOCKETS
181	WindowsHandle m_event;
182	OVERLAPPED m_overlapped;
183	bool m_resultPending;
184	DWORD m_lastResult;
185#else
186	unsigned int m_lastResult;
187#endif
188};
189
190//! socket-based implementation of NetworkSource
191class SocketSource : public NetworkSource, public Socket
192{
193public:
194	SocketSource(socket_t s = INVALID_SOCKET, bool pumpAll = false, BufferedTransformation *attachment = NULL)
195		: NetworkSource(attachment), Socket(s), m_receiver(*this)
196	{
197		if (pumpAll)
198			PumpAll();
199	}
200
201private:
202	NetworkReceiver & AccessReceiver() {return m_receiver;}
203	SocketReceiver m_receiver;
204};
205
206//! socket-based implementation of NetworkSink
207class SocketSink : public NetworkSink, public Socket
208{
209public:
210	SocketSink(socket_t s=INVALID_SOCKET, unsigned int maxBufferSize=0, unsigned int autoFlushBound=16*1024)
211		: NetworkSink(maxBufferSize, autoFlushBound), Socket(s), m_sender(*this) {}
212
213	void SendEof() {ShutDown(SD_SEND);}
214
215private:
216	NetworkSender & AccessSender() {return m_sender;}
217	SocketSender m_sender;
218};
219
220NAMESPACE_END
221
222#endif	// #ifdef SOCKETS_AVAILABLE
223
224#endif
225