xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/ServerConnection.cpp (revision 88e38c178a96634d52920e2de8bb3cbd49869f93)
1 // ServerConnection.cpp
2 
3 #include "ServerConnection.h"
4 
5 #include <AutoDeleter.h>
6 #include <ByteOrder.h>
7 #include <HashMap.h>
8 
9 #include "Connection.h"
10 #include "ConnectionFactory.h"
11 #include "DebugSupport.h"
12 #include "ExtendedServerInfo.h"
13 #include "RequestConnection.h"
14 #include "ShareVolume.h"
15 #include "VolumeEvent.h"
16 #include "VolumeManager.h"
17 
18 // VolumeMap
19 struct ServerConnection::VolumeMap : HashMap<HashKey32<int32>, ShareVolume*> {
20 };
21 
22 
23 // constructor
ServerConnection(VolumeManager * volumeManager,ExtendedServerInfo * serverInfo)24 ServerConnection::ServerConnection(VolumeManager* volumeManager,
25 	ExtendedServerInfo* serverInfo)
26 	:
27 	BReferenceable(),
28 	RequestHandler(),
29 	fLock("server connection"),
30 	fVolumeManager(volumeManager),
31 	fServerInfo(serverInfo),
32 	fConnection(NULL),
33 	fVolumes(NULL),
34 	fConnectionBrokenEvent(NULL),
35 	fConnected(false)
36 {
37 	if (fServerInfo)
38 		fServerInfo->AcquireReference();
39 }
40 
41 // destructor
~ServerConnection()42 ServerConnection::~ServerConnection()
43 {
44 PRINT(("ServerConnection::~ServerConnection()\n"))
45 	Close();
46 	delete fConnection;
47 	delete fVolumes;
48 	if (fConnectionBrokenEvent)
49 		fConnectionBrokenEvent->ReleaseReference();
50 	if (fServerInfo)
51 		fServerInfo->ReleaseReference();
52 }
53 
54 // Init
55 status_t
Init(vnode_id connectionBrokenTarget)56 ServerConnection::Init(vnode_id connectionBrokenTarget)
57 {
58 	if (!fServerInfo)
59 		RETURN_ERROR(B_BAD_VALUE);
60 
61 	// create a connection broken event
62 	fConnectionBrokenEvent
63 		= new(std::nothrow) ConnectionBrokenEvent(connectionBrokenTarget);
64 	if (!fConnectionBrokenEvent)
65 		return B_NO_MEMORY;
66 
67 	// get the server address
68 	const char* connectionMethod = fServerInfo->GetConnectionMethod();
69 	HashString server;
70 	status_t error = fServerInfo->GetAddress().GetString(&server, false);
71 	if (error != B_OK)
72 		RETURN_ERROR(error);
73 
74 	// create the volume map
75 	fVolumes = new(std::nothrow) VolumeMap;
76 	if (!fVolumes)
77 		RETURN_ERROR(B_NO_MEMORY);
78 	error = fVolumes->InitCheck();
79 	if (error != B_OK)
80 		RETURN_ERROR(error);
81 
82 	// establish the connection
83 	Connection* connection;
84 	ConnectionFactory factory;
85 	error = factory.CreateConnection(connectionMethod, server.GetString(),
86 		&connection);
87 	if (error != B_OK)
88 		RETURN_ERROR(error);
89 
90 	// create a request connection
91 	fConnection = new(std::nothrow) RequestConnection(connection, this);
92 	if (!fConnection) {
93 		delete connection;
94 		RETURN_ERROR(B_NO_MEMORY);
95 	}
96 	error = fConnection->Init();
97 	if (error != B_OK)
98 		return error;
99 
100 	// send an `init connection request'
101 
102 	// prepare the request
103 	InitConnectionRequest request;
104 	request.bigEndian = B_HOST_IS_BENDIAN;
105 
106 	// send the request
107 	Request* _reply;
108 	error = fConnection->SendRequest(&request, &_reply);
109 	if (error != B_OK)
110 		return error;
111 	ObjectDeleter<Request> replyDeleter(_reply);
112 
113 	// everything OK?
114 	InitConnectionReply* reply = dynamic_cast<InitConnectionReply*>(_reply);
115 	if (!reply)
116 		return B_BAD_DATA;
117 	if (reply->error != B_OK)
118 		return reply->error;
119 
120 	fConnected = true;
121 	return B_OK;
122 }
123 
124 // Close
125 void
Close()126 ServerConnection::Close()
127 {
128 	// mark the connection closed (events won't be delivered anymore)
129 	{
130 		AutoLocker<Locker> locker(fLock);
131 		fConnected = false;
132 	}
133 
134 	if (fConnection)
135 		fConnection->Close();
136 }
137 
138 // IsConnected
139 bool
IsConnected()140 ServerConnection::IsConnected()
141 {
142 	return fConnected;
143 }
144 
145 // GetRequestConnection
146 RequestConnection*
GetRequestConnection() const147 ServerConnection::GetRequestConnection() const
148 {
149 	return fConnection;
150 }
151 
152 // AddVolume
153 status_t
AddVolume(ShareVolume * volume)154 ServerConnection::AddVolume(ShareVolume* volume)
155 {
156 	if (!volume)
157 		return B_BAD_VALUE;
158 
159 	AutoLocker<Locker> _(fLock);
160 	return fVolumes->Put(volume->GetID(), volume);
161 }
162 
163 // RemoveVolume
164 void
RemoveVolume(ShareVolume * volume)165 ServerConnection::RemoveVolume(ShareVolume* volume)
166 {
167 	if (!volume)
168 		return;
169 
170 	AutoLocker<Locker> _(fLock);
171 	fVolumes->Remove(volume->GetID());
172 }
173 
174 // GetVolume
175 ShareVolume*
GetVolume(int32 volumeID)176 ServerConnection::GetVolume(int32 volumeID)
177 {
178 	AutoLocker<Locker> _(fLock);
179 	return fVolumes->Get(volumeID);
180 }
181 
182 // VisitConnectionBrokenRequest
183 status_t
VisitConnectionBrokenRequest(ConnectionBrokenRequest * request)184 ServerConnection::VisitConnectionBrokenRequest(ConnectionBrokenRequest* request)
185 {
186 	AutoLocker<Locker> locker(fLock);
187 	if (fConnected) {
188 		fConnected = false;
189 		fVolumeManager->SendVolumeEvent(fConnectionBrokenEvent);
190 	}
191 	return B_OK;
192 }
193 
194 // VisitNodeMonitoringRequest
195 status_t
VisitNodeMonitoringRequest(NodeMonitoringRequest * request)196 ServerConnection::VisitNodeMonitoringRequest(NodeMonitoringRequest* request)
197 {
198 	AutoLocker<Locker> locker(fLock);
199 	if (fConnected) {
200 		if (ShareVolume* volume = GetVolume(request->volumeID)) {
201 			if (fVolumeManager->GetVolume(volume->GetRootID())) {
202 				locker.Unlock();
203 				if (request->opcode == B_DEVICE_UNMOUNTED)
204 					volume->SetUnmounting(true);
205 				else
206 					volume->ProcessNodeMonitoringRequest(request);
207 				volume->PutVolume();
208 			}
209 		}
210 	}
211 	return B_OK;
212 }
213 
214