ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
                     size_t len, int flags, FAR const struct sockaddr *to,
                     socklen_t tolen)
{
#ifdef CONFIG_NET_UDP
  FAR struct uip_udp_conn *conn;
#ifdef CONFIG_NET_IPv6
  FAR const struct sockaddr_in6 *into = (const struct sockaddr_in6 *)to;
#else
  FAR const struct sockaddr_in *into = (const struct sockaddr_in *)to;
#endif
  struct sendto_s state;
  uip_lock_t save;
  int ret;
#endif
  int err;

  /* If to is NULL or tolen is zero, then this function is same as send (for
   * connected socket types)
   */

  if (!to || !tolen)
    {
#ifdef CONFIG_NET_TCP
      return psock_send(psock, buf, len, flags);
#else
      err = EINVAL;
      goto errout;
#endif
    }

  /* Verify that a valid address has been provided */

#ifdef CONFIG_NET_IPv6
  if (to->sa_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6))
#else
  if (to->sa_family != AF_INET || tolen < sizeof(struct sockaddr_in))
#endif
  {
      err = EBADF;
      goto errout;
  }

  /* Verify that the psock corresponds to valid, allocated socket */

  if (!psock || psock->s_crefs <= 0)
    {
      err = EBADF;
      goto errout;
    }

  /* If this is a connected socket, then return EISCONN */

  if (psock->s_type != SOCK_DGRAM)
    {
      err = EISCONN;
      goto errout;
    }

  /* Perform the UDP sendto operation */

#ifdef CONFIG_NET_UDP
  /* Set the socket state to sending */

  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);

  /* Initialize the state structure.  This is done with interrupts
   * disabled because we don't want anything to happen until we
   * are ready.
   */

  save = uip_lock();
  memset(&state, 0, sizeof(struct sendto_s));
  sem_init(&state.st_sem, 0, 0);
  state.st_buflen = len;
  state.st_buffer = buf;

  /* Set the initial time for calculating timeouts */

#ifdef CONFIG_NET_SENDTO_TIMEOUT
  state.st_sock = psock;
  state.st_time = clock_systimer();
#endif

  /* Setup the UDP socket */

  conn = (struct uip_udp_conn *)psock->s_conn;
  ret = uip_udpconnect(conn, into);
  if (ret < 0)
    {
      uip_unlock(save);
      err = -ret;
      goto errout;
    }

  /* Set up the callback in the connection */

  state.st_cb = uip_udpcallbackalloc(conn);
  if (state.st_cb)
    {
      state.st_cb->flags   = UIP_POLL;
      state.st_cb->priv    = (void*)&state;
      state.st_cb->event   = sendto_interrupt;

      /* Notify the device driver of the availabilty of TX data */

      netdev_txnotify(conn->ripaddr);

      /* Wait for either the receive to complete or for an error/timeout to occur.
       * NOTES:  (1) uip_lockedwait will also terminate if a signal is received, (2)
       * interrupts may be disabled!  They will be re-enabled while the task sleeps
       * and automatically re-enabled when the task restarts.
       */

      uip_lockedwait(&state.st_sem);

      /* Make sure that no further interrupts are processed */

      uip_udpcallbackfree(conn, state.st_cb);
    }
  uip_unlock(save);

  sem_destroy(&state.st_sem);

  /* Set the socket state to idle */

  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);

  /* Check for errors */

  if (state.st_sndlen < 0)
    {
      err = -state.st_sndlen;
      goto errout;
    }

  /* Sucess */

  return state.st_sndlen;
#else
  err = ENOSYS;
#endif

errout:
  set_errno(err);
  return ERROR;
}
Beispiel #2
0
static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
                            FAR struct sockaddr_in *infrom )
#endif
{
  struct uip_udp_conn *conn = (struct uip_udp_conn *)psock->s_conn;
  struct recvfrom_s    state;
  uip_lock_t           save;
  int                  ret;

  /* Perform the UDP recvfrom() operation */

  /* Initialize the state structure.  This is done with interrupts
   * disabled because we don't want anything to happen until we
   * are ready.
   */

  save = uip_lock();
  recvfrom_init(psock, buf, len, infrom, &state);

  /* Setup the UDP remote connection */

  ret = uip_udpconnect(conn, NULL);
  if (ret < 0)
    {
      goto errout_with_state;
    }

  /* Set up the callback in the connection */

  state.rf_cb = uip_udpcallbackalloc(conn);
  if (state.rf_cb)
    {
      /* Set up the callback in the connection */

      state.rf_cb->flags   = UIP_NEWDATA|UIP_POLL;
      state.rf_cb->priv    = (void*)&state;
      state.rf_cb->event   = recvfrom_udpinterrupt;

      /* Enable the UDP socket */

      uip_udpenable(conn);

      /* Wait for either the receive to complete or for an error/timeout to occur.
       * NOTES:  (1) uip_lockedwait will also terminate if a signal is received, (2)
       * interrupts are disabled!  They will be re-enabled while the task sleeps
       * and automatically re-enabled when the task restarts.
       */

      ret = uip_lockedwait(&state. rf_sem);

      /* Make sure that no further interrupts are processed */

      uip_udpdisable(conn);
      uip_udpcallbackfree(conn, state.rf_cb);
      ret = recvfrom_result(ret, &state);
    }
  else
    {
      ret = -EBUSY;
    }

errout_with_state:
  uip_unlock(save);
  recvfrom_uninit(&state);
  return ret;
}