You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
5.5KB

  1. /*
  2. * TCP protocol
  3. * Copyright (c) 2002 Fabrice Bellard.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include "avformat.h"
  20. #include <unistd.h>
  21. #include <ctype.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <netinet/in.h>
  25. #if defined(__APPLE__) || defined(__BEOS__)
  26. typedef int socklen_t;
  27. #endif
  28. #ifndef __BEOS__
  29. # include <arpa/inet.h>
  30. #else
  31. # include "barpainet.h"
  32. #endif
  33. #include <netdb.h>
  34. #include <sys/time.h>
  35. #include <fcntl.h>
  36. typedef struct TCPContext {
  37. int fd;
  38. } TCPContext;
  39. /* resolve host with also IP address parsing */
  40. int resolve_host(struct in_addr *sin_addr, const char *hostname)
  41. {
  42. struct hostent *hp;
  43. if ((inet_aton(hostname, sin_addr)) == 0) {
  44. hp = gethostbyname(hostname);
  45. if (!hp)
  46. return -1;
  47. memcpy (sin_addr, hp->h_addr, sizeof(struct in_addr));
  48. }
  49. return 0;
  50. }
  51. /* return non zero if error */
  52. static int tcp_open(URLContext *h, const char *uri, int flags)
  53. {
  54. struct sockaddr_in dest_addr;
  55. char hostname[1024], *q;
  56. int port, fd = -1;
  57. TCPContext *s;
  58. const char *p;
  59. fd_set wfds;
  60. int fd_max, ret;
  61. struct timeval tv;
  62. socklen_t optlen;
  63. s = av_malloc(sizeof(TCPContext));
  64. if (!s)
  65. return -ENOMEM;
  66. h->priv_data = s;
  67. p = uri;
  68. if (!strstart(p, "tcp://", &p))
  69. goto fail;
  70. q = hostname;
  71. while (*p != ':' && *p != '/' && *p != '\0') {
  72. if ((q - hostname) < sizeof(hostname) - 1)
  73. *q++ = *p;
  74. p++;
  75. }
  76. *q = '\0';
  77. if (*p != ':')
  78. goto fail;
  79. p++;
  80. port = strtoul(p, (char **)&p, 10);
  81. if (port <= 0 || port >= 65536)
  82. goto fail;
  83. dest_addr.sin_family = AF_INET;
  84. dest_addr.sin_port = htons(port);
  85. if (resolve_host(&dest_addr.sin_addr, hostname) < 0)
  86. goto fail;
  87. fd = socket(PF_INET, SOCK_STREAM, 0);
  88. if (fd < 0)
  89. goto fail;
  90. fcntl(fd, F_SETFL, O_NONBLOCK);
  91. redo:
  92. ret = connect(fd, (struct sockaddr *)&dest_addr,
  93. sizeof(dest_addr));
  94. if (ret < 0) {
  95. if (errno == EINTR)
  96. goto redo;
  97. if (errno != EINPROGRESS)
  98. goto fail;
  99. /* wait until we are connected or until abort */
  100. for(;;) {
  101. if (url_interrupt_cb()) {
  102. ret = -EINTR;
  103. goto fail1;
  104. }
  105. fd_max = fd;
  106. FD_ZERO(&wfds);
  107. FD_SET(fd, &wfds);
  108. tv.tv_sec = 0;
  109. tv.tv_usec = 100 * 1000;
  110. ret = select(fd_max + 1, NULL, &wfds, NULL, &tv);
  111. if (ret > 0 && FD_ISSET(fd, &wfds))
  112. break;
  113. }
  114. /* test error */
  115. optlen = sizeof(ret);
  116. getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
  117. if (ret != 0)
  118. goto fail;
  119. }
  120. s->fd = fd;
  121. return 0;
  122. fail:
  123. ret = -EIO;
  124. fail1:
  125. if (fd >= 0)
  126. close(fd);
  127. av_free(s);
  128. return ret;
  129. }
  130. static int tcp_read(URLContext *h, uint8_t *buf, int size)
  131. {
  132. TCPContext *s = h->priv_data;
  133. int size1, len, fd_max;
  134. fd_set rfds;
  135. struct timeval tv;
  136. size1 = size;
  137. while (size > 0) {
  138. if (url_interrupt_cb())
  139. return -EINTR;
  140. fd_max = s->fd;
  141. FD_ZERO(&rfds);
  142. FD_SET(s->fd, &rfds);
  143. tv.tv_sec = 0;
  144. tv.tv_usec = 100 * 1000;
  145. select(fd_max + 1, &rfds, NULL, NULL, &tv);
  146. #ifdef __BEOS__
  147. len = recv(s->fd, buf, size, 0);
  148. #else
  149. len = read(s->fd, buf, size);
  150. #endif
  151. if (len < 0) {
  152. if (errno != EINTR && errno != EAGAIN)
  153. #ifdef __BEOS__
  154. return errno;
  155. #else
  156. return -errno;
  157. #endif
  158. else
  159. continue;
  160. } else if (len == 0) {
  161. break;
  162. }
  163. size -= len;
  164. buf += len;
  165. }
  166. return size1 - size;
  167. }
  168. static int tcp_write(URLContext *h, uint8_t *buf, int size)
  169. {
  170. TCPContext *s = h->priv_data;
  171. int ret, size1, fd_max;
  172. fd_set wfds;
  173. struct timeval tv;
  174. size1 = size;
  175. while (size > 0) {
  176. if (url_interrupt_cb())
  177. return -EINTR;
  178. fd_max = s->fd;
  179. FD_ZERO(&wfds);
  180. FD_SET(s->fd, &wfds);
  181. tv.tv_sec = 0;
  182. tv.tv_usec = 100 * 1000;
  183. select(fd_max + 1, NULL, &wfds, NULL, &tv);
  184. #ifdef __BEOS__
  185. ret = send(s->fd, buf, size, 0);
  186. #else
  187. ret = write(s->fd, buf, size);
  188. #endif
  189. if (ret < 0 && errno != EINTR && errno != EAGAIN)
  190. #ifdef __BEOS__
  191. return errno;
  192. #else
  193. return -errno;
  194. #endif
  195. size -= ret;
  196. buf += ret;
  197. }
  198. return size1 - size;
  199. }
  200. static int tcp_close(URLContext *h)
  201. {
  202. TCPContext *s = h->priv_data;
  203. #ifdef CONFIG_BEOS_NETSERVER
  204. closesocket(s->fd);
  205. #else
  206. close(s->fd);
  207. #endif
  208. av_free(s);
  209. return 0;
  210. }
  211. URLProtocol tcp_protocol = {
  212. "tcp",
  213. tcp_open,
  214. tcp_read,
  215. tcp_write,
  216. NULL, /* seek */
  217. tcp_close,
  218. };