|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2003-2008 Fabrice Bellard ! 3: * Copyright (c) 2009 Red Hat, Inc. ! 4: * ! 5: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 6: * of this software and associated documentation files (the "Software"), to deal ! 7: * in the Software without restriction, including without limitation the rights ! 8: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 9: * copies of the Software, and to permit persons to whom the Software is ! 10: * furnished to do so, subject to the following conditions: ! 11: * ! 12: * The above copyright notice and this permission notice shall be included in ! 13: * all copies or substantial portions of the Software. ! 14: * ! 15: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 16: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 17: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 18: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 19: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 20: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 21: * THE SOFTWARE. ! 22: */ ! 23: ! 24: #include "net/queue.h" ! 25: #include "qemu-queue.h" ! 26: ! 27: /* The delivery handler may only return zero if it will call ! 28: * qemu_net_queue_flush() when it determines that it is once again able ! 29: * to deliver packets. It must also call qemu_net_queue_purge() in its ! 30: * cleanup path. ! 31: * ! 32: * If a sent callback is provided to send(), the caller must handle a ! 33: * zero return from the delivery handler by not sending any more packets ! 34: * until we have invoked the callback. Only in that case will we queue ! 35: * the packet. ! 36: * ! 37: * If a sent callback isn't provided, we just drop the packet to avoid ! 38: * unbounded queueing. ! 39: */ ! 40: ! 41: struct NetPacket { ! 42: QTAILQ_ENTRY(NetPacket) entry; ! 43: VLANClientState *sender; ! 44: unsigned flags; ! 45: int size; ! 46: NetPacketSent *sent_cb; ! 47: uint8_t data[0]; ! 48: }; ! 49: ! 50: struct NetQueue { ! 51: NetPacketDeliver *deliver; ! 52: NetPacketDeliverIOV *deliver_iov; ! 53: void *opaque; ! 54: ! 55: QTAILQ_HEAD(packets, NetPacket) packets; ! 56: ! 57: unsigned delivering : 1; ! 58: }; ! 59: ! 60: NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver, ! 61: NetPacketDeliverIOV *deliver_iov, ! 62: void *opaque) ! 63: { ! 64: NetQueue *queue; ! 65: ! 66: queue = qemu_mallocz(sizeof(NetQueue)); ! 67: ! 68: queue->deliver = deliver; ! 69: queue->deliver_iov = deliver_iov; ! 70: queue->opaque = opaque; ! 71: ! 72: QTAILQ_INIT(&queue->packets); ! 73: ! 74: queue->delivering = 0; ! 75: ! 76: return queue; ! 77: } ! 78: ! 79: void qemu_del_net_queue(NetQueue *queue) ! 80: { ! 81: NetPacket *packet, *next; ! 82: ! 83: QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { ! 84: QTAILQ_REMOVE(&queue->packets, packet, entry); ! 85: qemu_free(packet); ! 86: } ! 87: ! 88: qemu_free(queue); ! 89: } ! 90: ! 91: static ssize_t qemu_net_queue_append(NetQueue *queue, ! 92: VLANClientState *sender, ! 93: unsigned flags, ! 94: const uint8_t *buf, ! 95: size_t size, ! 96: NetPacketSent *sent_cb) ! 97: { ! 98: NetPacket *packet; ! 99: ! 100: packet = qemu_malloc(sizeof(NetPacket) + size); ! 101: packet->sender = sender; ! 102: packet->flags = flags; ! 103: packet->size = size; ! 104: packet->sent_cb = sent_cb; ! 105: memcpy(packet->data, buf, size); ! 106: ! 107: QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); ! 108: ! 109: return size; ! 110: } ! 111: ! 112: static ssize_t qemu_net_queue_append_iov(NetQueue *queue, ! 113: VLANClientState *sender, ! 114: unsigned flags, ! 115: const struct iovec *iov, ! 116: int iovcnt, ! 117: NetPacketSent *sent_cb) ! 118: { ! 119: NetPacket *packet; ! 120: size_t max_len = 0; ! 121: int i; ! 122: ! 123: for (i = 0; i < iovcnt; i++) { ! 124: max_len += iov[i].iov_len; ! 125: } ! 126: ! 127: packet = qemu_malloc(sizeof(NetPacket) + max_len); ! 128: packet->sender = sender; ! 129: packet->sent_cb = sent_cb; ! 130: packet->flags = flags; ! 131: packet->size = 0; ! 132: ! 133: for (i = 0; i < iovcnt; i++) { ! 134: size_t len = iov[i].iov_len; ! 135: ! 136: memcpy(packet->data + packet->size, iov[i].iov_base, len); ! 137: packet->size += len; ! 138: } ! 139: ! 140: QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); ! 141: ! 142: return packet->size; ! 143: } ! 144: ! 145: static ssize_t qemu_net_queue_deliver(NetQueue *queue, ! 146: VLANClientState *sender, ! 147: unsigned flags, ! 148: const uint8_t *data, ! 149: size_t size) ! 150: { ! 151: ssize_t ret = -1; ! 152: ! 153: queue->delivering = 1; ! 154: ret = queue->deliver(sender, flags, data, size, queue->opaque); ! 155: queue->delivering = 0; ! 156: ! 157: return ret; ! 158: } ! 159: ! 160: static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue, ! 161: VLANClientState *sender, ! 162: unsigned flags, ! 163: const struct iovec *iov, ! 164: int iovcnt) ! 165: { ! 166: ssize_t ret = -1; ! 167: ! 168: queue->delivering = 1; ! 169: ret = queue->deliver_iov(sender, flags, iov, iovcnt, queue->opaque); ! 170: queue->delivering = 0; ! 171: ! 172: return ret; ! 173: } ! 174: ! 175: ssize_t qemu_net_queue_send(NetQueue *queue, ! 176: VLANClientState *sender, ! 177: unsigned flags, ! 178: const uint8_t *data, ! 179: size_t size, ! 180: NetPacketSent *sent_cb) ! 181: { ! 182: ssize_t ret; ! 183: ! 184: if (queue->delivering) { ! 185: return qemu_net_queue_append(queue, sender, flags, data, size, NULL); ! 186: } ! 187: ! 188: ret = qemu_net_queue_deliver(queue, sender, flags, data, size); ! 189: if (ret == 0) { ! 190: qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); ! 191: return 0; ! 192: } ! 193: ! 194: qemu_net_queue_flush(queue); ! 195: ! 196: return ret; ! 197: } ! 198: ! 199: ssize_t qemu_net_queue_send_iov(NetQueue *queue, ! 200: VLANClientState *sender, ! 201: unsigned flags, ! 202: const struct iovec *iov, ! 203: int iovcnt, ! 204: NetPacketSent *sent_cb) ! 205: { ! 206: ssize_t ret; ! 207: ! 208: if (queue->delivering) { ! 209: return qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, NULL); ! 210: } ! 211: ! 212: ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt); ! 213: if (ret == 0) { ! 214: qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb); ! 215: return 0; ! 216: } ! 217: ! 218: qemu_net_queue_flush(queue); ! 219: ! 220: return ret; ! 221: } ! 222: ! 223: void qemu_net_queue_purge(NetQueue *queue, VLANClientState *from) ! 224: { ! 225: NetPacket *packet, *next; ! 226: ! 227: QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { ! 228: if (packet->sender == from) { ! 229: QTAILQ_REMOVE(&queue->packets, packet, entry); ! 230: qemu_free(packet); ! 231: } ! 232: } ! 233: } ! 234: ! 235: void qemu_net_queue_flush(NetQueue *queue) ! 236: { ! 237: while (!QTAILQ_EMPTY(&queue->packets)) { ! 238: NetPacket *packet; ! 239: int ret; ! 240: ! 241: packet = QTAILQ_FIRST(&queue->packets); ! 242: QTAILQ_REMOVE(&queue->packets, packet, entry); ! 243: ! 244: ret = qemu_net_queue_deliver(queue, ! 245: packet->sender, ! 246: packet->flags, ! 247: packet->data, ! 248: packet->size); ! 249: if (ret == 0) { ! 250: QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); ! 251: break; ! 252: } ! 253: ! 254: if (packet->sent_cb) { ! 255: packet->sent_cb(packet->sender, ret); ! 256: } ! 257: ! 258: qemu_free(packet); ! 259: } ! 260: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.