1/* -*- linux-c -*- */
2/*
3 *
4 *
5 *   Copyright (c) International Business Machines  Corp., 2000
6 *
7 *   This program is free software;  you can redistribute it and/or modify
8 *   it under the terms of the GNU General Public License as published by
9 *   the Free Software Foundation; either version 2 of the License, or
10 *   (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
15 *   the GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program;  if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 *
22 */
23/*
24 * ltpServer.c
25 *
26 * LTP Network Socket Test Server
27 *
28 *
29 */
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <netdb.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <pthread.h>
39#include <unistd.h>
40
41#define LOCAL_UDP_SERVER_PORT   10000
42#define LOCAL_TCP_SERVER_PORT   10001
43#define LOCAL_MULTI_SERVER_PORT 10002
44#define MAX_MSG_LEN             256
45#define MAX_HOSTNAME_LEN        256
46#define ERROR -1
47#define END_LINE                0x0A
48
49int udpSocketHandle,
50    rc, msg_bytes, tcpSocketHandle, newTcpSocketHandle, multiSocketHandle;
51
52socklen_t udpClientLen, tcpClientLen, multiClientLen;
53
54struct sockaddr_in udpClientAddr,
55    udpServerAddr,
56    tcpClientAddr, tcpServerAddr, multiClientAddr, multiServerAddr;
57
58struct ip_mreq multiCastReq;
59struct in_addr multiCastAddr;
60struct hostent *hostEntry;
61
62char message[MAX_MSG_LEN];
63char hostname[MAX_HOSTNAME_LEN];
64char ServerProg[MAX_HOSTNAME_LEN];
65
66void *ltp_udp_server_queue(void *);
67void *ltp_tcp_server_queue(void *);
68void *ltp_multi_server_queue(void *);
69int tcp_receive_buffer(int, char *);
70
71int main(int argc, char *argv[])
72{
73
74	pthread_t udp_server_queue, tcp_server_queue, multi_server_queue;
75
76	pthread_attr_t udpthread_attr, tcpthread_attr, multithread_attr;
77
78	if (argc != 2) {
79		printf
80		    ("Server arguments : %s <multiCast I.P.address/hostname>\n",
81		     argv[0]);
82		exit(0);
83	}
84
85	strncpy(hostname, argv[1], 255);
86	strncpy(ServerProg, argv[0], 255);
87
88	/* get mcast address to listen to */
89
90	hostEntry = gethostbyname(argv[1]);
91
92	if (hostEntry == NULL) {
93		printf("Server %s : You need to pass a multiCast group '%s'\n",
94		       argv[0], argv[1]);
95		exit(1);
96	}
97
98	memcpy(&multiCastAddr, hostEntry->h_addr_list[0], hostEntry->h_length);
99
100	/* check given address is multicast */
101	if (!IN_MULTICAST(ntohl(multiCastAddr.s_addr))) {
102		printf
103		    ("%s : Hostname [%s] passed [%s] is not a multicast server\n",
104		     argv[0], hostname, inet_ntoa(multiCastAddr));
105		printf("The multiCast Server will not be started \n");
106	} else {
107
108		/* create multiCast socket */
109		multiSocketHandle = socket(AF_INET, SOCK_DGRAM, 0);
110
111		if (multiSocketHandle < 0) {
112			printf("%s : cannot create multiCast socket\n",
113			       argv[0]);
114		} else {
115			/* bind multiCast port */
116			multiServerAddr.sin_family = AF_INET;
117			multiServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
118			multiServerAddr.sin_port =
119			    htons(LOCAL_MULTI_SERVER_PORT);
120
121			if (bind
122			    (multiSocketHandle,
123			     (struct sockaddr *)&multiServerAddr,
124			     sizeof(multiServerAddr)) < 0) {
125				printf("%s : cannot bind Multicast port %d \n",
126				       argv[0], LOCAL_MULTI_SERVER_PORT);
127			} else {
128				/* join multicast group */
129				multiCastReq.imr_multiaddr.s_addr =
130				    multiCastAddr.s_addr;
131				multiCastReq.imr_interface.s_addr =
132				    htonl(INADDR_ANY);
133
134				rc = setsockopt(multiSocketHandle, IPPROTO_IP,
135						IP_ADD_MEMBERSHIP,
136						(void *)&multiCastReq,
137						sizeof(multiCastReq));
138				if (rc < 0) {
139					printf
140					    ("%s : cannot join multicast group '%s'",
141					     argv[0], inet_ntoa(multiCastAddr));
142				} else {
143					printf
144					    ("%s : listening to mgroup %s:%d\n",
145					     argv[0], inet_ntoa(multiCastAddr),
146					     LOCAL_MULTI_SERVER_PORT);
147				}
148			}
149		}
150
151		rc = pthread_attr_init(&multithread_attr);
152		rc = pthread_create(&multi_server_queue, &multithread_attr,
153				    ltp_multi_server_queue, NULL);
154	}
155
156	/* udp socket creation */
157	udpSocketHandle = socket(AF_INET, SOCK_DGRAM, 0);
158
159	if (udpSocketHandle < 0) {
160		printf("%s: cannot open socket \n", argv[0]);
161		exit(1);
162	}
163
164	/* tcp socket creation */
165	tcpSocketHandle = socket(AF_INET, SOCK_STREAM, 0);
166
167	if (tcpSocketHandle < 0) {
168		printf("Error: cannot open socket %d \n", tcpSocketHandle);
169		return ERROR;
170	}
171
172	/* bind local udp server port */
173	udpServerAddr.sin_family = AF_INET;
174	udpServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
175	udpServerAddr.sin_port = htons(LOCAL_UDP_SERVER_PORT);
176
177	rc = bind(udpSocketHandle, (struct sockaddr *)&udpServerAddr,
178		  sizeof(udpServerAddr));
179
180	if (rc < 0) {
181		printf("%s: Error binding port number %d \n",
182		       argv[0], LOCAL_UDP_SERVER_PORT);
183		exit(1);
184	} else {
185		printf("%s: bound port number %d \n",
186		       argv[0], LOCAL_UDP_SERVER_PORT);
187	}
188
189	/* bind local tcp server port */
190	tcpServerAddr.sin_family = AF_INET;
191	tcpServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
192	tcpServerAddr.sin_port = htons(LOCAL_TCP_SERVER_PORT);
193
194	rc = bind(tcpSocketHandle, (struct sockaddr *)&tcpServerAddr,
195		  sizeof(tcpServerAddr));
196
197	if (rc < 0) {
198		printf("%s: Error binding port number %d \n",
199		       argv[0], LOCAL_TCP_SERVER_PORT);
200		exit(1);
201	} else {
202		printf("%s: bound port number %d \n",
203		       argv[0], LOCAL_TCP_SERVER_PORT);
204	}
205
206	rc = pthread_attr_init(&udpthread_attr);
207	rc = pthread_create(&udp_server_queue, &udpthread_attr,
208			    ltp_udp_server_queue, NULL);
209
210	rc = pthread_attr_init(&tcpthread_attr);
211	rc = pthread_create(&tcp_server_queue, &tcpthread_attr,
212			    ltp_tcp_server_queue, NULL);
213
214	while (1) ;
215
216	return 0;
217}
218
219/*
220 * Function:     ltp_udp_server_queue
221 * Description:  This function grabs the udp message from the queue and outputs to stdio
222 */
223void *ltp_udp_server_queue(void *junk)
224{
225
226	printf("%s: waiting for data on port UDP %u\n",
227	       hostname, LOCAL_UDP_SERVER_PORT);
228
229	/* server infinite loop */
230	while (1) {
231
232		/* init buffer */
233		memset(message, 0, MAX_MSG_LEN);
234
235		/* receive message */
236		udpClientLen = sizeof(udpClientAddr);
237
238		msg_bytes =
239		    recvfrom(udpSocketHandle, message, MAX_MSG_LEN, 0,
240			     (struct sockaddr *)&udpClientAddr, &udpClientLen);
241
242		printf("msg_bytes:%d \n", msg_bytes);
243
244		if (msg_bytes < 0) {
245			printf("%s: Error receiving data \n", hostname);
246		} else {
247			/* print message */
248			printf("%s: from %s:UDP%u : %s \n",
249			       hostname, inet_ntoa(udpClientAddr.sin_addr),
250			       ntohs(udpClientAddr.sin_port), message);
251		}
252
253	}			/* end of server infinite loop */
254
255	return NULL;
256
257}
258
259/*
260 * Function:     ltp_tcp_server_queue
261 * Description:  This function grabs the tcp message from the queue and outputs to stdio
262 */
263void *ltp_tcp_server_queue(void *junk)
264{
265
266	listen(tcpSocketHandle, 5);
267
268	while (1) {
269
270		printf("%s: waiting for data on port TCP %u\n", hostname,
271		       LOCAL_TCP_SERVER_PORT);
272
273		tcpClientLen = sizeof(tcpClientAddr);
274		newTcpSocketHandle =
275		    accept(tcpSocketHandle, (struct sockaddr *)&tcpClientAddr,
276			   &tcpClientLen);
277
278		if (newTcpSocketHandle < 0) {
279			printf("cannot accept TCP connection ");
280			break;
281		}
282
283		/* init line */
284		memset(message, 0x0, MAX_MSG_LEN);
285
286		/* receive segments */
287		while (tcp_receive_buffer(newTcpSocketHandle, message) != ERROR) {
288
289			printf("%s: received from %s:TCP%d : %s\n", hostname,
290			       inet_ntoa(tcpClientAddr.sin_addr),
291			       ntohs(tcpClientAddr.sin_port), message);
292
293			/* init line */
294			memset(message, 0x0, MAX_MSG_LEN);
295
296		}		/* while (read_line) */
297		printf("looping in TCP \n");
298
299	}			/* while (1) */
300
301	return NULL;
302
303}
304
305/*
306 * Function:     tcp_receive_buffer
307 * Description:  This function grabs the message from the tcp queue and
308 *               returns it to the calling function in the buffer.
309 */
310int tcp_receive_buffer(int newSocket, char *return_buffer)
311{
312
313	static int bytes_received = 0;
314	static char message_received[MAX_MSG_LEN];
315	static int count = 0;
316	int offset;
317
318	offset = 0;
319
320	while (1) {
321
322		if (bytes_received == 0) {
323			/* read data from socket */
324
325			memset(message_received, 0x0, MAX_MSG_LEN);	/* init buffer */
326
327			count =
328			    recvfrom(newSocket, message_received, MAX_MSG_LEN,
329				     0, (struct sockaddr *)&tcpClientAddr,
330				     &tcpClientLen);
331
332			if (count < 0) {
333				perror(" cannot receive data ");
334				return ERROR;
335			} else if (count == 0) {
336				printf(" connection closed by client\n");
337				close(newSocket);
338				if (count) {
339				}
340				return ERROR;
341			}
342		}
343
344		/* Check for new data read on socket or */
345		/* if still more data in buffer       */
346
347		/* copy line into 'return_buffer' */
348		while (*(message_received + bytes_received) != END_LINE
349		       && bytes_received < count) {
350			memcpy(return_buffer + offset,
351			       message_received + bytes_received, 1);
352			offset++;
353			bytes_received++;
354		}
355
356		/* end of line + end of buffer => return line */
357		if (bytes_received == count - 1) {
358			/* set last byte to END_LINE */
359			*(return_buffer + offset) = END_LINE;
360			bytes_received = 0;
361			return ++offset;
362		}
363
364		/* end of line but still some data in buffer => return line */
365		if (bytes_received < count - 1) {
366			/* set last byte to END_LINE */
367			*(return_buffer + offset) = END_LINE;
368			bytes_received++;
369			return ++offset;
370		}
371
372		/* end of buffer but line is not ended => */
373		/*  wait for more data to arrive on socket */
374		if (bytes_received == count) {
375			bytes_received = 0;
376			return offset;
377		}
378
379	}			/* while */
380
381}
382
383/*
384 * Function:     ltp_multi_server_queue
385 * Description:  This function grabs the multiCast message from the queue and outputs to stdio
386 */
387void *ltp_multi_server_queue(void *junk)
388{
389
390	printf("%s: waiting for data on port Multicast %u\n",
391	       hostname, LOCAL_MULTI_SERVER_PORT);
392
393	/* infinite server loop */
394	while (1) {
395
396		multiClientLen = sizeof(multiClientAddr);
397
398		msg_bytes =
399		    recvfrom(multiSocketHandle, message, MAX_MSG_LEN, 0,
400			     (struct sockaddr *)&multiClientAddr,
401			     &multiClientLen);
402
403		if (msg_bytes < 0) {
404			printf("%s : cannot receive data\n", hostname);
405			continue;
406		}
407
408		printf("%s : from %s:%d on %s : %s\n", ServerProg,
409		       inet_ntoa(multiClientAddr.sin_addr),
410		       ntohs(multiClientAddr.sin_port), hostname, message);
411
412	}			/* end of infinite server loop */
413
414	return NULL;
415
416}
417