Statistics
| Branch: | Tag: | Revision:

mongoose / examples / netcat / nc.c @ eaef5bd1

History | View | Annotate | Download (4.54 KB)

1
// Copyright (c) 2014-2016 Cesanta Software Limited
2
// All rights reserved
3
//
4
// This software is dual-licensed: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License version 2 as
6
// published by the Free Software Foundation. For the terms of this
7
// license, see <http://www.gnu.org/licenses/>.
8
//
9
// You are free to use this software under the terms of the GNU General
10
// Public License, but WITHOUT ANY WARRANTY; without even the implied
11
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
// See the GNU General Public License for more details.
13
//
14
// Alternatively, you can license this software under a commercial
15
// license, as set out in <https://www.cesanta.com/license>.
16

    
17
// This file implements "netcat" utility with SSL and traffic hexdump.
18

    
19
#include "mongoose.h"
20

    
21
static sig_atomic_t s_received_signal = 0;
22
static int s_is_websocket;
23

    
24
static void signal_handler(int sig_num) {
25
  signal(sig_num, signal_handler);
26
  s_received_signal = sig_num;
27
}
28

    
29
static void show_usage_and_exit(const char *prog_name) {
30
  fprintf(stderr, "%s\n", "Copyright (c) Cesanta. Built on: " __DATE__);
31
  fprintf(stderr, "Usage: %s [OPTIONS] [IP:]PORT\n", prog_name);
32
  fprintf(stderr, "%s\n", "Options:");
33
  fprintf(stderr, "%s\n", "  -l\t\tOpen a listening socket");
34
  fprintf(stderr, "%s\n", "  -d file\tHexdump traffic into a file");
35
  fprintf(stderr, "%s\n", "  -ws\t\tUse WebSocket protocol");
36
  exit(EXIT_FAILURE);
37
}
38

    
39
static void on_stdin_read(struct mg_connection *nc, int ev, void *p) {
40
  int ch = *(int *) p;
41

    
42
  (void) ev;
43

    
44
  if (ch < 0) {
45
    // EOF is received from stdin. Schedule the connection to close
46
    nc->flags |= MG_F_SEND_AND_CLOSE;
47
    if (nc->send_mbuf.len <= 0) {
48
      nc->flags |= MG_F_CLOSE_IMMEDIATELY;
49
    }
50
  } else {
51
    // A character is received from stdin. Send it to the connection.
52
    unsigned char c = (unsigned char) ch;
53
    if (s_is_websocket) {
54
      mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, &c, 1);
55
    } else {
56
      mg_send(nc, &c, 1);
57
    }
58
  }
59
}
60

    
61
static void *stdio_thread_func(void *param) {
62
  struct mg_mgr *mgr = (struct mg_mgr *) param;
63
  int ch;
64

    
65
  // Read stdin until EOF character by character, sending them to the mgr
66
  while ((ch = getchar()) != EOF) {
67
    mg_broadcast(mgr, on_stdin_read, &ch, sizeof(ch));
68
  }
69
  s_received_signal = 1;
70

    
71
  return NULL;
72
}
73

    
74
static void ev_handler(struct mg_connection *nc, int ev, void *p) {
75
  switch (ev) {
76
    case MG_EV_ACCEPT:
77
    case MG_EV_CONNECT:
78
      mg_start_thread(stdio_thread_func, nc->mgr);
79
      break;
80

    
81
    case MG_EV_WEBSOCKET_FRAME: {
82
      struct websocket_message *wm = (struct websocket_message *) p;
83
      fwrite(wm->data, 1, wm->size, stdout);
84
      break;
85
    }
86

    
87
    case MG_EV_CLOSE:
88
      s_received_signal = 1;
89
      break;
90

    
91
    case MG_EV_RECV:
92
      if (!s_is_websocket) {
93
        fwrite(nc->recv_mbuf.buf, 1, nc->recv_mbuf.len, stdout);
94
        mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len);
95
      }
96
      break;
97

    
98
    default:
99
      break;
100
  }
101
}
102

    
103
int main(int argc, char *argv[]) {
104
  struct mg_mgr mgr;
105
  int i, is_listening = 0;
106
  const char *address = NULL;
107
  struct mg_connection *c;
108
  const char *err = NULL;
109

    
110
  mg_mgr_init(&mgr, NULL);
111

    
112
  // Parse command line options
113
  for (i = 1; i < argc && argv[i][0] == '-'; i++) {
114
    if (strcmp(argv[i], "-l") == 0) {
115
      is_listening = 1;
116
    } else if (strcmp(argv[i], "-d") == 0 && i + 1 < argc) {
117
      mgr.hexdump_file = argv[++i];
118
    } else if (strcmp(argv[i], "-ws") == 0 && i + 1 < argc) {
119
      s_is_websocket = 1;
120
    } else {
121
      show_usage_and_exit(argv[0]);
122
    }
123
  }
124

    
125
  if (i + 1 == argc) {
126
    address = argv[i];
127
  } else {
128
    show_usage_and_exit(argv[0]);
129
  }
130

    
131
  signal(SIGTERM, signal_handler);
132
  signal(SIGINT, signal_handler);
133
  signal(SIGPIPE, SIG_IGN);
134

    
135
  if (is_listening) {
136
    struct mg_bind_opts opts;
137
    memset(&opts, 0, sizeof(opts));
138
    opts.error_string = &err;
139
    if ((c = mg_bind_opt(&mgr, address, ev_handler, opts)) == NULL) {
140
      fprintf(stderr, "mg_bind(%s) failed: %s\n", address, err);
141
      exit(EXIT_FAILURE);
142
    }
143
  } else {
144
    struct mg_connect_opts opts;
145
    memset(&opts, 0, sizeof(opts));
146
    opts.error_string = &err;
147
    if ((c = mg_connect_opt(&mgr, address, ev_handler, opts)) == NULL) {
148
      fprintf(stderr, "mg_connect(%s) failed: %s\n", address, err);
149
      exit(EXIT_FAILURE);
150
    }
151
  }
152
  if (s_is_websocket) {
153
    mg_set_protocol_http_websocket(c);
154
    if (!is_listening) {
155
      mg_send_websocket_handshake2(c, "/", address, NULL, NULL);
156
    }
157
  }
158

    
159
  while (s_received_signal == 0) {
160
    mg_mgr_poll(&mgr, 1000);
161
  }
162
  mg_mgr_free(&mgr);
163

    
164
  return EXIT_SUCCESS;
165
}