Una operación bloqueante sobre un socket queda bloqueada hasta completar la tarea, o que surja una condición de error (por ejemplo que el socket sea cerrado por la otra punta).
Tu función completeSend es en realidad una implementación de un send bloqueante implementado sobre send no bloqueantes (muy parecida a la que hay realmente dentro de una biblioteca de sockets)