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