FSocket_Posix.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. // FSocket was adapted from K.A. Knizhnik's very nice SAL library.
  2. #if defined(__svr4__)
  3. #define mutex system_mutex
  4. #endif
  5. #if defined(__FreeBSD__) || defined(__linux__) || defined(__CYGWIN__) || defined(__APPLE__)
  6. #include <sys/ioctl.h>
  7. #else
  8. #include <stropts.h>
  9. #endif
  10. #include <fcntl.h>
  11. #include <sys/time.h>
  12. #include <sys/errno.h>
  13. #include <sys/types.h>
  14. #include <sys/socket.h>
  15. #include <sys/utsname.h>
  16. #include <netinet/in.h>
  17. #include <arpa/inet.h>
  18. #ifndef __CYGWIN__
  19. #include <netinet/tcp.h>
  20. #endif
  21. #include <unistd.h>
  22. #include <errno.h>
  23. extern "C" {
  24. #include <netdb.h>
  25. }
  26. #undef mutex
  27. #include <assert.h>
  28. #include <string.h>
  29. #include <stdio.h>
  30. #include <stddef.h>
  31. #include <stdlib.h>
  32. #include "FSocket_Posix.H"
  33. #include <signal.h>
  34. #define MAX_HOST_NAME 256
  35. const char* FSocket_Posix::unix_socket_dir = "/tmp/";
  36. class FSocket_Posix_library {
  37. public:
  38. FSocket_Posix_library() {
  39. static struct sigaction sigpipe_ignore;
  40. sigpipe_ignore.sa_handler = SIG_IGN;
  41. sigaction(SIGPIPE, &sigpipe_ignore, NULL);
  42. }
  43. };
  44. static FSocket_Posix_library unisock_lib;
  45. int FSocket_Posix::open(int listen_queue_size) {
  46. char hostname[MAX_HOST_NAME];
  47. unsigned short port;
  48. char* p;
  49. assert(address != NULL);
  50. if ((p = strchr(address, ':')) == NULL
  51. || unsigned(p - address) >= sizeof(hostname)
  52. || sscanf(p+1, "%hd", &port) != 1) {
  53. errcode = bad_address;
  54. return 0;
  55. }
  56. memcpy(hostname, address, p - address);
  57. hostname[p - address] = '\0';
  58. create_file = 0;
  59. union {
  60. sockaddr sock;
  61. sockaddr_in sock_inet;
  62. //char name[MAX_HOST_NAME];
  63. } u;
  64. int sa_length;
  65. if (domain == sock_local_domain) {
  66. u.sock.sa_family = AF_UNIX;
  67. assert(strlen(unix_socket_dir) + strlen(address)
  68. < MAX_HOST_NAME - offsetof(sockaddr,sa_data));
  69. sa_length = offsetof(sockaddr,sa_data) +
  70. sprintf(u.sock.sa_data,"%s%s", unix_socket_dir, address);
  71. unlink(u.sock.sa_data); // remove file if existed
  72. create_file = 1;
  73. } else {
  74. u.sock_inet.sin_family= AF_INET;
  75. u.sock_inet.sin_addr.s_addr = htonl(INADDR_ANY);
  76. u.sock_inet.sin_port = htons(port);
  77. sa_length = sizeof(sockaddr_in);
  78. }
  79. if ((fd = socket(u.sock.sa_family, SOCK_STREAM, 0)) < 0) {
  80. errcode = errno;
  81. return 0;
  82. }
  83. if (bind(fd, &u.sock, sa_length) < 0) {
  84. errcode = errno;
  85. ::close(fd);
  86. return 0;
  87. }
  88. if (listen(fd, listen_queue_size) < 0) {
  89. errcode = errno;
  90. ::close(fd);
  91. return 0;
  92. }
  93. errcode = ok;
  94. state = ss_open;
  95. return 1;
  96. }
  97. int FSocket_Posix::valid() {
  98. return errcode == ok;
  99. }
  100. void FSocket_Posix::get_error_text(char* buf, size_t buf_size) {
  101. const char* msg;
  102. switch(errcode) {
  103. case ok:
  104. msg = "ok";
  105. break;
  106. case not_opened:
  107. msg = "socket not opened";
  108. break;
  109. case bad_address:
  110. msg = "bad address";
  111. break;
  112. case connection_failed:
  113. msg = "exceed limit of attempts of connection to server";
  114. break;
  115. case broken_pipe:
  116. msg = "connection is broken";
  117. break;
  118. case invalid_access_mode:
  119. msg = "invalid access mode";
  120. break;
  121. default:
  122. msg = strerror(errcode);
  123. }
  124. strncpy(buf, msg, buf_size);
  125. }
  126. FSocket* FSocket_Posix::accept() {
  127. int s;
  128. if (state != ss_open) {
  129. errcode = not_opened;
  130. return NULL;
  131. }
  132. while((s = ::accept(fd, NULL, NULL )) < 0 && errno == EINTR);
  133. if (s < 0) {
  134. errcode = errno;
  135. return NULL;
  136. } else if (state != ss_open) {
  137. errcode = not_opened;
  138. return NULL;
  139. } else {
  140. static struct linger l = {1, LINGER_TIME};
  141. if (domain == sock_global_domain) {
  142. int enabled = 1;
  143. if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&enabled,
  144. sizeof enabled) != 0) {
  145. errcode = errno;
  146. ::close(s);
  147. return NULL;
  148. }
  149. }
  150. if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof l) != 0) {
  151. errcode = invalid_access_mode;
  152. ::close(s);
  153. return NULL;
  154. }
  155. errcode = ok;
  156. return new FSocket_Posix(s);
  157. }
  158. }
  159. int FSocket_Posix::cancel_accept() {
  160. // Wakeup listener
  161. state = ss_shutdown;
  162. delete FSocket::connect(address, domain, 1, 0);
  163. return 1;
  164. }
  165. int FSocket_Posix::connect(int max_attempts, time_t timeout) {
  166. int rc;
  167. char* p;
  168. char hostname[MAX_HOST_NAME];
  169. unsigned short port;
  170. assert(address != NULL);
  171. if (domain != sock_local_domain) {
  172. if ((p = strchr(address, ':')) == NULL
  173. || unsigned(p - address) >= sizeof(hostname)
  174. || sscanf(p+1, "%hd", &port) != 1) {
  175. errcode = bad_address;
  176. return 0;
  177. }
  178. memcpy(hostname, address, p - address);
  179. hostname[p - address] = '\0';
  180. }
  181. create_file = 0;
  182. union {
  183. sockaddr sock;
  184. sockaddr_in sock_inet;
  185. char name[MAX_HOST_NAME];
  186. } u;
  187. int sa_length;
  188. if (domain == sock_local_domain || (domain == sock_any_domain &&
  189. strcmp(hostname, "localhost") == 0)) {
  190. // connect UNIX socket
  191. u.sock.sa_family = AF_UNIX;
  192. assert(strlen(unix_socket_dir) + strlen(address)
  193. < MAX_HOST_NAME - offsetof(sockaddr,sa_data));
  194. sa_length = offsetof(sockaddr,sa_data) +
  195. sprintf(u.sock.sa_data, "%s%s", unix_socket_dir, address);
  196. } else {
  197. u.sock_inet.sin_family = AF_INET;
  198. u.sock_inet.sin_addr.s_addr = inet_addr(hostname);
  199. if ((int)(u.sock_inet.sin_addr.s_addr) == -1) {
  200. struct hostent* hp; // entry in hosts table
  201. if ((hp=gethostbyname(hostname)) == NULL ||
  202. hp->h_addrtype != AF_INET) {
  203. errcode = bad_address;
  204. return 0;
  205. }
  206. memcpy(&u.sock_inet.sin_addr,hp->h_addr,sizeof u.sock_inet.sin_addr);
  207. }
  208. u.sock_inet.sin_port = htons(port);
  209. sa_length = sizeof(u.sock_inet);
  210. }
  211. while (1) {
  212. if ((fd = socket(u.sock.sa_family, SOCK_STREAM, 0)) < 0) {
  213. errcode = errno;
  214. return 0;
  215. }
  216. do {
  217. rc = ::connect(fd, &u.sock, sa_length);
  218. } while (rc < 0 && errno == EINTR);
  219. if (rc < 0) {
  220. errcode = errno;
  221. ::close(fd);
  222. if (errcode == ENOENT || errcode == ECONNREFUSED) {
  223. if (--max_attempts > 0) {
  224. sleep(timeout);
  225. } else {
  226. break;
  227. }
  228. } else {
  229. return 0;
  230. }
  231. } else {
  232. if (u.sock_inet.sin_family == AF_INET) {
  233. int enabled = 1;
  234. if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&enabled,
  235. sizeof enabled) != 0)
  236. {
  237. errcode = errno;
  238. ::close(fd);
  239. return 0;
  240. }
  241. }
  242. errcode = ok;
  243. state = ss_open;
  244. return 1;
  245. }
  246. }
  247. errcode = connection_failed;
  248. return 0;
  249. }
  250. int FSocket_Posix::read(void* buf, size_t min_size, size_t max_size,
  251. time_t timeout) {
  252. size_t size = 0;
  253. time_t start = 0;
  254. if (state != ss_open) {
  255. errcode = not_opened;
  256. return -1;
  257. }
  258. if (timeout != WAIT_FOREVER) {
  259. start = time(NULL);
  260. }
  261. do {
  262. ssize_t rc;
  263. if (timeout != WAIT_FOREVER) {
  264. fd_set events;
  265. struct timeval tm;
  266. FD_ZERO(&events);
  267. FD_SET(fd, &events);
  268. tm.tv_sec = timeout;
  269. tm.tv_usec = 0;
  270. while ((rc = select(fd+1, &events, NULL, NULL, &tm)) < 0
  271. && errno == EINTR);
  272. if (rc < 0) {
  273. errcode = errno;
  274. return -1;
  275. }
  276. if (rc == 0) {
  277. return size;
  278. }
  279. time_t now = time(NULL);
  280. timeout = start + timeout >= now ? 0 : timeout + start - now;
  281. }
  282. while ((rc = ::read(fd, (char*)buf + size, max_size - size)) < 0
  283. && errno == EINTR);
  284. if (rc < 0) {
  285. errcode = errno;
  286. return -1;
  287. } else if (rc == 0) {
  288. errcode = broken_pipe;
  289. return -1;
  290. } else {
  291. size += rc;
  292. }
  293. } while (size < min_size);
  294. return (int)size;
  295. }
  296. int FSocket_Posix::read(void* buf, size_t size) {
  297. if (state != ss_open) {
  298. errcode = not_opened;
  299. return 0;
  300. }
  301. do {
  302. ssize_t rc;
  303. while ((rc = ::read(fd, buf, size)) < 0 && errno == EINTR);
  304. if (rc < 0) {
  305. errcode = errno;
  306. return 0;
  307. } else if (rc == 0) {
  308. errcode = broken_pipe;
  309. return 0;
  310. } else {
  311. buf = (char*)buf + rc;
  312. size -= rc;
  313. }
  314. } while (size != 0);
  315. return 1;
  316. }
  317. int FSocket_Posix::write(void const* buf, size_t size) {
  318. if (state != ss_open) {
  319. errcode = not_opened;
  320. return 0;
  321. }
  322. do {
  323. ssize_t rc;
  324. while ((rc = ::write(fd, buf, size)) < 0 && errno == EINTR);
  325. if (rc < 0) {
  326. errcode = errno;
  327. return 0;
  328. } else if (rc == 0) {
  329. errcode = broken_pipe;
  330. return 0;
  331. } else {
  332. buf = (char*)buf + rc;
  333. size -= rc;
  334. }
  335. } while (size != 0);
  336. //
  337. // errcode is not assigned 'ok' value beacuse write function
  338. // can be called in parallel with other socket operations, so
  339. // we want to preserve old error code here.
  340. //
  341. return 1;
  342. }
  343. int FSocket_Posix::close() {
  344. if (state != ss_close) {
  345. state = ss_close;
  346. if (::close(fd) == 0) {
  347. errcode = ok;
  348. return 1;
  349. } else {
  350. errcode = errno;
  351. return 0;
  352. }
  353. }
  354. errcode = ok;
  355. return 1;
  356. }
  357. int FSocket_Posix::shutdown() {
  358. if (state == ss_open) {
  359. state = ss_shutdown;
  360. int rc = ::shutdown(fd, 2);
  361. if (rc != 0) {
  362. errcode = errno;
  363. return 0;
  364. }
  365. }
  366. return 1;
  367. }
  368. FSocket_Posix::~FSocket_Posix() {
  369. close();
  370. if (create_file) {
  371. char name[MAX_HOST_NAME];
  372. sprintf(name, "%s%s", unix_socket_dir, address);
  373. unlink(name);
  374. }
  375. delete[] address;
  376. }
  377. FSocket_Posix::FSocket_Posix(const char* addr, socket_domain domain) {
  378. address = strdup(addr);
  379. this->domain = domain;
  380. create_file = 0;
  381. errcode = ok;
  382. }
  383. FSocket_Posix::FSocket_Posix(int new_fd) {
  384. fd = new_fd;
  385. address = NULL;
  386. create_file = 0;
  387. state = ss_open;
  388. errcode = ok;
  389. }
  390. FSocket* FSocket::create_local(char const* address, int listen_queue_size) {
  391. FSocket_Posix* sock = new FSocket_Posix(address, sock_local_domain);
  392. sock->open(listen_queue_size);
  393. return sock;
  394. }
  395. FSocket* FSocket::create_global(char const* address, int listen_queue_size) {
  396. FSocket_Posix* sock = new FSocket_Posix(address, sock_global_domain);
  397. sock->open(listen_queue_size);
  398. return sock;
  399. }
  400. FSocket* FSocket::connect(char const* address,
  401. socket_domain domain,
  402. int max_attempts,
  403. time_t timeout) {
  404. FSocket_Posix* sock = new FSocket_Posix(address, domain);
  405. sock->connect(max_attempts, timeout);
  406. return sock;
  407. }
  408. char const* get_process_name() {
  409. static char name[MAX_HOST_NAME+8];
  410. struct utsname local_host;
  411. uname(&local_host);
  412. sprintf(name, "%s:%d", local_host.nodename, (int)getpid());
  413. return name;
  414. }