summaryrefslogtreecommitdiffstats
path: root/socket.c
blob: b63ce9cdf2ef0d16c1be35b8fefea938e0050e99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>


#include "socket.h"
#include "protocol.h"

struct event_base *evbase;


/**
 * Set a socket to non-blocking mode.
 */
int
setnonblock(int fd)
{
    int flags;

    flags = fcntl(fd, F_GETFL);
    if (flags < 0)
        return flags;
    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) < 0)
        return -1;

    return 0;
}

/**
 * called by libevent when there is data to read.
 */
void buffered_on_read(struct bufferevent *bev, void *arg)
{
    client_t *this_client = arg;
    uint8_t data[8192];
    size_t n;
    
    printf("reading data\n");
    
    for (;;) {
        n = bufferevent_read(bev, data, sizeof(data));
        if (n <= 0) {
            /* done */
            break;
        }
        parse_packet(this_client, (uint8_t*)&data);
    }
    
}

void buffered_on_error(struct bufferevent *bev, short what, void *arg)
{
    client_t *client = (client_t *)arg;
    
    if (what & BEV_EVENT_EOF) {
        printf("disconected\n");
    } else {
        warn("client socket error, disconecting\n");
    }
        
    mc_close_user(client);
}

void on_accept(int fd, short ev, void *arg)
{
    int client_fd;
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    client_t *client;
        
    client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
    if (client_fd < 0) {
        warn("accept failed");
        return;
    }
    
    printf("accepting...\n");
    
    if (setnonblock(client_fd) < 0) {
        warn("failed to set the client socket non-blocking");
    }
    
    client = calloc(1, sizeof(client_t));
    if (client == NULL) {
        close(client_fd);
        printf("malloc failed\n");
        return;
    }
    
    client->compression_threshold = -1; // disable compression per default
    client->fd = client_fd;
    client->buf_ev = bufferevent_socket_new(evbase, client_fd, 0);
    bufferevent_setcb(client->buf_ev, buffered_on_read, NULL, buffered_on_error, client);
    
    bufferevent_enable(client->buf_ev, EV_READ);
        
    printf("Accepted connection from %s\n", inet_ntoa(client_addr.sin_addr));
    
}

struct event ev_accept;
int open_socket(int port)
{
    int listen_fd;
    int reuseaddr_on, err;
    struct sockaddr_in listen_addr;

        
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        printf("error listening\n");
        return listen_fd;
    }
    memset(&listen_addr, 0, sizeof(listen_addr));
    listen_addr.sin_family = AF_INET;
    listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    listen_addr.sin_port = htons(port);
    err = bind(listen_fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr));
    if (err < 0) {
        close(listen_fd);
        printf("error bind\n");
        return err;
    }
    err = listen(listen_fd, 5);
    if (err < 0) {
        close(listen_fd);
        printf("error listening");
        return err;
    }
    
    reuseaddr_on = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on));
    
    err = setnonblock(listen_fd);
    if (err < 0) {
        close(listen_fd);
        printf("could not set to non blocking\n");
        return 1;
    }
    
    event_assign(&ev_accept, evbase, listen_fd, EV_READ|EV_PERSIST, on_accept, NULL);
    event_add(&ev_accept, NULL);
        
  return 0;
}