1// AbstractConnection.cpp
2
3#include "AbstractConnection.h"
4#include "AutoLocker.h"
5#include "Channel.h"
6#include "Debug.h"
7
8// constructor
9AbstractConnection::AbstractConnection()
10	: Connection(),
11	  fInitStatus(B_NO_INIT),
12	  fDownStreamChannels(),
13	  fUpStreamChannelSemaphore(-1),
14	  fUpStreamChannelLock(),
15	  fUpStreamChannels(),
16	  fFreeUpStreamChannels(0)
17{
18}
19
20// destructor
21AbstractConnection::~AbstractConnection()
22{
23	// Danger: If derived classes implement Close(), this call will not reach
24	// them. So, the caller should rather call Close() explicitely before
25	// destroying the connection.
26	Close();
27	// delete all channels
28	for (ChannelVector::Iterator it = fDownStreamChannels.Begin();
29		 it != fDownStreamChannels.End();
30		 it++) {
31		delete *it;
32	}
33	fDownStreamChannels.MakeEmpty();
34	AutoLocker<Locker> _(fUpStreamChannelLock);
35	for (ChannelVector::Iterator it = fUpStreamChannels.Begin();
36		 it != fUpStreamChannels.End();
37		 it++) {
38		delete *it;
39	}
40	fUpStreamChannels.MakeEmpty();
41}
42
43// Init
44status_t
45AbstractConnection::Init()
46{
47	fInitStatus = B_OK;
48	// create upstream channel semaphore
49	fUpStreamChannelSemaphore = create_sem(0, "upstream channels");
50	if (fUpStreamChannelSemaphore < 0)
51		return (fInitStatus = fUpStreamChannelSemaphore);
52	return fInitStatus;
53}
54
55// Close
56void
57AbstractConnection::Close()
58{
59	// close all channels
60	for (ChannelVector::Iterator it = fDownStreamChannels.Begin();
61		 it != fDownStreamChannels.End();
62		 it++) {
63		(*it)->Close();
64	}
65	AutoLocker<Locker> _(fUpStreamChannelLock);
66	for (ChannelVector::Iterator it = fUpStreamChannels.Begin();
67		 it != fUpStreamChannels.End();
68		 it++) {
69		(*it)->Close();
70	}
71}
72
73//// GetAuthorizedUser
74//User*
75//AbstractConnection::GetAuthorizedUser()
76//{
77//	return NULL;
78//}
79
80// AddDownStreamChannel
81status_t
82AbstractConnection::AddDownStreamChannel(Channel* channel)
83{
84	if (!channel)
85		return B_BAD_VALUE;
86	return fDownStreamChannels.PushBack(channel);
87}
88
89// AddUpStreamChannel
90status_t
91AbstractConnection::AddUpStreamChannel(Channel* channel)
92{
93	if (!channel)
94		return B_BAD_VALUE;
95	AutoLocker<Locker> _(fUpStreamChannelLock);
96	status_t error = fUpStreamChannels.PushBack(channel);
97	if (error != B_OK)
98		return error;
99	PutUpStreamChannel(channel);
100	return B_OK;
101}
102
103// CountDownStreamChannels
104int32
105AbstractConnection::CountDownStreamChannels() const
106{
107	return fDownStreamChannels.Count();
108}
109
110// GetDownStreamChannel
111Channel*
112AbstractConnection::DownStreamChannelAt(int32 index) const
113{
114	if (index < 0 || index >= fDownStreamChannels.Count())
115		return NULL;
116	return fDownStreamChannels.ElementAt(index);
117}
118
119// GetUpStreamChannel
120status_t
121AbstractConnection::GetUpStreamChannel(Channel** channel, bigtime_t timeout)
122{
123	if (!channel)
124		return B_BAD_VALUE;
125	if (timeout < 0)
126		timeout = 0;
127	// acquire the semaphore
128	status_t error = acquire_sem_etc(fUpStreamChannelSemaphore, 1,
129		B_RELATIVE_TIMEOUT, timeout);
130	if (error != B_OK)
131		return error;
132	// we've acquire the semaphore successfully, so a free channel must be
133	// waiting for us
134	AutoLocker<Locker> _(fUpStreamChannelLock);
135	if (fFreeUpStreamChannels < 1) {
136		ERROR(("AbstractConnection::GetUpStreamChannel(): Acquired the "
137			"upstream semaphore successfully, but there's no free channel!\n"));
138		return B_ERROR;
139	}
140	fFreeUpStreamChannels--;
141	*channel = fUpStreamChannels.ElementAt(fFreeUpStreamChannels);
142	return B_OK;
143}
144
145// PutUpStreamChannel
146status_t
147AbstractConnection::PutUpStreamChannel(Channel* channel)
148{
149	if (!channel)
150		return B_BAD_VALUE;
151	// find the channel
152	AutoLocker<Locker> _(fUpStreamChannelLock);
153	int32 index = fUpStreamChannels.IndexOf(channel, fFreeUpStreamChannels);
154	if (index < 0)
155		return B_BAD_VALUE;
156	// swap it with the first non-free channel, release the semaphore,
157	// and bump the free channel count
158	if (index != fFreeUpStreamChannels) {
159		Channel*& target = fUpStreamChannels.ElementAt(fFreeUpStreamChannels);
160		fUpStreamChannels.ElementAt(index) = target;
161		target = channel;
162	}
163	status_t error = release_sem(fUpStreamChannelSemaphore);
164	if (error == B_OK)
165		fFreeUpStreamChannels++;
166	return error;
167}
168
169