src/nexus.c
changeset 8 be88e543c8ff
parent 7 844f014409ff
child 9 4c4c906cc649
equal deleted inserted replaced
7:844f014409ff 8:be88e543c8ff
     7 #include <assert.h>
     7 #include <assert.h>
     8 
     8 
     9 #include <err.h>
     9 #include <err.h>
    10 
    10 
    11 #include "sock.h"
    11 #include "sock.h"
       
    12 #include "line_proto.h"
    12 
    13 
    13 #define CONNECT_HOST "irc.fixme.fi"
    14 #define CONNECT_HOST "irc.fixme.fi"
    14 #define CONNECT_SERV "66976"
    15 #define CONNECT_SERV "6697"
    15 #define LINE_LENGTH 512
    16 #define LINE_LENGTH 512
    16 
       
    17 struct recvline_state {
       
    18     size_t tail_offset;
       
    19     size_t tail_len;
       
    20 };
       
    21 
       
    22 /*
       
    23  * This looks for a full '\r\n' terminated line at the beginning of the given buffer. If found, the \r\n will be
       
    24  * replaced with a '\0', and the offset to the beginning of the next line returned. If not found, zero is returned
       
    25  * (which is never a valid next-line offset).
       
    26  *
       
    27  * The given \a hint is an hint as to the offset at which to start scanning, used for incremental invocations of this
       
    28  * on the same buffer.
       
    29  *
       
    30  */
       
    31 int _parse_line (char *buf, size_t len, size_t *hint) {
       
    32     int i;
       
    33 
       
    34     // empty buffer -> nothing
       
    35     if (len == 0)
       
    36         return 0;
       
    37 
       
    38     // look for terminating '\r\n' sequence
       
    39     for (i = *hint; i < len - 1; i++) {
       
    40         // match this + next char
       
    41         if (buf[i] == '\r' && buf[i + 1] == '\n')
       
    42             break;
       
    43     }
       
    44 
       
    45     // incomplete?
       
    46     if (i >= len - 1) {
       
    47         *hint = len - 1;
       
    48         return 0;
       
    49     }
       
    50 
       
    51     // mangle the newline off
       
    52     buf[i] = '\0';
       
    53 
       
    54     // return offset to next line
       
    55     return i + 2;
       
    56 }
       
    57 
       
    58 /*
       
    59  * Receive one line of data into the buffer of the given length
       
    60  */
       
    61 int recvline (struct sock_stream *sock, char *buf, size_t len, struct recvline_state *ctx) {
       
    62     size_t recv_offset = 0, peek_offset = 0, next_offset = 0;
       
    63     int ret;
       
    64 
       
    65     // adjust offset from previous data
       
    66     recv_offset = ctx->tail_len;
       
    67 
       
    68     // move trailing data from previous line to front of buffer
       
    69     if (ctx->tail_offset) {
       
    70         // move to front
       
    71         memmove(buf, buf + ctx->tail_offset, ctx->tail_len);
       
    72 
       
    73         // reset
       
    74         ctx->tail_offset = 0;
       
    75         ctx->tail_len = 0;
       
    76     }
       
    77 
       
    78     // readline loop
       
    79     do {
       
    80         // parse any line at the beginning of the buffer
       
    81         if ((next_offset = _parse_line(buf, recv_offset, &peek_offset)) > 0)
       
    82             break;
       
    83 
       
    84         // ensure there's enough space for it
       
    85         assert(recv_offset < len);
       
    86         
       
    87         // otherwise, read more data
       
    88         if ((ret = sock_stream_read(sock, buf + recv_offset, len - recv_offset)) < 0)
       
    89             err(1, "read");
       
    90 
       
    91         // EOF?
       
    92         if (ret == 0)
       
    93             errx(1, "read: EOF");
       
    94         
       
    95         // update recv_offset
       
    96         recv_offset += ret;
       
    97     } while (1);
       
    98 
       
    99     // update state for next call
       
   100     ctx->tail_offset = next_offset;
       
   101     ctx->tail_len = recv_offset - next_offset;
       
   102 
       
   103     // ok
       
   104     return 0;
       
   105 }
       
   106 
    17 
   107 int main (int argc, char **argv) {
    18 int main (int argc, char **argv) {
   108     struct sock_stream *sock;
    19     struct sock_stream *sock;
       
    20     struct line_proto *lp;
   109     char line_buf[LINE_LENGTH + 1];
    21     char line_buf[LINE_LENGTH + 1];
   110     struct recvline_state recvline_ctx;
       
   111     struct error_info err;
    22     struct error_info err;
   112 
    23 
   113     // initialize
    24     // initialize
   114     if (sock_init(&err))
    25     if (sock_init(&err))
   115         errx(1, "sock_init: %s", error_msg(&err));
    26         errx(1, "sock_init: %s", error_msg(&err));
   116 
    27 
   117     memset(&recvline_ctx, 0, sizeof(recvline_ctx));
       
   118     
       
   119     // over-simplified connect
    28     // over-simplified connect
   120     if (sock_gnutls_connect(&sock, CONNECT_HOST, CONNECT_SERV, &err))
    29     if (sock_gnutls_connect(&sock, CONNECT_HOST, CONNECT_SERV, &err))
   121         errx(1, "sock_gnutls_connect: %s", error_msg(&err));
    30         errx(1, "sock_gnutls_connect: %s", error_msg(&err));
   122 
    31 
       
    32     // line protocol
       
    33     if (line_proto_create(&lp, sock, &err))
       
    34         errx(1, "line_proto_create: %s", error_msg(&err));
       
    35 
   123     // read lines and dump them out
    36     // read lines and dump them out
   124     do {
    37     do {
   125         // recv
    38         // recv
   126         recvline(sock, line_buf, sizeof(line_buf), &recvline_ctx);
    39         if (line_proto_read(lp, line_buf, sizeof(line_buf)))
       
    40             errx(1, "line_proto_read: %s", error_msg(line_proto_error(lp)));
   127 
    41 
   128         // printf
    42         // printf
   129         printf("<<< %s\n", line_buf);
    43         printf("<<< %s\n", line_buf);
   130 
    44 
   131     } while (1);
    45     } while (1);