static int event_on_accept (struct event_data *self, struct kevent *event) { struct sockaddr client; socklen_t client_len = sizeof(client); int client_fd = accept(server_fd, &client, &client_len); int flags; int err; if (client_fd < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) return 0; on_error("Accept failed (should this be fatal?): %s\n", strerror(errno)); } flags = fcntl(client_fd, F_GETFL, 0); if (flags < 0) on_error("Could not get client socket flags: %s\n", strerror(errno)); err = fcntl(client_fd, F_SETFL, flags | O_NONBLOCK); if (err < 0) on_error("Could not set client socket to be non blocking: %s\n", strerror(errno)); struct event_data *client_data = (struct event_data *) malloc(sizeof(struct event_data)); client_data->on_read = event_on_read; client_data->on_write = event_on_write; event_change(client_fd, EVFILT_READ, EV_ADD | EV_ENABLE, client_data); event_change(client_fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, client_data); return 1; }
static int event_on_read (struct event_data *self, struct kevent *event) { if (self->buffer_read == BUFFER_SIZE) { event_change(event->ident, EVFILT_READ, EV_DISABLE, self); return 0; } int n = read(event->ident, self->buffer + self->buffer_read, BUFFER_SIZE - self->buffer_read); if (n < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) return 0; on_error("Read failed (should this be fatal?): %s\n", strerror(errno)); } if (n == 0) { free(self); close(event->ident); return 0; } if (self->buffer_read == 0) { event_change(event->ident, EVFILT_WRITE, EV_ENABLE, self); } self->buffer_read += n; return event_flush_write(self, event); }
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { jvmtiEventCallbacks *evCbs; jvmtiCapabilities caps; jvmtiEnv *jvmti; jint rc; jint jvmtiVer; agent_options = options ? strdup(options) : ""; evCbs = get_jvmti_callbacks(); memset(evCbs, 0, sizeof(*evCbs)); memset(&caps, 0, sizeof(caps)); evCbs->VMInit = cbVMInit; evCbs->VMDeath = cbVMDeath; caps.can_generate_breakpoint_events = 1; caps.can_generate_method_entry_events = 1; caps.can_generate_method_exit_events = 1; caps.can_generate_exception_events = 1; caps.can_tag_objects = 1; caps.can_get_source_file_name = 1; caps.can_get_line_numbers = 1; caps.can_access_local_variables = 1; caps.can_generate_single_step_events = 1; /* Used for line-oriented stepping */ /* caps.can_generate_frame_pop_events = 1; */ caps.can_force_early_return = 1; rc = (*jvm)->GetEnv(jvm, (void **)&jvmti, JVMTI_VERSION_1_0); if(rc < 0) { fprintf(stderr, "Failed to get JVMTI env\n"); return JNI_ERR; } Gagent.jvm = jvm; Gagent.jvmti = jvmti; Gagent.jerr = (*Gagent.jvmti)->GetVersionNumber(Gagent.jvmti, &jvmtiVer); check_jvmti_error(Gagent.jvmti, Gagent.jerr); printf("JVMTI version %d.%d.%d\n", (jvmtiVer & JVMTI_VERSION_MASK_MAJOR) >> JVMTI_VERSION_SHIFT_MAJOR, (jvmtiVer & JVMTI_VERSION_MASK_MINOR) >> JVMTI_VERSION_SHIFT_MINOR, (jvmtiVer & JVMTI_VERSION_MASK_MICRO) >> JVMTI_VERSION_SHIFT_MICRO); Gagent.jerr = (*Gagent.jvmti)->AddCapabilities(Gagent.jvmti, &caps); check_jvmti_error(Gagent.jvmti, Gagent.jerr); Gagent.jerr = (*Gagent.jvmti)->SetEventCallbacks(Gagent.jvmti, evCbs, sizeof(jvmtiEventCallbacks)); check_jvmti_error(Gagent.jvmti, Gagent.jerr); /* Check that any calls to SetEventNotificationMode are valid in the OnLoad phase before calling here. */ Gagent.jerr = event_change(Gagent.jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); check_jvmti_error(Gagent.jvmti, Gagent.jerr); Gagent.jerr = event_change(Gagent.jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL); check_jvmti_error(Gagent.jvmti, Gagent.jerr); return JNI_OK; }
static int event_on_write (struct event_data *self, struct kevent *event) { if (self->buffer_read == self->buffer_write) { event_change(event->ident, EVFILT_WRITE, EV_DISABLE, self); return 0; } return event_flush_write(self, event); }
int main (int argc, char *argv[]) { if (argc < 2) { printf("Usage: %s [socket-path]\n", argv[0]); exit(1); } struct event_data server = { .on_read = event_on_accept, .on_write = NULL }; event_server_listen(argv[1]); event_change(server_fd, EVFILT_READ, EV_ADD | EV_ENABLE, &server); event_loop(); return 0; }