#define EFL_NET_SOCKET_WINDOWS_PROTECTED 1 #define EFL_IO_READER_PROTECTED 1 #define EFL_IO_WRITER_PROTECTED 1 #define EFL_IO_CLOSER_PROTECTED 1 #define EFL_NET_SOCKET_PROTECTED 1 #ifdef HAVE_CONFIG_H # include #endif #include "Ecore.h" #include "Ecore_Con.h" #include "ecore_con_private.h" #define MY_CLASS EFL_NET_SOCKET_WINDOWS_CLASS #define BUFFER_SIZE (4 * 4096) typedef struct _Efl_Net_Socket_Windows_Data { Eina_Stringshare *address_local; Eina_Stringshare *address_remote; Eina_List *pending_ops; struct { union { uint8_t *bytes; void *mem; }; DWORD len; DWORD used; DWORD base; Efl_Net_Socket_Windows_Operation *pending; } recv; struct { union { uint8_t *bytes; void *mem; }; DWORD len; DWORD used; Efl_Net_Socket_Windows_Operation *pending; } send; HANDLE handle; Eina_Bool can_read; Eina_Bool eos; Eina_Bool pending_eos; Eina_Bool can_write; Eina_Bool io_started; Eina_Bool close_on_exec; Eina_Bool close_on_destructor; } Efl_Net_Socket_Windows_Data; struct _Efl_Net_Socket_Windows_Operation { OVERLAPPED base; Efl_Net_Socket_Windows_Operation_Success_Cb success_cb; Efl_Net_Socket_Windows_Operation_Failure_Cb failure_cb; const void *data; Ecore_Win32_Handler *event_handler; Eo *o; Eina_Bool deleting; }; /* * differences to evil_format_message(): * - shorter string * - no newline * - fallback to error code if format fails */ char * _efl_net_windows_error_msg_get(DWORD win32err) { LPTSTR msg; char *str; char *disp; int len, reqlen; if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, win32err, 0, /* Default language */ (LPTSTR)&msg, 0, NULL)) goto fallback; #ifdef UNICODE str = evil_wchar_to_char(msg); #else str = msg; #endif /* UNICODE */ len = strlen(str); if ((len > 0) && (str[len - 1] == '\n')) str[--len] = '\0'; if ((len > 0) && (str[len - 1] == '\r')) str[--len] = '\0'; if ((len > 0) && (str[len - 1] == '.')) str[--len] = '\0'; reqlen = snprintf("", 0, "%lu(%s)", win32err, str); if (reqlen < 1) goto error; disp = malloc(reqlen + 1); if (!disp) goto error; snprintf(disp, reqlen + 1, "%lu(%s)", win32err, str); #ifdef UNICODE free(str); #endif /* UNICODE */ LocalFree(msg); return disp; error: #ifdef UNICODE free(str); #endif /* UNICODE */ LocalFree(msg); fallback: { char buf[64]; snprintf(buf, sizeof(buf), "%ld", win32err); return strdup(buf); } } static void _efl_net_socket_windows_handle_close(HANDLE h) { if (!FlushFileBuffers(h)) { DWORD win32err = GetLastError(); if (win32err != ERROR_PIPE_NOT_CONNECTED) { char *msg = _efl_net_windows_error_msg_get(GetLastError()); WRN("HANDLE=%p could not flush buffers: %s", h, msg); free(msg); } } if (!DisconnectNamedPipe(h)) { DWORD win32err = GetLastError(); if ((win32err != ERROR_NOT_SUPPORTED) && /* dialer socket don't support it */ (win32err != ERROR_PIPE_NOT_CONNECTED)) { char *msg = _efl_net_windows_error_msg_get(win32err); WRN("HANDLE=%p could not disconnect: %s", h, msg); free(msg); } } CloseHandle(h); DBG("HANDLE=%p closed", h); } static Eina_Bool _efl_net_socket_windows_operation_event(void *, Ecore_Win32_Handler *wh); Efl_Net_Socket_Windows_Operation * _efl_net_socket_windows_operation_new(Eo *o, Efl_Net_Socket_Windows_Operation_Success_Cb success_cb, Efl_Net_Socket_Windows_Operation_Failure_Cb failure_cb, const void *data) { Efl_Net_Socket_Windows_Operation *op; Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, EFL_NET_SOCKET_WINDOWS_CLASS); EINA_SAFETY_ON_NULL_RETURN_VAL(pd, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(success_cb, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(failure_cb, NULL); op = calloc(1, sizeof(*op)); EINA_SAFETY_ON_NULL_RETURN_VAL(op, NULL); op->base.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!op->base.hEvent) { char *msg = _efl_net_windows_error_msg_get(GetLastError()); ERR("socket=%p success_cb=%p failure_cb=%p data=%p: error=%s", op->o, op->success_cb, op->failure_cb, op->data, msg); free(msg); goto error_event; } op->event_handler = ecore_main_win32_handler_add(op->base.hEvent, _efl_net_socket_windows_operation_event, op); if (!op->event_handler) { ERR("socket=%p success_cb=%p failure_cb=%p data=%p: could not create event handler", op->o, op->success_cb, op->failure_cb, op->data); goto error_handler; } op->success_cb = success_cb; op->failure_cb = failure_cb; op->data = data; op->o = o; pd->pending_ops = eina_list_append(pd->pending_ops, op); DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p", op, op->o, op->success_cb, op->failure_cb, op->data); return op; error_handler: CloseHandle(op->base.hEvent); error_event: free(op); return NULL; } static Eina_Error _efl_net_socket_windows_operation_done(Efl_Net_Socket_Windows_Operation *op, DWORD win32err, DWORD used_size) { Efl_Net_Socket_Windows_Data *pd; Eina_Error err = 0; if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p error=%s used_size=%lu", op, op->o, op->success_cb, op->failure_cb, op->data, msg, used_size); free(msg); } op->deleting = EINA_TRUE; efl_ref(op->o); pd = efl_data_scope_get(op->o, EFL_NET_SOCKET_WINDOWS_CLASS); if (pd) pd->pending_ops = eina_list_remove(pd->pending_ops, op); if (win32err) err = op->failure_cb((void *)op->data, op->o, win32err); else op->success_cb((void *)op->data, op->o, used_size); if (op->event_handler) { if (WaitForSingleObject(pd->handle, 0) != WAIT_OBJECT_0) { DWORD used_size = 0; if (GetOverlappedResult(pd->handle, &op->base, &used_size, FALSE)) { DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p GetOverlappedResult(%p, %p, &size=%lu, FALSE)", op, op->o, op->success_cb, op->failure_cb, op->data, pd->handle, &op->base, used_size); } else { win32err = GetLastError(); if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p GetOverlappedResult(%p, %p, &size=%lu, TRUE)=%s", op, op->o, op->success_cb, op->failure_cb, op->data, pd->handle, &op->base, used_size, msg); free(msg); } if (win32err == ERROR_IO_INCOMPLETE) { DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p: still pending I/O...", op, op->o, op->success_cb, op->failure_cb, op->data); efl_unref(op->o); op->o = NULL; return 0; } } } ecore_main_win32_handler_del(op->event_handler); } #ifndef ERROR_HANDLES_CLOSED #define ERROR_HANDLES_CLOSED 676 #endif if ((win32err == ERROR_HANDLES_CLOSED) && !efl_io_closer_closed_get(op->o)) efl_io_closer_close(op->o); efl_unref(op->o); CloseHandle(op->base.hEvent); free(op); return err; } Eina_Error _efl_net_socket_windows_operation_failed(Efl_Net_Socket_Windows_Operation *op, DWORD win32err) { EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINVAL); EINA_SAFETY_ON_TRUE_RETURN_VAL(op->deleting, EINVAL); return _efl_net_socket_windows_operation_done(op, win32err, 0); } Eina_Error _efl_net_socket_windows_operation_succeeded(Efl_Net_Socket_Windows_Operation *op, DWORD used_size) { EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINVAL); EINA_SAFETY_ON_TRUE_RETURN_VAL(op->deleting, EINVAL); return _efl_net_socket_windows_operation_done(op, 0, used_size); } static Eina_Bool _efl_net_socket_windows_operation_event(void *data, Ecore_Win32_Handler *wh EINA_UNUSED) { Efl_Net_Socket_Windows_Operation *op = data; HANDLE h = _efl_net_socket_windows_handle_get(op->o); DWORD used_size = 0; if ((op->deleting) || (h == INVALID_HANDLE_VALUE)) { DBG("op=%p was deleted and pending I/O completed!", op); CloseHandle(op->base.hEvent); free(op); return ECORE_CALLBACK_CANCEL; } op->event_handler = NULL; if (GetOverlappedResult(h, &op->base, &used_size, FALSE)) { DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p GetOverlappedResult(%p, %p, &size=%lu, FALSE)", op, op->o, op->success_cb, op->failure_cb, op->data, h, &op->base, used_size); _efl_net_socket_windows_operation_succeeded(op, used_size); } else { DWORD win32err = GetLastError(); if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p GetOverlappedResult(%p, %p, &size=%lu, FALSE)=%s", op, op->o, op->success_cb, op->failure_cb, op->data, h, &op->base, used_size, msg); free(msg); } _efl_net_socket_windows_operation_failed(op, win32err); } return ECORE_CALLBACK_CANCEL; } Eina_Error _efl_net_socket_windows_init(Eo *o, HANDLE h) { Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS); EINA_SAFETY_ON_TRUE_RETURN_VAL(h == INVALID_HANDLE_VALUE, EINVAL); EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINVAL); EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->handle != INVALID_HANDLE_VALUE, EALREADY); pd->handle = h; DBG("socket=%p adopted handle=%p", o, h); return 0; } static Eina_Error _efl_net_socket_windows_recv(Eo *o, Efl_Net_Socket_Windows_Data *pd); static Eina_Error _efl_net_socket_windows_recv_success(void *data EINA_UNUSED, Eo *o, DWORD used_size) { Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS); EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINVAL); pd->recv.pending = NULL; EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->recv.used + used_size > pd->recv.len, EINVAL); pd->recv.used += used_size; /* calls back the user, may read()/write()/close() */ efl_io_reader_can_read_set(o, pd->recv.used > 0); if (pd->handle == INVALID_HANDLE_VALUE) return 0; if (pd->recv.used == pd->recv.len) return 0; if (pd->recv.pending) return 0; return _efl_net_socket_windows_recv(o, pd); } static Eina_Error _efl_net_socket_windows_recv_failure(void *data EINA_UNUSED, Eo *o, DWORD win32err) { Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS); if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("socket=%p recv error=%s", o, msg); free(msg); } pd->recv.pending = NULL; if (pd->recv.used > 0) pd->pending_eos = EINA_TRUE; /* eos when buffer drains */ else { efl_io_writer_can_write_set(o, EINA_FALSE); efl_io_reader_can_read_set(o, EINA_FALSE); efl_io_reader_eos_set(o, EINA_TRUE); } switch (win32err) { case ERROR_INVALID_USER_BUFFER: return EFAULT; case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; case ERROR_OPERATION_ABORTED: return ECANCELED; case ERROR_BROKEN_PIPE: return EPIPE; default: return EIO; } } static Eina_Error _efl_net_socket_windows_recv(Eo *o, Efl_Net_Socket_Windows_Data *pd) { Efl_Net_Socket_Windows_Operation *op; OVERLAPPED *ovl; DWORD used_size = 0, win32err; BOOL r; EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->recv.pending != NULL, EINPROGRESS); if (pd->handle == INVALID_HANDLE_VALUE) return EBADF; if (pd->recv.len == 0) return ENOMEM; if (pd->recv.base > 0) { DWORD todo = pd->recv.used - pd->recv.base; if (todo > 0) memmove(pd->recv.bytes, pd->recv.bytes + pd->recv.base, todo); pd->recv.used -= pd->recv.base; pd->recv.base = 0; } if (pd->recv.used == pd->recv.len) return ENOSPC; op = _efl_net_socket_windows_operation_new(o, _efl_net_socket_windows_recv_success, _efl_net_socket_windows_recv_failure, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINVAL); ovl = _efl_net_socket_windows_operation_overlapped_get(op); r = ReadFile(pd->handle, pd->recv.bytes + pd->recv.used, pd->recv.len - pd->recv.used, &used_size, ovl); win32err = GetLastError(); if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("socket=%p ReadFile(%p, %p, %lu, &size=%lu, %p)=%s", o, pd->handle, pd->recv.bytes + pd->recv.used, pd->recv.len - pd->recv.used, used_size, ovl, msg); free(msg); } if (!r) { if (win32err == ERROR_IO_PENDING) { pd->recv.pending = op; return 0; } else { return _efl_net_socket_windows_operation_failed(op, win32err); } } return _efl_net_socket_windows_operation_succeeded(op, used_size); } static Eina_Error _efl_net_socket_windows_send(Eo *o, Efl_Net_Socket_Windows_Data *pd); static Eina_Error _efl_net_socket_windows_send_success(void *data EINA_UNUSED, Eo *o, DWORD used_size) { Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS); EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINVAL); pd->send.pending = NULL; EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->send.used < used_size, EINVAL); if (used_size > 0) { DWORD todo = pd->send.used - used_size; if (todo > 0) memmove(pd->send.bytes, pd->send.bytes + used_size, todo); pd->send.used -= used_size; } /* calls back the user, may read()/write()/close() */ /* only can_write if we're fully done with previous request! */ efl_io_writer_can_write_set(o, pd->send.used == 0); if (pd->handle == INVALID_HANDLE_VALUE) return 0; if (pd->send.used == 0) return 0; if (pd->send.pending) return 0; return _efl_net_socket_windows_send(o, pd); } static Eina_Error _efl_net_socket_windows_send_failure(void *data EINA_UNUSED, Eo *o, DWORD win32err) { Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS); EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINVAL); if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("socket=%p send error=%s", o, msg); free(msg); } pd->send.pending = NULL; efl_io_writer_can_write_set(o, EINA_FALSE); if (pd->recv.used > 0) pd->pending_eos = EINA_TRUE; /* eos when buffer drains */ else { efl_io_reader_can_read_set(o, EINA_FALSE); efl_io_reader_eos_set(o, EINA_TRUE); } switch (win32err) { case ERROR_INVALID_USER_BUFFER: return EFAULT; case ERROR_NOT_ENOUGH_MEMORY: return ENOMEM; case ERROR_OPERATION_ABORTED: return ECANCELED; case ERROR_BROKEN_PIPE: return EPIPE; default: return EIO; } } static Eina_Error _efl_net_socket_windows_send(Eo *o, Efl_Net_Socket_Windows_Data *pd) { Efl_Net_Socket_Windows_Operation *op; OVERLAPPED *ovl; DWORD used_size = 0, win32err; BOOL r; EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->send.pending != NULL, EINPROGRESS); if (pd->handle == INVALID_HANDLE_VALUE) return EBADF; if (pd->send.used == 0) return 0; op = _efl_net_socket_windows_operation_new(o, _efl_net_socket_windows_send_success, _efl_net_socket_windows_send_failure, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(op, EINVAL); ovl = _efl_net_socket_windows_operation_overlapped_get(op); r = WriteFile(pd->handle, pd->send.bytes, pd->send.used, &used_size, ovl); win32err = GetLastError(); if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("socket=%p WriteFile(%p, %p, %lu, &size=%lu, %p)=%s", o, pd->handle, pd->send.bytes, pd->send.used, used_size, ovl, msg); free(msg); } if (!r) { if (win32err == ERROR_IO_PENDING) { pd->send.pending = op; return 0; } else { return _efl_net_socket_windows_operation_failed(op, win32err); } } return _efl_net_socket_windows_operation_succeeded(op, used_size); } Eina_Error _efl_net_socket_windows_io_start(Eo *o) { Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS); Eina_Error err; EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINVAL); EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->io_started, EALREADY); if (!pd->recv.mem) { pd->recv.mem = malloc(BUFFER_SIZE); EINA_SAFETY_ON_NULL_RETURN_VAL(pd->recv.mem, ENOMEM); pd->recv.len = BUFFER_SIZE; pd->recv.used = 0; } if (!pd->send.mem) { pd->send.mem = malloc(BUFFER_SIZE); EINA_SAFETY_ON_NULL_RETURN_VAL(pd->send.mem, ENOMEM); pd->send.len = BUFFER_SIZE; pd->send.used = 0; } DBG("socket=%p starting I/O...", o); err = _efl_net_socket_windows_recv(o, pd); if (err) return err; efl_io_writer_can_write_set(o, EINA_TRUE); pd->io_started = EINA_TRUE; return 0; } HANDLE _efl_net_socket_windows_handle_get(const Eo *o) { Efl_Net_Socket_Windows_Data *pd = efl_data_scope_get(o, MY_CLASS); EINA_SAFETY_ON_NULL_RETURN_VAL(pd, INVALID_HANDLE_VALUE); return pd->handle; } EOLIAN static Eo * _efl_net_socket_windows_efl_object_constructor(Eo *o, Efl_Net_Socket_Windows_Data *pd) { pd->handle = INVALID_HANDLE_VALUE; return efl_constructor(efl_super(o, MY_CLASS)); } EOLIAN static void _efl_net_socket_windows_efl_object_destructor(Eo *o, Efl_Net_Socket_Windows_Data *pd) { if (efl_io_closer_close_on_destructor_get(o) && (!efl_io_closer_closed_get(o))) { efl_event_freeze(o); efl_io_closer_close(o); efl_event_thaw(o); } efl_destructor(efl_super(o, MY_CLASS)); eina_stringshare_replace(&pd->address_local, NULL); eina_stringshare_replace(&pd->address_remote, NULL); free(pd->recv.mem); pd->recv.mem = NULL; pd->recv.len = 0; pd->recv.used = 0; pd->recv.base = 0; free(pd->send.mem); pd->send.mem = NULL; pd->send.len = 0; pd->send.used = 0; } EOLIAN static Eina_Error _efl_net_socket_windows_efl_io_closer_close(Eo *o, Efl_Net_Socket_Windows_Data *pd) { HANDLE h; EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(o), EBADF); DBG("socket=%p closing handle=%p", o, pd->handle); if (pd->pending_ops) { if (pd->send.pending) { Efl_Net_Socket_Windows_Operation *op = pd->send.pending; DWORD used_size = 0; DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p: wait %lu bytes pending write...", op, op->o, op->success_cb, op->failure_cb, op->data, pd->send.used); if (GetOverlappedResult(pd->handle, &op->base, &used_size, TRUE)) { DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p GetOverlappedResult(%p, %p, &size=%lu, TRUE)", op, op->o, op->success_cb, op->failure_cb, op->data, pd->handle, &op->base, used_size); } else { DWORD win32err = GetLastError(); if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(win32err); DBG("op=%p (socket=%p) success_cb=%p failure_cb=%p data=%p GetOverlappedResult(%p, %p, &size=%lu, TRUE)=%s", op, op->o, op->success_cb, op->failure_cb, op->data, pd->handle, &op->base, used_size, msg); free(msg); } } } if (!FlushFileBuffers(pd->handle)) { char *msg = _efl_net_windows_error_msg_get(GetLastError()); WRN("HANDLE=%p could not flush buffers: %s", pd->handle, msg); free(msg); } if (CancelIo(pd->handle)) DBG("socket=%p CancelIo(%p)", o, pd->handle); else if (eina_log_domain_level_check(_ecore_con_log_dom, EINA_LOG_LEVEL_DBG)) { char *msg = _efl_net_windows_error_msg_get(GetLastError()); WRN("socket=%p CancelIo(%p)=%s", o, pd->handle, msg); free(msg); } } while (pd->pending_ops) _efl_net_socket_windows_operation_failed(pd->pending_ops->data, ERROR_OPERATION_ABORTED); efl_io_writer_can_write_set(o, EINA_FALSE); efl_io_reader_can_read_set(o, EINA_FALSE); efl_io_reader_eos_set(o, EINA_TRUE); h = InterlockedExchangePointer(&pd->handle, INVALID_HANDLE_VALUE); if (h != INVALID_HANDLE_VALUE) _efl_net_socket_windows_handle_close(h); efl_event_callback_call(o, EFL_IO_CLOSER_EVENT_CLOSED, NULL); return 0; } EOLIAN static Eina_Bool _efl_net_socket_windows_efl_io_closer_closed_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->handle == INVALID_HANDLE_VALUE; } EOLIAN static Eina_Bool _efl_net_socket_windows_efl_io_closer_close_on_exec_set(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd, Eina_Bool close_on_exec) { DBG("close on exec is not supported on windows"); pd->close_on_exec = close_on_exec; return EINA_FALSE; } EOLIAN static Eina_Bool _efl_net_socket_windows_efl_io_closer_close_on_exec_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->close_on_exec; } EOLIAN static void _efl_net_socket_windows_efl_io_closer_close_on_destructor_set(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd, Eina_Bool close_on_destructor) { pd->close_on_destructor = close_on_destructor; } EOLIAN static Eina_Bool _efl_net_socket_windows_efl_io_closer_close_on_destructor_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->close_on_destructor; } EOLIAN static Eina_Error _efl_net_socket_windows_efl_io_reader_read(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Rw_Slice *rw_slice) { Eina_Slice ro_slice; DWORD remaining; EINA_SAFETY_ON_NULL_RETURN_VAL(rw_slice, EINVAL); EINA_SAFETY_ON_TRUE_RETURN_VAL(pd->recv.base > pd->recv.used, EINVAL); ro_slice.len = pd->recv.used - pd->recv.base; if (ro_slice.len == 0) { rw_slice->len = 0; if (pd->pending_eos) { efl_io_reader_eos_set(o, EINA_TRUE); return 0; } return EAGAIN; } ro_slice.bytes = pd->recv.bytes + pd->recv.base; *rw_slice = eina_rw_slice_copy(*rw_slice, ro_slice); pd->recv.base += rw_slice->len; remaining = pd->recv.used - pd->recv.base; efl_io_reader_can_read_set(o, remaining > 0); if ((pd->pending_eos) && (remaining == 0)) { efl_io_reader_eos_set(o, EINA_TRUE); return 0; } if (!pd->recv.pending) { DBG("recv more from socket=%p", o); _efl_net_socket_windows_recv(o, pd); return 0; } return 0; } EOLIAN static void _efl_net_socket_windows_efl_io_reader_can_read_set(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Bool can_read) { EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o) && can_read); if (pd->can_read == can_read) return; pd->can_read = can_read; efl_event_callback_call(o, EFL_IO_READER_EVENT_CAN_READ_CHANGED, NULL); } EOLIAN static Eina_Bool _efl_net_socket_windows_efl_io_reader_can_read_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->can_read; } EOLIAN static void _efl_net_socket_windows_efl_io_reader_eos_set(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Bool is_eos) { if (pd->eos == is_eos) return; pd->eos = is_eos; if (is_eos) efl_event_callback_call(o, EFL_IO_READER_EVENT_EOS, NULL); } EOLIAN static Eina_Bool _efl_net_socket_windows_efl_io_reader_eos_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->eos; } EOLIAN static Eina_Error _efl_net_socket_windows_efl_io_writer_write(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Slice *slice, Eina_Slice *remaining) { Eina_Error err = EINVAL; DWORD available, todo; EINA_SAFETY_ON_NULL_RETURN_VAL(slice, EINVAL); EINA_SAFETY_ON_NULL_GOTO(slice->mem, error); EINA_SAFETY_ON_TRUE_GOTO(efl_io_closer_closed_get(o), error); err = ENOMEM; EINA_SAFETY_ON_NULL_GOTO(pd->send.mem, error); /* note: do not queue more data if one is already pending, * otherwise we over-commit a lot and on write() -> close(), it * would take us more than simply waiting on the pending send to * complete. */ if (pd->send.pending) { efl_io_writer_can_write_set(o, EINA_FALSE); err = EAGAIN; goto error; } err = EINVAL; EINA_SAFETY_ON_TRUE_GOTO(pd->send.used != 0, error); available = pd->send.len - pd->send.used; if (slice->len < available) todo = slice->len; else todo = available; memcpy(pd->send.bytes + pd->send.used, slice->mem, todo); if (remaining) { remaining->len = slice->len - todo; remaining->bytes = slice->bytes + todo; } slice->len = todo; pd->send.used += todo; efl_io_writer_can_write_set(o, EINA_FALSE); DBG("send %lu bytes more to socket=%p", pd->send.used, o); return _efl_net_socket_windows_send(o, pd); error: if (remaining) *remaining = *slice; slice->len = 0; slice->mem = NULL; return err; } EOLIAN static void _efl_net_socket_windows_efl_io_writer_can_write_set(Eo *o, Efl_Net_Socket_Windows_Data *pd, Eina_Bool can_write) { EINA_SAFETY_ON_TRUE_RETURN(efl_io_closer_closed_get(o) && can_write); if (pd->can_write == can_write) return; pd->can_write = can_write; efl_event_callback_call(o, EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, NULL); } EOLIAN static Eina_Bool _efl_net_socket_windows_efl_io_writer_can_write_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->can_write; } EOLIAN static void _efl_net_socket_windows_efl_net_socket_address_local_set(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd, const char *address) { eina_stringshare_replace(&pd->address_local, address); } EOLIAN static const char * _efl_net_socket_windows_efl_net_socket_address_local_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->address_local; } EOLIAN static void _efl_net_socket_windows_efl_net_socket_address_remote_set(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd, const char *address) { eina_stringshare_replace(&pd->address_remote, address); } EOLIAN static const char * _efl_net_socket_windows_efl_net_socket_address_remote_get(Eo *o EINA_UNUSED, Efl_Net_Socket_Windows_Data *pd) { return pd->address_remote; } #include "efl_net_socket_windows.eo.c"