examples/portscanner: quick hack to make it work on single host/portrange
[rofl0r-rocksock.git] / examples / polite_echoserver.c
blob25c464493b25be4cd0e1adf86a020427898eb61d
1 /* the polite echo server. requires you to send a HELO, afterwards
2 mimics a traditional echo server */
4 #include "../rocksockserver.h"
5 #include "../../lib/include/sblist.h"
6 #include <string.h>
8 #pragma RcB2 CFLAGS "-std=c99"
10 enum cstate {
11 cs_null = 0,
12 cs_error,
13 cs_said_hello,
14 cs_idle,
15 cs_msg,
18 typedef struct client {
19 int fd;
20 enum cstate state;
21 char msg[128];
22 } client;
24 typedef struct server_state {
25 rocksockserver srv;
26 sblist *clients;
27 } server;
29 struct client *client_from_fd(sblist *clients, int fd) {
30 struct client* c;
31 sblist_iter(clients, c) {
32 if(c->fd == fd) return c;
34 return 0;
37 static void disconnect_client(server* s, int fd) {
38 struct client *c;
39 sblist_iter_counter(s->clients, i, c) {
40 if(c->fd == fd) {
41 sblist_delete(s->clients, i);
42 break;
45 rocksockserver_disconnect_client(&s->srv, fd);
48 static int on_cdisconnect (void* userdata, int fd) {
49 server* s = userdata;
50 disconnect_client(s, fd);
51 return 0;
54 static int on_cconnect (void* userdata, struct sockaddr_storage* clientaddr, int fd) {
55 server* s = userdata;
56 struct client c = {.fd = fd };
57 if(!sblist_add(s->clients, &c)) {
58 disconnect_client(s, fd);
59 return -1;
61 return 0;
64 static void read_command(server *s, client *c, int fd) {
65 ssize_t nbytes;
66 if(c->state == cs_null) {
67 if(5 != (nbytes = recv(fd, c->msg, 5, 0)) ||
68 memcmp(c->msg, "HELO\n", 5)) {
69 c->state = cs_error;
70 } else c->state = cs_said_hello;
71 } else if (c->state == cs_idle) {
72 nbytes = recv(fd, c->msg, sizeof(c->msg)-1, 0);
73 if (nbytes == 0) on_cdisconnect(s, fd);
74 else if(nbytes < 1) c->state = cs_error;
75 else {
76 c->msg[nbytes] = 0;
77 c->state = cs_msg;
82 static int on_cread (void* userdata, int fd, size_t dummy) {
83 server* s = userdata;
84 struct client *c;
85 if(!(c = client_from_fd(s->clients, fd))) return -1;
86 read_command(s, c, fd);
87 return 0;
89 #define SL(X) X, sizeof(X)-1
90 static int on_cwantsdata (void* userdata, int fd) {
91 server* s = userdata;
92 struct client *c;
93 if(!(c = client_from_fd(s->clients, fd))) return -1;
94 switch(c->state) {
95 case cs_said_hello:
96 send(fd, SL("HELO. you may now say something.\n"), MSG_NOSIGNAL);
97 c->state = cs_idle;
98 case cs_idle:
99 case cs_null:
100 break;
101 case cs_error:
102 send(fd, SL("error: need to send HELO first\n"), MSG_NOSIGNAL);
103 disconnect_client(s, fd);
104 break;
105 case cs_msg:
106 send(fd, c->msg, strlen(c->msg), MSG_NOSIGNAL);
107 c->state = cs_idle;
108 break;
110 return 0;
113 int main() {
114 server sv, *s = &sv;
115 s->clients = sblist_new(sizeof(struct client), 32);
116 const int port = 9999;
117 const char* listenip = "0.0.0.0";
118 if(rocksockserver_init(&s->srv, listenip, port, (void*) s)) return -1;
119 if(rocksockserver_loop(&s->srv, NULL, 0,
120 &on_cconnect, &on_cread,
121 &on_cwantsdata, &on_cdisconnect)) return -2;
122 return 0;