server.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * netq/server.c
  3. *
  4. * Copyright (C) 2022 bzt (bztsrc@gitlab) MIT license
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief An example NetQ server for multiple clients on IPv4 and IPv6 UDP
  27. * https://gitlab.com/bztsrc/netq
  28. *
  29. * Compile with: gcc server.c -o server
  30. */
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <unistd.h>
  34. #include <netdb.h>
  35. #include <sys/socket.h>
  36. #include <netinet/in.h>
  37. #include <arpa/inet.h> /* for inet_ntop */
  38. #define NETQ_IMPLEMENTATION
  39. #define NETQ_SEND my_sender
  40. #include "netq.h"
  41. /* the transport layer context */
  42. typedef struct {
  43. int sock;
  44. struct sockaddr_storage peer_addr;
  45. socklen_t addrlen;
  46. } my_net_t;
  47. my_net_t my_net;
  48. /* the raw packet sender */
  49. int my_sender(void *net, const void *message, int length)
  50. {
  51. my_net_t *my_net = (my_net_t *)net;
  52. return sendto(my_net->sock, message, length, 0, (struct sockaddr*)&my_net->peer_addr, my_net->addrlen);
  53. }
  54. /* the raw packet receiver (note: it's non-blocking for the server) */
  55. int my_receiver(void *net, void *message, int length)
  56. {
  57. my_net_t *my_net = (my_net_t *)net;
  58. my_net->addrlen = sizeof(struct sockaddr_storage); /* <- the recvfrom() API is tricky */
  59. return recvfrom(my_net->sock, message, length, MSG_DONTWAIT, (struct sockaddr*)&my_net->peer_addr, &my_net->addrlen);
  60. }
  61. /* the server needs multiple queues, one for each peer */
  62. typedef struct {
  63. struct sockaddr peer_addr;
  64. netq_t nq;
  65. char lastmsg[NETQ_MTU];
  66. } peer_t;
  67. peer_t *peers = NULL;
  68. int numpeers = 0;
  69. /* return the context for a peer */
  70. netq_t *my_getqueue(my_net_t *net)
  71. {
  72. int i;
  73. /* look for matching source ip and port */
  74. for(i = 0; i < numpeers && memcmp(&peers[i].peer_addr, &net->peer_addr, sizeof(struct sockaddr)); i++);
  75. /* if not found, add a new record */
  76. if(i == numpeers) {
  77. peers = realloc(peers, ++numpeers * sizeof(peer_t));
  78. memset(&peers[i], 0, sizeof(peer_t));
  79. memcpy(&peers[i].peer_addr, &net->peer_addr, sizeof(struct sockaddr));
  80. /* should we have used pthreads */
  81. /* pthread_mutex_init(&peers[i].nq.mutex); */
  82. }
  83. return &peers[i].nq;
  84. }
  85. /* display peers in a nice ASCII table */
  86. void peers_dump()
  87. {
  88. char str[INET6_ADDRSTRLEN];
  89. int i;
  90. printf("\x1b[H\x1b[2J"
  91. "NetQ configuration: sequence number: uint%u_t, ack mask: uint%u_t, mtu: %u, header: %u, queue: %u, memory: %u bytes"
  92. #ifdef NETQ_MUTEX_TYPE
  93. ", thread-safety"
  94. #endif
  95. ".\n", NETQ_SEQ_BITS, NETQ_ACK_BITS, NETQ_MTU, (unsigned int)sizeof(netq_hdr_t), NETQ_QUEUE_SIZE, (unsigned int)sizeof(netq_t));
  96. printf( "\n| Peer | Source IP and Port | Out | In | Ack | Pop | Last Message |\n"
  97. "|------|----------------------------|-----|-----|-----|-----|----------------|\n");
  98. for(i = 0; i < numpeers; i++) {
  99. inet_ntop(peers[i].peer_addr.sa_family, peers[i].peer_addr.sa_family == AF_INET ?
  100. (void*)&((struct sockaddr_in*)&peers[i].peer_addr)->sin_addr :
  101. (void*)&((struct sockaddr_in6*)&peers[i].peer_addr)->sin6_addr, str, sizeof(str));
  102. printf("|%5u ""| %-20s %5u " "| %3u | %3u | %3u | %3u | %-15s" "|\n",
  103. i, str, ntohs(peers[i].peer_addr.sa_family == AF_INET ?
  104. ((struct sockaddr_in*)&peers[i].peer_addr)->sin_port : ((struct sockaddr_in6*)&peers[i].peer_addr)->sin6_port),
  105. peers[i].nq.seq_out, peers[i].nq.seq_in, peers[i].nq.seq_ack, peers[i].nq.seq_pop, peers[i].lastmsg
  106. );
  107. }
  108. printf("\n");
  109. }
  110. /**
  111. * Example server
  112. */
  113. int main(int argc, char **argv)
  114. {
  115. int i, ret, n = 1;
  116. struct sockaddr_storage bind_addr;
  117. struct addrinfo hints, *cur, *addr_list = NULL;
  118. char buf[NETQ_MTU];
  119. netq_t *nq;
  120. if(argc < 3) {
  121. printf("%s <bind ip> <port> [--peer-list]\n", argv[0]);
  122. return 1;
  123. }
  124. /* get binary ip address for hostname / ip string, the usual stuff, nothing NetQ specific here */
  125. memset(&bind_addr, 0, sizeof(bind_addr));
  126. memset(&my_net, 0, sizeof(my_net));
  127. memset(&hints, 0, sizeof(hints));
  128. hints.ai_family = AF_UNSPEC;
  129. hints.ai_socktype = SOCK_DGRAM;
  130. hints.ai_protocol = IPPROTO_UDP;
  131. if(getaddrinfo(argv[1], argv[2], &hints, &addr_list) != 0) {
  132. fprintf(stderr, "getaddrinfo failed.\n"); return 1; }
  133. for(cur = addr_list; cur != NULL && !my_net.addrlen; cur = cur->ai_next) {
  134. my_net.sock = (int)socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); n = 1;
  135. if(my_net.sock < 0) continue;
  136. if(setsockopt(my_net.sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&n, sizeof(n)) != 0 ||
  137. bind(my_net.sock, cur->ai_addr, cur->ai_addrlen) != 0) { close(my_net.sock); continue; }
  138. memcpy(&bind_addr, cur->ai_addr, cur->ai_addrlen);
  139. my_net.addrlen = cur->ai_addrlen;
  140. }
  141. freeaddrinfo(addr_list);
  142. /* print out what we've got */
  143. inet_ntop(bind_addr.ss_family, bind_addr.ss_family == AF_INET ?
  144. (void*)&((struct sockaddr_in*)&bind_addr)->sin_addr : (void*)&((struct sockaddr_in6*)&bind_addr)->sin6_addr,
  145. buf, sizeof(buf));
  146. printf("waiting for %s connections on %s port %u\n", bind_addr.ss_family == AF_INET ? "IPv4" : "IPv6", buf,
  147. ntohs(bind_addr.ss_family == AF_INET ? ((struct sockaddr_in*)&bind_addr)->sin_port : ((struct sockaddr_in6*)&bind_addr)->sin6_port));
  148. /**************************************************
  149. * the main server loop *
  150. **************************************************/
  151. while(1) {
  152. /* push the received raw packet to the peer's queue */
  153. if((ret = my_receiver(&my_net, buf, sizeof(buf))) > 0) {
  154. if(!argv[3]) printf("-------------------------------------------------------------------------------\n");
  155. nq = my_getqueue(&my_net);
  156. netq_push(nq, buf, ret, &my_net);
  157. if(!argv[3]) netq_dump(nq);
  158. }
  159. /* iterate on all network queues, and see if any has a message to be processed */
  160. for(i = 0; i < numpeers; i++)
  161. if((ret = netq_pop(&peers[i].nq, peers[i].lastmsg, sizeof(peers[i].lastmsg))) > 0) {
  162. /* process your message in buf here */
  163. printf("peer #%d has sent %d bytes: '%s'\n", i, ret, peers[i].lastmsg);
  164. /* send reply, echo message back */
  165. netq_send(&peers[i].nq, buf, strlen(buf) + 1, &my_net);
  166. /* dump queues */
  167. if(!argv[3]) netq_dump(&peers[i].nq);
  168. else peers_dump();
  169. }
  170. }
  171. close(my_net.sock);
  172. return 0;
  173. }