ithewei %!s(int64=6) %!d(string=hai) anos
pai
achega
1dd5142d82
Modificáronse 12 ficheiros con 411 adicións e 98 borrados
  1. 12 2
      Makefile
  2. 0 1
      event/epoll.c
  3. 36 29
      event/hloop.c
  4. 2 2
      event/hloop.h
  5. 26 23
      event/nio.c
  6. 157 0
      event/nmap.cpp
  7. 17 0
      event/nmap.h
  8. 64 34
      event/overlapio.c
  9. 3 0
      event/overlapio.h
  10. 2 6
      examples/nc.c
  11. 91 0
      examples/nmap.cpp
  12. 1 1
      http/HttpParser.h

+ 12 - 2
Makefile

@@ -3,7 +3,7 @@ TMPDIR=tmp
 
 default: all
 
-all: test ping loop tcp udp nc httpd
+all: test ping loop tcp udp nc nmap httpd
 
 clean:
 	$(MAKEF) clean SRCDIRS=". base utils event http http/client http/server examples $(TMPDIR)"
@@ -40,6 +40,16 @@ nc: prepare
 	cp examples/nc.c $(TMPDIR)
 	$(MAKEF) TARGET=$@ SRCDIRS=". base event $(TMPDIR)"
 
+nmap: prepare
+	-rm $(TMPDIR)/*.o $(TMPDIR)/*.h $(TMPDIR)/*.c $(TMPDIR)/*.cpp
+	cp examples/nmap.cpp $(TMPDIR)
+ifeq ($(OS), Windows)
+	# for nmap, on Windows platform, we suggest EVENT_POLL, not EVENT_IOCP
+	$(MAKEF) TARGET=$@ SRCDIRS=". base event $(TMPDIR)" DEFINES="PRINT_DEBUG EVENT_POLL"
+else
+	$(MAKEF) TARGET=$@ SRCDIRS=". base event $(TMPDIR)" DEFINES="PRINT_DEBUG"
+endif
+
 httpd: prepare
 	-rm $(TMPDIR)/*.o $(TMPDIR)/*.h $(TMPDIR)/*.c $(TMPDIR)/*.cpp
 	cp examples/httpd.cpp examples/httpd_conf.h examples/http_api_test.h $(TMPDIR)
@@ -55,4 +65,4 @@ CURL_SRCS    += examples/curl.cpp base/hstring.cpp base/hbase.c
 curl:
 	$(MAKEF) TARGET=$@ SRCDIRS="$(CURL_SRCDIRS)" INCDIRS="$(CURL_INCDIRS)" SRCS="$(CURL_SRCS)" DEFINES="CURL_STATICLIB" LIBS="curl"
 
-.PHONY: clean prepare test ping loop tcp udp nc httpd webbench curl
+.PHONY: clean prepare test ping loop tcp udp nc nmap httpd webbench curl

+ 0 - 1
event/epoll.c

@@ -12,7 +12,6 @@
 #define EVENTS_INIT_SIZE    64
 ARRAY_DECL(struct epoll_event, events);
 
-
 typedef struct epoll_ctx_s {
     int                 epfd;
     struct events       events;

+ 36 - 29
event/hloop.c

@@ -11,10 +11,10 @@
 #define PAUSE_TIME              10          // ms
 #define MAX_BLOCK_TIME          1000        // ms
 
-#define IO_ARRAY_INIT_SIZE      64
+#define IO_ARRAY_INIT_SIZE      1024
 static void hio_init(hio_t* io);
-static void hio_deinit(hio_t* io);
-static void hio_reset(hio_t* io);
+static void hio_ready(hio_t* io);
+static void hio_done(hio_t* io);
 static void hio_free(hio_t* io);
 
 static int timers_compare(const struct heap_node* lhs, const struct heap_node* rhs) {
@@ -140,14 +140,16 @@ process_timers:
         ntimers = hloop_process_timers(loop);
     }
 
-    if (loop->npendings == 0) {
+    int npendings = loop->npendings;
+    if (npendings == 0) {
         if (loop->nidles) {
             nidles= hloop_process_idles(loop);
         }
     }
     int ncbs = hloop_process_pendings(loop);
-    printd("blocktime=%d nios=%d ntimers=%d nidles=%d nactives=%d npendings=%d ncbs=%d\n",
-            blocktime, nios, ntimers, nidles, loop->nactives, loop->npendings, ncbs);
+    printd("blocktime=%d nios=%d/%u ntimers=%d/%u nidles=%d/%u nactives=%d npendings=%d ncbs=%d\n",
+            blocktime, nios/loop->nios, loop->nios, ntimers, loop->ntimers, nidles, loop->nidles,
+            loop->nactives, npendings, ncbs);
     return ncbs;
 }
 
@@ -198,7 +200,7 @@ void hloop_cleanup(hloop_t* loop) {
     for (int i = 0; i < loop->ios.maxsize; ++i) {
         hio_t* io = loop->ios.ptr[i];
         if (io) {
-            if (!(io->io_type&HIO_TYPE_STDIO)) {
+            if ((!(io->io_type&HIO_TYPE_STDIO)) && io->active) {
                 hclose(io);
             }
             hio_free(io);
@@ -354,7 +356,7 @@ static void fill_io_type(hio_t* io) {
     }
 }
 
-void hio_socket_init(hio_t* io) {
+static void hio_socket_init(hio_t* io) {
     // nonblocking
     nonblocking(io->fd);
     // fill io->localaddr io->peeraddr
@@ -362,7 +364,6 @@ void hio_socket_init(hio_t* io) {
         SAFE_ALLOC(io->localaddr, sizeof(struct sockaddr_in6));
     }
     if (io->peeraddr == NULL) {
-        io->peeraddrlen = sizeof(struct sockaddr_in6);
         SAFE_ALLOC(io->peeraddr, sizeof(struct sockaddr_in6));
     }
     socklen_t addrlen = sizeof(struct sockaddr_in6);
@@ -380,21 +381,9 @@ void hio_socket_init(hio_t* io) {
     }
 }
 
-void hio_reset(hio_t* io) {
-    fill_io_type(io);
-    if (io->io_type & HIO_TYPE_SOCKET) {
-        hio_socket_init(io);
-    }
-}
-
-void hio_deinit(hio_t* io) {
-    offset_buf_t* pbuf = NULL;
-    while (!write_queue_empty(&io->write_queue)) {
-        pbuf = write_queue_front(&io->write_queue);
-        SAFE_FREE(pbuf->base);
-        write_queue_pop_front(&io->write_queue);
-    }
-    write_queue_cleanup(&io->write_queue);
+void hio_ready(hio_t* io) {
+    if (io->ready) return;
+    io->ready = 1;
     io->closed = 0;
     io->accept = io->connect = io->connectex = 0;
     io->recv = io->send = 0;
@@ -409,11 +398,26 @@ void hio_deinit(hio_t* io) {
     io->connect_cb = 0;
     io->event_index[0] = io->event_index[1] = -1;
     io->hovlp = NULL;
+    fill_io_type(io);
+    if (io->io_type & HIO_TYPE_SOCKET) {
+        hio_socket_init(io);
+    }
+}
+
+void hio_done(hio_t* io) {
+    io->ready = 0;
+    offset_buf_t* pbuf = NULL;
+    while (!write_queue_empty(&io->write_queue)) {
+        pbuf = write_queue_front(&io->write_queue);
+        SAFE_FREE(pbuf->base);
+        write_queue_pop_front(&io->write_queue);
+    }
+    write_queue_cleanup(&io->write_queue);
 }
 
 void hio_free(hio_t* io) {
     if (io == NULL) return;
-    hio_deinit(io);
+    hio_done(io);
     SAFE_FREE(io->localaddr);
     SAFE_FREE(io->peeraddr);
     SAFE_FREE(io);
@@ -438,6 +442,10 @@ hio_t* hio_get(hloop_t* loop, int fd) {
         loop->ios.ptr[fd] = io;
     }
 
+    if (!io->ready) {
+        hio_ready(io);
+    }
+
     return io;
 }
 
@@ -445,7 +453,7 @@ int hio_add(hio_t* io, hio_cb cb, int events) {
     printd("hio_add fd=%d events=%d\n", io->fd, events);
     hloop_t* loop = io->loop;
     if (!io->active) {
-        hio_reset(io);
+        hio_ready(io);
         EVENT_ADD(loop, io, cb);
         loop->nios++;
     }
@@ -468,7 +476,7 @@ int hio_del(hio_t* io, int events) {
         io->loop->nios--;
         // NOTE: not EVENT_DEL, avoid free
         EVENT_INACTIVE(io);
-        hio_deinit(io);
+        hio_done(io);
     }
     return 0;
 }
@@ -482,7 +490,6 @@ void hio_setlocaladdr(hio_t* io, struct sockaddr* addr, int addrlen) {
 
 void hio_setpeeraddr (hio_t* io, struct sockaddr* addr, int addrlen) {
     if (io->peeraddr == NULL) {
-        io->peeraddrlen = sizeof(struct sockaddr_in6);
         SAFE_ALLOC(io->peeraddr, sizeof(struct sockaddr_in6));
     }
     memcpy(io->peeraddr, addr, addrlen);
@@ -514,13 +521,13 @@ void hclose(hio_t* io) {
     printd("close fd=%d\n", io->fd);
     if (io->closed) return;
     io->closed = 1;
+    hio_del(io, ALL_EVENTS);
     hio_close(io);
     if (io->close_cb) {
         printd("close_cb------\n");
         io->close_cb(io);
         printd("close_cb======\n");
     }
-    hio_del(io, ALL_EVENTS);
 }
 
 hio_t* haccept(hloop_t* loop, int listenfd, haccept_cb accept_cb) {

+ 2 - 2
event/hloop.h

@@ -26,7 +26,7 @@ typedef void (*htimer_cb)   (htimer_t* timer);
 typedef void (*hio_cb)      (hio_t* io);
 
 typedef void (*haccept_cb)  (hio_t* io, int connfd);
-typedef void (*hconnect_cb) (hio_t* io, int state);
+typedef void (*hconnect_cb) (hio_t* io);
 typedef void (*hread_cb)    (hio_t* io, void* buf, int readbytes);
 typedef void (*hwrite_cb)   (hio_t* io, const void* buf, int writebytes);
 typedef void (*hclose_cb)   (hio_t* io);
@@ -115,6 +115,7 @@ typedef enum {
 
 struct hio_s {
     HEVENT_FIELDS
+    unsigned    ready       :1;
     unsigned    closed      :1;
     unsigned    accept      :1;
     unsigned    connect     :1;
@@ -130,7 +131,6 @@ struct hio_s {
     int         revents;
     struct sockaddr*    localaddr;
     struct sockaddr*    peeraddr;
-    int                 peeraddrlen;    // for WSARecvFrom
     hbuf_t              readbuf;        // for hread
     struct write_queue  write_queue;    // for hwrite
     // callbacks

+ 26 - 23
event/nio.c

@@ -29,9 +29,9 @@ accept:
         printd("accept listenfd=%d connfd=%d [%s] <= [%s]\n", io->fd, connfd,
                 sockaddr_snprintf(io->localaddr, localaddrstr, sizeof(localaddrstr)),
                 sockaddr_snprintf(io->peeraddr, peeraddrstr, sizeof(peeraddrstr)));
-        printd("accept_cb------\n");
+        //printd("accept_cb------\n");
         io->accept_cb(io, connfd);
-        printd("accept_cb======\n");
+        //printd("accept_cb======\n");
     }
 
     goto accept;
@@ -42,13 +42,12 @@ accept_error:
 
 static void nio_connect(hio_t* io) {
     //printd("nio_connect connfd=%d\n", io->fd);
-    int state = 0;
     socklen_t addrlen = sizeof(struct sockaddr_in6);
     int ret = getpeername(io->fd, io->peeraddr, &addrlen);
     if (ret < 0) {
         io->error = socket_errno();
         printd("connect failed: %s: %d\n", strerror(socket_errno()), socket_errno());
-        state = 0;
+        hclose(io);
     }
     else {
         addrlen = sizeof(struct sockaddr_in6);
@@ -58,15 +57,11 @@ static void nio_connect(hio_t* io) {
         printd("connect connfd=%d [%s] => [%s]\n", io->fd,
                 sockaddr_snprintf(io->localaddr, localaddrstr, sizeof(localaddrstr)),
                 sockaddr_snprintf(io->peeraddr, peeraddrstr, sizeof(peeraddrstr)));
-        state = 1;
-    }
-    if (io->connect_cb) {
-        printd("connect_cb------\n");
-        io->connect_cb(io, state);
-        printd("connect_cb======\n");
-    }
-    if (state == 0) {
-        hclose(io);
+        if (io->connect_cb) {
+            //printd("connect_cb------\n");
+            io->connect_cb(io);
+            //printd("connect_cb======\n");
+        }
     }
 }
 
@@ -113,9 +108,9 @@ read:
     }
     //printd("> %s\n", buf);
     if (io->read_cb) {
-        printd("read_cb------\n");
+        //printd("read_cb------\n");
         io->read_cb(io, buf, nread);
-        printd("read_cb======\n");
+        //printd("read_cb======\n");
     }
     if (nread == len) {
         goto read;
@@ -168,9 +163,9 @@ write:
         goto disconnect;
     }
     if (io->write_cb) {
-        printd("write_cb------\n");
+        //printd("write_cb------\n");
         io->write_cb(io, buf, nwrite);
-        printd("write_cb======\n");
+        //printd("write_cb======\n");
     }
     pbuf->offset += nwrite;
     if (nwrite == len) {
@@ -196,6 +191,11 @@ static void hio_handle_events(hio_t* io) {
     }
 
     if ((io->events & WRITE_EVENT) && (io->revents & WRITE_EVENT)) {
+        // NOTE: del WRITE_EVENT, if write_queue empty
+        if (write_queue_empty(&io->write_queue)) {
+            iowatcher_del_event(io->loop, io->fd, WRITE_EVENT);
+            io->events &= ~WRITE_EVENT;
+        }
         if (io->connect) {
             // NOTE: connect just do once
             // ONESHOT
@@ -206,10 +206,6 @@ static void hio_handle_events(hio_t* io) {
         else {
             nio_write(io);
         }
-        // NOTE: del WRITE_EVENT, if write_queue empty
-        if (write_queue_empty(&io->write_queue)) {
-            hio_del(io, WRITE_EVENT);
-        }
     }
 
     io->revents = 0;
@@ -231,6 +227,13 @@ int hio_connect(hio_t* io) {
         hclose(io);
         return ret;
     }
+    if (ret == 0) {
+        // connect ok
+        if (io->connect_cb) {
+            io->connect_cb(io);
+        }
+        return 0;
+    }
     return hio_add(io, hio_handle_events, WRITE_EVENT);
 }
 
@@ -274,9 +277,9 @@ try_write:
             goto disconnect;
         }
         if (io->write_cb) {
-            printd("try_write_cb------\n");
+            //printd("try_write_cb------\n");
             io->write_cb(io, buf, nwrite);
-            printd("try_write_cb======\n");
+            //printd("try_write_cb======\n");
         }
         if (nwrite == len) {
             //goto write_done;

+ 157 - 0
event/nmap.cpp

@@ -0,0 +1,157 @@
+#include "nmap.h"
+#include "hloop.h"
+#include "netinet.h"
+#include "hstring.h"
+
+#define MAX_RECVFROM_TIMEOUT    5000 // ms
+
+typedef struct recvfrom_udata_s {
+    Nmap*   nmap;
+    int     send_cnt;
+    int     recv_cnt; int     up_cnt; } recvfrom_udata_t;
+
+void on_timer(htimer_t* timer) {
+    hloop_stop(timer->loop);
+}
+
+void on_recvfrom(hio_t* io, void* buf, int readbytes) {
+    //printf("on_recv fd=%d readbytes=%d\n", io->fd, readbytes);
+    //char localaddrstr[INET6_ADDRSTRLEN+16] = {0};
+    //char peeraddrstr[INET6_ADDRSTRLEN+16] = {0};
+    //printf("[%s] <=> [%s]\n",
+            //sockaddr_snprintf(io->localaddr, localaddrstr, sizeof(localaddrstr)),
+            //sockaddr_snprintf(io->peeraddr, peeraddrstr, sizeof(peeraddrstr)));
+    recvfrom_udata_t* udata = (recvfrom_udata_t*)io->userdata;
+    if (++udata->recv_cnt == udata->send_cnt) {
+        hloop_stop(io->loop);
+    }
+    Nmap* nmap = udata->nmap;
+    struct sockaddr_in* peeraddr = (struct sockaddr_in*)io->peeraddr;
+    auto iter = nmap->find(peeraddr->sin_addr.s_addr);
+    if (iter != nmap->end()) {
+        if (iter->second == 0) {
+            iter->second = 1;
+            if (++udata->up_cnt == nmap->size()) {
+                hloop_stop(io->loop);
+            }
+        }
+        else {
+            //hloop_stop(io->loop);
+        }
+    }
+    //else {
+        //hloop_stop(io->loop);
+    //}
+}
+
+int nmap_discovery(Nmap* nmap) {
+    // socket
+    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+    if (sockfd < 0) {
+        perror("socket");
+        if (errno == EPERM) {
+            fprintf(stderr, "please use root or sudo to create a raw socket.\n");
+        }
+        return -socket_errno();
+    }
+
+    hloop_t loop;
+    hloop_init(&loop);
+    uint64_t start_hrtime = hloop_now_hrtime(&loop);
+
+    nonblocking(sockfd);
+    hio_t* io = hio_get(&loop, sockfd);
+    if (io == NULL) return -1;
+    io->io_type = HIO_TYPE_IP;
+    struct sockaddr_in localaddr;
+    socklen_t addrlen = sizeof(localaddr);
+    memset(&localaddr, 0, addrlen);
+    localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    hio_setlocaladdr(io, (struct sockaddr*)&localaddr, addrlen);
+
+    recvfrom_udata_t udata;
+    udata.nmap = nmap;
+    udata.send_cnt = 0;
+    udata.recv_cnt = 0;
+    udata.up_cnt = 0;
+    io->userdata = &udata;
+    char recvbuf[128];
+    hrecvfrom(&loop, sockfd, recvbuf, sizeof(recvbuf), on_recvfrom);
+    // icmp
+    char sendbuf[64];
+    icmp_t* icmp_req = (icmp_t*)sendbuf;
+    icmp_req->icmp_type = ICMP_ECHO;
+    icmp_req->icmp_code = 0;
+    icmp_req->icmp_id = getpid();
+    for (int i = 0; i < sizeof(sendbuf) - sizeof(icmphdr_t); ++i) {
+        icmp_req->icmp_data[i] = i;
+    }
+    auto iter = nmap->begin();
+    struct sockaddr_in peeraddr;
+    while (iter != nmap->end()) {
+        icmp_req->icmp_seq = iter->first;
+        icmp_req->icmp_cksum = 0;
+        icmp_req->icmp_cksum = checksum((uint8_t*)icmp_req, sizeof(sendbuf));
+        socklen_t addrlen = sizeof(peeraddr);
+        memset(&peeraddr, 0, addrlen);
+        peeraddr.sin_family = AF_INET;
+        peeraddr.sin_addr.s_addr = iter->first;
+        hio_setpeeraddr(io, (struct sockaddr*)&peeraddr, addrlen);
+        hsendto(&loop, sockfd, sendbuf, sizeof(sendbuf), NULL);
+        ++udata.send_cnt;
+        ++iter;
+    }
+
+    htimer_add(&loop, on_timer, MAX_RECVFROM_TIMEOUT, 1);
+
+    hloop_run(&loop);
+    uint64_t end_hrtime = hloop_now_hrtime(&loop);
+
+    // print result
+    char ip[INET_ADDRSTRLEN];
+    iter = nmap->begin();
+    while (iter != nmap->end()) {
+        inet_ntop(AF_INET, (void*)&iter->first, ip, sizeof(ip));
+        printd("%s\t is %s.\n", ip, iter->second == 0 ? "down" : "up");
+        ++iter;
+    }
+    printd("Nmap done: %lu IP addresses (%d hosts up) scanned in %.2f seconds\n",
+            nmap->size(), udata.up_cnt, (end_hrtime-start_hrtime)/1000000.0f);
+
+    return udata.up_cnt;
+}
+
+int segment_discovery(const char* segment16, Nmap* nmap) {
+    StringList strlist = split(segment16, '.');
+    if (strlist.size() != 4) return -1;
+    uint32_t addr = 0;
+    uint8_t* p = (uint8_t*)&addr;
+    p[0] = atoi(strlist[0].c_str());
+    p[1] = atoi(strlist[1].c_str());
+    p[3] = 1;
+    printd("Nmap scan %u.%u.x.1...\n", p[0], p[1]);
+    nmap->clear();
+    for (int i = 0; i < 256; ++i) {
+        p[2] = i;
+        (*nmap)[addr] = 0;
+    }
+    return nmap_discovery(nmap);
+}
+
+int host_discovery(const char* segment24, Nmap* nmap) {
+    StringList strlist = split(segment24, '.');
+    if (strlist.size() != 4) return -1;
+    uint32_t addr = 0;
+    uint8_t* p = (uint8_t*)&addr;
+    p[0] = atoi(strlist[0].c_str());
+    p[1] = atoi(strlist[1].c_str());
+    p[2] = atoi(strlist[2].c_str());
+    printd("Nmap scan %u.%u.%u.x...\n", p[0], p[1], p[2]);
+    // 0,256 reserved
+    nmap->clear();
+    for (int i = 1; i < 255; ++i) {
+        p[3] = i;
+        (*nmap)[addr] = 0;
+    }
+    return nmap_discovery(nmap);
+}

+ 17 - 0
event/nmap.h

@@ -0,0 +1,17 @@
+#ifndef HW_NMAP_H_
+#define HW_NMAP_H_
+
+#include <map>
+#include "hsocket.h"
+typedef std::map<uint32_t, int> Nmap;
+
+// ip = segment + host
+// segment16: 192.168.x.x
+// segment24: 192.168.1.x
+
+// @return up_cnt
+int nmap_discovery(Nmap* nmap);
+int segment_discovery(const char* segment16, Nmap* nmap);
+int host_discovery(const char* segment24, Nmap* nmap);
+
+#endif // HW_NMAP_H_

+ 64 - 34
event/overlapio.c

@@ -1,3 +1,4 @@
+// WARN: overlapio maybe need MemoryPool to avoid alloc/free
 #include "iowatcher.h"
 
 #ifdef EVENT_IOCP
@@ -45,8 +46,13 @@ int post_recv(hio_t* io, hoverlapped_t* hovlp) {
     hovlp->fd = io->fd;
     hovlp->event = READ_EVENT;
     hovlp->io = io;
-    hovlp->buf.buf = io->readbuf.base;
     hovlp->buf.len = io->readbuf.len;
+    if (io->io_type == HIO_TYPE_UDP || io->io_type == HIO_TYPE_IP) {
+        SAFE_ALLOC(hovlp->buf.buf, hovlp->buf.len);
+    }
+    else {
+        hovlp->buf.buf = io->readbuf.base;
+    }
     memset(hovlp->buf.buf, 0, hovlp->buf.len);
     DWORD dwbytes = 0;
     DWORD flags = 0;
@@ -56,12 +62,16 @@ int post_recv(hio_t* io, hoverlapped_t* hovlp) {
     }
     else if (io->io_type == HIO_TYPE_UDP ||
             io->io_type == HIO_TYPE_IP) {
-        ret = WSARecvFrom(io->fd, &hovlp->buf, 1, &dwbytes, &flags, io->peeraddr, &io->peeraddrlen, &hovlp->ovlp, NULL);
+        if (hovlp->addr == NULL) {
+            hovlp->addrlen = sizeof(struct sockaddr_in6);
+            SAFE_ALLOC(hovlp->addr, sizeof(struct sockaddr_in6));
+        }
+        ret = WSARecvFrom(io->fd, &hovlp->buf, 1, &dwbytes, &flags, hovlp->addr, &hovlp->addrlen, &hovlp->ovlp, NULL);
     }
     else {
         ret = -1;
     }
-    printd("WSARecv ret=%d bytes=%u\n", ret, dwbytes);
+    //printd("WSARecv ret=%d bytes=%u\n", ret, dwbytes);
     if (ret != 0) {
         int err = WSAGetLastError();
         if (err != ERROR_IO_PENDING) {
@@ -76,8 +86,8 @@ static void on_acceptex_complete(hio_t* io) {
     printd("on_acceptex_complete------\n");
     hoverlapped_t* hovlp = (hoverlapped_t*)io->hovlp;
     int listenfd = io->fd;
-    int connfd = hovlp->fd;
     LPFN_GETACCEPTEXSOCKADDRS GetAcceptExSockaddrs = NULL;
+    int connfd = hovlp->fd;
     GUID guidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
     DWORD dwbytes = 0;
     if (WSAIoctl(connfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
@@ -101,9 +111,9 @@ static void on_acceptex_complete(hio_t* io) {
                 sockaddr_snprintf(io->localaddr, localaddrstr, sizeof(localaddrstr)),
                 sockaddr_snprintf(io->peeraddr, peeraddrstr, sizeof(peeraddrstr)));
         setsockopt(connfd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (const char*)&listenfd, sizeof(int));
-        printd("accept_cb------\n");
+        //printd("accept_cb------\n");
         io->accept_cb(io, connfd);
-        printd("accept_cb======\n");
+        //printd("accept_cb======\n");
     }
     post_acceptex(io, hovlp);
 }
@@ -111,8 +121,13 @@ static void on_acceptex_complete(hio_t* io) {
 static void on_connectex_complete(hio_t* io) {
     printd("on_connectex_complete------\n");
     hoverlapped_t* hovlp = (hoverlapped_t*)io->hovlp;
-    int state = hovlp->error == 0 ? 1 : 0;
-    if (state == 1) {
+    io->error = hovlp->error;
+    SAFE_FREE(io->hovlp);
+    if (io->errno != 0) {
+        hclose(io);
+        return;
+    }
+    if (io->connect_cb) {
         setsockopt(io->fd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
         socklen_t addrlen = sizeof(struct sockaddr_in6);
         getsockname(io->fd, io->localaddr, &addrlen);
@@ -123,18 +138,9 @@ static void on_connectex_complete(hio_t* io) {
         printd("connect connfd=%d [%s] => [%s]\n", io->fd,
                 sockaddr_snprintf(io->localaddr, localaddrstr, sizeof(localaddrstr)),
                 sockaddr_snprintf(io->peeraddr, peeraddrstr, sizeof(peeraddrstr)));
-    }
-    else {
-        io->error = hovlp->error;
-    }
-    if (io->connect_cb) {
-        printd("connect_cb------\n");
-        io->connect_cb(io, state);
-        printd("connect_cb======\n");
-    }
-    SAFE_FREE(io->hovlp);
-    if (state == 0) {
-        hclose(io);
+        //printd("connect_cb------\n");
+        io->connect_cb(io);
+        //printd("connect_cb======\n");
     }
 }
 
@@ -148,12 +154,27 @@ static void on_wsarecv_complete(hio_t* io) {
     }
 
     if (io->read_cb) {
-        printd("read_cb------\n");
+        if (io->io_type == HIO_TYPE_UDP || io->io_type == HIO_TYPE_IP) {
+            if (hovlp->addr && hovlp->addrlen) {
+                hio_setpeeraddr(io, hovlp->addr, hovlp->addrlen);
+            }
+        }
+        //printd("read_cb------\n");
         io->read_cb(io, hovlp->buf.buf, hovlp->bytes);
-        printd("read_cb======\n");
+        //printd("read_cb======\n");
+    }
+
+    if (io->io_type == HIO_TYPE_TCP) {
+        // reuse hovlp
+        if (!io->closed) {
+            post_recv(io, hovlp);
+        }
     }
-    if (!io->closed) {
-        post_recv(io, hovlp);
+    else if (io->io_type == HIO_TYPE_UDP ||
+            io->io_type == HIO_TYPE_IP) {
+        SAFE_FREE(hovlp->buf.buf);
+        SAFE_FREE(hovlp->addr);
+        SAFE_FREE(io->hovlp);
     }
 }
 
@@ -166,9 +187,14 @@ static void on_wsasend_complete(hio_t* io) {
         goto end;
     }
     if (io->write_cb) {
-        printd("write_cb------\n");
+        if (io->io_type == HIO_TYPE_UDP || io->io_type == HIO_TYPE_IP) {
+            if (hovlp->addr) {
+                hio_setpeeraddr(io, hovlp->addr, hovlp->addrlen);
+            }
+        }
+        //printd("write_cb------\n");
         io->write_cb(io, hovlp->buf.buf, hovlp->bytes);
-        printd("write_cb======\n");
+        //printd("write_cb======\n");
     }
 end:
     if (io->hovlp) {
@@ -190,7 +216,8 @@ static void hio_handle_events(hio_t* io) {
     if ((io->events & WRITE_EVENT) && (io->revents & WRITE_EVENT)) {
         // NOTE: WRITE_EVENT just do once
         // ONESHOT
-        hio_del(io, WRITE_EVENT);
+        iowatcher_del_event(io->loop, io->fd, WRITE_EVENT);
+        io->events &= ~WRITE_EVENT;
         if (io->connect) {
             io->connect = 0;
 
@@ -264,9 +291,11 @@ try_send:
     if (io->io_type == HIO_TYPE_TCP) {
         nwrite = send(io->fd, buf, len, 0);
     }
-    else if (io->io_type == HIO_TYPE_UDP ||
-             io->io_type == HIO_TYPE_IP) {
-        nwrite = recvfrom(io->fd, buf, len, 0, io->peeraddr, &io->peeraddrlen);
+    else if (io->io_type == HIO_TYPE_UDP) {
+        nwrite = sendto(io->fd, buf, len, 0, io->peeraddr, sizeof(struct sockaddr_in6));
+    }
+    else if (io->io_type == HIO_TYPE_IP) {
+        goto WSASend;
     }
     else {
         nwrite = -1;
@@ -287,9 +316,9 @@ try_send:
         goto disconnect;
     }
     if (io->write_cb) {
-        printd("try_write_cb------\n");
+        //printd("try_write_cb------\n");
         io->write_cb(io, buf, nwrite);
-        printd("try_write_cb======\n");
+        //printd("try_write_cb======\n");
     }
     if (nwrite == len) {
         //goto write_done;
@@ -314,12 +343,12 @@ WSASend:
         }
         else if (io->io_type == HIO_TYPE_UDP ||
                  io->io_type == HIO_TYPE_IP) {
-            ret = WSASendTo(io->fd, &hovlp->buf, 1, &dwbytes, flags, io->peeraddr, io->peeraddrlen, &hovlp->ovlp, NULL);
+            ret = WSASendTo(io->fd, &hovlp->buf, 1, &dwbytes, flags, io->peeraddr, sizeof(struct sockaddr_in6), &hovlp->ovlp, NULL);
         }
         else {
             ret = -1;
         }
-        printd("WSASend ret=%d bytes=%u\n", ret, dwbytes);
+        //printd("WSASend ret=%d bytes=%u\n", ret, dwbytes);
         if (ret != 0) {
             int err = WSAGetLastError();
             if (err != ERROR_IO_PENDING) {
@@ -361,6 +390,7 @@ void hio_close (hio_t* io) {
         if (hovlp->buf.buf != io->readbuf.base) {
             SAFE_FREE(hovlp->buf.buf);
         }
+        SAFE_FREE(hovlp->addr);
         SAFE_FREE(io->hovlp);
     }
 }

+ 3 - 0
event/overlapio.h

@@ -20,6 +20,9 @@ typedef struct hoverlapped_s {
     int         bytes;
     int         error;
     hio_t*      io;
+    // for recvfrom
+    struct sockaddr* addr;
+    int         addrlen;
 } hoverlapped_t;
 
 int post_acceptex(hio_t* listenio, hoverlapped_t* hovlp);

+ 2 - 6
examples/nc.c

@@ -48,12 +48,8 @@ void on_close(hio_t* io) {
     hio_del(stdinio, READ_EVENT);
 }
 
-void on_connect(hio_t* io, int state) {
-    //printf("on_connect fd=%d state=%d\n", io->fd, state);
-    if (state == 0) {
-        printf("connect failed: %d: %s\n", io->error, strerror(io->error));
-        return;
-    }
+void on_connect(hio_t* io) {
+    //printf("on_connect fd=%d\n", io->fd, state);
     if (verbose) {
         char localaddrstr[INET6_ADDRSTRLEN+16] = {0};
         char peeraddrstr[INET6_ADDRSTRLEN+16] = {0};

+ 91 - 0
examples/nmap.cpp

@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "nmap.h"
+#include "hthreadpool.h"
+
+int host_discovery_task(std::string segment, void* nmap) {
+    Nmap* hosts= (Nmap*)nmap;
+    printf("%p %s------------------------------------------------\n", nmap, segment.c_str());
+    return host_discovery(segment.c_str(), hosts);
+}
+
+int main(int argc, char* argv[]) {
+    if (argc < 2) {
+        printf("Usage: cmd segment\n");
+        printf("Examples: nmap 192.168.1.123\n");
+        printf("          nmap 192.168.1.x/24\n");
+        printf("          nmap 192.168.x.x/16\n");
+        return -1;
+    }
+
+    char* segment = argv[1];
+    char* split = strchr(segment, '/');
+    int n = 24;
+    if (split) {
+        *split = '\0';
+        n = atoi(split+1);
+        if (n != 24 && n != 16) {
+            return -2;
+        }
+    }
+
+    if (n == 24) {
+        Nmap nmap;
+        int ups = host_discovery(segment, &nmap);
+        return 0;
+    }
+
+    char ip[INET_ADDRSTRLEN];
+    if (n == 16) {
+        Nmap nmap;
+        int up_nsegs = segment_discovery(segment, &nmap);
+        if (up_nsegs == 0) return 0;
+        if (up_nsegs == 1) {
+            for (auto& pair : nmap) {
+                if (pair.second == 1) {
+                    inet_ntop(AF_INET, (void*)&pair.first, ip, sizeof(ip));
+                    Nmap hosts;
+                    return host_discovery(ip, &hosts);
+                }
+            }
+        }
+        Nmap* hosts = new Nmap[up_nsegs];
+        // use ThreadPool
+        HThreadPool tp(4);
+        tp.start();
+        std::vector<std::future<int>> futures;
+        int i = 0;
+        for (auto& pair : nmap) {
+            if (pair.second == 1) {
+                inet_ntop(AF_INET, (void*)&pair.first, ip, sizeof(ip));
+                auto future = tp.commit(host_discovery_task, std::string(ip), &hosts[i++]);
+                futures.push_back(std::move(future));
+            }
+        }
+        // wait all task done
+        int nhosts = 0;
+        for (auto& future : futures) {
+            nhosts += future.get();
+        }
+        // filter up hosts
+        std::vector<uint32_t> up_hosts;
+        for (int i = 0; i < up_nsegs; ++i) {
+            Nmap& nmap = hosts[i];
+            for (auto& host : nmap) {
+                if (host.second == 1) {
+                    up_hosts.push_back(host.first);
+                }
+            }
+        }
+        delete[] hosts;
+        // print up hosts
+        printf("Up hosts %d:\n", nhosts);
+        for (auto& host : up_hosts) {
+            inet_ntop(AF_INET, (void*)&host, ip, sizeof(ip));
+            printf("%s\n", ip);
+        }
+    }
+
+    return 0;
+}

+ 1 - 1
http/HttpParser.h

@@ -73,7 +73,7 @@ public:
         hp_userdata.init();
         hp_userdata.type = HTTP_RESPONSE;
         hp_userdata.payload = res;
-        http_parser_init(&hp_parser, HTTP_REQUEST);
+        http_parser_init(&hp_parser, HTTP_RESPONSE);
     }
 
     int execute(const char* data, size_t len) {