int network_write_data(network_socket * s, void* data, int len, struct sockaddr * write_addr) { char * odata = (char*)data; int rv; // are we a tcp or a udp socket? // tcp we can use a nonblocking write. // udp we have to send() and block. unfortunately. :( // however, it shouldn't be a long block as the data is just copied into the os's internal buffer for the // fd. if( write_addr == NULL ) // tcp. { // this will push out as much data as possible rv = send( s->fd, odata, len, 0 ); if( rv >= 0 || errno == EAGAIN ) { // save any additional data in our buffer. int copylen = len - rv; if( copylen > 0 ) { if( s->outlen + copylen > s->outbuffer_size ) { // buffer overflow, lets treat the socket liek it was dead return -1; } // copy into the obuf memcpy(&s->outbuffer[s->outlen], &odata[rv], copylen); s->outlen += copylen; } // avoid the if trigger if 0 bytes were written (this is ok with nonblocking) rv = 1; // switch the socket to writing mode network_mod(s->fd, EVFILT_WRITE, 1); } } else // udp { rv = sendto(s->fd, odata, len, 0, write_addr, sizeof(struct sockaddr)); } // error. :( if( rv <= 0 ) { log_write(DEBUG, "send() returned %d on socket %u (%s).", rv, s->fd, write_addr ? "UDP" : "TCP"); return -1; } g_bytesSent += rv; g_bytesSentTotal += rv; // everything went ok return rv; }
int network_io_poll() { int nevents; struct kevent events[MAXEVENTS]; struct timespec timeout; int fd; int evs; int n; network_socket * s; timeout.tv_sec = 1; timeout.tv_nsec = 0; // check size if( g_maxFd == 0 ) { // just sleep, to simulate the delay usleep(SLEEPSEC * 1000000); return 0; } nevents = kevent(g_kqueue, 0, 0, events, MAXEVENTS, &timeout); if( nevents < 0 ) { // some error occured. log_write(ERROR, "FATAL: kevent() returned %d", nevents); return -1; } // no events if( nevents == 0 ) return 0; // loop each each socket and handle events on each of them for( n = 0; n < nevents; ++n ) { fd = events[n].ident; evs = events[n].filter; s = g_fds[fd]; if( s != NULL ) { if( events[n].flags & EV_EOF || events[n].flags & EV_ERROR ) { if( s->event_handler(s, IOEVENT_ERROR) != 0 ) { network_close(s); continue; } } else { if( evs & EVFILT_READ ) { if( s->event_handler(s, IOEVENT_READ) != 0 ) { network_close(s); continue; } } if( evs & EVFILT_WRITE ) { if( s->write_handler(s, IOEVENT_WRITE) != 0 ) { network_close(s); continue; } else { // any data left? if( s->outlen == 0 ) { // all data written, switch back to read mode network_mod(s->fd, EVFILT_READ, 0); } else { // still data left, reset write event network_mod(s->fd, EVFILT_WRITE, 1); } // don't have to do anything } } } } } // no errors return 0; }
int network_io_poll() { int nevents; struct epoll_event events[MAXEVENTS]; int fd; int evs; int n; network_socket * s; // check size if( g_maxFd == 0 ) { // just sleep, to simulate the delay usleep(SLEEPSEC * 1000000); return 0; } // use our blocking epoll() nevents = epoll_wait(g_epoll, events, MAXEVENTS, 1000); if( nevents < 0 ) { // some error occured. log_write(ERROR, "FATAL: epoll_wait() returned %d", nevents); return -1; } // no events if( nevents == 0 ) return 0; // loop each each socket and handle events on each of them for( n = 0; n < nevents; ++n ) { fd = events[n].data.fd; evs = events[n].events; s = g_fds[fd]; if( s != NULL ) { if( evs & EPOLLHUP || evs & EPOLLERR ) { if( s->event_handler(s, IOEVENT_ERROR) != 0 ) { network_close(s); continue; } } else { if( evs & EPOLLIN ) { if( s->event_handler(s, IOEVENT_READ) != 0 ) { network_close(s); continue; } } if( evs & EPOLLOUT ) { if( s->write_handler(s, IOEVENT_WRITE) != 0 ) { network_close(s); continue; } else { // any data left? if( s->outlen == 0 ) { // all data written, switch back to read mode network_mod(s->fd, EPOLLIN); } // don't have to do anything } } } } } // no errors return 0; }