int _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { #ifdef HAVE_W32_SYSTEM if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) { struct sockaddr_in myaddr; struct sockaddr_un *unaddr; unsigned short port; char nonce[16]; int ret; unaddr = (struct sockaddr_un *)addr; if (read_port_and_nonce (unaddr->sun_path, &port, nonce)) return -1; myaddr.sin_family = AF_INET; myaddr.sin_port = htons (port); myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); /* Set return values. */ unaddr->sun_family = myaddr.sin_family; unaddr->sun_port = myaddr.sin_port; unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; ret = connect (HANDLE2SOCKET(sockfd), (struct sockaddr *)&myaddr, sizeof myaddr); if (!ret) { /* Send the nonce. */ ret = _assuan_io_write (sockfd, nonce, 16); if (ret >= 0 && ret != 16) { errno = EIO; ret = -1; } } return ret; } else { int res; res = connect (HANDLE2SOCKET (sockfd), addr, addrlen); if (res < 0) errno = _assuan_sock_wsa2errno (WSAGetLastError ()); return res; } #else return connect (sockfd, addr, addrlen); #endif }
/* Write to the domain server. */ static ssize_t uds_writer (assuan_context_t ctx, const void *buf, size_t buflen) { #ifndef HAVE_W32_SYSTEM struct msghdr msg; struct iovec iovec; ssize_t len; memset (&msg, 0, sizeof (msg)); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iovlen = 1; msg.msg_iov = &iovec; iovec.iov_base = (void*)buf; iovec.iov_len = buflen; len = _assuan_sendmsg (ctx, ctx->outbound.fd, &msg, 0); return len; #else /*HAVE_W32_SYSTEM*/ int res = sendto (HANDLE2SOCKET(ctx->outbound.fd), buf, buflen, 0, (struct sockaddr *)&ctx->serveraddr, sizeof (struct sockaddr_in)); if (res < 0) gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ())); return res; #endif /*HAVE_W32_SYSTEM*/ }
/* Close the given file descriptor, created with _assuan_pipe or one of the socket functions. Default implementation. */ int __assuan_close (assuan_context_t ctx, assuan_fd_t fd) { int rc = closesocket (HANDLE2SOCKET(fd)); if (rc) gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()) ); if (rc && WSAGetLastError () == WSAENOTSOCK) { rc = CloseHandle (fd); if (rc) /* FIXME. */ gpg_err_set_errno (EIO); } return rc; }
int _assuan_close (assuan_fd_t fd) { #ifdef HAVE_W32_SYSTEM int rc = closesocket (HANDLE2SOCKET(fd)); if (rc) errno = _assuan_sock_wsa2errno (WSAGetLastError ()); if (rc && WSAGetLastError () == WSAENOTSOCK) { rc = CloseHandle (fd); if (rc) /* FIXME. */ errno = EIO; } return rc; #else return close (fd); #endif }
/* Close the given file descriptor, created with _assuan_pipe or one of the socket functions. Default implementation. */ int __assuan_close (assuan_context_t ctx, assuan_fd_t fd) { int rc = closesocket (HANDLE2SOCKET(fd)); int err = WSAGetLastError (); /* Note that gpg_err_set_errno on Windows CE overwrites WSAGetLastError() (via SetLastError()). */ if (rc) gpg_err_set_errno (_assuan_sock_wsa2errno (err)); if (rc && err == WSAENOTSOCK) { rc = CloseHandle (fd); if (rc) /* FIXME. */ gpg_err_set_errno (EIO); } return rc; }
static int accept_connection (assuan_context_t ctx) { assuan_fd_t fd; struct sockaddr_un clnt_addr; socklen_t len = sizeof clnt_addr; fd = SOCKET2HANDLE(accept (HANDLE2SOCKET(ctx->listen_fd), (struct sockaddr*)&clnt_addr, &len )); if (fd == ASSUAN_INVALID_FD) { ctx->os_errno = errno; return _assuan_error (ASSUAN_Accept_Failed); } if (_assuan_sock_check_nonce (fd, &ctx->listen_nonce)) { _assuan_close (fd); ctx->os_errno = EACCES; return _assuan_error (ASSUAN_Accept_Failed); } ctx->connected_fd = fd; return accept_connection_bottom (ctx); }
int _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { #ifdef HAVE_W32_SYSTEM if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) { struct sockaddr_in myaddr; struct sockaddr_un *unaddr; HANDLE filehd; int len = sizeof myaddr; int rc; char nonce[16]; char tmpbuf[33+16]; DWORD nwritten; if (get_nonce (nonce, 16)) return -1; unaddr = (struct sockaddr_un *)addr; myaddr.sin_port = 0; myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); filehd = MyCreateFile (unaddr->sun_path, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if (filehd == INVALID_HANDLE_VALUE) { if (GetLastError () == ERROR_FILE_EXISTS) gpg_err_set_errno (WSAEADDRINUSE); return -1; } rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len); if (!rc) rc = getsockname (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, &len); if (rc) { int save_e = errno; CloseHandle (filehd); MyDeleteFile (unaddr->sun_path); gpg_err_set_errno (save_e); return rc; } snprintf (tmpbuf, sizeof tmpbuf, "%d\n", ntohs (myaddr.sin_port)); len = strlen (tmpbuf); memcpy (tmpbuf+len, nonce,16); len += 16; if (!WriteFile (filehd, tmpbuf, len, &nwritten, NULL)) { CloseHandle (filehd); MyDeleteFile (unaddr->sun_path); gpg_err_set_errno (EIO); return -1; } CloseHandle (filehd); return 0; } else { int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen); if (res < 0) gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ())); return res; } #else return bind (sockfd, addr, addrlen); #endif }
ssize_t __assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size) { int res; int ec = 0; if (is_socket (fd)) { int tries = 3; again: ec = 0; res = send (HANDLE2SOCKET (fd), buffer, size, 0); if (res == -1) ec = WSAGetLastError (); if (ec == WSAEWOULDBLOCK && tries--) { /* EAGAIN: Use select to wait for resources and try again. We do this 3 times and then give up. The higher level layer then needs to take care of EAGAIN. No need to specify a timeout - the socket is not expected to be in blocking mode. */ fd_set fds; FD_ZERO (&fds); FD_SET (HANDLE2SOCKET (fd), &fds); select (0, NULL, &fds, NULL, NULL); goto again; } } else { DWORD nwrite; if (!WriteFile (fd, buffer, size, &nwrite, NULL)) { res = -1; ec = GetLastError (); } else res = (int)nwrite; } if (res == -1) { switch (ec) { case WSAENOTSOCK: gpg_err_set_errno (EBADF); break; case WSAEWOULDBLOCK: gpg_err_set_errno (EAGAIN); break; case ERROR_BROKEN_PIPE: case ERROR_NO_DATA: gpg_err_set_errno (EPIPE); break; default: gpg_err_set_errno (EIO); break; } } return res; }
int _assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { #ifdef HAVE_W32_SYSTEM if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) { struct sockaddr_in myaddr; struct sockaddr_un *unaddr; int filefd; FILE *fp; int len = sizeof myaddr; int rc; char nonce[16]; if (get_nonce (nonce, 16)) return -1; unaddr = (struct sockaddr_un *)addr; myaddr.sin_port = 0; myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); filefd = open (unaddr->sun_path, (O_WRONLY|O_CREAT|O_EXCL|O_BINARY), (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)); if (filefd == -1) { if (errno == EEXIST) errno = WSAEADDRINUSE; return -1; } fp = fdopen (filefd, "wb"); if (!fp) { int save_e = errno; close (filefd); errno = save_e; return -1; } rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len); if (!rc) rc = getsockname (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, &len); if (rc) { int save_e = errno; fclose (fp); remove (unaddr->sun_path); errno = save_e; return rc; } fprintf (fp, "%d\n", ntohs (myaddr.sin_port)); fwrite (nonce, 16, 1, fp); fclose (fp); return 0; } else { int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen); if (res < 0) errno = _assuan_sock_wsa2errno (WSAGetLastError ()); return res; } #else return bind (sockfd, addr, addrlen); #endif }
static ssize_t __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) { /* Due to the peculiarities of the W32 API we can't use read for a network socket and thus we try to use recv first and fallback to read if recv detects that it is not a network socket. */ int res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx, "fd=0x%x, buffer=%p, size=%i", fd, buffer, size); #ifdef HAVE_W32CE_SYSTEM /* This is a bit of a hack to support stdin over ssh. Note that fread buffers fully while getchar is line buffered. Weird, but that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are special handle values that shouldn't occur in the wild. */ if (fd == ASSUAN_STDIN) { int i = 0; int chr; while (i < size) { chr = getchar(); if (chr == EOF) break; ((char*)buffer)[i++] = (char) chr; if (chr == '\n') break; } return TRACE_SYSRES (i); } #endif res = recv (HANDLE2SOCKET (fd), buffer, size, 0); if (res == -1) { TRACE_LOG1 ("recv failed: rc=%d", (int)WSAGetLastError ()); switch (WSAGetLastError ()) { case WSAENOTSOCK: { DWORD nread = 0; res = ReadFile (fd, buffer, size, &nread, NULL); if (! res) { TRACE_LOG1 ("ReadFile failed: rc=%d", (int)GetLastError ()); switch (GetLastError ()) { case ERROR_BROKEN_PIPE: gpg_err_set_errno (EPIPE); break; case ERROR_PIPE_NOT_CONNECTED: case ERROR_BUSY: gpg_err_set_errno (EAGAIN); break; default: gpg_err_set_errno (EIO); } res = -1; } else res = (int) nread; } break; case WSAEWOULDBLOCK: gpg_err_set_errno (EAGAIN); break; case ERROR_BROKEN_PIPE: gpg_err_set_errno (EPIPE); break; default: gpg_err_set_errno (EIO); break; } } return TRACE_SYSRES (res); }
/* Read from a unix domain socket using sendmsg. */ static ssize_t uds_reader (assuan_context_t ctx, void *buf, size_t buflen) { #ifndef HAVE_W32_SYSTEM int len = 0; /* This loop should be OK. As FDs are followed by data, the readable status of the socket does not change and no new select/event-loop round is necessary. */ while (!len) /* No data is buffered. */ { struct msghdr msg; struct iovec iovec; #ifdef USE_DESCRIPTOR_PASSING union { struct cmsghdr cm; char control[CMSG_SPACE(sizeof (int))]; } control_u; struct cmsghdr *cmptr; #endif /*USE_DESCRIPTOR_PASSING*/ memset (&msg, 0, sizeof (msg)); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iovec; msg.msg_iovlen = 1; iovec.iov_base = buf; iovec.iov_len = buflen; #ifdef USE_DESCRIPTOR_PASSING msg.msg_control = control_u.control; msg.msg_controllen = sizeof (control_u.control); #endif len = _assuan_recvmsg (ctx, ctx->inbound.fd, &msg, 0); if (len < 0) return -1; if (len == 0) return 0; #ifdef USE_DESCRIPTOR_PASSING cmptr = CMSG_FIRSTHDR (&msg); if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int))) { if (cmptr->cmsg_level != SOL_SOCKET || cmptr->cmsg_type != SCM_RIGHTS) TRACE0 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx, "unexpected ancillary data received"); else { int fd; memcpy (&fd, CMSG_DATA (cmptr), sizeof (fd)); if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds)) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "uds_reader", ctx, "too many descriptors pending - " "closing received descriptor %d", fd); _assuan_close (ctx, fd); } else ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd; } } #endif /*USE_DESCRIPTOR_PASSING*/ } return len; #else /*HAVE_W32_SYSTEM*/ int res = recvfrom (HANDLE2SOCKET(ctx->inbound.fd), buf, buflen, 0, NULL, NULL); if (res < 0) gpg_err_set_errno (_assuan_sock_wsa2errno (WSAGetLastError ())); return res; #endif /*HAVE_W32_SYSTEM*/ }