1#define DEBUG 1
2#include <Debug.h>
3#include <OS.h>
4#include <errno.h>
5#include <socket.h>
6#include <string.h>
7#include <Application.h>
8#include "ksocket_internal.h"
9
10sem_id printf_sem;
11
12static void send_reply (port_id port, const void *reply, size_t size)
13{
14	status_t result;
15
16	do
17	{
18		result=write_port (port,0,reply,size);
19	}
20	while (result==B_INTERRUPTED);
21
22	ASSERT (result>=B_OK);
23}
24
25static void ks_socket (const struct ks_socket_param *param)
26{
27	struct ks_socket_reply reply;
28
29	reply.result=socket (param->family,param->type,param->proto);
30	reply.header.error=errno;
31
32	send_reply (param->header.port,&reply,sizeof(reply));
33}
34
35static void ks_multi1 (int32 code, const struct ks_bind_param *param)
36{
37	struct ks_bind_reply reply;
38
39	if (code==KS_BIND)
40		reply.result=bind (param->fd,(const struct sockaddr *)param->addr,param->size);
41	else
42		reply.result=connect (param->fd,(const struct sockaddr *)param->addr,param->size);
43
44	reply.header.error=errno;
45
46	send_reply (param->header.port,&reply,sizeof(reply));
47}
48
49static void ks_multi2 (int32 code, const struct ks_getsockname_param *param)
50{
51	struct sockaddr *addr=(struct sockaddr *)malloc(param->size);
52	int size=param->size;
53	int result;
54	size_t replySize;
55	struct ks_getsockname_reply *reply;
56
57	switch (code)
58	{
59		case KS_GETSOCKNAME:
60			result=getsockname(param->fd,addr,&size);
61			break;
62		case KS_GETPEERNAME:
63			result=getpeername(param->fd,addr,&size);
64			break;
65		case KS_ACCEPT:
66			result=accept(param->fd,addr,&size);
67			break;
68	}
69
70	if (result<0)
71		size=0;
72
73	replySize=sizeof(struct ks_getsockname_reply)+size;
74	reply=(struct ks_getsockname_reply *)malloc(replySize);
75	reply->result=result;
76	reply->header.error=errno;
77
78	if (result>=0)
79	{
80		reply->size=size;
81		memcpy (reply->addr,addr,size);
82	}
83
84	send_reply (param->header.port,reply,replySize);
85
86	free (reply);
87	free (addr);
88}
89
90static void ks_recvfrom (const struct ks_recvfrom_param *param)
91{
92	char *buffer=(char *)malloc(param->size);
93	struct sockaddr *addr=(struct sockaddr *)malloc(param->fromlen);
94	int fromlen=param->fromlen;
95	ssize_t result;
96	size_t replySize;
97	struct ks_recvfrom_reply *reply;
98
99	result=recvfrom(param->fd,buffer,param->size,param->flags,addr,&fromlen);
100
101	if (result<0)
102		replySize=sizeof(struct ks_recvfrom_reply);
103	else
104		replySize=sizeof(struct ks_recvfrom_reply)+fromlen+result;
105
106	reply=(struct ks_recvfrom_reply *)malloc(replySize);
107	reply->result=result;
108	reply->header.error=errno;
109
110	if (result>=0)
111	{
112		reply->fromlen=fromlen;
113		memcpy (reply->data,buffer,result);
114		memcpy (reply->data+result,addr,fromlen);
115	}
116
117	send_reply (param->header.port,reply,replySize);
118
119	free (reply);
120	free (addr);
121	free (buffer);
122}
123
124static void ks_sendto (const struct ks_sendto_param *param)
125{
126	struct ks_sendto_reply reply;
127
128	reply.result=sendto (param->fd,param->data,param->size,param->flags,
129							(const struct sockaddr *)(param->data+param->size),
130							param->tolen);
131
132	reply.header.error=errno;
133
134	send_reply (param->header.port,&reply,sizeof(reply));
135}
136
137static void ks_recv (const struct ks_recv_param *param)
138{
139	char *buffer=(char *)malloc(param->size);
140	ssize_t result;
141	size_t replySize;
142	struct ks_recv_reply *reply;
143
144	result=recv(param->fd,buffer,param->size,param->flags);
145
146	if (result<0)
147		replySize=sizeof(struct ks_recvfrom_reply);
148	else
149		replySize=sizeof(struct ks_recvfrom_reply)+result;
150
151	reply=(struct ks_recv_reply *)malloc(replySize);
152	reply->result=result;
153	reply->header.error=errno;
154
155	if (result>=0)
156		memcpy (reply->data,buffer,result);
157
158	send_reply (param->header.port,reply,replySize);
159
160	free (reply);
161	free (buffer);
162}
163
164static void ks_send (const struct ks_send_param *param)
165{
166	struct ks_send_reply reply;
167
168	reply.result=send (param->fd,param->data,param->size,param->flags);
169
170	reply.header.error=errno;
171
172	send_reply (param->header.port,&reply,sizeof(reply));
173}
174
175static void ks_listen (const struct ks_listen_param *param)
176{
177	struct ks_listen_reply reply;
178
179	reply.result=listen (param->fd,param->backlog);
180	reply.header.error=errno;
181
182	send_reply (param->header.port,&reply,sizeof(reply));
183}
184
185static void ks_closesocket (const struct ks_closesocket_param *param)
186{
187	struct ks_closesocket_reply reply;
188
189	reply.result=closesocket (param->fd);
190	reply.header.error=errno;
191
192	send_reply (param->header.port,&reply,sizeof(reply));
193}
194
195static status_t client_func (void *buffer)
196{
197	thread_id from;
198	int32 code=receive_data (&from,NULL,0);
199
200	ASSERT (code>=B_OK);
201
202	switch (code)
203	{
204		case KS_SOCKET:
205			ks_socket ((const struct ks_socket_param *)buffer);
206			break;
207
208		case KS_BIND:
209		case KS_CONNECT:
210			ks_multi1 (code,(const struct ks_bind_param *)buffer);
211			break;
212
213		case KS_GETSOCKNAME:
214		case KS_GETPEERNAME:
215		case KS_ACCEPT:
216			ks_multi2 (code,(const struct ks_getsockname_param *)buffer);
217			break;
218
219		case KS_RECVFROM:
220			ks_recvfrom ((const struct ks_recvfrom_param *)buffer);
221			break;
222
223		case KS_SENDTO:
224			ks_sendto ((const struct ks_sendto_param *)buffer);
225			break;
226
227		case KS_RECV:
228			ks_recv ((const struct ks_recv_param *)buffer);
229			break;
230
231		case KS_SEND:
232			ks_send ((const struct ks_send_param *)buffer);
233			break;
234
235		case KS_LISTEN:
236			ks_listen ((const struct ks_listen_param *)buffer);
237			break;
238
239		case KS_CLOSESOCKET:
240			ks_closesocket ((const struct ks_closesocket_param *)buffer);
241			break;
242
243		case KS_MESSAGE:
244		{
245			while (acquire_sem (printf_sem)==B_INTERRUPTED) ;
246
247			printf ("%s\n",buffer);
248
249			while (release_sem (printf_sem)==B_INTERRUPTED) ;
250			break;
251		}
252	}
253
254	free (buffer);
255
256	return B_OK;
257}
258
259class CApplication : public BApplication
260{
261	port_id port;
262	thread_id fTID;
263
264	static status_t WorkhorseWrapper (CApplication *me);
265	status_t Workhorse ();
266
267	public:
268		CApplication (const char *signature);
269
270		virtual void ReadyToRun();
271		virtual bool QuitRequested();
272};
273
274CApplication::CApplication(const char *signature)
275	: BApplication (signature)
276{
277}
278
279void
280CApplication::ReadyToRun()
281{
282	resume_thread (fTID=spawn_thread((thread_func)WorkhorseWrapper,"Workhorse",B_NORMAL_PRIORITY,this));
283}
284
285bool
286CApplication::QuitRequested()
287{
288	if (!BApplication::QuitRequested())
289		return false;
290
291	while (write_port(port,KS_QUIT,NULL,0)==B_INTERRUPTED)
292		;
293
294	status_t result;
295	wait_for_thread (fTID,&result);
296
297	return true;
298}
299
300status_t
301CApplication::WorkhorseWrapper(CApplication *me)
302{
303	return me->Workhorse();
304}
305
306status_t
307CApplication::Workhorse()
308{
309	char *buffer;
310	ssize_t bufferSize;
311	int32 code;
312	thread_id tid;
313	status_t result;
314	BList clientList;
315
316	printf_sem=create_sem (1,"printf_sem");
317
318	if (printf_sem<B_OK)
319		return 1;
320
321	port=create_port (10,KSOCKET_DAEMON_NAME);
322
323	if (port<B_OK)
324	{
325		delete_sem (printf_sem);
326		return 1;
327	}
328
329	while (true)
330	{
331		do
332		{
333			bufferSize=port_buffer_size (port);
334		}
335		while (bufferSize==B_INTERRUPTED);
336
337		ASSERT (bufferSize>=B_OK);
338
339		buffer=(char *)malloc(bufferSize);
340
341		do
342		{
343			result=read_port (port,&code,buffer,bufferSize);
344		}
345		while (result==B_INTERRUPTED);
346
347		ASSERT (result>=B_OK);
348
349		if (code==KS_QUIT)
350			break;
351
352		tid=spawn_thread (client_func,"ksocketd_client",B_NORMAL_PRIORITY,buffer);
353
354		ASSERT (tid>=B_OK);
355
356		clientList.AddItem((void *)tid);
357
358		result=resume_thread (tid);
359
360		ASSERT (result>=B_OK);
361
362		result=send_data (tid,code,NULL,0);
363
364		ASSERT (result>=B_OK);
365	}
366
367	for (int32 i=clientList.CountItems()-1;i>=0;i--)
368	{
369		thread_id tid=(thread_id)clientList.RemoveItem(i);
370		status_t result;
371		wait_for_thread (tid,&result);
372	}
373
374	delete_sem (printf_sem);
375	delete_port (port);
376
377	return B_OK;
378}
379
380int main ()
381{
382	CApplication app(KSOCKETD_SIGNATURE);
383
384	app.Run();
385
386	return 0;
387}
388