Home | History | Annotate | Download | only in sockets
      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 
     49 int udpSocketHandle,
     50     rc, msg_bytes, tcpSocketHandle, newTcpSocketHandle, multiSocketHandle;
     51 
     52 socklen_t udpClientLen, tcpClientLen, multiClientLen;
     53 
     54 struct sockaddr_in udpClientAddr,
     55     udpServerAddr,
     56     tcpClientAddr, tcpServerAddr, multiClientAddr, multiServerAddr;
     57 
     58 struct ip_mreq multiCastReq;
     59 struct in_addr multiCastAddr;
     60 struct hostent *hostEntry;
     61 
     62 char message[MAX_MSG_LEN];
     63 char hostname[MAX_HOSTNAME_LEN];
     64 char ServerProg[MAX_HOSTNAME_LEN];
     65 
     66 void *ltp_udp_server_queue(void *);
     67 void *ltp_tcp_server_queue(void *);
     68 void *ltp_multi_server_queue(void *);
     69 int tcp_receive_buffer(int, char *);
     70 
     71 int 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  */
    223 void *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  */
    263 void *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  */
    310 int 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  */
    387 void *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