void OSCAcceptPacket(OSCPacketBuffer packet) { if ((packet->n % 4) != 0) { OSCProblem("OSC packet size (%d bytes) not a multiple of 4.", packet->n); DropPacket(packet); return; } #ifdef DEBUG printf("OSCAcceptPacket(OSCPacketBuffer %p, buf %p, size %d)\n", packet, packet->buf, packet->n); #endif /* If the packet came from the user, it's return address is OK. */ packet->returnAddrOK = TRUE; InsertBundleOrMessage(packet->buf, packet->n, packet, OSCTT_Immediately()); #ifdef PARANOID if (packet->refcount == 0) { if (freePackets != packet) { fatal_error("OSCAcceptPacket: packet refcount 0, but it's not the head of the free list!"); } } #endif OSCInvokeAllMessagesThatAreReady(globals.lastTimeTag); }
static void ParseBundle(queuedData *qd) { /* A queued bundle has been removed from the scheduler queue, and now it's time to parse all the stuff inside it and schedule the enclosed messages and bundles. Once all the contents of the bundle have been parsed and scheduled, we trash the bundle, decrementing the packet count and freeing the QD. */ int size; int i = 0; if (qd->type != BUNDLE) { fatal_error("This can't happen: bundle isn't a bundle!"); } while (i < qd->data.bundle.length) { size = *((int *) (qd->data.bundle.bytes + i)); if ((size % 4) != 0) { OSCProblem("Bad size count %d in bundle (not a multiple of 4).", size); DropBundle(qd->data.bundle.bytes, qd->data.bundle.length, qd->myPacket); goto bag; } if ((size + i + 4) > qd->data.bundle.length) { OSCProblem("Bad size count %d in bundle (only %d bytes left in entire bundle).", size, qd->data.bundle.length-i-4); DropBundle(qd->data.bundle.bytes, qd->data.bundle.length, qd->myPacket); goto bag; } /* Recursively handle element of bundle */ InsertBundleOrMessage(qd->data.bundle.bytes+i+4, size, qd->myPacket, qd->timetag); i += 4 + size; } if (i != qd->data.bundle.length) { fatal_error("This can't happen: internal logic error parsing bundle"); } bag: /* If we got here successfully, we've added to the packet's reference count for each message or subbundle by calling InsertBundleOrMessage(), so we remove the one reference for bundle that we just parsed. If we got here by "goto bag", there's a problem with the bundle so we also want to lose the reference count. */ PacketRemoveRef(qd->myPacket); FreeQD(qd); }
callbackList OSCDispatchMessage(char *pattern) { callbackListEnds result; if (pattern[0] != '/') { OSCProblem("Invalid address \"%s\" does not begin with /", pattern); return 0; } result = DispatchSubMessage(pattern+1, OSCTopLevelContainer); return result.begin; }
OSCMethod OSCNewMethod(Name name, OSCcontainer me, methodCallback callback, void *context, struct OSCMethodQueryResponseInfoStruct *QueryResponseInfo) { char addr[LONG_ADDR_SIZE]; OSCMethod m; #ifdef DEBUG printf("OSCNewMethod(name %s, container %p, callback %p, context %p)\n", name, me, callback, context); #endif if (strchr(name, '/') != NULL) { OSCProblem("Method name \"%s\" contains a slash --- not good.", name); return 0; } if (me->numMethods >= MAX_METHODS_PER_CONTAINER) { addr[0] = '\0'; OSCGetAddressString(addr, LONG_ADDR_SIZE, me); OSCProblem("OSCNewMethod: container %s already has %d methods; can't add another\n" "Change MAX_METHODS_PER_CONTAINER in OSC-address-space.c and recompile.", addr, me->numMethods); return 0; } m = AllocMethod(); if (!m) return 0; m->callback = callback; m->context = context; m->QueryResponseInfo = *QueryResponseInfo; me->methodNames[me->numMethods] = name; me->methods[me->numMethods] = m; ++(me->numMethods); return m; }
Boolean OSCGetAddressString(char *target, int maxLength, OSCcontainer c) { int lenNeeded; if (maxLength <= 1) return FALSE; lenNeeded = gasHelp(target, maxLength-1, c) + 1; /* -1, +1 are for null char. */ if (lenNeeded > maxLength) { OSCProblem("Address string too long (room for %d chars; need %d)", maxLength, lenNeeded); target[0] = '\0'; return FALSE; } return TRUE; }
static Boolean ParseMessage(queuedData *qd) { /* Fill in all the information we'll need to execute the message as quickly as possible when the time comes. This means figuring out where the address ends and the arguments begin, and also pattern matching the address to find the callbacks associated with it. The message may be something we have to invoke now, or it may be some message scheduled for the future that's just waiting on the queue; this procedure doesn't care. */ char *args; /* char * so we can do pointer subtraction */ int messageLen; char *DAAS_errormsg; if (qd->type != MESSAGE) { fatal_error("This can't happen: message isn't a message!"); } args = OSCDataAfterAlignedString(qd->data.message.messageName, qd->data.message.messageName+qd->data.message.length, &DAAS_errormsg); if (args == 0) { OSCProblem("Bad message name string: %s\n", DAAS_errormsg); DropMessage(qd->data.message.messageName, qd->data.message.length, qd->myPacket); return FALSE; } qd->data.message.args = args; messageLen = args - qd->data.message.messageName; qd->data.message.argLength = qd->data.message.length - messageLen; qd->data.message.callbacks = OSCDispatchMessage(qd->data.message.messageName); if (qd->data.message.callbacks == 0) { OSCWarning("Message pattern \"%s\" did not correspond to any address in the synth.", qd->data.message.messageName); return FALSE; } return TRUE; }
OSCcontainer OSCNewContainer(Name name, OSCcontainer parent, struct OSCContainerQueryResponseInfoStruct *QueryResponseInfo) { OSCcontainer me; me = AllocContainer(); if (me == 0) return 0; if (strchr(name, '/') != NULL) { OSCProblem("Container name \"%s\" contains a slash --- not good.", name); return 0; } me->parent = parent; AddSubContainer(me->parent, me, name); me->numChildren = 0; me->numMethods = 0; me->QueryResponseInfo = (*QueryResponseInfo); return me; }
static void InsertBundleOrMessage(char *buf, int n, OSCPacketBuffer packet, OSCTimeTag enclosingTimeTag) { Boolean IsBundle; queuedData *qd; /* We add the reference first thing so in case any of the upcoming potential failure situations come we can call PacketRemoveRef, thereby freeing the packet if necessary. */ PacketAddRef(packet); #ifdef PARANOID if ((n % 4) != 0) { OSCProblem("OSC message or bundle size (%d bytes) not a multiple of 4.", n); DropMessage(buf, n, packet) PacketRemoveRef(packet); return; } #endif if ((n >= 8) && (strncmp(buf, "#bundle", 8) == 0)) { IsBundle = TRUE; if (n < 16) { OSCProblem("Bundle message too small (%d bytes) for time tag.", n); DropBundle(buf, n, packet); PacketRemoveRef(packet); return; } } else { IsBundle = FALSE; } qd = AllocQD(); if (qd == 0) { OSCProblem("Not enough memory for queued data!"); DropBundle(buf, n, packet); PacketRemoveRef(packet); return; } qd->myPacket = packet; qd->type = IsBundle ? BUNDLE : MESSAGE; if (IsBundle) { /* Be careful of 8-byte alignment when copying the time tag. Here's a good way to get a bus error when buf happens not to be 8-byte aligned: qd->timetag = *((OSCTimeTag *)(buf+8)); */ memcpy(&(qd->timetag), buf+8, sizeof(OSCTimeTag)); if (OSCTT_Compare(qd->timetag, enclosingTimeTag) < 0) { OSCProblem("Time tag of sub-bundle is before time tag of enclosing bundle."); DropBundle(buf, n, packet); PacketRemoveRef(packet); FreeQD(qd); return; } qd->data.bundle.bytes = buf + 16; qd->data.bundle.length = n - 16; } else { qd->timetag = enclosingTimeTag; qd->data.message.messageName = buf; qd->data.message.length = n; qd->data.message.callbacks = NOT_DISPATCHED_YET; } OSCQueueInsert(globals.TheQueue, (OSCSchedulableObject) qd); }