protocol parsers
authorpk910 <philipp@zoelle1.de>
Thu, 17 Jul 2014 23:45:24 +0000 (01:45 +0200)
committerpk910 <philipp@zoelle1.de>
Thu, 17 Jul 2014 23:45:24 +0000 (01:45 +0200)
src/ircd_client.c
src/ircd_client.h
src/ircd_parse.c [new file with mode: 0644]
src/ircd_parse.h [new file with mode: 0644]
src/ircd_sock.c
src/struct_servermsg.h [new file with mode: 0644]

index 9fe8181f2ec5994e2163ddd1407326d65f9adb0b..28d650baea1def84998d0c7293526d67d04f91e5 100644 (file)
@@ -54,13 +54,3 @@ void client_connected(struct Connection *conn) {
 void client_disconnected(struct Connection *conn) {
     
 }
-
-void client_recv(struct Connection *conn, char *line) {
-       if(conn->server) {
-               // Server protocol
-       } else {
-               
-               
-               
-       }
-}
index e0e07355936297d39e2042d817d911b22e3d37b4..f113ae373c4c26fc32abdac7b829de6ed29c0452 100644 (file)
@@ -23,7 +23,6 @@ struct Connection;
 /* -- called from ircd_sock.c */
 void client_connected(struct Connection *conn);
 void client_disconnected(struct Connection *conn);
-void client_recv(struct Connection *conn, char *line);
 /* -- */
 
 
diff --git a/src/ircd_parse.c b/src/ircd_parse.c
new file mode 100644 (file)
index 0000000..392459b
--- /dev/null
@@ -0,0 +1,290 @@
+/* ircd_client.c - NextIRCd
+ * Copyright (C) 2012-2013  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#include "tools.h"
+#include "IOHandler/IOSockets.h"
+
+typedef int cmd_client_t(struct Client *client, char *argv[], int argc);
+typedef int cmd_auth_t(struct Auth *auth, char *argv[], int argc);
+typedef int cmd_server_t(struct Server *server, char *argv[], int argc);
+
+static struct ServerMsg parse_static_srvmsg;
+
+#define PARSE_CLIFLAG_OPONLY 0x01
+
+//include all commands
+#include "cmd_ping.h"
+
+
+struct {
+       struct {
+               const char *client;
+               const char *server;
+       } tokens;
+       struct {
+               cmd_client_t *function;
+               unsigned int min_argc : 8;
+               unsigned int max_argc : 8;
+               unsigned int flags : 8;
+       } client;
+       struct {
+               cmd_auth_t *function;
+               unsigned int min_argc : 8;
+               unsigned int max_argc : 8;
+               unsigned int flags : 8;
+       } auth;
+       struct {
+               cmd_server_t *function;
+               unsigned int min_argc : 8;
+               unsigned int max_argc : 8;
+               unsigned int flags : 8;
+       } server;
+       
+} parse_command_list {
+       {{"PING", "P"}, /* Ping Command */
+               {NULL, 0, 1, 0}, /* Client */
+               {NULL, 0, 1, 0}, /* Unauthed */
+               {NULL, 0, 1, 0}  /* Server */
+       },
+       
+       {{NULL, NULL},{NULL, 0, 0, 0},{NULL, 0, 0, 0},{NULL, 0, 0, 0}}
+};
+
+static char *parse_irc_token(char **data) {
+       //find next " "
+       int i;
+       char *token = *data;
+       for(i = 0; *data[i]; i++) {
+               if(*data[i] != ' ') {
+                       *data[i] = '\0';
+                       *data += i+1;
+                       break;
+               }
+       }
+       return token;
+}
+
+static char **parse_irc_params(char *data, int *argc, int maxargs) {
+       if(maxargs == 0) {
+               *argc = 0;
+               return NULL;
+       }
+    char **argv = calloc(maxargs, sizeof(*argv));
+    while(*data) {
+        //skip leading spaces
+        while (*line == ' ')
+            *line++ = 0;
+        if (*line == ':') {
+           //the rest is a single parameter
+           argv[*argc++] = line + 1;
+           break;
+        }
+        argv[*argc++] = line;
+        if (argc >= maxargs)
+            break;
+        while (*line != ' ' && *line)
+            line++;
+    }
+    return argv;
+}
+
+/* Client Data Format
+* <TOKEN> <arg1> <arg2>
+*/
+void parse_client_data(struct Client *client, char *data) {
+    char *token = parse_irc_token(&data);
+       int found = 0;
+       int i;
+       for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
+               if(stricmp(parse_command_list[i].tokens.client, token)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if(found && !parse_command_list[i].client.function) {
+               // reply 462 You may not reregister
+       } else if(found) {
+               int argc;
+               char **argv = parse_irc_params(data, &argc, parse_command_list[i].client.max_argc);
+               if(argc < parse_command_list[i].client.min_argc) {
+                       // reply 461 Not enough parameters
+               } else {
+                       int ret = parse_command_list[i].client.function(client, argv, argc);
+                       if(ret) {
+                               // error occurred!
+                               // do something?
+                       }
+               }
+               free(argv);
+       } else {
+               // reply 421 Unknown command
+       }
+}
+
+void parse_unauth_data(struct Auth *auth, char *data) {
+       char *token = parse_irc_token(&data);
+       int found = 0;
+       int i;
+       for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
+               if(stricmp(parse_command_list[i].tokens.client, token)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if(found && !parse_command_list[i].auth.function) {
+               // reply 451 Register first.
+       } else if(found) {
+               int argc;
+               char **argv = parse_irc_params(data, &argc, parse_command_list[i].auth.max_argc);
+               if(argc < parse_command_list[i].auth.min_argc) {
+                       // reply 461 Not enough parameters
+               } else {
+                       int ret = parse_command_list[i].auth.function(auth, argv, argc);
+                       if(ret) {
+                               // error occurred!
+                               // do something?
+                       }
+               }
+               free(argv);
+       } else {
+               // reply 421 Unknown command
+       }
+}
+
+/* Unicast                  Multicast                 Broadcast
+* <src-srvnum> 4 Bytes      <source>     4 Bytes      <source>     4 Bytes
+* <length>     2 Bytes      <length>     2 Bytes      <length>     2 Bytes
+* <flags>      1 Byte       <flags>      1 Byte       <flags>      1 Byte
+* <token>      x Bytes      <token>      x Bytes      <token>      x Bytes
+* " "          1 Byte       " "          1 Byte       " "          1 Byte
+* <dst-srvnum> 4 Bytes      <servers>    1 Byte       <ttl>        1 Byte
+*                           <dst-srv01>  4 Bytes      
+*                           <dst-srv02>  4 Bytes      
+* <args>                    <args>                    <args>
+*/
+void parse_server_data(struct Server *server, struct IOSocketBuffer *buffer) {
+       struct ServerMsg *srvmsg = &parse_static_srvmsg;
+       unsigned char *buf = (unsigned char *)buffer->buffer;
+       unsigned int buflen, require_more = 0;
+       int i;
+       
+       while(buffer->bufpos >= 9 && !require_more) { //require at least 9 Bytes
+               srvmsg->source.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+               srvmsg->resolved_source = 0;
+               srvmsg->msglen = ((buf[4] << 8) | buf[5]);
+               srvmsg->msgflags = buf[6];
+               srvmsg->msgtype  = (buf[6] & SERVERMSG_TYPEMASK);
+               
+               if(buffer->bufpos < srvmsg->msglen) {
+                       require_more = 1;
+                       break;
+               }
+               
+               for(i = 0; buffer->bufpos > i+7; i++) {
+                       if(buf[i+7] == ' ') {
+                               if(i >= MAXSERVERTOKENLEN)
+                                       srvmsg->token[MAXSERVERTOKENLEN] = '\0';
+                               else
+                                       srvmsg->token[i] = '\0';
+                               break;
+                       }
+                       if(i >= MAXSERVERTOKENLEN)
+                               continue;
+                       srvmsg->token[i] = buf[i+7];
+               }
+               if(buf[i+7] != ' ') {
+                       require_more = 1;
+                       break;
+               }
+               buf += i+8;
+               buflen = buffer->bufpos - (i+8);
+               
+               switch(srvmsg->msgtype) {
+               case SERVERMSG_TYPE_UNICAST:
+                       if(buflen < 4) {
+                               require_more = 1;
+                               break;
+                       }
+                       srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap));
+                       srvmsg->destinations->dstcount = 1;
+                       srvmsg->destinations->dst[0].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+                       srvmsg->destinations->dst[0].destination.resolved_destination = 0;
+                       break;
+               case SERVERMSG_TYPE_MULTICAST:
+                       if(buflen < 5) {
+                               require_more = 1;
+                               break;
+                       }
+                       unsigned int srvcount = buf[0];
+                       buf++;
+                       buflen--;
+                       if(buflen < (srvcount * 4)) {
+                               require_more = 1;
+                               break;
+                       }
+                       srvmsg->destinations = malloc(sizeof(struct ServerMsgDstMap) + (sizeof(struct ServerMsgDestination) * (srvcount - 1)));
+                       srvmsg->destinations->dstcount = srvcount;
+                       for(i = 0; i < srvcount; i++) {
+                               srvmsg->destinations->dst[i].destination.srvnum = ((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+                               srvmsg->destinations->dst[i].destination.resolved_destination = 0;
+                               buf += 4;
+                               buflen -= 4;
+                       }
+                       break;
+               case SERVERMSG_TYPE_BROADCAST:
+                       if(buflen == 0) {
+                               require_more = 1;
+                               break;
+                       }
+                       srvmsg->destinations = NULL;
+                       srvmsg->msgttl = buf[0];
+                       buf++;
+                       buflen--;
+                       break;
+               default:
+                       // PARSE ERROR
+                       goto parse_server_data_finish;
+               }
+               
+               srvmsg->arglen = srvmsg->msglen - (buf - buffer->buffer);
+               srvmsg->args = buf;
+               
+               int found = 0;
+               for(i = 0; (parse_command_list[i].tokens.client ||  parse_command_list[i].tokens.server); i++) {
+                       if(stricmp(parse_command_list[i].tokens.server, srvmsg->token)) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if(!found)
+                       goto parse_server_data_finish;
+               
+               //exec command function
+               
+       
+               parse_server_data_finish:
+               if(srvmsg->destinations)
+                       free(srvmsg->destinations);
+               
+               if(srvmsg->msglen > buffer->bufpos) {
+                       memmove(buffer->buffer, buffer->buffer + srvmsg->msglen, srvmsg->msglen - buffer->bufpos);
+                       buffer->bufpos -= srvmsg->msglen;
+               } else 
+                       srvmsg->bufpos = 0;
+       }
+}
+
diff --git a/src/ircd_parse.h b/src/ircd_parse.h
new file mode 100644 (file)
index 0000000..2360273
--- /dev/null
@@ -0,0 +1,33 @@
+/* ircd_parse.h - NextIRCd
+ * Copyright (C) 2012-2013  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef _ircd_parse_h
+#define _ircd_parse_h
+
+struct Client;
+struct Auth;
+struct Server;
+struct IOSocketBuffer;
+
+/* -- called from ircd_client.c */
+void parse_client_data(struct Client *client, char *data);
+void parse_unauth_data(struct Auth *auth, char *data);
+void parse_server_data(struct Server *server, struct IOSocketBuffer *buffer);
+/* -- */
+
+
+#endif
index 602282a35302caa16242da44181b0dee38c44329..5e750082ca75ab57fb46a865ac15a53d7f3e43b0 100644 (file)
@@ -18,6 +18,7 @@
 #include "ircd_config.h"
 #include "ircd_sock.h"
 #include "ircd_client.h"
+#include "ircd_parse.h"
 #include "struct_connection.h"
 
 #include "IOHandler/IOSockets.h"
@@ -196,11 +197,12 @@ static IOSOCKET_CALLBACK(sockets_iohandler_callback) {
         break;
     
     case IOSOCKETEVENT_RECV:
-        if(connection->server) {
-            
-        } else {
-            client_recv(connection, event->data.recv_str);
-        }
+               if(!connection->authed)
+                       parse_unauth_data(connection->data.auth, event->data.recv_str);
+        else if(connection->server)
+            parse_server_data(connection->data.server, event->data.recv_buf);
+        else
+            parse_client_data(connection->data.client, event->data.recv_str);
         break;
     
     default:
@@ -212,3 +214,8 @@ void socket_send(struct Connection *conn, char *data, int len) {
     iosocket_send(conn->socket, data, len);
 }
 
+void socket_set_server(struct Connection *conn) {
+       struct IOSocket *iosock = conn->socket;
+       iosock->parse_delimiter = 0;
+       conn->server = 1;
+}
diff --git a/src/struct_servermsg.h b/src/struct_servermsg.h
new file mode 100644 (file)
index 0000000..09b1460
--- /dev/null
@@ -0,0 +1,64 @@
+/* struct_servermsg.h - NextIRCd
+ * Copyright (C) 2012-2013  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef _struct_servermsg_h
+#define _struct_servermsg_h
+
+#define MAXSERVERTOKENLEN 5
+
+#define SERVERMSG_TYPE_UNICAST   0x01
+#define SERVERMSG_TYPE_MULTICAST 0x02
+#define SERVERMSG_TYPE_BROADCAST 0x03
+#define SERVERMSG_TYPEMASK       0x07
+#define SERVERMSG_FLAG_ENCRYPTED 0x08
+#define SERVERMSG_FLAGMASK       0xF8
+
+struct ServerMsgDestination {
+       union {
+               struct Server *server;
+               unsigned int srvnum;
+       } destination;
+       unsigned int resolved_destination : 1;
+};
+
+struct ServerMsgDstMap {
+       unsigned int dstcount : 8;
+       struct ServerMsgDestination dst[1];
+};
+
+struct ServerMsg {
+       union {
+               struct Server *server;
+               unsigned int srvnum;
+       } source;
+       unsigned int resolved_source : 1;
+       
+       unsigned int msgtype      : 3;
+       unsigned int msgflags     : 8;
+       unsigned int msglen       : 16;
+       unsigned int arglen       : 16;
+       unsigned int msgttl       : 8;
+       
+       char token[MAXSERVERTOKENLEN+1];
+       
+       struct ServerMsgDstMap *destinations;
+       
+       
+       unsigned char *args;
+};
+
+#endif