PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/src/host/descriptor/shd-socket.c

https://github.com/amiller/shadow
C | 431 lines | 309 code | 86 blank | 36 comment | 35 complexity | 0dbbc1acb36bd42c60eb14450cb04aba MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * The Shadow Simulator
  3. * Copyright (c) 2010-2011, Rob Jansen
  4. * See LICENSE for licensing information
  5. */
  6. #include "shadow.h"
  7. void socket_free(gpointer data) {
  8. Socket* socket = data;
  9. MAGIC_ASSERT(socket);
  10. MAGIC_ASSERT(socket->vtable);
  11. if(socket->peerString) {
  12. g_free(socket->peerString);
  13. }
  14. if(socket->boundString) {
  15. g_free(socket->boundString);
  16. }
  17. if(socket->unixPath) {
  18. g_free(socket->unixPath);
  19. }
  20. while(g_queue_get_length(socket->inputBuffer) > 0) {
  21. packet_unref(g_queue_pop_head(socket->inputBuffer));
  22. }
  23. g_queue_free(socket->inputBuffer);
  24. while(g_queue_get_length(socket->outputBuffer) > 0) {
  25. packet_unref(g_queue_pop_head(socket->outputBuffer));
  26. }
  27. g_queue_free(socket->outputBuffer);
  28. MAGIC_CLEAR(socket);
  29. socket->vtable->free((Descriptor*)socket);
  30. }
  31. void socket_close(Socket* socket) {
  32. MAGIC_ASSERT(socket);
  33. MAGIC_ASSERT(socket->vtable);
  34. Tracker* tracker = host_getTracker(worker_getCurrentHost());
  35. Descriptor* descriptor = (Descriptor *)socket;
  36. tracker_removeSocket(tracker, descriptor->handle);
  37. socket->vtable->close((Descriptor*)socket);
  38. }
  39. gssize socket_sendUserData(Socket* socket, gconstpointer buffer, gsize nBytes,
  40. in_addr_t ip, in_port_t port) {
  41. MAGIC_ASSERT(socket);
  42. MAGIC_ASSERT(socket->vtable);
  43. return socket->vtable->send((Transport*)socket, buffer, nBytes, ip, port);
  44. }
  45. gssize socket_receiveUserData(Socket* socket, gpointer buffer, gsize nBytes,
  46. in_addr_t* ip, in_port_t* port) {
  47. MAGIC_ASSERT(socket);
  48. MAGIC_ASSERT(socket->vtable);
  49. return socket->vtable->receive((Transport*)socket, buffer, nBytes, ip, port);
  50. }
  51. TransportFunctionTable socket_functions = {
  52. (DescriptorFunc) socket_close,
  53. (DescriptorFunc) socket_free,
  54. (TransportSendFunc) socket_sendUserData,
  55. (TransportReceiveFunc) socket_receiveUserData,
  56. MAGIC_VALUE
  57. };
  58. void socket_init(Socket* socket, SocketFunctionTable* vtable, DescriptorType type, gint handle,
  59. guint receiveBufferSize, guint sendBufferSize) {
  60. utility_assert(socket && vtable);
  61. transport_init(&(socket->super), &socket_functions, type, handle);
  62. MAGIC_INIT(socket);
  63. MAGIC_INIT(vtable);
  64. socket->vtable = vtable;
  65. socket->protocol = type == DT_TCPSOCKET ? PTCP : type == DT_UDPSOCKET ? PUDP : PLOCAL;
  66. socket->inputBuffer = g_queue_new();
  67. socket->inputBufferSize = receiveBufferSize;
  68. socket->outputBuffer = g_queue_new();
  69. socket->outputBufferSize = sendBufferSize;
  70. Tracker* tracker = host_getTracker(worker_getCurrentHost());
  71. Descriptor* descriptor = (Descriptor *)socket;
  72. tracker_addSocket(tracker, descriptor->handle, socket->protocol, socket->inputBufferSize, socket->outputBufferSize);
  73. }
  74. enum ProtocolType socket_getProtocol(Socket* socket) {
  75. MAGIC_ASSERT(socket);
  76. return socket->protocol;
  77. }
  78. /* interface functions, implemented by subtypes */
  79. gboolean socket_isFamilySupported(Socket* socket, sa_family_t family) {
  80. MAGIC_ASSERT(socket);
  81. MAGIC_ASSERT(socket->vtable);
  82. return socket->vtable->isFamilySupported(socket, family);
  83. }
  84. gint socket_connectToPeer(Socket* socket, in_addr_t ip, in_port_t port, sa_family_t family) {
  85. MAGIC_ASSERT(socket);
  86. MAGIC_ASSERT(socket->vtable);
  87. Tracker* tracker = host_getTracker(worker_getCurrentHost());
  88. Descriptor* descriptor = (Descriptor *)socket;
  89. tracker_updateSocketPeer(tracker, descriptor->handle, ip, ntohs(port));
  90. return socket->vtable->connectToPeer(socket, ip, port, family);
  91. }
  92. void socket_pushInPacket(Socket* socket, Packet* packet) {
  93. MAGIC_ASSERT(socket);
  94. MAGIC_ASSERT(socket->vtable);
  95. packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_PROCESSED);
  96. return socket->vtable->process(socket, packet);
  97. }
  98. void socket_dropPacket(Socket* socket, Packet* packet) {
  99. MAGIC_ASSERT(socket);
  100. MAGIC_ASSERT(socket->vtable);
  101. return socket->vtable->dropPacket(socket, packet);
  102. }
  103. /* functions implemented by socket */
  104. Packet* socket_pullOutPacket(Socket* socket) {
  105. return socket_removeFromOutputBuffer(socket);
  106. }
  107. Packet* socket_peekNextPacket(const Socket* socket) {
  108. MAGIC_ASSERT(socket);
  109. return g_queue_peek_head(socket->outputBuffer);
  110. }
  111. gboolean socket_getPeerName(Socket* socket, in_addr_t* ip, in_port_t* port) {
  112. MAGIC_ASSERT(socket);
  113. utility_assert(ip && port);
  114. if(socket->peerIP == 0 || socket->peerPort == 0) {
  115. return FALSE;
  116. }
  117. if(ip) {
  118. *ip = socket->peerIP;
  119. }
  120. if(port) {
  121. *port = socket->peerPort;
  122. }
  123. return TRUE;
  124. }
  125. void socket_setPeerName(Socket* socket, in_addr_t ip, in_port_t port) {
  126. MAGIC_ASSERT(socket);
  127. socket->peerIP = ip;
  128. socket->peerPort = port;
  129. /* store the new ascii name of this peer */
  130. if(socket->peerString) {
  131. g_free(socket->peerString);
  132. }
  133. gchar* ipString = address_ipToNewString(ip);
  134. GString* stringBuffer = g_string_new(ipString);
  135. g_free(ipString);
  136. g_string_append_printf(stringBuffer, ":%u", ntohs(port));
  137. socket->peerString = g_string_free(stringBuffer, FALSE);
  138. }
  139. gboolean socket_getSocketName(Socket* socket, in_addr_t* ip, in_port_t* port) {
  140. MAGIC_ASSERT(socket);
  141. /* boundAddress could be 0 (INADDR_NONE), so just check port */
  142. if(!socket_isBound(socket)) {
  143. return FALSE;
  144. }
  145. if(ip) {
  146. *ip = socket->boundAddress;
  147. }
  148. if(port) {
  149. *port = socket->boundPort;
  150. }
  151. return TRUE;
  152. }
  153. void socket_setSocketName(Socket* socket, in_addr_t ip, in_port_t port, gboolean isInternal) {
  154. MAGIC_ASSERT(socket);
  155. socket->boundAddress = ip;
  156. socket->boundPort = port;
  157. /* store the new ascii name of this socket endpoint */
  158. if(socket->boundString) {
  159. g_free(socket->boundString);
  160. }
  161. gchar* ipString = address_ipToNewString(ip);
  162. GString* stringBuffer = g_string_new(ipString);
  163. g_free(ipString);
  164. g_string_append_printf(stringBuffer, ":%u (descriptor %i)", ntohs(port), socket->super.super.handle);
  165. socket->boundString = g_string_free(stringBuffer, FALSE);
  166. /* children of server sockets must not have the same key as the parent
  167. * otherwise when the child is closed, the parent's interface association
  168. * will be removed. in fact, they dont need a key because their parent
  169. * will handle incoming packets and will hand them off as necessary */
  170. if(isInternal) {
  171. socket->associationKey = 0;
  172. } else {
  173. socket->associationKey = PROTOCOL_DEMUX_KEY(socket->protocol, port);
  174. }
  175. /* the socket is now bound */
  176. socket->flags |= SF_BOUND;
  177. }
  178. gboolean socket_isBound(Socket* socket) {
  179. MAGIC_ASSERT(socket);
  180. return (socket->flags & SF_BOUND) ? TRUE : FALSE;
  181. }
  182. gint socket_getAssociationKey(Socket* socket) {
  183. MAGIC_ASSERT(socket);
  184. utility_assert((socket->flags & SF_BOUND));
  185. return socket->associationKey;
  186. }
  187. gsize socket_getInputBufferSpace(Socket* socket) {
  188. MAGIC_ASSERT(socket);
  189. utility_assert(socket->inputBufferSize >= socket->inputBufferLength);
  190. return (socket->inputBufferSize - socket->inputBufferLength);
  191. }
  192. gsize socket_getOutputBufferSpace(Socket* socket) {
  193. MAGIC_ASSERT(socket);
  194. utility_assert(socket->outputBufferSize >= socket->outputBufferLength);
  195. return (socket->outputBufferSize - socket->outputBufferLength);
  196. }
  197. gsize socket_getInputBufferLength(Socket* socket) {
  198. MAGIC_ASSERT(socket);
  199. return socket->inputBufferLength;
  200. }
  201. gsize socket_getOutputBufferLength(Socket* socket) {
  202. MAGIC_ASSERT(socket);
  203. return socket->outputBufferLength;
  204. }
  205. gsize socket_getInputBufferSize(Socket* socket) {
  206. MAGIC_ASSERT(socket);
  207. return socket->inputBufferSize;
  208. }
  209. gsize socket_getOutputBufferSize(Socket* socket) {
  210. MAGIC_ASSERT(socket);
  211. return socket->outputBufferSize;
  212. }
  213. void socket_setInputBufferSize(Socket* socket, gsize newSize) {
  214. MAGIC_ASSERT(socket);
  215. if(newSize >= socket->inputBufferLength) {
  216. socket->inputBufferSize = newSize;
  217. socket->inputBufferSizePending = 0;
  218. } else {
  219. /* ensure positive size, reduce size as buffer drains */
  220. socket->inputBufferSize = socket->inputBufferLength;
  221. socket->inputBufferSizePending = newSize;
  222. }
  223. }
  224. void socket_setOutputBufferSize(Socket* socket, gsize newSize) {
  225. MAGIC_ASSERT(socket);
  226. if(newSize >= socket->outputBufferLength) {
  227. socket->outputBufferSize = newSize;
  228. socket->outputBufferSizePending = 0;
  229. } else {
  230. /* ensure positive size, reduce size as buffer drains */
  231. socket->outputBufferSize = socket->outputBufferLength;
  232. socket->outputBufferSizePending = newSize;
  233. }
  234. }
  235. gboolean socket_addToInputBuffer(Socket* socket, Packet* packet) {
  236. MAGIC_ASSERT(socket);
  237. /* check if the packet fits */
  238. guint length = packet_getPayloadLength(packet);
  239. if(length > socket_getInputBufferSpace(socket)) {
  240. return FALSE;
  241. }
  242. /* add to our queue */
  243. g_queue_push_tail(socket->inputBuffer, packet);
  244. packet_ref(packet);
  245. socket->inputBufferLength += length;
  246. packet_addDeliveryStatus(packet, PDS_RCV_SOCKET_BUFFERED);
  247. /* update the tracker input buffer stats */
  248. Tracker* tracker = host_getTracker(worker_getCurrentHost());
  249. Descriptor* descriptor = (Descriptor *)socket;
  250. tracker_updateSocketInputBuffer(tracker, descriptor->handle, socket->inputBufferLength, socket->inputBufferSize);
  251. /* we just added a packet, so we are readable */
  252. if(socket->inputBufferLength > 0) {
  253. descriptor_adjustStatus((Descriptor*)socket, DS_READABLE, TRUE);
  254. }
  255. return TRUE;
  256. }
  257. Packet* socket_removeFromInputBuffer(Socket* socket) {
  258. MAGIC_ASSERT(socket);
  259. /* see if we have any packets */
  260. Packet* packet = g_queue_pop_head(socket->inputBuffer);
  261. if(packet) {
  262. /* just removed a packet */
  263. guint length = packet_getPayloadLength(packet);
  264. socket->inputBufferLength -= length;
  265. /* check if we need to reduce the buffer size */
  266. if(socket->inputBufferSizePending > 0) {
  267. socket_setInputBufferSize(socket, socket->inputBufferSizePending);
  268. }
  269. /* update the tracker input buffer stats */
  270. Tracker* tracker = host_getTracker(worker_getCurrentHost());
  271. Descriptor* descriptor = (Descriptor *)socket;
  272. tracker_updateSocketInputBuffer(tracker, descriptor->handle, socket->inputBufferLength, socket->inputBufferSize);
  273. /* we are not readable if we are now empty */
  274. if(socket->inputBufferLength <= 0) {
  275. descriptor_adjustStatus((Descriptor*)socket, DS_READABLE, FALSE);
  276. }
  277. }
  278. return packet;
  279. }
  280. gboolean socket_addToOutputBuffer(Socket* socket, Packet* packet) {
  281. MAGIC_ASSERT(socket);
  282. /* check if the packet fits */
  283. guint length = packet_getPayloadLength(packet);
  284. if(length > socket_getOutputBufferSpace(socket)) {
  285. return FALSE;
  286. }
  287. /* add to our queue */
  288. g_queue_push_tail(socket->outputBuffer, packet);
  289. socket->outputBufferLength += length;
  290. packet_addDeliveryStatus(packet, PDS_SND_SOCKET_BUFFERED);
  291. /* update the tracker input buffer stats */
  292. Tracker* tracker = host_getTracker(worker_getCurrentHost());
  293. Descriptor* descriptor = (Descriptor *)socket;
  294. tracker_updateSocketOutputBuffer(tracker, descriptor->handle, socket->outputBufferLength, socket->outputBufferSize);
  295. /* we just added a packet, we are no longer writable if full */
  296. if(socket_getOutputBufferSpace(socket) <= 0) {
  297. descriptor_adjustStatus((Descriptor*)socket, DS_WRITABLE, FALSE);
  298. }
  299. /* tell the interface to include us when sending out to the network */
  300. in_addr_t ip = packet_getSourceIP(packet);
  301. NetworkInterface* interface = host_lookupInterface(worker_getCurrentHost(), ip);
  302. networkinterface_wantsSend(interface, socket);
  303. return TRUE;
  304. }
  305. Packet* socket_removeFromOutputBuffer(Socket* socket) {
  306. MAGIC_ASSERT(socket);
  307. /* see if we have any packets */
  308. Packet* packet = g_queue_pop_head(socket->outputBuffer);
  309. if(packet) {
  310. /* just removed a packet */
  311. guint length = packet_getPayloadLength(packet);
  312. socket->outputBufferLength -= length;
  313. /* check if we need to reduce the buffer size */
  314. if(socket->outputBufferSizePending > 0) {
  315. socket_setOutputBufferSize(socket, socket->outputBufferSizePending);
  316. }
  317. /* update the tracker input buffer stats */
  318. Tracker* tracker = host_getTracker(worker_getCurrentHost());
  319. Descriptor* descriptor = (Descriptor *)socket;
  320. tracker_updateSocketOutputBuffer(tracker, descriptor->handle, socket->outputBufferLength, socket->outputBufferSize);
  321. /* we are writable if we now have space */
  322. if(socket_getOutputBufferSpace(socket) > 0) {
  323. descriptor_adjustStatus((Descriptor*)socket, DS_WRITABLE, TRUE);
  324. }
  325. }
  326. return packet;
  327. }
  328. gboolean socket_isUnix(Socket* socket) {
  329. return (socket->flags & SF_UNIX) ? TRUE : FALSE;
  330. }
  331. void socket_setUnix(Socket* socket, gboolean isUnixSocket) {
  332. MAGIC_ASSERT(socket);
  333. socket->flags = isUnixSocket ? (socket->flags | SF_UNIX) : (socket->flags & ~SF_UNIX);
  334. }
  335. void socket_setUnixPath(Socket* socket, const gchar* path, gboolean isBound) {
  336. MAGIC_ASSERT(socket);
  337. if(isBound) {
  338. socket->flags |= SF_UNIX_BOUND;
  339. }
  340. socket->unixPath = g_strdup(path);
  341. }
  342. gchar* socket_getUnixPath(Socket* socket) {
  343. MAGIC_ASSERT(socket);
  344. return socket->unixPath;
  345. }