/* not del list,just detach it from one link list */ void mempool_detach_list(struct list_head *del_head,struct list_head *hl_head) { cds_mempool_head_list_t *head_list; cds_mempool_t *mempool_list; dbg_str(DBG_ALLOC_DETAIL,"mempool_detach_list"); head_list = container_of(hl_head,cds_mempool_head_list_t,list_head); /* *pthread_rwlock_wrlock(&head_list->head_lock); */ sync_lock(&head_list->head_lock,NULL); /* *dbg_str(DBG_ALLOC_DETAIL,"mempool del head:%p, hl_head:%p",del_head,hl_head); *dbg_str(DBG_ALLOC_DETAIL,"mempool del heads next:%p, prev:%p",del_head->next,del_head->prev); */ list_del(del_head); head_list->count--; mempool_list = container_of(del_head,cds_mempool_t,list_head); sync_unlock(&head_list->head_lock); /* *pthread_rwlock_unlock(&head_list->head_lock); */ dbg_str(DBG_ALLOC_DETAIL,"del_mempool list,list count =%d",head_list->count); }
int vector_push_back(vector_t *vector,void *data) { uint32_t data_size = vector->data_size; void *vector_head = vector->vector_head; uint32_t step = vector->step; uint32_t capacity = vector->capacity; uint32_t push_pos = vector->end.vector_pos; sync_lock(&vector->vector_lock,NULL); if(push_pos < capacity){ memcpy(vector_head + (push_pos++)*step,data,data_size); vector_pos_init(&vector->end,push_pos,vector); }else{ dbg_str(DBG_CONTAINER_WARNNING,"realloc mem"); vector->vector_head = allocator_mem_alloc( vector->allocator, 2*capacity * (vector->step)); if(vector->vector_head == NULL){ dbg_str(DBG_CONTAINER_ERROR,"vector_push_back,realloc mem"); } vector->capacity = 2*capacity; memcpy(vector->vector_head,vector_head,capacity*step); memcpy(vector->vector_head + (push_pos++)*step,data,data_size); vector_pos_init(&vector->end,push_pos,vector); allocator_mem_free(vector->allocator,vector_head); } sync_unlock(&vector->vector_lock); dbg_str(DBG_CONTAINER_DETAIL,"vector_push_back,push_pos=%d,capacity=%d",push_pos,vector->capacity); return 0; }
int zmq::socket_base_t::setsockopt (int option_, const void *optval_, size_t optvallen_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); if (!options.is_valid(option_)) { errno = EINVAL; return -1; } if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // First, check whether specific socket type overloads the option. int rc = xsetsockopt (option_, optval_, optvallen_); if (rc == 0 || errno != EINVAL) { return rc; } // If the socket type doesn't support the option, pass it to // the generic option parser. rc = options.setsockopt (option_, optval_, optvallen_); update_pipe_options(option_); return rc; }
void zmq::socket_base_t::start_reaping (poller_t *poller_) { // Plug the socket to the reaper thread. poller = poller_; fd_t fd; if (!thread_safe) fd = ((mailbox_t*)mailbox)->get_fd(); else { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); reaper_signaler = new signaler_t(); // Add signaler to the safe mailbox fd = reaper_signaler->get_fd(); ((mailbox_safe_t*)mailbox)->add_signaler(reaper_signaler); // Send a signal to make sure reaper handle existing commands reaper_signaler->send(); } handle = poller->add_fd (fd, this); poller->set_pollin (handle); // Initialise the termination and check whether it can be deallocated // immediately. terminate (); check_destroy (); }
int zmq::socket_base_t::leave (const char* group_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); int rc = xleave (group_); return rc; }
void vfs_user_remount(void) { sync_lock(); // Only start a remount if in the connected state and not in a transition if (!changing_state() && (VFS_USER_STATE_CONNECTED == vfs_state)) { vfs_state_next = VFS_USER_STATE_RECONNECTING; vfs_state_remaining_ms = disconnect_delay_ms; } sync_unlock(); }
void vfs_mngr_fs_remount(void) { sync_lock(); // Only start a remount if in the connected state and not in a transition if (!changing_state() && (VFS_MNGR_STATE_CONNECTED == vfs_state)) { vfs_state_next = VFS_MNGR_STATE_RECONNECTING; } sync_unlock(); }
int zmq::socket_base_t::remove_signaler(signaler_t *s_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); if (!thread_safe) { errno = EINVAL; return -1; } ((mailbox_safe_t*)mailbox)->remove_signaler(s_); return 0; }
void vfs_mngr_fs_enable(bool enable) { sync_lock(); if (enable) { if (VFS_MNGR_STATE_DISCONNECTED == vfs_state_next) { vfs_state_next = VFS_MNGR_STATE_CONNECTED; } } else { vfs_state_next = VFS_MNGR_STATE_DISCONNECTED; } sync_unlock(); }
// Rebuild the virtual filesystem. This must only be called // when mass storage is inactive. void vfs_user_enable(bool enable) { sync_lock(); if (enable) { if (VFS_USER_STATE_DISCONNECTED == vfs_state_next) { vfs_state_remaining_ms = connect_delay_ms; vfs_state_next = VFS_USER_STATE_CONNECTED; } } else { vfs_state_remaining_ms = disconnect_delay_ms; vfs_state_next = VFS_USER_STATE_DISCONNECTED; } sync_unlock(); }
void * vector_get(vector_t *vector,int index) { uint32_t get_pos = index; uint8_t *vector_head = vector->vector_head; uint32_t step = vector->step; void * ret = NULL; dbg_str(DBG_CONTAINER_DETAIL,"get_pos=%d",get_pos); sync_lock(&vector->vector_lock,NULL); ret = (vector_head + get_pos * step); sync_unlock(&vector->vector_lock); return ret; }
int vector_pop_back(vector_t *vector) { uint32_t pop_pos = vector->end.vector_pos; dbg_str(DBG_CONTAINER_DETAIL,"pop back"); sync_lock(&vector->vector_lock,NULL); if(!vector_pos_equal(&vector->begin,&vector->end)){ vector_pos_init(&vector->end,--pop_pos,vector); } else{ dbg_str(DBG_CONTAINER_WARNNING,"vector is NULL"); } sync_unlock(&vector->vector_lock); return 0; }
void zmq::socket_base_t::in_event () { // This function is invoked only once the socket is running in the context // of the reaper thread. Process any commands from other threads/sockets // that may be available at the moment. Ultimately, the socket will // be destroyed. { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); // If the socket is thread safe we need to unsignal the reaper signaler if (thread_safe) reaper_signaler->recv(); process_commands (0, false); } check_destroy(); }
void mempool_print_list_for_each(struct list_head *hl_head) { cds_mempool_head_list_t *head_list; cds_mempool_t *mempool_list; struct list_head *pos,*n; mempool_print_head_list(hl_head); head_list = container_of(hl_head,cds_mempool_head_list_t,list_head); /* *pthread_rwlock_rdlock(&head_list->head_lock); */ sync_lock(&head_list->head_lock,NULL); list_for_each_safe(pos, n, hl_head) { mempool_list = container_of(pos,cds_mempool_t,list_head); mempool_print_list(mempool_list); }
int vector_set(vector_t *vector,int index,void *data) { uint32_t set_pos = index; uint32_t end_pos = vector->end.vector_pos; void *vector_head = vector->vector_head; uint32_t step = vector->step; int ret = 0; dbg_str(DBG_CONTAINER_DETAIL,"set_pos=%d",set_pos); sync_lock(&vector->vector_lock,NULL); memcpy(vector_head + set_pos * step,data,step); if(set_pos > end_pos){ vector_pos_init(&vector->end,set_pos,vector); } sync_unlock(&vector->vector_lock); return ret; }
int zmq::socket_base_t::close () { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); // Remove all existing signalers for thread safe sockets if (thread_safe) ((mailbox_safe_t*)mailbox)->clear_signalers(); // Mark the socket as dead tag = 0xdeadbeef; // Transfer the ownership of the socket from this application thread // to the reaper thread which will take care of the rest of shutdown // process. send_reap (this); return 0; }
int vector_insert(vector_t *vector, vector_pos_t *it, void *data) { uint32_t insert_pos = it->vector_pos; uint32_t end_pos = vector->end.vector_pos; uint32_t count = end_pos - insert_pos; void *vector_head = vector->vector_head; uint32_t step = vector->step; vector_pos_t to; vector_pos_init(&to,insert_pos + 1,vector); dbg_str(DBG_CONTAINER_DETAIL,"insert_pos=%d,to_pos=%d",insert_pos,to.vector_pos); sync_lock(&vector->vector_lock,NULL); vector_copy(vector,&to,it,count); memcpy(vector_head + insert_pos * step,data,step); vector_pos_init(&vector->end,end_pos + 1,vector); sync_unlock(&vector->vector_lock); return 0; }
int vector_delete(vector_t *vector, vector_pos_t *it) { uint32_t delete_pos = it->vector_pos; uint32_t end_pos = vector->end.vector_pos; uint32_t count = end_pos - delete_pos; vector_pos_t from; vector_pos_init(&from,delete_pos + 1,vector); sync_lock(&vector->vector_lock,0); if(vector_pos_equal(it,&vector->end)){ dbg_str(DBG_CONTAINER_WARNNING,"can't del end pos"); }else if(vector_pos_equal(it,&vector->begin)&&vector_pos_equal(&from,&vector->end)){ dbg_str(DBG_CONTAINER_WARNNING,"vector is NULL"); }else{ vector_copy(vector,it,&from,count); vector_pos_init(&vector->end,end_pos - 1,vector); } sync_unlock(&vector->vector_lock); return 0; }
void mempool_attach_list(struct list_head *new_head,struct list_head *hl_head) { cds_mempool_head_list_t *head_list; head_list = container_of(hl_head,cds_mempool_head_list_t,list_head); sync_lock(&head_list->head_lock,NULL); /* *pthread_rwlock_wrlock(&head_list->head_lock); */ list_add(new_head,hl_head); head_list->count++; sync_unlock(&head_list->head_lock); /* *pthread_rwlock_unlock(&head_list->head_lock); */ /* *dbg_str(DBG_ALLOC_DETAIL,"add head:%p hl_head:%p",new_head,hl_head); *dbg_str(DBG_ALLOC_DETAIL,"new heads next:%p, prev:%p",new_head->next,new_head->prev); *dbg_str(DBG_ALLOC_DETAIL,"add mempool list,list count =%d",head_list->count); */ }
int log_print_print_str_vl(debugger_t *debugger,size_t level,const char *fmt,va_list vl) { #define MAX_LOG_PRINT_BUFFER_LEN 1024*4 char buffer_str[MAX_LOG_PRINT_BUFFER_LEN]; size_t ret = 0,offset = 0; debug_log_prive_t *log_priv = &debugger->priv.log; level = 0; /* *pthread_mutex_t *lock = &log_priv->log_file_lock; *pthread_mutex_lock(lock); */ sync_lock(&log_priv->log_file_lock,NULL); memset(buffer_str,'\0',MAX_LOG_PRINT_BUFFER_LEN); offset = vsnprintf(buffer_str,MAX_LOG_PRINT_BUFFER_LEN,fmt,vl); ret = log_print_write_log(log_priv->fp,buffer_str); sync_unlock(&log_priv->log_file_lock); /* *pthread_mutex_unlock(&log_priv->log_file_lock); */ return ret; #undef MAX_LOG_PRINT_BUFFER_LEN }
static int control_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; return sync_lock(sdp, mode, flags, GFS2_CONTROL_LOCK, &ls->ls_control_lksb, "control_lock"); }
static int mounted_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags) { struct lm_lockstruct *ls = &sdp->sd_lockstruct; return sync_lock(sdp, mode, flags, GFS2_MOUNTED_LOCK, &ls->ls_mounted_lksb, "mounted_lock"); }
void vfs_user_periodic(uint32_t elapsed_ms) { vfs_user_state_t vfs_state_local; vfs_user_state_t vfs_state_local_prev; sync_assert_usb_thread(); sync_lock(); // Return immediately if the desired state has been reached if (!changing_state()) { sync_unlock(); return; } // Wait until the required amount of time has passed // before changing state if (vfs_state_remaining_ms > 0) { vfs_state_remaining_ms -= MIN(elapsed_ms, vfs_state_remaining_ms); sync_unlock(); return; } vfs_user_printf("vfs_user_periodic()\r\n"); // Transistion to new state vfs_state_local_prev = vfs_state; vfs_state = vfs_state_next; switch (vfs_state) { case VFS_USER_STATE_RECONNECTING: // Transition back to the connected state vfs_state_next = VFS_USER_STATE_CONNECTED; vfs_state_remaining_ms = reconnect_delay_ms; break; default: // No state change logic required in other states break; } vfs_state_local = vfs_state; sync_unlock(); // Processing when leaving a state vfs_user_printf(" state %i->%i\r\n", vfs_state_local_prev, vfs_state_local); switch (vfs_state_local_prev) { case VFS_USER_STATE_DISCONNECTED: // No action needed break; case VFS_USER_STATE_RECONNECTING: // No action needed break; case VFS_USER_STATE_CONNECTED: if (file_transfer_state.stream_open) { error_t status; file_transfer_state.stream_open = false; status = stream_close(); if (ERROR_SUCCESS == fail_reason) { fail_reason = status; } vfs_user_printf(" stream_close ret %i\r\n", status); } // Reset if programming was successful //TODO - move to flash layer if (daplink_is_bootloader() && (ERROR_SUCCESS == fail_reason)) { NVIC_SystemReset(); } // If hold in bootloader has been set then reset after usb is disconnected if (daplink_is_interface() && config_ram_get_hold_in_bl()) { NVIC_SystemReset(); } // Resume the target if configured to do so //TODO - move to flash layer if (config_get_auto_rst()) { target_set_state(RESET_RUN); } break; } // Processing when entering a state switch (vfs_state_local) { case VFS_USER_STATE_DISCONNECTED: USBD_MSC_MediaReady = 0; break; case VFS_USER_STATE_RECONNECTING: USBD_MSC_MediaReady = 0; break; case VFS_USER_STATE_CONNECTED: build_filesystem(); USBD_MSC_MediaReady = 1; break; } return; }
int zmq::socket_base_t::send (msg_t *msg_, int flags_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); // Check whether the library haven't been shut down yet. if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Check whether message passed to the function is valid. if (unlikely (!msg_ || !msg_->check ())) { errno = EFAULT; return -1; } // Process pending commands, if any. int rc = process_commands (0, true); if (unlikely (rc != 0)) { return -1; } // Clear any user-visible flags that are set on the message. msg_->reset_flags (msg_t::more); // At this point we impose the flags on the message. if (flags_ & ZMQ_SNDMORE) msg_->set_flags (msg_t::more); msg_->reset_metadata (); // Try to send the message using method in each socket class rc = xsend (msg_); if (rc == 0) { return 0; } if (unlikely (errno != EAGAIN)) { return -1; } // In case of non-blocking send we'll simply propagate // the error - including EAGAIN - up the stack. if (flags_ & ZMQ_DONTWAIT || options.sndtimeo == 0) { return -1; } // Compute the time when the timeout should occur. // If the timeout is infinite, don't care. int timeout = options.sndtimeo; uint64_t end = timeout < 0 ? 0 : (clock.now_ms () + timeout); // Oops, we couldn't send the message. Wait for the next // command, process it and try to send the message again. // If timeout is reached in the meantime, return EAGAIN. while (true) { if (unlikely (process_commands (timeout, false) != 0)) { return -1; } rc = xsend (msg_); if (rc == 0) break; if (unlikely (errno != EAGAIN)) { return -1; } if (timeout > 0) { timeout = (int) (end - clock.now_ms ()); if (timeout <= 0) { errno = EAGAIN; return -1; } } } return 0; }
void vfs_mngr_periodic(uint32_t elapsed_ms) { bool change_state; vfs_mngr_state_t vfs_state_local; vfs_mngr_state_t vfs_state_local_prev; sync_assert_usb_thread(); sync_lock(); // Return immediately if the desired state has been reached if (!changing_state()) { sync_unlock(); return; } change_state = ready_for_state_change(); if (time_usb_idle < MAX_EVENT_TIME_MS) { time_usb_idle += elapsed_ms; } sync_unlock(); if (!change_state) { return; } vfs_mngr_printf("vfs_mngr_periodic()\r\n"); vfs_mngr_printf(" time_usb_idle=%i\r\n", time_usb_idle); vfs_mngr_printf(" transfer_state=%i\r\n", file_transfer_state.transfer_state); // Transistion to new state vfs_state_local_prev = vfs_state; vfs_state = vfs_state_next; switch (vfs_state) { case VFS_MNGR_STATE_RECONNECTING: // Transition back to the connected state vfs_state_next = VFS_MNGR_STATE_CONNECTED; break; default: // No state change logic required in other states break; } vfs_state_local = vfs_state; time_usb_idle = 0; sync_unlock(); // Processing when leaving a state vfs_mngr_printf(" state %i->%i\r\n", vfs_state_local_prev, vfs_state_local); switch (vfs_state_local_prev) { case VFS_MNGR_STATE_DISCONNECTED: // No action needed break; case VFS_MNGR_STATE_RECONNECTING: // No action needed break; case VFS_MNGR_STATE_CONNECTED: // Close ongoing transfer if there is one if (file_transfer_state.transfer_state != TRASNFER_FINISHED) { vfs_mngr_printf(" transfer timeout\r\n"); file_transfer_state.transfer_timeout = true; transfer_update_state(ERROR_SUCCESS); } util_assert(TRASNFER_FINISHED == file_transfer_state.transfer_state); vfs_user_disconnecting(); break; } // Processing when entering a state switch (vfs_state_local) { case VFS_MNGR_STATE_DISCONNECTED: USBD_MSC_MediaReady = 0; break; case VFS_MNGR_STATE_RECONNECTING: USBD_MSC_MediaReady = 0; break; case VFS_MNGR_STATE_CONNECTED: build_filesystem(); USBD_MSC_MediaReady = 1; break; } return; }
int zmq::socket_base_t::recv (msg_t *msg_, int flags_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); // Check whether the library haven't been shut down yet. if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Check whether message passed to the function is valid. if (unlikely (!msg_ || !msg_->check ())) { errno = EFAULT; return -1; } // Once every inbound_poll_rate messages check for signals and process // incoming commands. This happens only if we are not polling altogether // because there are messages available all the time. If poll occurs, // ticks is set to zero and thus we avoid this code. // // Note that 'recv' uses different command throttling algorithm (the one // described above) from the one used by 'send'. This is because counting // ticks is more efficient than doing RDTSC all the time. if (++ticks == inbound_poll_rate) { if (unlikely (process_commands (0, false) != 0)) { return -1; } ticks = 0; } // Get the message. int rc = xrecv (msg_); if (unlikely (rc != 0 && errno != EAGAIN)) { return -1; } // If we have the message, return immediately. if (rc == 0) { extract_flags (msg_); return 0; } // If the message cannot be fetched immediately, there are two scenarios. // For non-blocking recv, commands are processed in case there's an // activate_reader command already waiting in a command pipe. // If it's not, return EAGAIN. if (flags_ & ZMQ_DONTWAIT || options.rcvtimeo == 0) { if (unlikely (process_commands (0, false) != 0)) { return -1; } ticks = 0; rc = xrecv (msg_); if (rc < 0) { return rc; } extract_flags (msg_); return 0; } // Compute the time when the timeout should occur. // If the timeout is infinite, don't care. int timeout = options.rcvtimeo; uint64_t end = timeout < 0 ? 0 : (clock.now_ms () + timeout); // In blocking scenario, commands are processed over and over again until // we are able to fetch a message. bool block = (ticks != 0); while (true) { if (unlikely (process_commands (block ? timeout : 0, false) != 0)) { return -1; } rc = xrecv (msg_); if (rc == 0) { ticks = 0; break; } if (unlikely (errno != EAGAIN)) { return -1; } block = true; if (timeout > 0) { timeout = (int) (end - clock.now_ms ()); if (timeout <= 0) { errno = EAGAIN; return -1; } } } extract_flags (msg_); return 0; }
int zmq::socket_base_t::term_endpoint (const char *addr_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); // Check whether the library haven't been shut down yet. if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Check whether endpoint address passed to the function is valid. if (unlikely (!addr_)) { errno = EINVAL; return -1; } // Process pending commands, if any, since there could be pending unprocessed process_own()'s // (from launch_child() for example) we're asked to terminate now. int rc = process_commands (0, false); if (unlikely(rc != 0)) { return -1; } // Parse addr_ string. std::string protocol; std::string address; if (parse_uri(addr_, protocol, address) || check_protocol(protocol)) { return -1; } // Disconnect an inproc socket if (protocol == "inproc") { if (unregister_endpoint (std::string(addr_), this) == 0) { return 0; } std::pair <inprocs_t::iterator, inprocs_t::iterator> range = inprocs.equal_range (std::string (addr_)); if (range.first == range.second) { errno = ENOENT; return -1; } for (inprocs_t::iterator it = range.first; it != range.second; ++it) it->second->terminate (true); inprocs.erase (range.first, range.second); return 0; } std::string resolved_addr = std::string (addr_); std::pair <endpoints_t::iterator, endpoints_t::iterator> range; // The resolved last_endpoint is used as a key in the endpoints map. // The address passed by the user might not match in the TCP case due to // IPv4-in-IPv6 mapping (EG: tcp://[::ffff:127.0.0.1]:9999), so try to // resolve before giving up. Given at this stage we don't know whether a // socket is connected or bound, try with both. if (protocol == "tcp") { range = endpoints.equal_range (resolved_addr); if (range.first == range.second) { tcp_address_t *tcp_addr = new (std::nothrow) tcp_address_t (); alloc_assert (tcp_addr); rc = tcp_addr->resolve (address.c_str (), false, options.ipv6); if (rc == 0) { tcp_addr->to_string (resolved_addr); range = endpoints.equal_range (resolved_addr); if (range.first == range.second) { rc = tcp_addr->resolve (address.c_str (), true, options.ipv6); if (rc == 0) { tcp_addr->to_string (resolved_addr); } } } LIBZMQ_DELETE(tcp_addr); } } // Find the endpoints range (if any) corresponding to the addr_ string. range = endpoints.equal_range (resolved_addr); if (range.first == range.second) { errno = ENOENT; return -1; } for (endpoints_t::iterator it = range.first; it != range.second; ++it) { // If we have an associated pipe, terminate it. if (it->second.second != NULL) it->second.second->terminate (false); term_child (it->second.first); } endpoints.erase (range.first, range.second); return 0; }
int zmq::socket_base_t::getsockopt (int option_, void *optval_, size_t *optvallen_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } if (option_ == ZMQ_RCVMORE) { if (*optvallen_ < sizeof (int)) { errno = EINVAL; return -1; } memset(optval_, 0, *optvallen_); *((int*) optval_) = rcvmore ? 1 : 0; *optvallen_ = sizeof (int); return 0; } if (option_ == ZMQ_FD) { if (*optvallen_ < sizeof (fd_t)) { errno = EINVAL; return -1; } if (thread_safe) { // thread safe socket doesn't provide file descriptor errno = EINVAL; return -1; } *((fd_t*)optval_) = ((mailbox_t*)mailbox)->get_fd(); *optvallen_ = sizeof(fd_t); return 0; } if (option_ == ZMQ_EVENTS) { if (*optvallen_ < sizeof (int)) { errno = EINVAL; return -1; } int rc = process_commands (0, false); if (rc != 0 && (errno == EINTR || errno == ETERM)) { return -1; } errno_assert (rc == 0); *((int*) optval_) = 0; if (has_out ()) *((int*) optval_) |= ZMQ_POLLOUT; if (has_in ()) *((int*) optval_) |= ZMQ_POLLIN; *optvallen_ = sizeof (int); return 0; } if (option_ == ZMQ_LAST_ENDPOINT) { if (*optvallen_ < last_endpoint.size () + 1) { errno = EINVAL; return -1; } strncpy(static_cast <char *> (optval_), last_endpoint.c_str(), last_endpoint.size() + 1); *optvallen_ = last_endpoint.size () + 1; return 0; } if (option_ == ZMQ_THREAD_SAFE) { if (*optvallen_ < sizeof (int)) { errno = EINVAL; return -1; } memset(optval_, 0, *optvallen_); *((int*) optval_) = thread_safe ? 1 : 0; *optvallen_ = sizeof (int); return 0; } int rc = options.getsockopt (option_, optval_, optvallen_); return rc; }
int zmq::socket_base_t::bind (const char *addr_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Process pending commands, if any. int rc = process_commands (0, false); if (unlikely (rc != 0)) { return -1; } // Parse addr_ string. std::string protocol; std::string address; if (parse_uri (addr_, protocol, address) || check_protocol (protocol)) { return -1; } if (protocol == "inproc") { const endpoint_t endpoint = { this, options }; rc = register_endpoint (addr_, endpoint); if (rc == 0) { connect_pending (addr_, this); last_endpoint.assign (addr_); options.connected = true; } return rc; } if (protocol == "pgm" || protocol == "epgm" || protocol == "norm") { // For convenience's sake, bind can be used interchangeable with // connect for PGM, EPGM, NORM transports. rc = connect (addr_); if (rc != -1) options.connected = true; return rc; } if (protocol == "udp") { if (!(options.type == ZMQ_DGRAM || options.type == ZMQ_DISH)) { errno = ENOCOMPATPROTO; return -1; } // Choose the I/O thread to run the session in. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; return -1; } address_t *paddr = new (std::nothrow) address_t (protocol, address, this->get_ctx ()); alloc_assert (paddr); paddr->resolved.udp_addr = new (std::nothrow) udp_address_t (); alloc_assert (paddr->resolved.udp_addr); rc = paddr->resolved.udp_addr->resolve (address.c_str(), true); if (rc != 0) { LIBZMQ_DELETE(paddr); return -1; } session_base_t *session = session_base_t::create (io_thread, true, this, options, paddr); errno_assert (session); pipe_t *newpipe = NULL; // Create a bi-directional pipe. object_t *parents [2] = {this, session}; pipe_t *new_pipes [2] = {NULL, NULL}; int hwms [2] = {options.sndhwm, options.rcvhwm}; bool conflates [2] = {false, false}; rc = pipepair (parents, new_pipes, hwms, conflates); errno_assert (rc == 0); // Attach local end of the pipe to the socket object. attach_pipe (new_pipes [0], true); newpipe = new_pipes [0]; // Attach remote end of the pipe to the session object later on. session->attach_pipe (new_pipes [1]); // Save last endpoint URI paddr->to_string (last_endpoint); add_endpoint (addr_, (own_t *) session, newpipe); return 0; } // Remaining transports require to be run in an I/O thread, so at this // point we'll choose one. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; return -1; } if (protocol == "tcp") { tcp_listener_t *listener = new (std::nothrow) tcp_listener_t ( io_thread, this, options); alloc_assert (listener); rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno()); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL); options.connected = true; return 0; } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS if (protocol == "ipc") { ipc_listener_t *listener = new (std::nothrow) ipc_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno()); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL); options.connected = true; return 0; } #endif #if defined ZMQ_HAVE_TIPC if (protocol == "tipc") { tipc_listener_t *listener = new (std::nothrow) tipc_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno()); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (addr_, (own_t *) listener, NULL); options.connected = true; return 0; } #endif #if defined ZMQ_HAVE_VMCI if (protocol == "vmci") { vmci_listener_t *listener = new (std::nothrow) vmci_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno ()); return -1; } listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str(), (own_t *) listener, NULL); options.connected = true; return 0; } #endif zmq_assert (false); return -1; }
int zmq::socket_base_t::connect (const char *addr_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Process pending commands, if any. int rc = process_commands (0, false); if (unlikely (rc != 0)) { return -1; } // Parse addr_ string. std::string protocol; std::string address; if (parse_uri (addr_, protocol, address) || check_protocol (protocol)) { return -1; } if (protocol == "inproc") { // TODO: inproc connect is specific with respect to creating pipes // as there's no 'reconnect' functionality implemented. Once that // is in place we should follow generic pipe creation algorithm. // Find the peer endpoint. endpoint_t peer = find_endpoint (addr_); // The total HWM for an inproc connection should be the sum of // the binder's HWM and the connector's HWM. int sndhwm = 0; if (peer.socket == NULL) sndhwm = options.sndhwm; else if (options.sndhwm != 0 && peer.options.rcvhwm != 0) sndhwm = options.sndhwm + peer.options.rcvhwm; int rcvhwm = 0; if (peer.socket == NULL) rcvhwm = options.rcvhwm; else if (options.rcvhwm != 0 && peer.options.sndhwm != 0) rcvhwm = options.rcvhwm + peer.options.sndhwm; // Create a bi-directional pipe to connect the peers. object_t *parents [2] = {this, peer.socket == NULL ? this : peer.socket}; pipe_t *new_pipes [2] = {NULL, NULL}; bool conflate = options.conflate && (options.type == ZMQ_DEALER || options.type == ZMQ_PULL || options.type == ZMQ_PUSH || options.type == ZMQ_PUB || options.type == ZMQ_SUB); int hwms [2] = {conflate? -1 : sndhwm, conflate? -1 : rcvhwm}; bool conflates [2] = {conflate, conflate}; rc = pipepair (parents, new_pipes, hwms, conflates); if (!conflate) { new_pipes[0]->set_hwms_boost(peer.options.sndhwm, peer.options.rcvhwm); new_pipes[1]->set_hwms_boost(options.sndhwm, options.rcvhwm); } errno_assert (rc == 0); if (!peer.socket) { // The peer doesn't exist yet so we don't know whether // to send the identity message or not. To resolve this, // we always send our identity and drop it later if // the peer doesn't expect it. msg_t id; rc = id.init_size (options.identity_size); errno_assert (rc == 0); memcpy (id.data (), options.identity, options.identity_size); id.set_flags (msg_t::identity); bool written = new_pipes [0]->write (&id); zmq_assert (written); new_pipes [0]->flush (); const endpoint_t endpoint = {this, options}; pend_connection (std::string (addr_), endpoint, new_pipes); } else { // If required, send the identity of the local socket to the peer. if (peer.options.recv_identity) { msg_t id; rc = id.init_size (options.identity_size); errno_assert (rc == 0); memcpy (id.data (), options.identity, options.identity_size); id.set_flags (msg_t::identity); bool written = new_pipes [0]->write (&id); zmq_assert (written); new_pipes [0]->flush (); } // If required, send the identity of the peer to the local socket. if (options.recv_identity) { msg_t id; rc = id.init_size (peer.options.identity_size); errno_assert (rc == 0); memcpy (id.data (), peer.options.identity, peer.options.identity_size); id.set_flags (msg_t::identity); bool written = new_pipes [1]->write (&id); zmq_assert (written); new_pipes [1]->flush (); } // Attach remote end of the pipe to the peer socket. Note that peer's // seqnum was incremented in find_endpoint function. We don't need it // increased here. send_bind (peer.socket, new_pipes [1], false); } // Attach local end of the pipe to this socket object. attach_pipe (new_pipes [0]); // Save last endpoint URI last_endpoint.assign (addr_); // remember inproc connections for disconnect inprocs.insert (inprocs_t::value_type (std::string (addr_), new_pipes [0])); options.connected = true; return 0; } bool is_single_connect = (options.type == ZMQ_DEALER || options.type == ZMQ_SUB || options.type == ZMQ_REQ); if (unlikely (is_single_connect)) { const endpoints_t::iterator it = endpoints.find (addr_); if (it != endpoints.end ()) { // There is no valid use for multiple connects for SUB-PUB nor // DEALER-ROUTER nor REQ-REP. Multiple connects produces // nonsensical results. return 0; } } // Choose the I/O thread to run the session in. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; return -1; } address_t *paddr = new (std::nothrow) address_t (protocol, address, this->get_ctx ()); alloc_assert (paddr); // Resolve address (if needed by the protocol) if (protocol == "tcp") { // Do some basic sanity checks on tcp:// address syntax // - hostname starts with digit or letter, with embedded '-' or '.' // - IPv6 address may contain hex chars and colons. // - IPv6 link local address may contain % followed by interface name / zone_id // (Reference: https://tools.ietf.org/html/rfc4007) // - IPv4 address may contain decimal digits and dots. // - Address must end in ":port" where port is *, or numeric // - Address may contain two parts separated by ':' // Following code is quick and dirty check to catch obvious errors, // without trying to be fully accurate. const char *check = address.c_str (); if (isalnum (*check) || isxdigit (*check) || *check == '[') { check++; while (isalnum (*check) || isxdigit (*check) || *check == '.' || *check == '-' || *check == ':' || *check == '%' || *check == ';' || *check == '[' || *check == ']' || *check == '_' ) { check++; } } // Assume the worst, now look for success rc = -1; // Did we reach the end of the address safely? if (*check == 0) { // Do we have a valid port string? (cannot be '*' in connect check = strrchr (address.c_str (), ':'); if (check) { check++; if (*check && (isdigit (*check))) rc = 0; // Valid } } if (rc == -1) { errno = EINVAL; LIBZMQ_DELETE(paddr); return -1; } // Defer resolution until a socket is opened paddr->resolved.tcp_addr = NULL; } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS else if (protocol == "ipc") { paddr->resolved.ipc_addr = new (std::nothrow) ipc_address_t (); alloc_assert (paddr->resolved.ipc_addr); int rc = paddr->resolved.ipc_addr->resolve (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(paddr); return -1; } } #endif if (protocol == "udp") { if (options.type != ZMQ_RADIO) { errno = ENOCOMPATPROTO; LIBZMQ_DELETE(paddr); return -1; } paddr->resolved.udp_addr = new (std::nothrow) udp_address_t (); alloc_assert (paddr->resolved.udp_addr); rc = paddr->resolved.udp_addr->resolve (address.c_str(), false); if (rc != 0) { LIBZMQ_DELETE(paddr); return -1; } } // TBD - Should we check address for ZMQ_HAVE_NORM??? #ifdef ZMQ_HAVE_OPENPGM if (protocol == "pgm" || protocol == "epgm") { struct pgm_addrinfo_t *res = NULL; uint16_t port_number = 0; int rc = pgm_socket_t::init_address(address.c_str(), &res, &port_number); if (res != NULL) pgm_freeaddrinfo (res); if (rc != 0 || port_number == 0) { return -1; } } #endif #if defined ZMQ_HAVE_TIPC else if (protocol == "tipc") { paddr->resolved.tipc_addr = new (std::nothrow) tipc_address_t (); alloc_assert (paddr->resolved.tipc_addr); int rc = paddr->resolved.tipc_addr->resolve (address.c_str()); if (rc != 0) { LIBZMQ_DELETE(paddr); return -1; } } #endif #if defined ZMQ_HAVE_VMCI else if (protocol == "vmci") { paddr->resolved.vmci_addr = new (std::nothrow) vmci_address_t (this->get_ctx ()); alloc_assert (paddr->resolved.vmci_addr); int rc = paddr->resolved.vmci_addr->resolve (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(paddr); return -1; } } #endif // Create session. session_base_t *session = session_base_t::create (io_thread, true, this, options, paddr); errno_assert (session); // PGM does not support subscription forwarding; ask for all data to be // sent to this pipe. (same for NORM, currently?) bool subscribe_to_all = protocol == "pgm" || protocol == "epgm" || protocol == "norm" || protocol == "udp"; pipe_t *newpipe = NULL; if (options.immediate != 1 || subscribe_to_all) { // Create a bi-directional pipe. object_t *parents [2] = {this, session}; pipe_t *new_pipes [2] = {NULL, NULL}; bool conflate = options.conflate && (options.type == ZMQ_DEALER || options.type == ZMQ_PULL || options.type == ZMQ_PUSH || options.type == ZMQ_PUB || options.type == ZMQ_SUB); int hwms [2] = {conflate? -1 : options.sndhwm, conflate? -1 : options.rcvhwm}; bool conflates [2] = {conflate, conflate}; rc = pipepair (parents, new_pipes, hwms, conflates); errno_assert (rc == 0); // Attach local end of the pipe to the socket object. attach_pipe (new_pipes [0], subscribe_to_all); newpipe = new_pipes [0]; // Attach remote end of the pipe to the session object later on. session->attach_pipe (new_pipes [1]); } // Save last endpoint URI paddr->to_string (last_endpoint); add_endpoint (addr_, (own_t *) session, newpipe); return 0; }