1 /**************************************************************************************************
2 * Filename: socket_server.c
3 * Description: Socket Remote Procedure Call Interface - sample device application.
4 *
5 *
6 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
19 * distribution.
20 *
21 * Neither the name of Texas Instruments Incorporated nor the names of
22 * its contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
39 /*********************************************************************
40 * INCLUDES
41 */
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <fcntl.h>
51 #include <sys/signal.h>
52 #include <sys/ioctl.h>
53 #include <poll.h>
54 #include <errno.h>
56 #include "socket_server.h"
58 #define MAX_CLIENTS 50
60 /*********************************************************************
61 * GLOBAL VARIABLES
62 */
64 /*********************************************************************
65 * TYPEDEFS
66 */
67 typedef struct {
68 void *next;
69 int socketFd;
70 socklen_t clilen;
71 struct sockaddr_in cli_addr;
72 } socketRecord_t;
74 socketRecord_t *socketRecordHead = NULL;
76 socketServerCb_t socketServerRxCb;
77 socketServerCb_t socketServerConnectCb;
79 /*********************************************************************
80 * LOCAL FUNCTION PROTOTYPES
81 */
82 static void deleteSocketRec(int rmSocketFd);
83 static int createSocketRec(void);
85 /*********************************************************************
86 * FUNCTIONS
87 *********************************************************************/
89 /*********************************************************************
90 * @fn createSocketRec
91 *
92 * @brief create a socket and add a rec fto the list.
93 *
94 * @param table
95 * @param rmTimer
96 *
97 * @return new clint fd
98 */
99 int createSocketRec(void)
100 {
101 int tr = 1;
102 socketRecord_t *srchRec;
104 socketRecord_t *newSocket = malloc(sizeof(socketRecord_t));
106 //open a new client connection with the listening socket (at head of list)
107 newSocket->clilen = sizeof(newSocket->cli_addr);
109 //Head is always the listening socket
110 newSocket->socketFd = accept(socketRecordHead->socketFd,
111 (struct sockaddr *) &(newSocket->cli_addr), &(newSocket->clilen));
113 //printf("connected\n");
115 if (newSocket->socketFd < 0) printf("ERROR on accept");
117 // Set the socket option SO_REUSEADDR to reduce the chance of a
118 // "Address Already in Use" error on the bind
119 setsockopt(newSocket->socketFd, SOL_SOCKET, SO_REUSEADDR, &tr, sizeof(int));
120 // Set the fd to none blocking
121 fcntl(newSocket->socketFd, F_SETFL, O_NONBLOCK);
123 //printf("New Client Connected fd:%d - IP:%s\n", newSocket->socketFd, inet_ntoa(newSocket->cli_addr.sin_addr));
125 newSocket->next = NULL;
127 //find the end of the list and add the record
128 srchRec = socketRecordHead;
129 // Stop at the last record
130 while (srchRec->next)
131 srchRec = srchRec->next;
133 // Add to the list
134 srchRec->next = newSocket;
136 return (newSocket->socketFd);
137 }
139 /*********************************************************************
140 * @fn deleteSocketRec
141 *
142 * @brief Delete a rec from list.
143 *
144 * @param table
145 * @param rmTimer
146 *
147 * @return none
148 */
149 void deleteSocketRec(int rmSocketFd)
150 {
151 socketRecord_t *srchRec, *prevRec = NULL;
153 // Head of the timer list
154 srchRec = socketRecordHead;
156 // Stop when rec found or at the end
157 while ((srchRec->socketFd != rmSocketFd) && (srchRec->next))
158 {
159 prevRec = srchRec;
160 // over to next
161 srchRec = srchRec->next;
162 }
164 if (srchRec->socketFd != rmSocketFd)
165 {
166 printf("deleteSocketRec: record not found\n");
167 return;
168 }
170 // Does the record exist
171 if (srchRec)
172 {
173 // delete the timer from the list
174 if (prevRec == NULL)
175 {
176 //trying to remove first rec, which is always the listining socket
177 printf(
178 "deleteSocketRec: removing first rec, which is always the listining socket\n");
179 return;
180 }
182 //remove record from list
183 prevRec->next = srchRec->next;
185 close(srchRec->socketFd);
186 free(srchRec);
187 }
188 }
190 /***************************************************************************************************
191 * @fn serverSocketInit
192 *
193 * @brief initialises the server.
194 * @param
195 *
196 * @return Status
197 */
198 int32 socketSeverInit(uint32 port)
199 {
200 struct sockaddr_in serv_addr;
201 int stat, tr = 1;
203 if (socketRecordHead == NULL)
204 {
205 // New record
206 socketRecord_t *lsSocket = malloc(sizeof(socketRecord_t));
208 lsSocket->socketFd = socket(AF_INET, SOCK_STREAM, 0);
209 if (lsSocket->socketFd < 0)
210 {
211 printf("ERROR opening socket");
212 return -1;
213 }
215 // Set the socket option SO_REUSEADDR to reduce the chance of a
216 // "Address Already in Use" error on the bind
217 setsockopt(lsSocket->socketFd, SOL_SOCKET, SO_REUSEADDR, &tr, sizeof(int));
218 // Set the fd to none blocking
219 fcntl(lsSocket->socketFd, F_SETFL, O_NONBLOCK);
221 bzero((char *) &serv_addr, sizeof(serv_addr));
222 serv_addr.sin_family = AF_INET;
223 serv_addr.sin_addr.s_addr = INADDR_ANY;
224 serv_addr.sin_port = htons(port);
225 stat = bind(lsSocket->socketFd, (struct sockaddr *) &serv_addr,
226 sizeof(serv_addr));
227 if (stat < 0)
228 {
229 printf("ERROR on binding: %s\n", strerror(errno));
230 return -1;
231 }
232 //will have 5 pending open client requests
233 listen(lsSocket->socketFd, 5);
235 lsSocket->next = NULL;
236 //Head is always the listening socket
237 socketRecordHead = lsSocket;
238 }
240 //printf("waiting for socket new connection\n");
242 return 0;
243 }
245 /***************************************************************************************************
246 * @fn serverSocketConfig
247 *
248 * @brief register the Rx Callback.
249 * @param
250 *
251 * @return Status
252 */
253 int32 serverSocketConfig(socketServerCb_t rxCb, socketServerCb_t connectCb)
254 {
255 socketServerRxCb = rxCb;
256 socketServerConnectCb = connectCb;
258 return 0;
259 }
260 /*********************************************************************
261 * @fn socketSeverGetClientFds()
262 *
263 * @brief get clients fd's.
264 *
265 * @param none
266 *
267 * @return list of Timerfd's
268 */
269 void socketSeverGetClientFds(int *fds, int maxFds)
270 {
271 uint32 recordCnt = 0;
272 socketRecord_t *srchRec;
274 // Head of the timer list
275 srchRec = socketRecordHead;
277 // Stop when at the end or max is reached
278 while ((srchRec) && (recordCnt < maxFds))
279 {
280 //printf("getClientFds: adding fd%d, to idx:%d \n", srchRec->socketFd, recordCnt);
281 fds[recordCnt++] = srchRec->socketFd;
283 srchRec = srchRec->next;
284 }
286 return;
287 }
289 /*********************************************************************
290 * @fn socketSeverGetNumClients()
291 *
292 * @brief get clients fd's.
293 *
294 * @param none
295 *
296 * @return list of Timerfd's
297 */
298 uint32 socketSeverGetNumClients(void)
299 {
300 uint32 recordCnt = 0;
301 socketRecord_t *srchRec;
303 //printf("socketSeverGetNumClients++\n", recordCnt);
305 // Head of the timer list
306 srchRec = socketRecordHead;
308 if (srchRec == NULL)
309 {
310 //printf("socketSeverGetNumClients: socketRecordHead NULL\n");
311 return -1;
312 }
314 // Stop when rec found or at the end
315 while (srchRec)
316 {
317 //printf("socketSeverGetNumClients: recordCnt=%d\n", recordCnt);
318 srchRec = srchRec->next;
319 recordCnt++;
320 }
322 //printf("socketSeverGetNumClients %d\n", recordCnt);
323 return (recordCnt);
324 }
326 /*********************************************************************
327 * @fn socketSeverPoll()
328 *
329 * @brief services the Socket events.
330 *
331 * @param clinetFd - Fd to services
332 * @param revent - event to services
333 *
334 * @return none
335 */
336 void socketSeverPoll(int clinetFd, int revent)
337 {
338 //printf("pollSocket++\n");
340 //is this a new connection on the listening socket
341 if (clinetFd == socketRecordHead->socketFd)
342 {
343 int newClientFd = createSocketRec();
345 if (socketServerConnectCb)
346 {
347 socketServerConnectCb(newClientFd);
348 }
349 }
350 else
351 {
352 //this is a client socket is it a input or shutdown event
353 if (revent & POLLIN)
354 {
355 //uint32 pakcetCnt = 0;
356 //its a Rx event
357 //printf("got Rx on fd %d, pakcetCnt=%d\n", clinetFd, pakcetCnt++);
358 if (socketServerRxCb)
359 {
360 socketServerRxCb(clinetFd);
361 }
363 }
364 if (revent & POLLRDHUP)
365 {
366 //its a shut down close the socket
367 //printf("Client fd:%d disconnected\n", clinetFd);
369 //remove the record and close the socket
370 deleteSocketRec(clinetFd);
371 }
372 }
374 //write(clientSockFd,"I got your message",18);
376 return;
377 }
379 /***************************************************************************************************
380 * @fn socketSeverSend
381 *
382 * @brief Send a buffer to a clients.
383 * @param uint8* srpcMsg - message to be sent
384 * int32 fdClient - Client fd
385 *
386 * @return Status
387 */
388 int32 socketSeverSend(uint8* buf, uint32 len, int32 fdClient)
389 {
390 int32 rtn;
392 //printf("socketSeverSend++: writing to socket fd %d\n", fdClient);
394 if (fdClient)
395 {
396 rtn = write(fdClient, buf, len);
397 if (rtn < 0)
398 {
399 printf("ERROR writing to socket %d\n", fdClient);
400 return rtn;
401 }
402 }
404 //printf("socketSeverSend--\n");
405 return 0;
406 }
408 /***************************************************************************************************
409 * @fn socketSeverSendAllclients
410 *
411 * @brief Send a buffer to all clients.
412 * @param uint8* srpcMsg - message to be sent
413 *
414 * @return Status
415 */
416 int32 socketSeverSendAllclients(uint8* buf, uint32 len)
417 {
418 int rtn;
419 socketRecord_t *srchRec;
421 // first client socket
422 srchRec = socketRecordHead->next;
424 // Stop when at the end or max is reached
425 while (srchRec)
426 {
427 //printf("SRPC_Send: client %d\n", cnt++);
428 rtn = write(srchRec->socketFd, buf, len);
429 if (rtn < 0)
430 {
431 printf("ERROR writing to socket %d\n", srchRec->socketFd);
432 printf("closing client socket\n");
433 //remove the record and close the socket
434 deleteSocketRec(srchRec->socketFd);
436 return rtn;
437 }
438 srchRec = srchRec->next;
439 }
441 return 0;
442 }
444 /***************************************************************************************************
445 * @fn socketSeverClose
446 *
447 * @brief Closes the client connections.
448 *
449 * @return Status
450 */
451 void socketSeverClose(void)
452 {
453 int fds[MAX_CLIENTS], idx = 0;
455 socketSeverGetClientFds(fds, MAX_CLIENTS);
457 while (socketSeverGetNumClients() > 1)
458 {
459 printf("socketSeverClose: Closing socket fd:%d\n", fds[idx]);
460 deleteSocketRec(fds[idx++]);
461 }
463 //Now remove the listening socket
464 if (fds[0])
465 {
466 printf("socketSeverClose: Closing the listening socket\n");
467 close(fds[0]);
468 }
469 }