00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: netstring.c,v 1.1 2007-06-03 23:43:45 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025 #include <errno.h>
00026
00027 #define MAX_LEN 1000000
00028
00029 typedef struct {
00030 char *data;
00031 int len;
00032 int msg_len;
00033 int msg_offset;
00034 } netstring_t;
00035
00036 static int netstring_on_write(void *client_data, int idx, const char *data, int len)
00037 {
00038 char buf[517];
00039 char *sendbuf;
00040 int pos;
00041
00042 if (len > MAX_LEN) len = MAX_LEN;
00043 if (len <= 512) sendbuf = buf;
00044 else sendbuf = malloc(len + 12);
00045
00046 pos = sprintf(sendbuf, "%d:", len);
00047 memcpy(sendbuf + pos, data, len);
00048 pos += len;
00049 sendbuf[pos] = ',';
00050 sockbuf_on_write(idx, SOCKBUF_LEVEL_TEXT_BUFFER, sendbuf, pos + 1);
00051 if (sendbuf != buf) free(sendbuf);
00052
00053 return 0;
00054 }
00055
00056 static int netstring_on_read(void *client_data, int idx, char *data, int len)
00057 {
00058 netstring_t *old_data = client_data;
00059 char *buffer, *start, *p;
00060 int buflen, msg_len, msg_offset;
00061
00062 if (!old_data->data) {
00063 buffer = data;
00064 buflen = len;
00065 msg_len = -1;
00066 msg_offset = -1;
00067 } else {
00068 old_data->data = realloc(old_data->data, old_data->len + len);
00069 memcpy(old_data->data + old_data->len, data, len);
00070 old_data->len += len;
00071 buffer = old_data->data;
00072 buflen = old_data->len;
00073 msg_len = old_data->msg_len;
00074 msg_offset = old_data->msg_offset;
00075 }
00076
00077 start = buffer;
00078 do {
00079 if (msg_len < 0) {
00080 p = memchr(start, ':', buflen);
00081 if (!p) {
00082 if (buflen >= 10) {
00083 sockbuf_on_eof(idx, SOCKBUF_LEVEL_INTERNAL, EIO, _("Invalid line format."));
00084 return 0;
00085 }
00086 break;
00087 }
00088 *p = 0;
00089 msg_len = atoi(start);
00090 if (msg_len > MAX_LEN) {
00091 sockbuf_on_eof(idx, SOCKBUF_LEVEL_INTERNAL, EIO, _("Invalid line format."));
00092 return 0;
00093 }
00094 msg_offset = p - start + 1;
00095 }
00096
00097 if (buflen <= msg_len + msg_offset) break;
00098
00099 if (start[msg_len + msg_offset] != ',') {
00100 sockbuf_on_eof(idx, SOCKBUF_LEVEL_INTERNAL, EIO, _("Invalid line format."));
00101 return 0;
00102 }
00103
00104 start[msg_len + msg_offset] = 0;
00105 sockbuf_on_read(idx, SOCKBUF_LEVEL_TEXT_BUFFER, start + msg_offset, msg_len);
00106 if (!sockbuf_isvalid(idx)) return 0;
00107
00108 start += msg_offset + msg_len + 1;
00109 buflen -= msg_offset + msg_len + 1;
00110 msg_offset = -1;
00111 msg_len = -1;
00112
00113 } while (buflen);
00114
00115 old_data->len = buflen;
00116 old_data->msg_len = msg_len;
00117 old_data->msg_offset = msg_offset;
00118
00119 if (start == old_data->data) return 0;
00120
00121 if (!buflen) {
00122 if (old_data->data) free(old_data->data);
00123 old_data->data = NULL;
00124 } else {
00125 if (old_data->data) {
00126 memmove(old_data->data, start, buflen);
00127 old_data->data = realloc(old_data->data, buflen);
00128 } else {
00129 old_data->data = malloc(buflen);
00130 memcpy(old_data->data, start, buflen);
00131 }
00132 }
00133 return 0;
00134 }
00135
00136 static int linemode_on_delete(void *client_data, int idx)
00137 {
00138 netstring_t *old_data = client_data;
00139
00140 if (old_data->data) free(old_data->data);
00141 free(old_data);
00142 return 0;
00143 }
00144
00145 static sockbuf_filter_t netstring_filter = {
00146 "netstring",
00147 SOCKBUF_LEVEL_TEXT_BUFFER,
00148 NULL, NULL, NULL,
00149 netstring_on_read, netstring_on_write, NULL,
00150 NULL, linemode_on_delete
00151 };
00152
00160 int netstring_on(int idx)
00161 {
00162 netstring_t *old_data;
00163
00164 if (netstring_check(idx)) return -1;
00165 old_data = malloc(sizeof(*old_data));
00166 old_data->data = NULL;
00167 old_data->len = 0;
00168 old_data->msg_len = 0;
00169 sockbuf_attach_filter(idx, &netstring_filter, old_data);
00170 return(0);
00171 }
00172
00182 int netstring_off(int idx)
00183 {
00184 int ret;
00185 netstring_t *old_data;
00186
00187 ret = sockbuf_detach_filter(idx, &netstring_filter, &old_data);
00188 if (ret) return ret;
00189 if (old_data) {
00190 if (old_data->data) {
00191 if (old_data->len) {
00192 old_data->data[old_data->len] = 0;
00193 sockbuf_on_read(idx, SOCKBUF_LEVEL_TEXT_BUFFER, old_data->data, old_data->len);
00194 old_data->len = 0;
00195 }
00196 free(old_data->data);
00197 }
00198 free(old_data);
00199 }
00200 return(0);
00201 }
00202
00210 int netstring_check(int idx)
00211 {
00212 if (!sockbuf_isvalid(idx)) return -1;
00213 return !sockbuf_get_filter_data(idx, &netstring_filter, 0);
00214 }